<!DOCTYPE html>

<head>
	<meta charset="UTF-8" />
	<meta name="format-detection" content="telephone=no" />
	<meta name="apple-mobile-web-app-capable" content="yes" />
	<meta name="viewport" content="user-scalable=no, viewport-fit=cover" />
	<title>无名杀</title>
	<script>
		if (
			typeof window.require == "function" &&
			typeof window.process == "object" &&
			typeof window.__dirname == "string"
		) {
			// 使importMap解析node内置模块
			const builtinModules = require("module").builtinModules;
			if (Array.isArray(builtinModules)) {
				const importMap = {
					imports: {},
				};
				for (const module of builtinModules) {
					importMap.imports[module] = importMap.imports[`node:${module}`] =
						`./noname-builtinModules/${module}`;
				}
				const im = document.createElement("script");
				im.type = "importmap";
				im.textContent = JSON.stringify(importMap);
				document.currentScript.after(im);
			}
		}
	</script>
	<script>
		"use strict";
		(() => {
			window.onerror = function (msg, src, line, column, err) {
				let str = `错误文件: ${typeof src == "string" && src.length > 0 ? decodeURI(src) : "未知文件"}`;
				str += `\n错误信息: ${msg}`;
				str += `\n行号: ${line}`;
				str += `\n列号: ${column}`;
				if (err && err.stack) str += "\n" + decodeURI(err.stack);
				console.error(str);
				alert(str);
			};
			const STACK_REGEXP = /^\s*at .*(\S+:\d+|\(native\))/m;
			const errorList = [];
			function extractLocation(urlLike) {
				// 不存在地址信息的字符串
				if (!/:/.test(urlLike)) {
					return [urlLike];
				}

				// 捕获位置用到的正则
				const regExp = /(.+?)(?::(\d+))?(?::(\d+))?$/;
				const parts = regExp.exec(urlLike.replace(/[()]/g, ""));

				// @ts-ignore
				return [parts[1], parts[2] || void 0, parts[3] || void 0];
			}
			window.onunhandledrejection = async (event) => {
				event.promise.catch((error) => {
					console.log(error);
					// 如果`error`是个错误,则继续处理
					if (error instanceof Error) {
						// 如果已经处理过该错误,则不再处理
						if (errorList.includes(error)) return;
						errorList.push(error);
						// 如果`error`拥有字符串形式的报错栈堆,且报错栈堆确实符合v8的stack
						if (typeof error.stack === "string" && STACK_REGEXP.test(error.stack)) {
							// 获取符合栈堆信息的字符串,一般来说就是从第二行开始的所有行
							// 为了处理eval的情况,故必须获取完行数
							let lines = error.stack.split("\n").filter((line) => STACK_REGEXP.test(line));

							// 提供类型信息防止vscode报错
							/**
							 * @type {string | undefined}
							 */
							let fileName = void 0;

							/**
							 * @type {number | undefined}
							 */
							let line = void 0;

							/**
							 * @type {number | undefined}
							 */
							let column = void 0;

							// 从第一条开始遍历,一直遍历到不存在eval的位置
							for (let currentLine = 0; currentLine < lines.length; ++currentLine) {
								if (/\(eval /.test(lines[currentLine])) continue;

								let formatedLine = lines[currentLine]
									.replace(/^\s+/, "")
									.replace(/\(eval code/g, "(")
									.replace(/^.*?\s+/, "");

								const location = formatedLine.match(/ (\(.+\)$)/);
								if (location) formatedLine = formatedLine.replace(location[0], "");

								const locationParts = extractLocation(location ? location[1] : formatedLine);

								fileName = ["eval", "<anonymous>"].includes(locationParts[0])
									? void 0
									: locationParts[0];
								line = Number(locationParts[1]);
								column = Number(locationParts[2]);
								break;
							}

							// @ts-ignore
							window.onerror(error.message, fileName, line, column, error);
						}
						// 反之我们只能不考虑报错文件信息,直接调用onerror
						else {
							try {
								// @ts-ignore
								let [_, src = void 0, line = void 0, column = void 0] =
									/at\s+.*\s+\((.*):(\d*):(\d*)\)/i.exec(error.stack.split("\n")[1]);
								if (typeof line == "string") line = Number(line);
								if (typeof column == "string") column = Number(column);
								// @ts-ignore
								window.onerror(error.message, src, line, column, error);
							} catch (e) {
								window.onerror(error.message, "", 0, 0, error);
							}
						}
					}
				});
			};
		})();
	</script>
	<script>
		"use strict";
		if (
			location.href.startsWith("http") &&
			typeof window.initReadWriteFunction != "function" &&
			!window.require &&
			!window.__dirname
		) {
			window.initReadWriteFunction = async function (game) {
				return new Promise((resolve, reject) => {
					fetch(`./readFile?fileName=noname.js`)
						.then((response) => {
							return response.json();
						})
						.then((result) => {
							if (result && result.success) callback();
							else reject(result.errorMsg);
						})
						.catch(reject);

					function callback() {
						game.readFile = function (fileName, callback = () => {}, error = () => {}) {
							fetch(`./readFile?fileName=${fileName}`)
								.then((response) => {
									return response.json();
								})
								.then((result) => {
									if (result && result.success)
										callback(new Uint8Array(result.data).buffer);
									else error(result && result.errorMsg);
								})
								.catch(error);
						};

						game.readFileAsText = function (fileName, callback = () => {}, error = () => {}) {
							fetch(`./readFileAsText?fileName=${fileName}`)
								.then((response) => {
									return response.json();
								})
								.then((result) => {
									if (result && result.success) callback(result.data);
									else error(result && result.errorMsg);
								})
								.catch(error);
						};

						game.writeFile = function (data, path, name, callback = () => {}) {
							game.ensureDirectory(path, function () {
								if (Object.prototype.toString.call(data) == "[object File]") {
									const fileReader = new FileReader();
									fileReader.onload = function (e) {
										game.writeFile(e.target.result, path, name, callback);
									};
									fileReader.readAsArrayBuffer(data, "UTF-8");
								} else {
									let filePath = path;
									if (path.endsWith("/")) {
										filePath += name;
									} else if (path == "") {
										filePath += name;
									} else {
										filePath += "/" + name;
									}

									fetch(`./writeFile`, {
										method: "post",
										headers: { "Content-Type": "application/json" },
										body: JSON.stringify({
											data:
												typeof data == "string"
													? data
													: Array.prototype.slice.call(new Uint8Array(data)),
											path: filePath,
										}),
									})
										.then((response) => {
											return response.json();
										})
										.then((result) => {
											if (result && result.success) {
												callback();
											} else {
												callback(result.errorMsg);
											}
										});
								}
							});
						};

						game.removeFile = function (fileName, callback = () => {}) {
							fetch(`./removeFile?fileName=${fileName}`)
								.then((response) => {
									return response.json();
								})
								.then((result) => {
									callback(result.errorMsg);
								})
								.catch(error);
						};

						game.getFileList = function (dir, callback = () => {}, onerror) {
							fetch(`./getFileList?dir=${dir}`)
								.then((response) => {
									return response.json();
								})
								.then((result) => {
									if (!result) {
										throw new Error("Cannot get available resource.");
									}

									if (result.success) {
										callback(result.data.folders, result.data.files);
									} else if (onerror) {
										onerror(new Error(result.errorMsg));
									}
								});
						};

						game.ensureDirectory = function (list, callback = () => {}, file = false) {
							let pathArray = typeof list == "string" ? list.split("/") : list;
							if (file) {
								pathArray = pathArray.slice(0, -1);
							}
							game.createDir(pathArray.join("/"), callback, console.error);
						};

						game.createDir = (
							directory,
							successCallback = () => {},
							errorCallback = () => {}
						) => {
							fetch(`./createDir?dir=${directory}`)
								.then((response) => {
									return response.json();
								})
								.then((result) => {
									if (result && result.success) {
										successCallback();
									} else {
										errorCallback(new Error("创建文件夹失败"));
									}
								})
								.catch(errorCallback);
						};
						game.removeDir = (
							directory,
							successCallback = () => {},
							errorCallback = () => {}
						) => {
							fetch(`./removeDir?dir=${directory}`)
								.then((response) => {
									return response.json();
								})
								.then((result) => {
									if (result && result.success) {
										successCallback();
									} else {
										errorCallback(new Error("创建文件夹失败"));
									}
								})
								.catch(errorCallback);
						};

						resolve();
					}
				});
			};
		}
	</script>
	<script src="game/update.js"></script>
	<script src="game/config.js"></script>
	<script src="game/package.js"></script>
	<script src="game/game.js"></script>
</head>