Decompiled source of Sideload v1.33.0

Sideload.dll

Decompiled a month ago
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.WebSockets;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.ExceptionServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using AngleSharp.Dom;
using AngleSharp.Html.Dom;
using AngleSharp.Html.Parser;
using Esprima;
using Esprima.Ast;
using HarmonyLib;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppScheduleOne;
using Il2CppScheduleOne.Building;
using Il2CppScheduleOne.DevUtilities;
using Il2CppScheduleOne.PlayerScripts;
using Il2CppScheduleOne.State;
using Il2CppScheduleOne.UI;
using Il2CppScheduleOne.UI.Input;
using Il2CppScheduleOne.UI.Phone;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Il2CppTMPro;
using Jint;
using Jint.Native;
using Jint.Native.Function;
using Jint.Native.Object;
using Jint.Runtime;
using Jint.Runtime.Descriptors;
using Jint.Runtime.Interop;
using MelonLoader;
using MelonLoader.Preferences;
using MelonLoader.Utils;
using Microsoft.CodeAnalysis;
using Sideload;
using Sideload.Bundle;
using Sideload.Config;
using Sideload.Css;
using Sideload.Devtools.Cdp;
using Sideload.Dom;
using Sideload.Host;
using Sideload.Input;
using Sideload.Layout;
using Sideload.Model;
using Sideload.Net;
using Sideload.Paint;
using Sideload.Phone;
using Sideload.Profiling;
using Sideload.Script;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.SceneManagement;
using UnityEngine.TextCore;
using UnityEngine.TextCore.LowLevel;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(Core), "Sideload", "1.33.0", "DooDesch", "https://github.com/DooDesch-Mods/ScheduleOne-Sideload")]
[assembly: MelonGame("TVGS", "Schedule I")]
[assembly: MelonOptionalDependencies(new string[] { "AngleSharp", "Jint", "Esprima" })]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("DooDesch")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright © DooDesch")]
[assembly: AssemblyFileVersion("1.33.0.0")]
[assembly: AssemblyInformationalVersion("1.33.0+d80da31b51e4f5a7871540653b74c67308e16437")]
[assembly: AssemblyProduct("Sideload")]
[assembly: AssemblyTitle("Sideload")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.33.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
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;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace DooDesch
{
	internal static class ModVersion
	{
		internal const string Current = "1.33.0";
	}
}
namespace Sideload
{
	public class Core : MelonMod
	{
		internal static Instance Log;

		private static readonly string[] RuntimeDependencies = new string[3] { "AngleSharp", "Esprima", "Jint" };

		private static readonly Dictionary<string, Assembly> _resolved = new Dictionary<string, Assembly>(StringComparer.OrdinalIgnoreCase);

		public override void OnInitializeMelon()
		{
			Log = ((MelonBase)this).LoggerInstance;
			HostAllowlist.Log = delegate(string line)
			{
				Log.Warning(line);
			};
			Platform.LogMsg = delegate(string line)
			{
				Log.Msg(line);
			};
			Platform.LogWarning = delegate(string line)
			{
				Log.Warning(line);
			};
			Platform.LogError = delegate(string line)
			{
				Log.Error(line);
			};
			Platform.UserDataDirectory = () => MelonEnvironment.UserDataDirectory;
			Platform.IsPortrait = (string id) => Registry.Find(id)?.Portrait ?? false;
			Platform.SetOrientation = Registry.SetOrientation;
			AppDomain.CurrentDomain.AssemblyResolve += ResolveRuntimeDependency;
			PreloadRuntimeDependency("AngleSharp.dll");
			PreloadRuntimeDependency("Esprima.dll");
			PreloadRuntimeDependency("Jint.dll");
			WarmUp();
			try
			{
				((MelonBase)this).HarmonyInstance.PatchAll();
				Log.Msg("patches applied.");
			}
			catch (Exception ex)
			{
				Log.Error("PatchAll failed - no app will reach the phone: " + ex);
			}
			TmpCaretGuard.Apply(((MelonBase)this).HarmonyInstance);
			Preferences.Initialize();
			if (Preferences.DevTools)
			{
				CdpServer.Start(Preferences.DevToolsPort);
			}
		}

		private static void WarmUp()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			try
			{
				Stopwatch stopwatch = Stopwatch.StartNew();
				IHtmlDocument val = new HtmlParser().ParseDocument("<style>b{color:#fff;padding:1px}</style><div id=w><b>x</b></div>");
				CssParser.Parse("b{color:#fff;padding:1px}");
				Engine val2 = new Engine();
				val2.Execute("var a=[1,2,3].map(function(v){return v*2;}).join(',');", (string)null);
				Log.Msg($"warmed the parsers in {stopwatch.ElapsedMilliseconds} ms (document has {((IHtmlCollection<IElement>)(object)((IDocument)val).All).Length} node(s), script returned {val2.Evaluate("a", (string)null)}).");
			}
			catch (Exception ex)
			{
				Log.Warning("warming the parsers failed, the first page will pay for it: " + ex.Message);
			}
		}

		public override void OnUpdate()
		{
			using (Phase.Of("sideload.views"))
			{
				WebView.TickAll(Time.deltaTime);
			}
			using (Phase.Of("sideload.turninput"))
			{
				TurnInput.Tick();
			}
			using (Phase.Of("sideload.globalkeys"))
			{
				GlobalKeys.Tick();
			}
			using (Phase.Of("sideload.typingexit"))
			{
				TypingExit.Tick();
			}
			using (Phase.Of("sideload.appfade"))
			{
				AppFade.Tick(Time.unscaledDeltaTime);
			}
			using (Phase.Of("sideload.cdp"))
			{
				CdpServer.Pump();
			}
		}

		public override void OnSceneWasLoaded(int buildIndex, string sceneName)
		{
			TurnPrompt.SceneChanged();
		}

		public override void OnDeinitializeMelon()
		{
			CdpServer.Stop();
			ChromeLauncher.Close();
		}

		private static Assembly ResolveRuntimeDependency(object sender, ResolveEventArgs args)
		{
			string name;
			try
			{
				name = new AssemblyName(args.Name).Name;
			}
			catch
			{
				return null;
			}
			if (_resolved.TryGetValue(name, out var value))
			{
				return value;
			}
			if (Array.IndexOf(RuntimeDependencies, name) < 0)
			{
				return null;
			}
			Assembly assembly = LoadEmbeddedAssembly(name + ".dll");
			if (assembly == null)
			{
				return null;
			}
			_resolved[name] = assembly;
			Log.Msg($"resolved {name} from the embedded copy (requested by {args.RequestingAssembly?.GetName().Name ?? "the runtime"})");
			return assembly;
		}

		private static void PreloadRuntimeDependency(string fileName)
		{
			try
			{
				string text = Path.Combine(MelonEnvironment.UserLibsDirectory, fileName);
				if (!File.Exists(text))
				{
					string text2 = Path.Combine(Path.GetDirectoryName(typeof(Core).Assembly.Location) ?? MelonEnvironment.ModsDirectory, fileName);
					text = ((!File.Exists(text2)) ? null : text2);
				}
				Assembly assembly = ((text != null) ? Assembly.LoadFrom(text) : LoadEmbeddedAssembly(fileName));
				if (assembly == null)
				{
					Log.Error("runtime dependency " + fileName + " is neither on disk nor embedded - no app will render.");
					return;
				}
				AssemblyName name = assembly.GetName();
				_resolved[name.Name] = assembly;
				Log.Msg($"preloaded {name.Name} {name.Version} {((text != null) ? ("from disk (" + text + ")") : "(embedded)")}");
			}
			catch (Exception ex)
			{
				Log.Warning("preloading " + fileName + " failed: " + ex.Message);
			}
		}

		private static Assembly LoadEmbeddedAssembly(string fileName)
		{
			string text = "Sideload.Libs." + fileName;
			using Stream stream = typeof(Core).Assembly.GetManifestResourceStream(text);
			if (stream == null)
			{
				Log.Warning("embedded dependency '" + text + "' is missing from this build.");
				return null;
			}
			byte[] array = new byte[stream.Length];
			int i;
			int num;
			for (i = 0; i < array.Length; i += num)
			{
				num = stream.Read(array, i, array.Length - i);
				if (num <= 0)
				{
					break;
				}
			}
			if (i != array.Length)
			{
				Log.Warning($"embedded dependency '{text}' is truncated ({i} of {array.Length} bytes).");
				return null;
			}
			return Assembly.Load(array);
		}
	}
	internal sealed class AppRegistration
	{
		internal string Id;

		internal string Title;

		internal string IconLabel;

		internal string BundlePrefix;

		internal Assembly HostAssembly;

		internal AppBundle Bundle;

		internal Sprite IconSprite;

		internal bool Portrait;

		internal bool DeclaredPortrait;

		internal bool CanTurn;

		internal int Badge;

		internal bool Iconless;

		internal Action OrientationChanged;

		internal bool Supports(bool portrait)
		{
			if (!CanTurn)
			{
				return DeclaredPortrait == portrait;
			}
			return true;
		}
	}
	internal static class Registry
	{
		private static readonly List<AppRegistration> _apps = new List<AppRegistration>();

		internal static Action<string, int> BadgeTap;

		internal static Action<string, string, string> NotifyTap;

		internal static IReadOnlyList<AppRegistration> Apps => _apps;

		internal static void RegisterApp(string id, string title, string iconLabel, string bundlePrefix, Assembly host)
		{
			if (string.IsNullOrWhiteSpace(id) || host == null)
			{
				return;
			}
			AppRegistration appRegistration = new AppRegistration
			{
				Id = id.Trim(),
				Title = (string.IsNullOrWhiteSpace(title) ? id : title),
				IconLabel = ((!string.IsNullOrWhiteSpace(iconLabel)) ? iconLabel : (string.IsNullOrWhiteSpace(title) ? id : title)),
				BundlePrefix = (bundlePrefix ?? ""),
				HostAssembly = host
			};
			appRegistration.Bundle = new AppBundle(appRegistration.Id, appRegistration.BundlePrefix, host);
			for (int i = 0; i < _apps.Count; i++)
			{
				if (string.Equals(_apps[i].Id, appRegistration.Id, StringComparison.OrdinalIgnoreCase))
				{
					_apps[i] = appRegistration;
					Instance log = Core.Log;
					if (log != null)
					{
						log.Warning("app '" + appRegistration.Id + "' registered twice; the later registration wins.");
					}
					return;
				}
			}
			_apps.Add(appRegistration);
			Instance log2 = Core.Log;
			if (log2 != null)
			{
				log2.Msg($"app registered: {appRegistration.Id} ('{appRegistration.Title}') from {host.GetName().Name}");
			}
		}

		internal static void DeclareOrientations(string appId, string orientations)
		{
			AppRegistration appRegistration = Find(appId);
			if (appRegistration == null)
			{
				Instance log = Core.Log;
				if (log != null)
				{
					log.Warning("orientation: no app '" + appId + "'.");
				}
				return;
			}
			OrientationSet orientationSet = OrientationSet.Parse(orientations);
			foreach (string item in orientationSet.Ignored)
			{
				Instance log2 = Core.Log;
				if (log2 != null)
				{
					log2.Warning($"'{appId}' declared orientation '{item}', which is neither 'portrait' " + "nor 'landscape' - ignored.");
				}
			}
			if (orientationSet.Declared)
			{
				appRegistration.DeclaredPortrait = orientationSet.Portrait;
				appRegistration.CanTurn = orientationSet.CanTurn;
				appRegistration.Portrait = orientationSet.Portrait;
			}
		}

		internal static void SetOrientation(string appId, string orientation)
		{
			AppRegistration appRegistration = Find(appId);
			if (appRegistration == null)
			{
				Instance log = Core.Log;
				if (log != null)
				{
					log.Warning("setOrientation: no app '" + appId + "'.");
				}
				return;
			}
			bool flag = string.Equals((orientation ?? "").Trim(), "portrait", StringComparison.OrdinalIgnoreCase);
			if (appRegistration.Portrait == flag)
			{
				return;
			}
			if (!appRegistration.Supports(flag))
			{
				Instance log2 = Core.Log;
				if (log2 != null)
				{
					log2.Warning($"'{appRegistration.Id}' was asked for {(flag ? "portrait" : "landscape")} but " + "only declared the other one - ignored. Declare both to allow turning: Apps.Register(...).Orientation(\"landscape\", \"portrait\").");
				}
			}
			else
			{
				appRegistration.Portrait = flag;
				appRegistration.OrientationChanged?.Invoke();
			}
		}

		internal static void SetBadge(string appId, int count)
		{
			AppRegistration appRegistration = Find(appId);
			if (appRegistration == null)
			{
				Instance log = Core.Log;
				if (log != null)
				{
					log.Warning("badge: no app '" + appId + "'.");
				}
			}
			else
			{
				appRegistration.Badge = Math.Max(0, count);
				BadgeTap?.Invoke(appRegistration.Id, appRegistration.Badge);
				LiveHost(appId)?.SetBadge(appRegistration.Badge);
			}
		}

		internal static void Notify(string appId, string title, string subtitle)
		{
			NotifyFor(appId, title, subtitle, 0f);
		}

		internal static void NotifyFor(string appId, string title, string subtitle, float seconds)
		{
			NotifyTap?.Invoke(appId, title ?? "", subtitle ?? "");
			GlobalKeys.Attend(appId);
			LiveHost(appId)?.Notify(title, subtitle, seconds);
		}

		internal static void ClaimKeys(string appId, string declaration, Func<string, string, bool> handler)
		{
			GlobalKeys.Claim(appId, declaration, handler);
		}

		internal static bool IsOnScreen(string appId)
		{
			return LiveHost(appId)?.IsShowing ?? false;
		}

		internal static void SetIconHidden(string appId, bool hidden)
		{
			AppRegistration appRegistration = Find(appId);
			if (appRegistration == null)
			{
				Instance log = Core.Log;
				if (log != null)
				{
					log.Warning("icon: no app '" + appId + "'.");
				}
			}
			else
			{
				appRegistration.Iconless = hidden;
				LiveHost(appId)?.SetIconVisible(!hidden);
			}
		}

		internal static void SetAppOpen(string appId, bool open)
		{
			PhoneAppHost phoneAppHost = LiveHost(appId);
			if (phoneAppHost == null)
			{
				Instance log = Core.Log;
				if (log != null)
				{
					log.Warning("open: '" + appId + "' is not on a phone.");
				}
			}
			else if (open)
			{
				phoneAppHost.Open();
			}
			else
			{
				phoneAppHost.Close();
			}
		}

		internal static bool SetPhoneRaised(bool raised)
		{
			if (!raised)
			{
				return PhoneScreen.Lower();
			}
			return PhoneScreen.Raise();
		}

		internal static bool IsPhoneRaised()
		{
			return PhoneScreen.IsRaised;
		}

		internal static bool IsAppOpen(string appId)
		{
			return LiveHost(appId)?.IsOpen ?? false;
		}

		private static PhoneAppHost LiveHost(string appId)
		{
			IReadOnlyList<PhoneAppHost> hosts = HomeScreenPatch.Hosts;
			for (int i = 0; i < hosts.Count; i++)
			{
				if (string.Equals(hosts[i].Id, appId, StringComparison.OrdinalIgnoreCase) && hosts[i].IsAlive)
				{
					return hosts[i];
				}
			}
			return null;
		}

		internal static AppRegistration Find(string appId)
		{
			if (string.IsNullOrWhiteSpace(appId))
			{
				return null;
			}
			for (int i = 0; i < _apps.Count; i++)
			{
				if (string.Equals(_apps[i].Id, appId, StringComparison.OrdinalIgnoreCase))
				{
					return _apps[i];
				}
			}
			return null;
		}
	}
}
namespace Sideload.Script
{
	public sealed class Bridge
	{
		public sealed class JsStorage
		{
			private readonly string _path;

			private readonly Dictionary<string, string> _values = new Dictionary<string, string>(StringComparer.Ordinal);

			private bool _loaded;

			public int Length
			{
				get
				{
					Load();
					return _values.Count;
				}
			}

			internal JsStorage(string appId)
			{
				string path = Path.Combine(Platform.UserDataDirectory(), "Sideload");
				_path = Path.Combine(path, Sanitise(appId) + ".json");
			}

			public string Get(string key, string fallback = "")
			{
				Load();
				if (key == null || !_values.TryGetValue(key, out var value))
				{
					return fallback;
				}
				return value;
			}

			public void Set(string key, string value)
			{
				if (!string.IsNullOrEmpty(key))
				{
					Load();
					_values[key] = value ?? "";
					Save();
				}
			}

			public void Remove(string key)
			{
				if (!string.IsNullOrEmpty(key))
				{
					Load();
					if (_values.Remove(key))
					{
						Save();
					}
				}
			}

			public void Clear()
			{
				Load();
				_values.Clear();
				Save();
			}

			public string GetItem(string key)
			{
				Load();
				if (key == null || !_values.TryGetValue(key, out var value))
				{
					return null;
				}
				return value;
			}

			public void SetItem(string key, string value)
			{
				Set(key, value);
			}

			public void RemoveItem(string key)
			{
				Remove(key);
			}

			public string Key(int index)
			{
				Load();
				if (index < 0 || index >= _values.Count)
				{
					return null;
				}
				int num = 0;
				foreach (string key in _values.Keys)
				{
					if (num++ == index)
					{
						return key;
					}
				}
				return null;
			}

			private void Load()
			{
				if (_loaded)
				{
					return;
				}
				_loaded = true;
				try
				{
					if (!File.Exists(_path))
					{
						return;
					}
					foreach (KeyValuePair<string, string> item in MiniJson.ParseObject(File.ReadAllText(_path)))
					{
						_values[item.Key] = item.Value;
					}
				}
				catch (Exception ex)
				{
					Platform.Warning("storage read failed: " + ex.Message);
				}
			}

			private void Save()
			{
				try
				{
					Directory.CreateDirectory(Path.GetDirectoryName(_path));
					File.WriteAllText(_path, MiniJson.WriteObject(_values));
				}
				catch (Exception ex)
				{
					Platform.Warning("storage write failed: " + ex.Message);
				}
			}

			private static string Sanitise(string id)
			{
				StringBuilder stringBuilder = new StringBuilder(id?.Length ?? 0);
				string text = id ?? "app";
				foreach (char c in text)
				{
					stringBuilder.Append((char.IsLetterOrDigit(c) || c == '-' || c == '_') ? c : '-');
				}
				if (stringBuilder.Length != 0)
				{
					return stringBuilder.ToString();
				}
				return "app";
			}
		}

		private static readonly Dictionary<string, Func<string, string, string>> _handlers = new Dictionary<string, Func<string, string, string>>(StringComparer.OrdinalIgnoreCase);

		private static readonly Dictionary<string, List<Bridge>> _subscribers = new Dictionary<string, List<Bridge>>(StringComparer.OrdinalIgnoreCase);

		private readonly Dictionary<string, List<JsValue>> _listeners = new Dictionary<string, List<JsValue>>(StringComparer.OrdinalIgnoreCase);

		private readonly ScriptHost _host;

		private readonly string _appId;

		internal static Action<string, string, string> Tap = null;

		public JsStorage Storage { get; }

		public string AppId => _appId;

		public string Orientation
		{
			get
			{
				if (!Platform.IsPortrait(_appId))
				{
					return "landscape";
				}
				return "portrait";
			}
		}

		internal Bridge(ScriptHost host, string appId)
		{
			_host = host;
			_appId = appId;
			Storage = new JsStorage(appId);
		}

		internal static void Handle(string appId, string name, Func<string, string, string> handler)
		{
			if (!string.IsNullOrWhiteSpace(name) && handler != null)
			{
				_handlers[Key(appId, name)] = handler;
			}
		}

		internal static void Emit(string appId, string name, string payload)
		{
			if (string.IsNullOrWhiteSpace(name))
			{
				return;
			}
			Tap?.Invoke(appId, name, payload ?? "");
			if (!_subscribers.TryGetValue(name, out var value))
			{
				return;
			}
			Bridge[] array = value.ToArray();
			foreach (Bridge bridge in array)
			{
				if (appId == null || string.Equals(bridge._appId, appId, StringComparison.OrdinalIgnoreCase))
				{
					bridge.Deliver(name, payload ?? "");
				}
			}
		}

		internal static string Invoke(string appId, string name, string argument)
		{
			if (string.IsNullOrWhiteSpace(name))
			{
				return "";
			}
			if (!_handlers.TryGetValue(Key(appId, name), out var value) && !_handlers.TryGetValue(Key(null, name), out value))
			{
				Platform.Warning(appId + ": s1.call('" + name + "') has no handler.");
				return "";
			}
			try
			{
				return value(appId, argument ?? "") ?? "";
			}
			catch (Exception ex)
			{
				Platform.Error($"{appId}: s1.call('{name}') threw: {ex.Message}");
				return "";
			}
		}

		private static string Key(string appId, string name)
		{
			return appId + "\0" + name.Trim();
		}

		public string Call(string name, string argument = "")
		{
			try
			{
				return Invoke(_appId, name, argument);
			}
			finally
			{
				_host?.RestartBudget();
			}
		}

		public void On(string name, JsValue handler)
		{
			if (!string.IsNullOrWhiteSpace(name) && !(handler == (JsValue)null) && JsValueExtensions.IsObject(handler))
			{
				if (!_listeners.TryGetValue(name, out var value))
				{
					value = (_listeners[name] = new List<JsValue>());
				}
				value.Add(handler);
				if (!_subscribers.TryGetValue(name, out var value2))
				{
					value2 = (_subscribers[name] = new List<Bridge>());
				}
				if (!value2.Contains(this))
				{
					value2.Add(this);
				}
			}
		}

		public void Log(params object[] args)
		{
			Platform.Msg("[" + _appId + "] " + string.Join(" ", Array.ConvertAll(args ?? Array.Empty<object>(), (object a) => a?.ToString() ?? "null")));
		}

		public void SetOrientation(string orientation)
		{
			Platform.SetOrientation(_appId, orientation);
		}

		internal void Dispose()
		{
			foreach (KeyValuePair<string, List<Bridge>> subscriber in _subscribers)
			{
				subscriber.Value.Remove(this);
			}
			_listeners.Clear();
		}

		private void Deliver(string name, string payload)
		{
			if (!_listeners.TryGetValue(name, out var value))
			{
				return;
			}
			JsValue[] array = value.ToArray();
			foreach (JsValue val in array)
			{
				try
				{
					_host.Engine.Invoke(val, new object[1] { payload });
				}
				catch (Exception ex)
				{
					Platform.Error($"{_appId}: s1.on('{name}') handler failed: {ex.Message}");
				}
			}
		}
	}
	public abstract class JsNode : ObjectInstance
	{
		internal ScriptHost Host { get; }

		internal INode Node { get; }

		private protected abstract int NodeTypeCode { get; }

		private protected abstract string NodeName { get; }

		private protected virtual JsValue NodeValue => JsValue.Null;

		internal JsNode(ScriptHost host, INode node)
			: base(host.Engine)
		{
			Host = host;
			Node = node;
			ObjectInstance val = Interface(host.Types);
			if ((JsValue)(object)val != (JsValue)null)
			{
				((ObjectInstance)this).Prototype = val;
			}
		}

		private protected virtual ObjectInstance Interface(DomTypes types)
		{
			return types?.Node;
		}

		public override JsValue Get(JsValue property, JsValue receiver)
		{
			if (!JsValueExtensions.IsString(property))
			{
				return ((ObjectInstance)this).Get(property, receiver);
			}
			string name = JsValueExtensions.AsString(property);
			JsValue val = Member(name);
			if (val != null)
			{
				return val;
			}
			Func<JsValue[], JsValue> func = Method(name);
			if (func != null)
			{
				return Bind(name, func);
			}
			return ((ObjectInstance)this).Get(property, receiver);
		}

		public override bool Set(JsValue property, JsValue value, JsValue receiver)
		{
			if (JsValueExtensions.IsString(property) && Assign(JsValueExtensions.AsString(property), value))
			{
				return true;
			}
			return ((ObjectInstance)this).Set(property, value, receiver);
		}

		public override bool HasProperty(JsValue property)
		{
			if (JsValueExtensions.IsString(property))
			{
				string name = JsValueExtensions.AsString(property);
				if (Member(name) != null || Method(name) != null)
				{
					return true;
				}
			}
			return ((ObjectInstance)this).HasProperty(property);
		}

		private protected virtual JsValue Member(string name)
		{
			return (JsValue)(name switch
			{
				"nodeType" => JsValue.op_Implicit(NodeTypeCode), 
				"nodeName" => JsValue.op_Implicit(NodeName), 
				"nodeValue" => NodeValue, 
				"textContent" => JsValue.op_Implicit(Node.TextContent ?? ""), 
				"parentNode" => Wrap(Node.Parent), 
				"parentElement" => Wrap((INode)(object)Node.ParentElement), 
				"ownerDocument" => Host.DocumentObject, 
				"isConnected" => JsValue.op_Implicit(Node.Owner != null && Node.Parent != null), 
				"firstChild" => Wrap(Node.FirstChild), 
				"lastChild" => Wrap(Node.LastChild), 
				"nextSibling" => Wrap(Node.NextSibling), 
				"previousSibling" => Wrap(Node.PreviousSibling), 
				"childNodes" => Host.WrapNodes((IEnumerable<INode>)Node.ChildNodes), 
				_ => null, 
			});
		}

		private protected virtual bool Assign(string name, JsValue value)
		{
			if (name == "nodeValue" || name == "textContent")
			{
				SetText(Text(value));
				return true;
			}
			return false;
		}

		private protected virtual Func<JsValue[], JsValue> Method(string name)
		{
			return name switch
			{
				"appendChild" => (JsValue[] a) => Insert(Arg(a, 0), null, append: true), 
				"insertBefore" => (JsValue[] a) => Insert(Arg(a, 0), Arg(a, 1), append: false), 
				"removeChild" => (JsValue[] a) => Detach(Arg(a, 0)), 
				"replaceChild" => (JsValue[] a) => Replace(Arg(a, 0), Arg(a, 1)), 
				"remove" => delegate
				{
					DetachSelf();
					return JsValue.Undefined;
				}, 
				"cloneNode" => (JsValue[] a) => Clone(a.Length != 0 && TypeConverter.ToBoolean(a[0])), 
				"contains" => (JsValue[] a) => Contains(Arg(a, 0)), 
				"hasChildNodes" => (JsValue[] _) => JsValue.op_Implicit(Node.ChildNodes.Length > 0), 
				"addEventListener" => delegate(JsValue[] a)
				{
					Host.AddListener(Node, (a.Length != 0) ? ((object)a[0]).ToString() : null, (a.Length > 1) ? a[1] : null, Capture(a, 2));
					return JsValue.Undefined;
				}, 
				"removeEventListener" => delegate(JsValue[] a)
				{
					Host.RemoveListener(Node, (a.Length != 0) ? ((object)a[0]).ToString() : null, (a.Length > 1) ? a[1] : null, Capture(a, 2));
					return JsValue.Undefined;
				}, 
				"dispatchEvent" => (JsValue[] a) => Host.DispatchFromScript(Node, (ObjectInstance)(((object)Arg(a, 0)) ?? ((object)((a.Length != 0) ? /*isinst with value type is only supported in some contexts*/: null)))), 
				_ => null, 
			};
		}

		private protected virtual void SetText(string text)
		{
			if (!string.Equals(Node.TextContent ?? "", text, StringComparison.Ordinal))
			{
				Node.TextContent = text;
				INode node = Node;
				IElement val = (IElement)(object)((node is IElement) ? node : null);
				if (val == null || !Host.TryRetext(val, text))
				{
					Host.MarkDirty();
				}
			}
		}

		private JsValue Insert(JsNode child, JsNode reference, bool append)
		{
			if ((JsValue)(object)child == (JsValue)null)
			{
				return JsValue.Null;
			}
			if (append || (JsValue)(object)reference == (JsValue)null)
			{
				Node.AppendChild(child.Node);
			}
			else
			{
				Node.InsertBefore(child.Node, reference.Node);
			}
			Host.MarkDirty();
			return (JsValue)(object)child;
		}

		private JsValue Detach(JsNode child)
		{
			if ((JsValue)(object)child == (JsValue)null)
			{
				return JsValue.Null;
			}
			Node.RemoveChild(child.Node);
			Host.Forget(child.Node);
			Host.MarkDirty();
			return (JsValue)(object)child;
		}

		private JsValue Replace(JsNode fresh, JsNode stale)
		{
			if ((JsValue)(object)fresh == (JsValue)null || (JsValue)(object)stale == (JsValue)null)
			{
				return JsValue.Null;
			}
			Node.ReplaceChild(fresh.Node, stale.Node);
			Host.Forget(stale.Node);
			Host.MarkDirty();
			return (JsValue)(object)stale;
		}

		private void DetachSelf()
		{
			INode parent = Node.Parent;
			if (parent != null)
			{
				parent.RemoveChild(Node);
			}
			Host.Forget(Node);
			Host.MarkDirty();
		}

		private JsValue Clone(bool deep)
		{
			INode val = Node.Clone(deep);
			if (val != null)
			{
				return Wrap(val);
			}
			return JsValue.Null;
		}

		private JsValue Contains(JsNode other)
		{
			if ((JsValue)(object)other == (JsValue)null)
			{
				return JsValue.op_Implicit(false);
			}
			for (INode val = other.Node; val != null; val = val.Parent)
			{
				if (val == Node)
				{
					return JsValue.op_Implicit(true);
				}
			}
			return JsValue.op_Implicit(false);
		}

		private protected JsValue Wrap(INode node)
		{
			return (JsValue)(((object)Host.WrapNode(node)) ?? ((object)JsValue.Null));
		}

		private protected JsNode Arg(JsValue[] args, int index)
		{
			if (index >= args.Length)
			{
				return null;
			}
			return args[index] as JsNode;
		}

		private static bool Capture(JsValue[] args, int index)
		{
			if (index >= args.Length)
			{
				return false;
			}
			JsValue val = args[index];
			if (JsValueExtensions.IsBoolean(val))
			{
				return JsValueExtensions.AsBoolean(val);
			}
			ObjectInstance val2 = (ObjectInstance)(object)((val is ObjectInstance) ? val : null);
			if (val2 != null)
			{
				JsValue val3 = ((JsValue)val2).Get(JsValue.op_Implicit("capture"));
				if (!JsValueExtensions.IsUndefined(val3))
				{
					return TypeConverter.ToBoolean(val3);
				}
				return false;
			}
			return false;
		}

		private protected static string Text(JsValue value)
		{
			if (!JsValueExtensions.IsNull(value) && !JsValueExtensions.IsUndefined(value))
			{
				return ((object)value).ToString();
			}
			return "";
		}

		private JsValue Bind(string name, Func<JsValue[], JsValue> body)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Expected O, but got Unknown
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Expected O, but got Unknown
			PropertyDescriptor ownProperty = ((ObjectInstance)this).GetOwnProperty(JsValue.op_Implicit(name));
			if (ownProperty != PropertyDescriptor.Undefined)
			{
				return ownProperty.Value;
			}
			ClrFunction val = new ClrFunction(((ObjectInstance)this).Engine, name, (Func<JsValue, JsValue[], JsValue>)((JsValue _, JsValue[] args) => body(args)), 0, (PropertyFlag)42);
			((ObjectInstance)this).FastSetProperty(name, new PropertyDescriptor((JsValue)(object)val, (bool?)true, (bool?)false, (bool?)true));
			return (JsValue)(object)val;
		}
	}
	public sealed class JsElement : JsNode
	{
		private static readonly HashSet<string> StringProperties = new HashSet<string>(StringComparer.Ordinal)
		{
			"value", "type", "name", "placeholder", "src", "href", "alt", "title", "rel", "target",
			"maxLength", "step", "min", "max", "accept", "pattern", "role"
		};

		private static readonly HashSet<string> BoolProperties = new HashSet<string>(StringComparer.Ordinal) { "disabled", "checked", "selected", "required", "multiple", "hidden", "autofocus", "open" };

		internal IElement Native { get; }

		private protected override int NodeTypeCode => 1;

		private protected override string NodeName => Native.LocalName?.ToUpperInvariant() ?? "";

		private int TabIndex
		{
			get
			{
				if (!int.TryParse(Native.GetAttribute("tabindex"), out var result))
				{
					return -1;
				}
				return result;
			}
		}

		internal JsElement(ScriptHost host, IElement element)
			: base(host, (INode)(object)element)
		{
			Native = element;
		}

		private protected override ObjectInstance Interface(DomTypes types)
		{
			if (types == null)
			{
				return null;
			}
			INode node = base.Node;
			INode obj = ((node is IElement) ? node : null);
			return types.For((obj != null) ? ((IElement)obj).LocalName : null);
		}

		public override string ToString()
		{
			return "<" + Native.LocalName + ">";
		}

		private protected override JsValue Member(string name)
		{
			switch (name)
			{
			case "tagName":
				return JsValue.op_Implicit(NodeName);
			case "localName":
				return JsValue.op_Implicit(Native.LocalName ?? "");
			case "id":
				return JsValue.op_Implicit(Native.Id ?? "");
			case "className":
				return JsValue.op_Implicit(Native.ClassName ?? "");
			case "classList":
				return JsValue.FromObject(((ObjectInstance)this).Engine, (object)new JsClassList(base.Host, Native));
			case "style":
				return (JsValue)(object)new JsStyle(base.Host, Native);
			case "innerHTML":
				return JsValue.op_Implicit(Native.InnerHtml ?? "");
			case "outerHTML":
				return JsValue.op_Implicit(Native.OuterHtml ?? "");
			case "value":
				return JsValue.op_Implicit(Native.GetAttribute("value") ?? "");
			case "children":
				return base.Host.WrapNodes((IEnumerable<IElement>)((IParentNode)Native).Children);
			case "childElementCount":
				return JsValue.op_Implicit(((IParentNode)Native).ChildElementCount);
			case "firstElementChild":
				return Wrap((INode)(object)((IParentNode)Native).FirstElementChild);
			case "lastElementChild":
				return Wrap((INode)(object)((IParentNode)Native).LastElementChild);
			case "nextElementSibling":
				return Wrap((INode)(object)((INonDocumentTypeChildNode)Native).NextElementSibling);
			case "previousElementSibling":
				return Wrap((INode)(object)((INonDocumentTypeChildNode)Native).PreviousElementSibling);
			case "tabIndex":
				return JsValue.op_Implicit(TabIndex);
			case "htmlFor":
				return JsValue.op_Implicit(Native.GetAttribute("for") ?? "");
			case "readOnly":
				return JsValue.op_Implicit(Native.HasAttribute("readonly"));
			case "namespaceURI":
				return JsValue.op_Implicit(Native.NamespaceUri) ?? JsValue.Null;
			default:
				if (StringProperties.Contains(name))
				{
					return JsValue.op_Implicit(Native.GetAttribute(Attribute(name)) ?? "");
				}
				if (BoolProperties.Contains(name))
				{
					return JsValue.op_Implicit(Native.HasAttribute(Attribute(name)));
				}
				if (IsHandlerName(name))
				{
					return base.Host.InlineHandler((INode)(object)Native, name.Substring(2));
				}
				return base.Member(name);
			}
		}

		private protected override bool Assign(string name, JsValue value)
		{
			switch (name)
			{
			case "id":
				return Write("id", JsNode.Text(value));
			case "className":
				return Write("class", JsNode.Text(value));
			case "htmlFor":
				return Write("for", JsNode.Text(value));
			case "readOnly":
				return Flag("readonly", TypeConverter.ToBoolean(value));
			case "tabIndex":
				return Write("tabindex", JsNode.Text(value));
			case "innerHTML":
				if (string.Equals(Native.InnerHtml ?? "", JsNode.Text(value), StringComparison.Ordinal))
				{
					return true;
				}
				foreach (INode item in (IEnumerable<INode>)((INode)Native).ChildNodes)
				{
					base.Host.Forget(item);
				}
				Native.InnerHtml = JsNode.Text(value);
				base.Host.MarkDirty();
				return true;
			case "textContent":
				foreach (INode item2 in (IEnumerable<INode>)((INode)Native).ChildNodes)
				{
					base.Host.Forget(item2);
				}
				SetText(JsNode.Text(value));
				return true;
			default:
				if (StringProperties.Contains(name))
				{
					return Write(Attribute(name), JsNode.Text(value));
				}
				if (BoolProperties.Contains(name))
				{
					return Flag(Attribute(name), TypeConverter.ToBoolean(value));
				}
				if (IsHandlerName(name))
				{
					base.Host.SetInlineHandler((INode)(object)Native, name.Substring(2), value);
					return true;
				}
				return base.Assign(name, value);
			}
		}

		private protected override Func<JsValue[], JsValue> Method(string name)
		{
			switch (name)
			{
			case "getAttribute":
				return (JsValue[] a) => JsValue.op_Implicit(Native.GetAttribute(Name(a, 0))) ?? JsValue.Null;
			case "hasAttribute":
				return (JsValue[] a) => JsValue.op_Implicit(Native.HasAttribute(Name(a, 0)));
			case "setAttribute":
				return delegate(JsValue[] a)
				{
					Write(Name(a, 0), (a.Length > 1) ? JsNode.Text(a[1]) : "");
					return JsValue.Undefined;
				};
			case "removeAttribute":
				return delegate(JsValue[] a)
				{
					Erase(Name(a, 0));
					return JsValue.Undefined;
				};
			case "querySelector":
				return (JsValue[] a) => Wrap((INode)(object)Query(() => ((IParentNode)Native).QuerySelector(Name(a, 0))));
			case "querySelectorAll":
				return (JsValue[] a) => base.Host.WrapNodes(QueryAll(() => (IEnumerable<IElement>)((IParentNode)Native).QuerySelectorAll(Name(a, 0))));
			case "matches":
				return (JsValue[] a) => JsValue.op_Implicit(Query(() => (!Native.Matches(Name(a, 0))) ? null : Native) != null);
			case "closest":
				return (JsValue[] a) => Wrap((INode)(object)Query(() => Native.Closest(Name(a, 0))));
			case "replaceChildren":
				return delegate
				{
					ReplaceChildren();
					return JsValue.Undefined;
				};
			case "click":
				return delegate
				{
					base.Host.Dispatch(Native, "click");
					return JsValue.Undefined;
				};
			case "focus":
				return delegate
				{
					base.Host.RequestFocus(Native);
					return JsValue.Undefined;
				};
			case "blur":
				return delegate
				{
					base.Host.RequestBlur(Native);
					return JsValue.Undefined;
				};
			case "scrollToEnd":
				return delegate
				{
					base.Host.RequestScrollToEnd(Native);
					return JsValue.Undefined;
				};
			case "rect":
			case "getBoundingClientRect":
				return (JsValue[] _) => JsValue.FromObject(((ObjectInstance)this).Engine, (object)Rect());
			default:
				return base.Method(name);
			}
		}

		private JsRect Rect()
		{
			float[] array = base.Host.RectOf(Native);
			return new JsRect
			{
				x = array[0],
				y = array[1],
				width = array[2],
				height = array[3],
				left = array[0],
				top = array[1],
				right = array[0] + array[2],
				bottom = array[1] + array[3]
			};
		}

		private void ReplaceChildren()
		{
			foreach (INode item in (IEnumerable<INode>)((INode)Native).ChildNodes)
			{
				base.Host.Forget(item);
			}
			Native.InnerHtml = "";
			base.Host.MarkDirty();
		}

		private bool Write(string attribute, string value)
		{
			if (string.IsNullOrEmpty(attribute))
			{
				return true;
			}
			if (string.Equals(Native.GetAttribute(attribute) ?? "", value, StringComparison.Ordinal))
			{
				return true;
			}
			Native.SetAttribute(attribute, value ?? "");
			base.Host.MarkDirty();
			return true;
		}

		private bool Flag(string attribute, bool on)
		{
			if (Native.HasAttribute(attribute) == on)
			{
				return true;
			}
			if (on)
			{
				Native.SetAttribute(attribute, "");
			}
			else
			{
				Native.RemoveAttribute(attribute);
			}
			base.Host.MarkDirty();
			return true;
		}

		private void Erase(string attribute)
		{
			if (!string.IsNullOrEmpty(attribute) && Native.HasAttribute(attribute))
			{
				Native.RemoveAttribute(attribute);
				base.Host.MarkDirty();
			}
		}

		private static IElement Query(Func<IElement> run)
		{
			try
			{
				return run();
			}
			catch
			{
				return null;
			}
		}

		private static IEnumerable<IElement> QueryAll(Func<IEnumerable<IElement>> run)
		{
			try
			{
				return run();
			}
			catch
			{
				return Array.Empty<IElement>();
			}
		}

		private static string Name(JsValue[] args, int index)
		{
			if (index >= args.Length)
			{
				return "";
			}
			return ((object)args[index]).ToString();
		}

		private static bool IsHandlerName(string name)
		{
			if (name.Length < 4 || name[0] != 'o' || name[1] != 'n')
			{
				return false;
			}
			for (int i = 2; i < name.Length; i++)
			{
				if (name[i] < 'a' || name[i] > 'z')
				{
					return false;
				}
			}
			return true;
		}

		private static string Attribute(string property)
		{
			return property switch
			{
				"className" => "class", 
				"htmlFor" => "for", 
				"readOnly" => "readonly", 
				"tabIndex" => "tabindex", 
				"maxLength" => "maxlength", 
				_ => property, 
			};
		}
	}
	public sealed class JsText : JsNode
	{
		internal IText Native { get; }

		private protected override int NodeTypeCode => 3;

		private protected override string NodeName => "#text";

		private protected override JsValue NodeValue => JsValue.op_Implicit(((ICharacterData)Native).Data ?? "");

		internal JsText(ScriptHost host, IText text)
			: base(host, (INode)(object)text)
		{
			Native = text;
		}

		private protected override ObjectInstance Interface(DomTypes types)
		{
			return types?.Text;
		}

		public override string ToString()
		{
			return ((ICharacterData)Native).Data ?? "";
		}

		private protected override JsValue Member(string name)
		{
			return (JsValue)(name switch
			{
				"data" => JsValue.op_Implicit(((ICharacterData)Native).Data ?? ""), 
				"length" => JsValue.op_Implicit((((ICharacterData)Native).Data ?? "").Length), 
				"wholeText" => JsValue.op_Implicit(((ICharacterData)Native).Data ?? ""), 
				_ => base.Member(name), 
			});
		}

		private protected override bool Assign(string name, JsValue value)
		{
			if (name != "data")
			{
				return base.Assign(name, value);
			}
			SetText(JsNode.Text(value));
			return true;
		}
	}
	public sealed class JsComment : JsNode
	{
		internal IComment Native { get; }

		private protected override int NodeTypeCode => 8;

		private protected override string NodeName => "#comment";

		private protected override JsValue NodeValue => JsValue.op_Implicit(((ICharacterData)Native).Data ?? "");

		internal JsComment(ScriptHost host, IComment comment)
			: base(host, (INode)(object)comment)
		{
			Native = comment;
		}

		private protected override ObjectInstance Interface(DomTypes types)
		{
			return types?.Comment;
		}

		public override string ToString()
		{
			return "<!--" + ((ICharacterData)Native).Data + "-->";
		}

		private protected override JsValue Member(string name)
		{
			if (!(name == "data"))
			{
				return base.Member(name);
			}
			return JsValue.op_Implicit(((ICharacterData)Native).Data ?? "");
		}

		private protected override bool Assign(string name, JsValue value)
		{
			if (name != "data")
			{
				return base.Assign(name, value);
			}
			SetText(JsNode.Text(value));
			return true;
		}
	}
	public sealed class JsClassList
	{
		private readonly ScriptHost _host;

		private readonly IElement _element;

		public int Length => _element.ClassList.Length;

		internal JsClassList(ScriptHost host, IElement element)
		{
			_host = host;
			_element = element;
		}

		public bool Contains(string name)
		{
			return _element.ClassList.Contains(name);
		}

		public void Add(string name)
		{
			_element.ClassList.Add(new string[1] { name });
			_host.MarkDirty();
		}

		public void Remove(string name)
		{
			_element.ClassList.Remove(new string[1] { name });
			_host.MarkDirty();
		}

		public bool Toggle(string name)
		{
			bool flag = !_element.ClassList.Contains(name);
			if (flag)
			{
				_element.ClassList.Add(new string[1] { name });
			}
			else
			{
				_element.ClassList.Remove(new string[1] { name });
			}
			_host.MarkDirty();
			return flag;
		}
	}
	public sealed class JsStyle : ObjectInstance
	{
		private const string Attribute = "style";

		private readonly ScriptHost _host;

		private readonly IElement _element;

		internal JsStyle(ScriptHost host, IElement element)
			: base(host.Engine)
		{
			_host = host;
			_element = element;
		}

		public override JsValue Get(JsValue property, JsValue receiver)
		{
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Expected O, but got Unknown
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Expected O, but got Unknown
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Expected O, but got Unknown
			string text = (JsValueExtensions.IsString(property) ? JsValueExtensions.AsString(property) : null);
			if (text == null)
			{
				return JsValue.Undefined;
			}
			switch (text)
			{
			case "cssText":
				return JsValue.op_Implicit(_element.GetAttribute("style") ?? "");
			case "setProperty":
				return (JsValue)new ClrFunction(((ObjectInstance)this).Engine, text, (Func<JsValue, JsValue[], JsValue>)delegate(JsValue _, JsValue[] a)
				{
					Apply((a.Length != 0) ? Kebab(((object)a[0]).ToString()) : "", (a.Length > 1) ? Str(a[1]) : "");
					return JsValue.Undefined;
				}, 0, (PropertyFlag)42);
			case "removeProperty":
				return (JsValue)new ClrFunction(((ObjectInstance)this).Engine, text, (Func<JsValue, JsValue[], JsValue>)delegate(JsValue _, JsValue[] a)
				{
					string text3 = ((a.Length != 0) ? Kebab(((object)a[0]).ToString()) : "");
					JsValue result = JsValue.op_Implicit(Read(text3)) ?? JsValue.op_Implicit("");
					Apply(text3, "");
					return result;
				}, 0, (PropertyFlag)42);
			case "getPropertyValue":
				return (JsValue)new ClrFunction(((ObjectInstance)this).Engine, text, (Func<JsValue, JsValue[], JsValue>)((JsValue _, JsValue[] a) => JsValue.op_Implicit(Read((a.Length != 0) ? Kebab(((object)a[0]).ToString()) : "")) ?? JsValue.op_Implicit("")), 0, (PropertyFlag)42);
			default:
			{
				string text2 = Read(Kebab(text));
				if (text2 == null)
				{
					return JsValue.op_Implicit("");
				}
				return JsValue.op_Implicit(text2);
			}
			}
		}

		public override bool Set(JsValue property, JsValue value, JsValue receiver)
		{
			if (!JsValueExtensions.IsString(property))
			{
				return false;
			}
			string text = JsValueExtensions.AsString(property);
			Apply((text == "cssText") ? null : Kebab(text), Str(value));
			return true;
		}

		public override bool HasProperty(JsValue property)
		{
			if (JsValueExtensions.IsString(property))
			{
				if (!(JsValueExtensions.AsString(property) == "cssText"))
				{
					return Read(Kebab(JsValueExtensions.AsString(property))) != null;
				}
				return true;
			}
			return false;
		}

		private static string Str(JsValue value)
		{
			if (!JsValueExtensions.IsNull(value) && !JsValueExtensions.IsUndefined(value))
			{
				return ((object)value).ToString();
			}
			return "";
		}

		private void Apply(string css, string text)
		{
			if (!string.Equals(((css == null) ? _element.GetAttribute("style") : Read(css)) ?? "", text, StringComparison.Ordinal))
			{
				Write(css, text);
				if (PaintOnlyProperties.Covers(css))
				{
					_host.MarkPaintDirty(_element);
				}
				else
				{
					_host.MarkDirty();
				}
			}
		}

		private string Read(string property)
		{
			if (string.IsNullOrEmpty(property))
			{
				return null;
			}
			foreach (Declaration item in CssParser.ParseDeclarations(_element.GetAttribute("style") ?? ""))
			{
				if (string.Equals(item.Property, property, StringComparison.OrdinalIgnoreCase))
				{
					return item.Value;
				}
			}
			return null;
		}

		private void Write(string property, string value)
		{
			if (property == null)
			{
				_element.SetAttribute("style", value);
				return;
			}
			List<string> list = new List<string>();
			foreach (Declaration item in CssParser.ParseDeclarations(_element.GetAttribute("style") ?? ""))
			{
				if (!string.Equals(item.Property, property, StringComparison.OrdinalIgnoreCase))
				{
					list.Add(item.Property + ": " + item.Value);
				}
			}
			if (!string.IsNullOrEmpty(value))
			{
				list.Add(property + ": " + value);
			}
			_element.SetAttribute("style", string.Join("; ", list));
		}

		private static string Kebab(string name)
		{
			if (string.IsNullOrEmpty(name) || name.IndexOf('-') >= 0)
			{
				return name;
			}
			StringBuilder stringBuilder = new StringBuilder(name.Length + 4);
			foreach (char c in name)
			{
				if (char.IsUpper(c))
				{
					stringBuilder.Append('-');
					stringBuilder.Append(char.ToLowerInvariant(c));
				}
				else
				{
					stringBuilder.Append(c);
				}
			}
			return stringBuilder.ToString();
		}
	}
	public sealed class JsDocument
	{
		private readonly ScriptHost _host;

		private readonly IDocument _document;

		public int NodeType => 9;

		public string NodeName => "#document";

		public string ReadyState => "complete";

		public JsElement Body
		{
			get
			{
				ScriptHost host = _host;
				IElement body = (IElement)(object)_document.Body;
				return host.Wrap(body ?? _document.DocumentElement);
			}
		}

		public JsElement DocumentElement => _host.Wrap(_document.DocumentElement);

		public JsElement Head => _host.Wrap((IElement)(object)_document.Head);

		public JsElement ActiveElement => _host.Wrap(_host.ActiveElement());

		public string Title
		{
			get
			{
				return _document.Title ?? "";
			}
			set
			{
				_document.Title = value ?? "";
			}
		}

		internal JsDocument(ScriptHost host, IDocument document)
		{
			_host = host;
			_document = document;
		}

		public JsElement GetElementById(string id)
		{
			return _host.Wrap(((INonElementParentNode)_document).GetElementById(id));
		}

		public JsElement QuerySelector(string selector)
		{
			return _host.Wrap(Try(() => ((IParentNode)_document).QuerySelector(selector)));
		}

		public JsValue QuerySelectorAll(string selector)
		{
			return _host.WrapNodes(Try(() => (IEnumerable<IElement>)((IParentNode)_document).QuerySelectorAll(selector)) ?? Array.Empty<IElement>());
		}

		public JsElement CreateElement(string tag)
		{
			return _host.Wrap(_document.CreateElement(tag));
		}

		public JsElement CreateElement(string tag, JsValue options)
		{
			return CreateElement(tag);
		}

		public JsElement CreateElementNS(string ns, string tag)
		{
			return _host.Wrap(string.IsNullOrEmpty(ns) ? _document.CreateElement(tag) : (Try(() => _document.CreateElement(ns, tag)) ?? _document.CreateElement(tag)));
		}

		public JsElement CreateElementNS(string ns, string tag, JsValue options)
		{
			return CreateElementNS(ns, tag);
		}

		public JsNode CreateTextNode(string text)
		{
			return _host.WrapNode((INode)(object)_document.CreateTextNode(text ?? ""));
		}

		public JsNode CreateComment(string text)
		{
			return _host.WrapNode((INode)(object)_document.CreateComment(text ?? ""));
		}

		public void AddEventListener(string type, JsValue handler)
		{
			AddEventListener(type, handler, (JsValue)(object)JsBoolean.False);
		}

		public void AddEventListener(string type, JsValue handler, JsValue options)
		{
			ScriptHost host = _host;
			INode body = (INode)(object)_document.Body;
			host.AddListener((INode)(((object)body) ?? ((object)_document.DocumentElement)), type, handler, IsCapture(options));
		}

		public void RemoveEventListener(string type, JsValue handler)
		{
			RemoveEventListener(type, handler, (JsValue)(object)JsBoolean.False);
		}

		public void RemoveEventListener(string type, JsValue handler, JsValue options)
		{
			ScriptHost host = _host;
			INode body = (INode)(object)_document.Body;
			host.RemoveListener((INode)(((object)body) ?? ((object)_document.DocumentElement)), type, handler, IsCapture(options));
		}

		internal static bool IsCapture(JsValue options)
		{
			if (options == (JsValue)null || JsValueExtensions.IsUndefined(options) || JsValueExtensions.IsNull(options))
			{
				return false;
			}
			if (JsValueExtensions.IsBoolean(options))
			{
				return JsValueExtensions.AsBoolean(options);
			}
			ObjectInstance val = (ObjectInstance)(object)((options is ObjectInstance) ? options : null);
			if (val != null)
			{
				JsValue val2 = ((JsValue)val).Get(JsValue.op_Implicit("capture"));
				if (!JsValueExtensions.IsUndefined(val2))
				{
					return TypeConverter.ToBoolean(val2);
				}
				return false;
			}
			return false;
		}

		private static T Try<T>(Func<T> run) where T : class
		{
			try
			{
				return run();
			}
			catch
			{
				return null;
			}
		}
	}
	public sealed class JsRect
	{
		public double x { get; set; }

		public double y { get; set; }

		public double width { get; set; }

		public double height { get; set; }

		public double top { get; set; }

		public double left { get; set; }

		public double right { get; set; }

		public double bottom { get; set; }
	}
	public sealed class JsEvent
	{
		public string Type { get; }

		public JsNode Target { get; }

		public JsNode CurrentTarget { get; internal set; }

		public int EventPhase { get; internal set; }

		public bool Bubbles { get; internal set; } = true;

		public string Value { get; internal set; } = "";

		public string Key { get; internal set; } = "";

		public bool CtrlKey { get; internal set; }

		public bool ShiftKey { get; internal set; }

		public bool AltKey { get; internal set; }

		public bool Repeat { get; internal set; }

		public bool HasSelection { get; internal set; }

		public string Source { get; internal set; } = "";

		public float OffsetX { get; internal set; }

		public float OffsetY { get; internal set; }

		public float NormX { get; internal set; }

		public float NormY { get; internal set; }

		public float DeltaX { get; internal set; }

		public float DeltaY { get; internal set; }

		public float WheelDelta { get; internal set; }

		public float ClientX { get; internal set; }

		public float ClientY { get; internal set; }

		public int Button { get; internal set; }

		public int Detail { get; internal set; }

		public bool DefaultPrevented { get; private set; }

		internal bool PropagationStopped { get; private set; }

		internal bool ImmediatelyStopped { get; private set; }

		internal JsEvent(string type, JsNode target)
		{
			Type = type;
			Target = target;
			CurrentTarget = target;
		}

		public void PreventDefault()
		{
			DefaultPrevented = true;
		}

		public void StopPropagation()
		{
			PropagationStopped = true;
		}

		public void StopImmediatePropagation()
		{
			PropagationStopped = true;
			ImmediatelyStopped = true;
		}
	}
	internal sealed class DomTypes
	{
		private const string Bootstrap = "(function () {\n  function extend(child, parent) {\n    child.prototype = Object.create(parent.prototype);\n    child.prototype.constructor = child;\n    return child;\n  }\n\n  function EventTarget() {}\n  function Node() {}                 extend(Node, EventTarget);\n  function CharacterData() {}        extend(CharacterData, Node);\n  function Text() {}                 extend(Text, CharacterData);\n  function Comment() {}              extend(Comment, CharacterData);\n  function Document() {}             extend(Document, Node);\n  function Element() {}              extend(Element, Node);\n  function HTMLElement() {}          extend(HTMLElement, Element);\n\n  var tags = {\n    HTMLDivElement: 'div', HTMLSpanElement: 'span', HTMLParagraphElement: 'p',\n    HTMLButtonElement: 'button', HTMLInputElement: 'input', HTMLTextAreaElement: 'textarea',\n    HTMLSelectElement: 'select', HTMLOptionElement: 'option', HTMLLabelElement: 'label',\n    HTMLAnchorElement: 'a', HTMLImageElement: 'img', HTMLUListElement: 'ul',\n    HTMLOListElement: 'ol', HTMLLIElement: 'li', HTMLFormElement: 'form',\n    HTMLHeadingElement: 'h1', HTMLTableElement: 'table', HTMLCanvasElement: 'canvas',\n    // Nothing is ever one of these. They are here because code branches on them and an absent name throws.\n    HTMLIFrameElement: null, HTMLVideoElement: null, HTMLAudioElement: null, SVGElement: null,\n  };\n\n  // `new CustomEvent('picked', { detail: id })` and `el.dispatchEvent(evt)`, which is how one part of a page\n  // tells another that something happened without the two knowing about each other. Only `type` reaches the\n  // listeners - see ScriptHost.DispatchFromScript for why nothing else could be honest here.\n  function Event(type, init) {\n    init = init || {};\n    this.type = String(type);\n    this.bubbles = !!init.bubbles;\n    this.cancelable = !!init.cancelable;\n    this.defaultPrevented = false;\n  }\n  Event.prototype.preventDefault = function () { if (this.cancelable) this.defaultPrevented = true; };\n  Event.prototype.stopPropagation = function () {};\n  Event.prototype.stopImmediatePropagation = function () {};\n\n  function CustomEvent(type, init) { Event.call(this, type, init); this.detail = init ? init.detail : null; }\n  extend(CustomEvent, Event);\n\n  var byTag = {};\n  var globals = {\n    EventTarget: EventTarget, Node: Node, CharacterData: CharacterData, Text: Text,\n    Comment: Comment, Document: Document, Element: Element, HTMLElement: HTMLElement,\n    Event: Event, CustomEvent: CustomEvent,\n  };\n\n  for (var name in tags) {\n    var ctor = new Function('return function ' + name + '() {}')();\n    extend(ctor, HTMLElement);\n    globals[name] = ctor;\n    if (tags[name]) byTag[tags[name]] = ctor.prototype;\n  }\n\n  for (var key in globals) globalThis[key] = globals[key];\n\n  return {\n    node: Node.prototype,\n    text: Text.prototype,\n    comment: Comment.prototype,\n    document: Document.prototype,\n    element: HTMLElement.prototype,\n    byTag: byTag,\n  };\n})()";

		private readonly ObjectInstance _byTag;

		internal ObjectInstance Node { get; }

		internal ObjectInstance Text { get; }

		internal ObjectInstance Comment { get; }

		internal ObjectInstance Document { get; }

		internal ObjectInstance Element { get; }

		internal DomTypes(Engine engine)
		{
			ObjectInstance val = JsValueExtensions.AsObject(engine.Evaluate("(function () {\n  function extend(child, parent) {\n    child.prototype = Object.create(parent.prototype);\n    child.prototype.constructor = child;\n    return child;\n  }\n\n  function EventTarget() {}\n  function Node() {}                 extend(Node, EventTarget);\n  function CharacterData() {}        extend(CharacterData, Node);\n  function Text() {}                 extend(Text, CharacterData);\n  function Comment() {}              extend(Comment, CharacterData);\n  function Document() {}             extend(Document, Node);\n  function Element() {}              extend(Element, Node);\n  function HTMLElement() {}          extend(HTMLElement, Element);\n\n  var tags = {\n    HTMLDivElement: 'div', HTMLSpanElement: 'span', HTMLParagraphElement: 'p',\n    HTMLButtonElement: 'button', HTMLInputElement: 'input', HTMLTextAreaElement: 'textarea',\n    HTMLSelectElement: 'select', HTMLOptionElement: 'option', HTMLLabelElement: 'label',\n    HTMLAnchorElement: 'a', HTMLImageElement: 'img', HTMLUListElement: 'ul',\n    HTMLOListElement: 'ol', HTMLLIElement: 'li', HTMLFormElement: 'form',\n    HTMLHeadingElement: 'h1', HTMLTableElement: 'table', HTMLCanvasElement: 'canvas',\n    // Nothing is ever one of these. They are here because code branches on them and an absent name throws.\n    HTMLIFrameElement: null, HTMLVideoElement: null, HTMLAudioElement: null, SVGElement: null,\n  };\n\n  // `new CustomEvent('picked', { detail: id })` and `el.dispatchEvent(evt)`, which is how one part of a page\n  // tells another that something happened without the two knowing about each other. Only `type` reaches the\n  // listeners - see ScriptHost.DispatchFromScript for why nothing else could be honest here.\n  function Event(type, init) {\n    init = init || {};\n    this.type = String(type);\n    this.bubbles = !!init.bubbles;\n    this.cancelable = !!init.cancelable;\n    this.defaultPrevented = false;\n  }\n  Event.prototype.preventDefault = function () { if (this.cancelable) this.defaultPrevented = true; };\n  Event.prototype.stopPropagation = function () {};\n  Event.prototype.stopImmediatePropagation = function () {};\n\n  function CustomEvent(type, init) { Event.call(this, type, init); this.detail = init ? init.detail : null; }\n  extend(CustomEvent, Event);\n\n  var byTag = {};\n  var globals = {\n    EventTarget: EventTarget, Node: Node, CharacterData: CharacterData, Text: Text,\n    Comment: Comment, Document: Document, Element: Element, HTMLElement: HTMLElement,\n    Event: Event, CustomEvent: CustomEvent,\n  };\n\n  for (var name in tags) {\n    var ctor = new Function('return function ' + name + '() {}')();\n    extend(ctor, HTMLElement);\n    globals[name] = ctor;\n    if (tags[name]) byTag[tags[name]] = ctor.prototype;\n  }\n\n  for (var key in globals) globalThis[key] = globals[key];\n\n  return {\n    node: Node.prototype,\n    text: Text.prototype,\n    comment: Comment.prototype,\n    document: Document.prototype,\n    element: HTMLElement.prototype,\n    byTag: byTag,\n  };\n})()", (string)null));
			Node = JsValueExtensions.AsObject(((JsValue)val).Get(JsValue.op_Implicit("node")));
			Text = JsValueExtensions.AsObject(((JsValue)val).Get(JsValue.op_Implicit("text")));
			Comment = JsValueExtensions.AsObject(((JsValue)val).Get(JsValue.op_Implicit("comment")));
			Document = JsValueExtensions.AsObject(((JsValue)val).Get(JsValue.op_Implicit("document")));
			Element = JsValueExtensions.AsObject(((JsValue)val).Get(JsValue.op_Implicit("element")));
			_byTag = JsValueExtensions.AsObject(((JsValue)val).Get(JsValue.op_Implicit("byTag")));
		}

		internal ObjectInstance For(string tag)
		{
			if (string.IsNullOrEmpty(tag))
			{
				return Element;
			}
			JsValue val = ((JsValue)_byTag).Get(JsValue.op_Implicit(tag.ToLowerInvariant()));
			if (!JsValueExtensions.IsObject(val))
			{
				return Element;
			}
			return JsValueExtensions.AsObject(val);
		}
	}
	internal sealed class FetchApi
	{
		private const int MaxInFlight = 8;

		private const string ResponseFactory = "(function (status, statusText, url, headerLines, body, redirected) {\n  var map = {};\n  var lines = headerLines ? headerLines.split('\\n') : [];\n  for (var i = 0; i < lines.length; i++) {\n    var at = lines[i].indexOf(':');\n    if (at > 0) map[lines[i].substring(0, at).trim().toLowerCase()] = lines[i].substring(at + 1).trim();\n  }\n\n  return {\n    ok: status >= 200 && status < 300,\n    status: status,\n    statusText: statusText,\n    url: url,\n    redirected: redirected,\n    headers: {\n      get: function (name) { var k = String(name).toLowerCase(); return k in map ? map[k] : null; },\n      has: function (name) { return String(name).toLowerCase() in map; }\n    },\n    // Already-settled promises: the body was read before the page was handed the response, so these match the web's\n    // shape without ever being pending.\n    text: function () { return Promise.resolve(body); },\n    json: function () {\n      try { return Promise.resolve(JSON.parse(body)); }\n      catch (e) { return Promise.reject(e); }\n    }\n  };\n})";

		private const string Wrapper = "(function (call) {\n  return function fetch(url, init) {\n    return call(url === undefined || url === null ? '' : String(url), init);\n  };\n})";

		private readonly ConcurrentQueue<Action> _finished = new ConcurrentQueue<Action>();

		private readonly Engine _engine;

		private readonly Promises _promises;

		private readonly Action<string> _onError;

		private readonly string _appId;

		private JsValue _responseFactory;

		private int _inFlight;

		internal int Ready => _finished.Count;

		internal FetchApi(Engine engine, string appId, Promises promises, Action<string> onError)
		{
			_engine = engine;
			_appId = appId ?? "";
			_promises = promises;
			_onError = onError;
		}

		internal void Install()
		{
			_responseFactory = _engine.Evaluate("(function (status, statusText, url, headerLines, body, redirected) {\n  var map = {};\n  var lines = headerLines ? headerLines.split('\\n') : [];\n  for (var i = 0; i < lines.length; i++) {\n    var at = lines[i].indexOf(':');\n    if (at > 0) map[lines[i].substring(0, at).trim().toLowerCase()] = lines[i].substring(at + 1).trim();\n  }\n\n  return {\n    ok: status >= 200 && status < 300,\n    status: status,\n    statusText: statusText,\n    url: url,\n    redirected: redirected,\n    headers: {\n      get: function (name) { var k = String(name).toLowerCase(); return k in map ? map[k] : null; },\n      has: function (name) { return String(name).toLowerCase() in map; }\n    },\n    // Already-settled promises: the body was read before the page was handed the response, so these match the web's\n    // shape without ever being pending.\n    text: function () { return Promise.resolve(body); },\n    json: function () {\n      try { return Promise.resolve(JSON.parse(body)); }\n      catch (e) { return Promise.reject(e); }\n    }\n  };\n})", (string)null);
			JsValue val = JsValue.FromObject(_engine, (object)new Func<string, JsValue, JsValue>(Call));
			_engine.SetValue("fetch", _engine.Invoke(_engine.Evaluate("(function (call) {\n  return function fetch(url, init) {\n    return call(url === undefined || url === null ? '' : String(url), init);\n  };\n})", (string)null), new object[1] { val }));
		}

		internal void Settle()
		{
			Action result;
			while (_finished.TryDequeue(out result))
			{
				try
				{
					result();
				}
				catch (Exception ex)
				{
					_onError?.Invoke("settling a fetch failed: " + ex.Message);
				}
			}
		}

		private JsValue Call(string url, JsValue init)
		{
			Deferred deferred = _promises.Create();
			FetchCall fetchCall = new FetchCall
			{
				AppId = _appId
			};
			if (!Uri.TryCreate(url, UriKind.Absolute, out Uri result) || (result.Scheme != Uri.UriSchemeHttp && result.Scheme != Uri.UriSchemeHttps))
			{
				Later(delegate
				{
					deferred.Reject("fetch needs an absolute http(s) URL - got '" + Trim(url) + "'.");
				});
				return deferred.Promise;
			}
			fetchCall.Url = result;
			try
			{
				ReadInit(_engine, init, fetchCall);
			}
			catch (Exception ex)
			{
				Exception ex2 = ex;
				Exception e = ex2;
				Later(delegate
				{
					deferred.Reject("the second argument to fetch is not usable: " + e.Message);
				});
				return deferred.Promise;
			}
			if (!HostAllowlist.Allows(_appId, result, out var reason))
			{
				HostAllowlist.ReportOnce(_appId, result, reason);
				Later(delegate
				{
					deferred.Reject(reason);
				});
				return deferred.Promise;
			}
			if (_inFlight >= 8)
			{
				Later(delegate
				{
					deferred.Reject($"too many requests at once - this app already has {8} " + "fetches in flight. Wait for one to settle before starting another.");
				});
				return deferred.Promise;
			}
			_inFlight++;
			Fetcher.Send(fetchCall, delegate(FetchOutcome outcome)
			{
				_finished.Enqueue(delegate
				{
					_inFlight--;
					if (outcome.Failed)
					{
						deferred.Reject(outcome.Error);
					}
					else
					{
						deferred.Resolve(Response(outcome));
					}
				});
			});
			return deferred.Promise;
		}

		private void Later(Action settle)
		{
			_finished.Enqueue(settle);
		}

		private JsValue Response(FetchOutcome outcome)
		{
			return _engine.Invoke(_responseFactory, new object[6] { outcome.Status, outcome.StatusText, outcome.Url, outcome.HeaderLines, outcome.Body, outcome.Redirected });
		}

		private static void ReadInit(Engine engine, JsValue init, FetchCall call)
		{
			if (init == (JsValue)null || JsValueExtensions.IsUndefined(init) || JsValueExtensions.IsNull(init) || !JsValueExtensions.IsObject(init))
			{
				return;
			}
			ObjectInstance obj = JsValueExtensions.AsObject(init);
			JsValue val = ((JsValue)obj).Get(JsValue.op_Implicit("method"));
			if (!JsValueExtensions.IsUndefined(val) && !JsValueExtensions.IsNull(val))
			{
				call.Method = ((object)val).ToString();
			}
			JsValue val2 = ((JsValue)obj).Get(JsValue.op_Implicit("body"));
			bool flag = false;
			if (!JsValueExtensions.IsUndefined(val2) && !JsValueExtensions.IsNull(val2))
			{
				call.Body = ((object)val2).ToString();
				flag = WebApis.IsFormData(engine, val2);
			}
			JsValue val3 = ((JsValue)obj).Get(JsValue.op_Implicit("timeout"));
			if (JsValueExtensions.IsNumber(val3))
			{
				call.TimeoutMs = (int)JsValueExtensions.AsNumber(val3);
			}
			bool flag2 = false;
			JsValue val4 = ((JsValue)obj).Get(JsValue.op_Implicit("headers"));
			if (JsValueExtensions.IsObject(val4))
			{
				ObjectInstance val5 = JsValueExtensions.AsObject(val4);
				foreach (KeyValuePair<JsValue, PropertyDescriptor> ownProperty in val5.GetOwnProperties())
				{
					JsValue val6 = ((JsValue)val5).Get(ownProperty.Key);
					if (!JsValueExtensions.IsUndefined(val6) && !JsValueExtensions.IsNull(val6))
					{
						string text = ((object)ownProperty.Key).ToString();
						flag2 |= string.Equals(text, "content-type", StringComparison.OrdinalIgnoreCase);
						call.Headers.Add(new KeyValuePair<string, string>(text, ((object)val6).ToString()));
					}
				}
			}
			if (flag && !flag2)
			{
				call.Headers.Add(new KeyValuePair<string, string>("Content-Type", "application/x-www-form-urlencoded"));
			}
		}

		private static string Trim(string url)
		{
			string text;
			if (url == null || url.Length <= 80)
			{
				text = url;
				if (text == null)
				{
					return "";
				}
			}
			else
			{
				text = url.Substring(0, 80) + "...";
			}
			return text;
		}
	}
	internal static class MiniJson
	{
		internal static string WriteObject(Dictionary<string, string> values)
		{
			if (values == null || values.Count == 0)
			{
				return "{}";
			}
			StringBuilder stringBuilder = new StringBuilder("{");
			bool flag = true;
			foreach (KeyValuePair<string, string> value in values)
			{
				if (!flag)
				{
					stringBuilder.Append(',');
				}
				flag = false;
				stringBuilder.Append('\n').Append("  ");
				Escape(stringBuilder, value.Key);
				stringBuilder.Append(": ");
				Escape(stringBuilder, value.Value);
			}
			return stringBuilder.Append("\n}").ToString();
		}

		internal static Dictionary<string, string> ParseObject(string json)
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.Ordinal);
			if (string.IsNullOrWhiteSpace(json))
			{
				return dictionary;
			}
			int i = 0;
			SkipWhitespace(json, ref i);
			if (i >= json.Length || json[i] != '{')
			{
				return dictionary;
			}
			i++;
			while (true)
			{
				SkipWhitespace(json, ref i);
				if (i >= json.Length || json[i] == '}')
				{
					break;
				}
				if (json[i] == ',')
				{
					i++;
					continue;
				}
				if (json[i] != '"')
				{
					break;
				}
				string key = ReadString(json, ref i);
				SkipWhitespace(json, ref i);
				if (i >= json.Length || json[i] != ':')
				{
					break;
				}
				i++;
				SkipWhitespace(json, ref i);
				if (i >= json.Length)
				{
					break;
				}
				dictionary[key] = ((json[i] == '"') ? ReadString(json, ref i) : ReadBareValue(json, ref i));
			}
			return dictionary;
		}

		private static void Escape(StringBuilder sb, string value)
		{
			sb.Append('"');
			string text = value ?? "";
			foreach (char c in text)
			{
				switch (c)
				{
				case '"':
					sb.Append("\\\"");
					continue;
				case '\\':
					sb.Append("\\\\");
					continue;
				case '\n':
					sb.Append("\\n");
					continue;
				case '\r':
					sb.Append("\\r");
					continue;
				case '\t':
					sb.Append("\\t");
					continue;
				}
				if (c < ' ')
				{
					StringBuilder stringBuilder = sb.Append("\\u");
					int num = c;
					stringBuilder.Append(num.ToString("x4"));
				}
				else
				{
					sb.Append(c);
				}
			}
			sb.Append('"');
		}

		private static string ReadString(string json, ref int i)
		{
			StringBuilder stringBuilder = new StringBuilder();
			i++;
			while (i < json.Length)
			{
				char c = json[i++];
				switch (c)
				{
				default:
					stringBuilder.Append(c);
					continue;
				case '\\':
				{
					if (i >= json.Length)
					{
						break;
					}
					char c2 = json[i++];
					switch (c2)
					{
					case 'n':
						stringBuilder.Append('\n');
						break;
					case 'r':
						stringBuilder.Append('\r');
						break;
					case 't':
						stringBuilder.Append('\t');
						break;
					case 'b':
						stringBuilder.Append('\b');
						break;
					case 'f':
						stringBuilder.Append('\f');
						break;
					case 'u':
					{
						if (i + 4 <= json.Length && int.TryParse(json.Substring(i, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var result))
						{
							stringBuilder.Append((char)result);
							i += 4;
						}
						break;
					}
					default:
						stringBuilder.Append(c2);
						break;
					}
					continue;
				}
				case '"':
					break;
				}
				break;
			}
			return stringBuilder.ToString();
		}

		private static string ReadBareValue(string json, ref int i)
		{
			int num = i;
			while (i < json.Length && json[i] != ',' && json[i] != '}')
			{
				i++;
			}
			return json.Substring(num, i - num).Trim();
		}

		private static void SkipWhitespace(string json, ref int i)
		{
			while (i < json.Length && char.IsWhiteSpace(json[i]))
			{
				i++;
			}
		}
	}
	internal sealed class Promises
	{
		private const string Factory = "(function (report) {\n  var settle, fail;\n  var root = new Promise(function (ok, no) { settle = ok; fail = no; });\n\n  function watch(p) {\n    var chained = false;\n    var then = p.then.bind(p);\n\n    p.then    = function (ok, no) { chained = true; return watch(then(ok, no)); };\n    p.catch   = function (no)     { chained = true; return watch(then(undefined, no)); };\n    p.finally = function (fn)     { chained = true; return watch(then(\n                                      function (v) { fn(); return v; },\n                                      function (e) { fn(); throw e; })); };\n\n    then(undefined, function (err) {\n      if (!chained) report(String(err && err.message ? err.message : err));\n    });\n    return p;\n  }\n\n  return {\n    promise: watch(root),\n    resolve: settle,\n    reject: function (message) { fail(new Error(message)); }\n  };\n})";

		private readonly Engine _engine;

		private readonly JsValue _factory;

		private readonly JsValue _report;

		internal Promises(Engine engine, Action<string> onUnhandledRejection)
		{
			_engine = engine;
			_factory = engine.Evaluate("(function (report) {\n  var settle, fail;\n  var root = new Promise(function (ok, no) { settle = ok; fail = no; });\n\n  function watch(p) {\n    var chained = false;\n    var then = p.then.bind(p);\n\n    p.then    = function (ok, no) { chained = true; return watch(then(ok, no)); };\n    p.catch   = function (no)     { chained = true; return watch(then(undefined, no)); };\n    p.finally = function (fn)     { chained = true; return watch(then(\n                                      function (v) { fn(); return v; },\n                                      function (e) { fn(); throw e; })); };\n\n    then(undefined, function (err) {\n      if (!chained) report(String(err && err.message ? err.message : err));\n    });\n    return p;\n  }\n\n  return {\n    promise: watch(root),\n    resolve: settle,\n    reject: function (message) { fail(new Error(message)); }\n  };\n})", (string)null);
			_report = JsValue.FromObject(engine, (object)(Action<string>)delegate(string m)
			{
				onUnhandledRejection?.Invoke(m);
			});
		}

		internal Deferred Create()
		{
			ObjectInstance val = JsValueExtensions.AsObject(_engine.Invoke(_factory, new object[1] { _report }));
			return new Deferred(_engine, ((JsValue)val).Get(JsValue.op_Implicit("promise")), ((JsValue)val).Get(JsValue.op_Implicit("resolve")), ((JsValue)val).Get(JsValue.op_Implicit("reject")));
		}

		internal void Pump()
		{
			_engine.Constraints.Reset();
			_engine.Advanced.ProcessTasks();
		}
	}
	internal sealed class Deferred
	{
		private readonly Engine _engine;

		private readonly JsValue _resolve;

		private readonly JsValue _reject;

		internal JsValue Promise { get; }

		internal Deferred(Engine engine, JsValue promise, JsValue resolve, JsValue reject)
		{
			_engine = engine;
			Promise = promise;
			_resolve = resolve;
			_reject = reject;
		}

		internal void Resolve(JsValue value)
		{
			_engine.Invoke(_resolve, new object[1] { value ?? JsValue.Undefined });
		}

		internal void Reject(string message)
		{
			_engine.Invoke(_reject, new object[1] { message ?? "" });
		}
	}
	internal sealed class ScriptHost
	{
		private readonly struct Listener
		{
			internal JsValue Handler { get; }

			internal bool Capture { get; }

			internal Listener(JsValue handler, bool capture)
			{
				Handler = handler;
				Capture = capture;
			}
		}

		private sealed class Timer
		{
			internal int Id;

			internal JsValue Callback;

			internal double Remaining;

			internal double Interval;

			internal bool Cancelled;
		}

		public sealed class Console
		{
			private readonly string _appId;

			internal Console(string appId)
			{
				_appId = appId;
			}

			public void Log(params object[] args)
			{
				Emit("log", args);
			}

			public void Info(params object[] args)
			{
				Emit("info", args);
			}

			public void Warn(params object[] args)
			{
				Emit("warn", args);
			}

			public void Error(params object[] args)
			{
				Emit("error", args);
			}

			private void Emit(string level, object[] args)
			{
				string text = Format(args);
				if (!(level == "warn"))
				{
					if (level == "error")
					{
						Platform.Error(text);
					}
					else
					{
						Platform.Msg(text);
					}
				}
				else
				{
					Platform.Warning(text);
				}
				Diagnostics?.Invoke(_appId, level, args, text);
			}

			private string Format(object[] args)
			{
				if (args == null || args.Length == 0)
				{
					return "[" + _appId + "]";
				}
				return "[" + _appId + "] " + string.Join(" ", Array.ConvertAll(args, (object a) => a?.ToString() ?? "null"));
			}
		}

		private readonly TimeBudget _budget = new TimeBudget();

		internal static Action<string, string, object[], string> Diagnostics = null;

		private readonly Dictionary<INode, Dictionary<string, List<Listener>>> _listeners = new Dictionary<INode, Dictionary<string, List<Listener>>>();

		private readonly Dictionary<INode, JsNode> _wrappers = new Dictionary<INode, JsNode>();

		private readonly List<Timer> _timers = new List<Timer>();

		private readonly string _appId;

		private Promises _promises;

		private FetchApi _fetch;

		private IDocument _document;

		private JsDocument _documentObject;

		private Bridge _bridge;

		private int _nextTimerId = 1;

		private bool _failed;

		private static readonly Dictionary<string, Prepared<Script>> _prepared = new Dictionary<string, Prepared<Script>>(StringComparer.Ordinal);

		private const int PrepareFrom = 2048;

		private static readonly HashSet<string> Dispatchable = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
		{
			"click", "dblclick", "contextmenu", "mousedown", "mouseup", "mouseenter", "mouseleave", "mouseover", "mouseout", "mousemove",
			"wheel", "input", "change", "keydown", "focus", "blur", "focusin", "focusout", "dragstart", "drag",
			"dragend", "orientationchange", "back"
		};

		private static readonly HashSet<string> NonBubbling = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "mouseenter", "mouseleave", "focus", "blur" };

		private readonly Dictionary<INode, Dictionary<string, JsValue>> _inlineHandlers = new Dictionary<INode, Dictionary<string, JsValue>>();

		internal Engine Engine { get; }

		internal Action OnDomChanged { get; }

		internal Action<IElement> OnFocusRequested { get; }

		internal Action<IElement> OnBlurRequested { get; }

		internal Action<IElement> OnScrollToEnd { get; }

		internal Func<IElement, float[]> OnRectRequested { get; }

		internal Func<IElement> OnActiveElementRequested { get; }

		internal Func<float[]> OnViewportRequested { get; }

		internal Action<IElement> OnPaintOnlyChange { get; }

		internal bool Failed => _failed;

		internal string LastError { get; private set; } = "";

		internal JsValue DocumentObject => JsValue.FromObject(Engine, (object)_documentObject);

		internal Func<IElement, string, bool> OnTextOnlyChange { get; set; }

		internal DomTypes Types { get; private set; }

		internal ScriptHost(string appId, IDocument document, Action onDomChanged, Action<IElement> onFocusRequested, Action<IElement> onScrollToEnd, Action<IElement> onPaintOnlyChange = null, Func<IElement, float[]> onRectRequested = null, Action<IElement> onBlurRequested = null, Func<IElement> onActiveElementRequested = null, Func<float[]> onViewportRequested = null)
		{
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Expected O, but got Unknown
			_appId = appId;
			_document = document;
			OnDomChanged = onDomChanged;
			OnFocusRequested = onFocusRequested;
			OnScrollToEnd = onScrollToEnd;
			OnPaintOnlyChange = onPaintOnlyChange;
			OnRectRequested = onRectRequested;
			OnBlurRequested = onBlurRequested;
			OnActiveElementRequested = onActiveElementRequested;
			OnViewportRequested = onViewportRequested;
			Engine = new Engine((Action<Options>)delegate(Options options)
			{
				//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)
				//IL_0068: Expected O, but got Unknown
				options.Constraints.Constraints.Add((Constraint)(object)_budget);
				ConstraintsOptionsExtensions.MaxStatements(options, 2000000);
				OptionsExtensions.LimitRecursion(options, 256);
				options.Strict = false;
				options.ExperimentalFeatures = (ExperimentalFeature)3;
				OptionsExtensions.SetTypeResolver(options, new TypeResolver
				{
					MemberNameCreator = BothCasings
				});
			});
			Bind();
		}

		internal void RestartBudget()
		{
			Engine engine = Engine;
			if (engine != null)
			{
				engine.Constraints.Reset();
			}
		}

		internal void Rebound(IDocument document)
		{
			_document = document;
			_wrappers.Clear();
			_documentObject = new JsDocument(this, _document);
			Engine.SetValue<JsDocument>("document", _documentObject);
		}

		internal IElement ActiveElement()
		{
			return OnActiveElementRequested?.Invoke();
		}

		internal void Dispose()
		{
			_bridge?.Dispose();
			_listeners.Clear();
			_inlineHandlers.Clear();
			_wrappers.Clear();
			_timers.Clear();
		}

		internal void Forget(INode node)
		{
			if (node == null)
			{
				return;
			}
			_wrappers.Remove(node);
			_listeners.Remove(node);
			_inlineHandlers.Remove(node);
			foreach (INode item in (IEnumerable<INode>)node.ChildNodes)
			{
				Forget(item);
			}
		}

		internal void MarkDirty()
		{
			OnDomChanged?.Invoke();
		}

		internal bool TryRetext(IElement element, string text)
		{
			if (OnTextOnlyChange != null)
			{
				return OnTextOnlyChange(element, text);
			}
			return false;
		}

		internal void MarkPaintDirty(IElement element)
		{
			if (OnPaintOnlyChange == null)
			{
				MarkDirty();
			}
			else
			{
				OnPaintOnlyChange(element);
			}
		}

		internal void RequestFocus(IElement element)
		{
			OnFocusRequested?.Invoke(element);
		}

		internal void RequestBlur(IElement element)
		{
			OnBlurRequested?.Invoke(element);
		}

		internal void RequestScrollToEnd(IElement element)
		{
			OnScrollToEnd?.Invoke(element);
		}

		internal float[] RectOf(IElement element)
		{
			return OnRectRequested?.Invoke(element) ?? new float[4];
		}

		internal JsElement Wrap(IElement element)
		{
			return (JsElement)WrapNode((INode)(object)element);
		}

		internal JsNode WrapNode(INode node)
		{
			if (node == null)
			{
				return null;
			}
			if (_wrappers.TryGetValue(node, out var value))
			{
				return value;
			}
			IElement val = (IElement)(object)((node is IElement) ? node : null);
			JsNode jsNode;
			if (val == null)
			{
				IText val2 = (IText)(object)((node is IText) ? node : null);
				if (val2 == null)
				{
					IComment val3 = (IComment)(object)((node is IComment) ? node : null);
					jsNode = ((val3 == null) ? null : new JsComment(this, val3));
				}
				else
				{
					jsNode = new JsText(this, val2);
				}
			}
			else
			{
				jsNode = new JsElement(this, val);
			}
			JsNode jsNode2 = jsNode;
			if ((JsValue)(object)jsNode2 != (JsValue)null)
			{
				_wrappers[node] = jsNode2;
			}
			return jsNode2;
		}

		internal JsValue WrapNodes(IEnumerable<INode> nodes)
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Expected O, but got Unknown
			List<JsValue> list = new List<JsValue>();
			if (nodes != null)
			{
				foreach (INode node in nodes)
				{
					JsNode jsNode = WrapNode(node);
					if ((JsValue)(object)jsNode != (JsValue)null)
					{
						list.Add((JsValue)(object)jsNode);
					}
				}
			}
			return (JsValue)new JsArray(Engine, list.ToArray());
		}

		internal JsValue WrapNodes(IEnumerable<IElement> elements)
		{
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Expected O, but got Unknown
			List<JsValue> list = new List<JsValue>();
			if (elements != null)
			{
				foreach (IElement element in elements)
				{
					JsNode jsNode = WrapNode((INode)(object)element);
					if ((JsValue)(object)jsNode != (JsValue)null)
					{
						list.Add((JsValue)(object)jsNode);
					}
				}
			}
			return (JsValue)new JsArray(Engine, list.ToArray());
		}

		internal void Run(string source, string fileName)
		{
			if (string.IsNullOrWhiteSpace(source))
			{
				return;
			}
			WarnAboutAwaitedFetch(source, fileName);
			try
			{
				_budget.During(Engine, TimeBudget.Load, delegate
				{
					//IL_003f: Unknown result type (might be due to invalid IL or missing references)
					//IL_0044: Unknown result type (might be due to invalid IL or missing references)
					//IL_0045: Unknown result type (might be due to invalid IL or missing references)
					if (source.Length >= 2048)
					{
						if (!_prepared.TryGetValue(source, out var value))
						{
							value = (_prepared[source] = Engine.PrepareScript(source, fileName, false, (ScriptPreparationOptions)null));
						}
						Engine.Execute(ref value);
					}
					else
					{
						Engine.Execute(source, fileName);
					}
				});
				Platform.Msg($"{fileName} executed ({source.Length} chars).");
			}
			catch (Exception e)
			{
				_failed = true;
				LastError = Describe(e);
				Platform.Error(fileName + " failed: " + LastError);
				Diagnostics?.Invoke(_appId, "exception", null, fileName + ": " + LastError);
			}
		}

		private static void WarnAboutAwaitedFetch(string source, string fileName)
		{
			if (source.IndexOf("fetch(", StringComparison.Ordinal) >= 0 && Regex.IsMatch(source, "\\bawait\\b"))
			{
				Platform.Warning("[Sideload] " + fileName + " uses both `await` and `fetch(`. Awaiting a PENDING promise freezes the game on this engine - it blocks the main thread that would settle it. Use `fetch(url).then(res => ...)` instead. Awaiting an already-settled promise, such as `res.text()`, is safe.");
			}
		}

		internal string Evaluate(string source, out bool failed)
		{
			failed = false;
			if (string.IsNullOrWhiteSpace(source))
			{
				return "";
			}
			try
			{
				JsValue val = Engine.Evaluate(source, (string)null);
				return JsValueExtensions.IsUndefined(val) ? "undefined" : Describe(val);
			}
			catch (Exception e)
			{
				failed = true;
				LastError = Describe(e);
				return LastError;
			}
		}

		private string Describe(JsValue value)
		{
			try
			{
				if (JsValueExtensions.IsNull(value))
				{
					return "null";
				}
				if (JsValueExtensions.IsString(value) || JsValueExtensions.IsNumber(value) || JsValueExtensions.IsBoolean(value))
				{
					return ((object)value).ToString();
				}
				JsValue val = JsValueExtensions.Call(Engine.Evaluate("JSON.stringify", (string)null), JsValue.Undefined, value);
				return JsValueExtensions.IsUndefined(val) ? ((object)value).ToString() : JsValueExtensions.AsString(val);
			}
			catch
			{
				return ((object)value).ToString();
			}
		}

		internal static bool Bubbles(string type)
		{
			return !NonBubbling.Contains(type ?? "");
		}

		internal void AddListener(INode node, string type, JsValue handler, bool capture = false)
		{
			if (node == null || string.IsNullOrEmpty(type) || handler == (JsValue)null || !JsValueExtensions.IsObject(handler))
			{
				return;
			}
			if (!Dispatchable.Contains(type))
			{
				Sideload.Model.Diagnostics.Report(DiagnosticKind.DeadEventListener, type);
			}
			if (!_listeners.TryGetValue(node, out var value))
			{
				value = (_listeners[node] = new Dictionary<string, List<Listener>>(StringComparer.OrdinalIgnoreCase));
			}
			if (!value.TryGetValue(type, out var value2))
			{
				value2 = (value[type] = new List<Listener>());
			}
			foreach (Listener item in value2)
			{
				if (item.Capture == capture && Same(item.Handler, handler))
				{
					return;
				}
			}
			value2.Add(new Listener(handler, capture));
			MarkDirty();
		}

		internal void RemoveListener(INode node, string type, JsValue handler, bool capture = false)
		{
			if (node != null && !(handler == (JsValue)null) && !string.IsNullOrEmpty(type) && _listeners.TryGetValue(node, out var value) && value.TryGetValue(type, out var value2) && value2.RemoveAll((Listener l) => l.Capture == capture && Same(l.Handler, handler)) > 0)
			{
				MarkDirty();
			}
		}

		private static bool Same(JsValue a, JsValue b)
		{
			if (a != b)
			{
				return object.Equals(a, b);
			}
			return true;
		}

		internal JsValue InlineHandler(INode node, string type)
		{
			if (_inlineHandlers.TryGetValue(node, out var value) && value.TryGetValue(type, out var value2))
			{
				return value2;
			}
			return JsValue.Null;
		}

		internal void SetInlineHandler(INode node, string type, JsValue handler)
		{
			if (!_inlineHandlers.TryGetValue(node, out var value))
			{
				value = (_inlineHandlers[node] = new Dictionary<string, JsValue>(StringComparer.OrdinalIgnoreCase));
			}
			if (value.TryGetValue(type, out var value2))
			{
				RemoveListener(node, type, value2);
			}
			if (handler == (JsValue)null || !JsValueExtensions.IsObject(handler))
			{
				value.Remove(type);
				return;
			}
			value[type] = handler;
			AddListener(node, type, handler);
		}

		internal IEnumerable<IElement> ElementsListeningFor(string type)
		{
			foreach (KeyValuePair<INode, Dictionary<string, List<Listener>>> listener in _listeners)
			{
				INode key = listener.Key;
				IElement val = (IElement)(object)((key is IElement) ? key : null);
				if (val != null && listener.Value.TryGetValue(type, out var value) && value.Count > 0)
				{
					yield return val;
				}
			}
		}

		internal JsEvent Dispatch(IElement target, string type, string value = "", string key = "", string source = "", PointerSpot spot = default(PointerSpot), float deltaX = 0f, float deltaY = 0f, float wheelDelta = 0f, bool ctrl = false, bool shift = false, bool alt = false, bool repeat = false, bool hasSelection = false, bool? bubbles = null, float clientX = 0f, float clientY = 0f, int button = 0, int detail = 0)
		{
			JsEvent jsEvent = new JsEvent(type, WrapNode((INode)(object)target))
			{
				Value = (value ?? ""),
				Key = (key ?? ""),
				Source = (source ?? ""),
				OffsetX = spot.OffsetX,
				OffsetY = spot.OffsetY,
				NormX = spot.NormX,
				NormY = spot.NormY,
				DeltaX = deltaX,
				DeltaY = deltaY,
				WheelDelta = wheelDelta,
				CtrlKey = ctrl,
				ShiftKey = shift,
				AltKey = alt,
				Repeat = repeat,
				HasSelection = hasSelection,
				ClientX = clientX,
				ClientY = clientY,
				Button = button,
				Detail = detail
			};
			if (_failed || target == null)
			{
				return jsEvent;
			}
			bool flag = bubbles ?? Bubbles(type);
			jsEvent.Bubbles = flag;
			List<IElement> list = new List<IElement>();
			for (IElement val = target; val != null; val = ((INode)val).ParentElement)
			{
				list.Add(val);
				if (!flag)
				{
					break;
				}
			}
			for (int num = list.Count - 1; num > 0; num--)
			{
				jsEvent.EventPhase = 1;
				if (!RunHandlers(list[num], type, jsEvent, capture: true))
				{
					return jsEvent;
				}
			}
			jsEvent.EventPhase = 2;
			if (!RunHandlers(target, type, jsEvent, capture: true))
			{
				return jsEvent;
			}
			if (!RunHandlers(target, type, jsEvent, capture: false))
			{
				return jsEvent;
			}
			for (int i = 1; i < list.Count; i++)
			{
				jsEvent.EventPhase = 3;
				if (!RunHandlers(list[i], type, jsEvent, capture: false))
				{
					return jsEvent;
				}
			}
			return jsEvent;
		}

		private bool RunHandlers(IElement node, string type, JsEvent evt, bool capture)
		{
			if (!_listeners.TryGetValue((INode)(object)node, out var value))
			{
				return true;
			}
			if (!value.TryGetValue(type, out var value2) || value2.Count == 0)
			{
				return true;
			}
			JsNode self = (evt.CurrentTarget = WrapNode((INode)(object)node));
			Listener[] array = value2.ToArray();
			for (int i = 0; i < array.Length; i++)
			{
				Listener listener = array[i];
				if (listener.Capture == capture)
				{
					InvokeOn(listener.Handler, (JsValue)(object)self, type + " handler on <" + node.LocalName + ">", JsValue.FromObject(Engine, (object)evt));
					if (evt.ImmediatelyStopped)
					{
						return false;
					}
				}
			}
			return !evt.PropagationStopped;
		}

		internal JsValue DispatchFromScript(INode node, ObjectInstance evt)
		{
			IElement val = (IElement)(object)((node is IElement) ? node : null);
			if (val == null || (JsValue)(object)evt == (JsValue)null)
			{
				return JsValue.op_Implicit(true);
			}
			JsValue val2 = ((JsValue)evt).Get(JsValue.op_Implicit("type"));
			if (JsValueExtensions.IsUndefined(val2) || JsValueExtensions.IsNull(val2))
			{
				return JsValue.op_Implicit(true);
			}
			return JsValue.op_Implicit(!Dispatch(val, ((object)val2).ToString()).DefaultPrevented);
		}

		internal void Tick(float deltaSeconds)
		{
			if (_failed)
			{
				return;
			}
			try
			{
				_fetch?.Settle();
			}
			catch (Exception e)
			{
				Report("settling a fetch", e);
			}
			try
			{
				_promises?.Pump();
			}
			catch (Exception e2)
			{
				Report("a pending promise", e2);
			}
			if (_timers.Count == 0)
			{
				return;
			}
			double num = (double)deltaSeconds * 1000.0;
			Timer[] array = _timers.ToArray();
			foreach (Timer timer in array)
			{
				if (timer.Cancelled)
				{
					continue;
				}
				timer.Remaining -= num;
				if (!(timer.Remaining > 0.0))
				{
					if (timer.Interval > 0.0)
					{
						timer.Remaining += timer.Interval;
					}
					else
					{
						timer.Cancelled = true;
					}
					Invoke(timer.Callback, $"timer {timer.Id}");
				}
			}
			_timers.RemoveAll((Timer t) => t.Cancelled);
		}

		private int AddTimer(JsValue callback, double delayMs, bool repeating)
		{
			if (callback == (JsValue)null || !JsValueExtensions.IsObject(callback))
			{
				return 0;
			}
			Timer timer = new Timer
			{
				Id = _nextTimerId++,
				Callback = callback,
				Remaining = Math.Max(delayMs, 0.0),
				Interval = (repeating ? Math.Max(delayMs, 16.0) : 0.0)
			};
			_timers.Add(timer);
			return timer.Id;
		}

		private void ClearTimer(double id)
		{
			foreach (Timer timer in _timers)
			{
				if (timer.Id == (int)id)
				{
					timer.Cancelled = true;
				}
			}
		}

		private void Invoke(JsValue callback, string what, params JsValue[] args)
		{
			InvokeOn(callback, JsValue.Undefined, what, args);
		}

		private void InvokeOn(JsValue callback, JsValue self, string what, params JsValue[] args)
		{
			try
			{
				Engine.Invoke(callback, (object)self, Array.ConvertAll(args, (Converter<JsValue, object>)((JsValue a) => a)));
			}
			catch (Exception e)
			{
				LastError = Describe(e);
				Platform.Error(what + " failed: " + LastError);
				Diagnostics?.Invoke(_appId, "exception", null, what + " failed: " + LastError);
			}
		}

		private void Report(string what, Exception e)
		{
			LastError = Describe(e);
			Fault(what + " failed: " + LastError);
		}

		private void Fault(string line)
		{
			Platform.Error("[" + _appId + "] " + line);
			Diagnostics?.Invoke(_appId, "error", null, "[" + _appId + "] " + line);
		}

		private void Bind()
		{
			Types = new DomTypes(Engine);
			_documentObject = new JsDocument(this, _document);
			Engine.SetValue<JsDocument>("document", _documentObject);
			_bridge = new Bridge(this, _appId);
			Engine.SetValue<Bridge>("s1", _bridge);
			Engine.SetValue<Bridge.JsStorage>("localStorage", _bridge.Storage);
			Engine.SetValue<Bridge.JsStorage>("sessionStorage", _bridge.Storage);
			Engine.SetValue<Console>("console", new Console(_appId));
			BindWindow();
			_promises = new Promises(Engine, delegate(string message)
			{
				Fault("unhandled promise rejection: " + message);
			});
			_fetch = new FetchApi(Engine, _appId, _promises, delegate(string line)
			{
				Fault(line);
			});
			_fetch.Install();
			WebApis.Install(Engine);
			Engine.SetValue<Func<JsValue, double, int>>("setTimeout", (Func<JsValue, double, int>)((JsValue fn, double ms) => AddTimer(fn, ms, repeating: false)));
			Engine.SetValue<Func<JsValue, double, int>>("setInterval", (Func<JsValue, double, int>)((JsValue fn, double ms) => AddTimer(fn, ms, repeating: true)));
			Engine.SetValue<Action<double>>("clearTimeout", (Action<double>)ClearTimer);
			Engine.SetValue<Action<double>>("clearInterval", (Action<double>)ClearTimer);
			Engine.SetValue<Func<JsValue, int>>("requestAnimationFrame", (Func<JsValue, int>)((JsValue fn) => AddTimer(fn, 16.0, repeating: false)));
			Engine.SetValue<Action<double>>("cancelAnimationFrame", (Action<double>)ClearTimer);
		}

		private void BindWindow()
		{
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Expected O, but got Unknown
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Expected O, but got Unknown
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Expected O, but got Unknown
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Expected O, but got Unknown
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Expected O, but got Unknown
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Expected O, but got Unknown
			ObjectInstance global = Engine.Global;
			Engine.SetValue<ObjectInstance>("window", global);
			Engine.SetValue<ObjectInstance>("self", global);
			Engine.SetValue<ObjectInstance>("globalThis", global);
			Engine.SetValue<ClrFunction>("addEventListener", new ClrFunction(Engine, "addEventListener", (Func<JsValue, JsValue[], JsValue>)delegate(JsValue _, JsValue[] a)
			{
				AddListener(Root(), (a.Length != 0) ? ((object)a[0]).ToString() : null, (a.Length > 1) ? a[1] : null, JsDocument.IsCapture((a.Length > 2) ? a[2] : null));
				return JsValue.Undefined;
			}, 0, (PropertyFlag)42));
			Engine.SetValue<ClrFunction>("removeEventListener", new ClrFunction(Engine, "removeEventListener", (Func<JsValue, JsValue[], JsValue>)delegate(JsValue _, JsValue[] a)
			{
				RemoveListener(Root(), (a.Length != 0) ? ((object)a[0]).ToString() : null, (a.Length > 1) ? a[1] : null, JsDocument.IsCapture((a.Length > 2) ? a[2] : null));
				return JsValue.Undefined;
			}, 0, (PropertyFlag)42));
			global.FastSetProperty("innerWidth", (PropertyDescriptor)new GetSetPropertyDescriptor((JsValue)new ClrFunction(Engine, "innerWidth", (Func<JsValue, JsValue[], JsValue>)((JsValue _, JsValue[] _) => JsValue.op_Implicit((double)Viewport()[0])), 0, (PropertyFlag)42), (JsValue)null, (bool?)false, (bool?)true));
			global.FastSetProperty("innerHeight", (PropertyDescriptor)new GetSetPropertyDescriptor((JsValue)new ClrFunction(Engine, "innerHeight", (Func<JsValue, JsValue[], JsValue>)((JsValue _, JsValue[] _) => JsValue.op_Implicit((double)Viewport()[1])), 0, (PropertyFlag)42), (JsValue)null, (bool?)false, (bool?)true));
			Engine.SetValue("devicePixelRatio", 1);
		}

		private INode Root()
		{
			INode body = (INode)(object)_document.Body;
			return (INode)(((object)body) ?? ((object)_document.DocumentElement));
		}

		private float[] Viewport()
		{
			return OnViewportRequested?.Invoke() ?? new float[2];
		}

		private static IEnumerable<string> BothCasings(MemberInfo member)
		{
			string name = member.Name;
			if (!string.IsNullOrEmpty(name))
			{
				string camel = (char.IsUpper(name[0]) ? (char.ToLowerInvariant(name[0]) + name.Substring(1)) : name);
				yield return camel;
				if (camel != name)
				{
					yield return name;
				}
			}
		}

		private static string Describe(Exception e)
		{
			JavaScriptException ex = (JavaScriptException)(object)((e is JavaScriptException) ? e : null);
			if (ex != null)
			{
				return $"{((Exception)(object)ex).Message} ({((Location)ex.Location).Source}:{((Location)ex.Location).Start.Line}:{((Location)ex.Location).Start.Column})";
			}
			ParserException ex2 = (ParserException)(object)((e is ParserException) ? e : null);
			if (ex2 != null)
			{
				return "syntax error: " + ((Exception)(object)ex2).Message;
			}
			return e.ToString();
		}
	}
	internal sealed class TimeBudget : Constraint
	{
		internal static readonly TimeSpan Handler = TimeSpan.FromMilliseconds(250.0);

		internal static readonly TimeSpan Load = TimeSpan.FromSeconds(5.0);

		private DateTime _deadline = DateTime.MaxValue;

		internal TimeSpan Ceiling { get; set; } = Handler;

		public override void Reset()
		{
			_deadline = DateTime.UtcNow + Ceiling;
		}

		public override void Check()
		{
			if (DateTime.UtcNow <= _deadline)
			{
				return;
			}
			throw new TimeoutException($"script ran longer than {Ceiling.TotalMilliseconds:0} ms");
		}

		internal void During(Engine engine, TimeSpan ceiling, Action run)
		{
			TimeSpan ceiling2 = Ceiling;
			Ceiling = ceiling;
			try
			{
				if (engine != null)
				{
					engine.Constraints.Reset();
				}
				run();
			}
			finally
			{
				Ceiling = ceiling2;
				if (engine != null)
				{
					engine.Constraints.Reset();
				}
			}
		}
	}
	in