timetable2lua

Export timetable data as lua table.

スクリプトをインストールするには、Tampermonkey, GreasemonkeyViolentmonkey のような拡張機能のインストールが必要です。

You will need to install an extension such as Tampermonkey to install this script.

スクリプトをインストールするには、TampermonkeyViolentmonkey のような拡張機能のインストールが必要です。

スクリプトをインストールするには、TampermonkeyUserscripts のような拡張機能のインストールが必要です。

このスクリプトをインストールするには、Tampermonkeyなどの拡張機能をインストールする必要があります。

このスクリプトをインストールするには、ユーザースクリプト管理ツールの拡張機能をインストールする必要があります。

(ユーザースクリプト管理ツールは設定済みなのでインストール!)

Advertisement:

このスタイルをインストールするには、Stylusなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus などの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus tなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

(ユーザースタイル管理ツールは設定済みなのでインストール!)

Advertisement:

このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください
// ==UserScript==
// @name         timetable2lua
// @namespace    https://dvxg.de/
// @version      0.2.6
// @author       davidxuang
// @description  Export timetable data as lua table.
// @license      AGPL-3.0-only
// @icon         https://cdn.jsdelivr.net/gh/microsoft/fluentui-emoji/assets/Metro/3D/metro_3d.png
// @homepage     https://github.com/davidxuang/timetable2lua
// @homepageURL  https://github.com/davidxuang/timetable2lua
// @match        https://www.cqmetro.cn/smbsj/
// @match        https://www.wuhanrt.com/news-content.html*
// ==/UserScript==

(function() {
	"use strict";
	var __create = Object.create;
	var __defProp = Object.defineProperty;
	var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
	var __getOwnPropNames = Object.getOwnPropertyNames;
	var __getProtoOf = Object.getPrototypeOf;
	var __hasOwnProp = Object.prototype.hasOwnProperty;
	var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
	var __copyProps = (to, from, except, desc) => {
		if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
			key = keys[i];
			if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
				get: ((k) => from[k]).bind(null, key),
				enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
			});
		}
		return to;
	};
	var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
		value: mod,
		enumerable: true
	}) : target, mod));
	function t(t) {
		return t && t.__esModule && Object.prototype.hasOwnProperty.call(t, "default") ? t.default : t;
	}
	var r, e, n, o, u, f, i = { exports: {} }, c = { exports: {} };
	function l() {
		return r || (r = 1, function(t) {
			var r = function() {
				function t(r, n, o, u) {
					"object" == typeof n && (o = n.depth, u = n.prototype, n.filter, n = n.circular);
					var f = [], i = [], c = "undefined" != typeof Buffer;
					return void 0 === n && (n = !0), void 0 === o && (o = Infinity), function r(o, l) {
						if (null === o) return null;
						if (0 == l) return o;
						var s, a;
						if ("object" != typeof o) return o;
						if (t.__isArray(o)) s = [];
						else if (t.__isRegExp(o)) s = new RegExp(o.source, e(o)), o.lastIndex && (s.lastIndex = o.lastIndex);
						else if (t.__isDate(o)) s = new Date(o.getTime());
						else {
							if (c && Buffer.isBuffer(o)) return s = Buffer.allocUnsafe ? Buffer.allocUnsafe(o.length) : new Buffer(o.length), o.copy(s), s;
							void 0 === u ? (a = Object.getPrototypeOf(o), s = Object.create(a)) : (s = Object.create(u), a = u);
						}
						if (n) {
							var p = f.indexOf(o);
							if (-1 != p) return i[p];
							f.push(o), i.push(s);
						}
						for (var g in o) {
							var y;
							a && (y = Object.getOwnPropertyDescriptor(a, g)), y && null == y.set || (s[g] = r(o[g], l - 1));
						}
						return s;
					}(r, o);
				}
				function r(t) {
					return Object.prototype.toString.call(t);
				}
				function e(t) {
					var r = "";
					return t.global && (r += "g"), t.ignoreCase && (r += "i"), t.multiline && (r += "m"), r;
				}
				return t.clonePrototype = function(t) {
					if (null === t) return null;
					var r = function() {};
					return r.prototype = t, new r();
				}, t.__objToStr = r, t.__isDate = function(t) {
					return "object" == typeof t && "[object Date]" === r(t);
				}, t.__isArray = function(t) {
					return "object" == typeof t && "[object Array]" === r(t);
				}, t.__isRegExp = function(t) {
					return "object" == typeof t && "[object RegExp]" === r(t);
				}, t.__getRegExpFlags = e, t;
			}();
			t.exports && (t.exports = r);
		}(c)), c.exports;
	}
	function s() {
		if (n) return e;
		n = 1;
		var t = l();
		return e = function(r, e) {
			return r = r || {}, Object.keys(e).forEach((function(n) {
				void 0 === r[n] && (r[n] = t(e[n]));
			})), r;
		};
	}
	function a() {
		return u ? o : (u = 1, o = [
			[768, 879],
			[1155, 1158],
			[1160, 1161],
			[1425, 1469],
			[1471, 1471],
			[1473, 1474],
			[1476, 1477],
			[1479, 1479],
			[1536, 1539],
			[1552, 1557],
			[1611, 1630],
			[1648, 1648],
			[1750, 1764],
			[1767, 1768],
			[1770, 1773],
			[1807, 1807],
			[1809, 1809],
			[1840, 1866],
			[1958, 1968],
			[2027, 2035],
			[2305, 2306],
			[2364, 2364],
			[2369, 2376],
			[2381, 2381],
			[2385, 2388],
			[2402, 2403],
			[2433, 2433],
			[2492, 2492],
			[2497, 2500],
			[2509, 2509],
			[2530, 2531],
			[2561, 2562],
			[2620, 2620],
			[2625, 2626],
			[2631, 2632],
			[2635, 2637],
			[2672, 2673],
			[2689, 2690],
			[2748, 2748],
			[2753, 2757],
			[2759, 2760],
			[2765, 2765],
			[2786, 2787],
			[2817, 2817],
			[2876, 2876],
			[2879, 2879],
			[2881, 2883],
			[2893, 2893],
			[2902, 2902],
			[2946, 2946],
			[3008, 3008],
			[3021, 3021],
			[3134, 3136],
			[3142, 3144],
			[3146, 3149],
			[3157, 3158],
			[3260, 3260],
			[3263, 3263],
			[3270, 3270],
			[3276, 3277],
			[3298, 3299],
			[3393, 3395],
			[3405, 3405],
			[3530, 3530],
			[3538, 3540],
			[3542, 3542],
			[3633, 3633],
			[3636, 3642],
			[3655, 3662],
			[3761, 3761],
			[3764, 3769],
			[3771, 3772],
			[3784, 3789],
			[3864, 3865],
			[3893, 3893],
			[3895, 3895],
			[3897, 3897],
			[3953, 3966],
			[3968, 3972],
			[3974, 3975],
			[3984, 3991],
			[3993, 4028],
			[4038, 4038],
			[4141, 4144],
			[4146, 4146],
			[4150, 4151],
			[4153, 4153],
			[4184, 4185],
			[4448, 4607],
			[4959, 4959],
			[5906, 5908],
			[5938, 5940],
			[5970, 5971],
			[6002, 6003],
			[6068, 6069],
			[6071, 6077],
			[6086, 6086],
			[6089, 6099],
			[6109, 6109],
			[6155, 6157],
			[6313, 6313],
			[6432, 6434],
			[6439, 6440],
			[6450, 6450],
			[6457, 6459],
			[6679, 6680],
			[6912, 6915],
			[6964, 6964],
			[6966, 6970],
			[6972, 6972],
			[6978, 6978],
			[7019, 7027],
			[7616, 7626],
			[7678, 7679],
			[8203, 8207],
			[8234, 8238],
			[8288, 8291],
			[8298, 8303],
			[8400, 8431],
			[12330, 12335],
			[12441, 12442],
			[43014, 43014],
			[43019, 43019],
			[43045, 43046],
			[64286, 64286],
			[65024, 65039],
			[65056, 65059],
			[65279, 65279],
			[65529, 65531],
			[68097, 68099],
			[68101, 68102],
			[68108, 68111],
			[68152, 68154],
			[68159, 68159],
			[119143, 119145],
			[119155, 119170],
			[119173, 119179],
			[119210, 119213],
			[119362, 119364],
			[917505, 917505],
			[917536, 917631],
			[917760, 917999]
		]);
	}
	var g = t(function() {
		if (f) return i.exports;
		f = 1;
		var t = s(), r = a(), e = {
			nul: 0,
			control: 0
		};
		function n(t, r) {
			if ("string" != typeof t) return o(t, r);
			for (var e = 0, n = 0; n < t.length; n++) {
				var u = o(t.charCodeAt(n), r);
				if (u < 0) return -1;
				e += u;
			}
			return e;
		}
		function o(t, e) {
			return 0 === t ? e.nul : t < 32 || t >= 127 && t < 160 ? e.control : function(t) {
				var e, n = 0, o = r.length - 1;
				if (t < r[0][0] || t > r[o][1]) return !1;
				for (; o >= n;) if (e = Math.floor((n + o) / 2), t > r[e][1]) n = e + 1;
				else {
					if (!(t < r[e][0])) return !0;
					o = e - 1;
				}
				return !1;
			}(t) ? 0 : 1 + (t >= 4352 && (t <= 4447 || 9001 == t || 9002 == t || t >= 11904 && t <= 42191 && 12351 != t || t >= 44032 && t <= 55203 || t >= 63744 && t <= 64255 || t >= 65040 && t <= 65049 || t >= 65072 && t <= 65135 || t >= 65280 && t <= 65376 || t >= 65504 && t <= 65510 || t >= 131072 && t <= 196605 || t >= 196608 && t <= 262141));
		}
		return i.exports = function(t) {
			return n(t, e);
		}, i.exports.config = function(r) {
			return r = t(r || {}, e), function(t) {
				return n(t, r);
			};
		}, i.exports;
	}());
	function y(t, r, e = {}) {
		const n = "number" == typeof t;
		let o = n ? r : t;
		const u = n ? t : r;
		"string" == typeof e && (e = { char: e }), e.char || (e.char = " "), e.strip || (e.strip = !1), "string" != typeof o && (o = o.toString());
		let f = null, i = "";
		if (e.colors) f = o.replace(/\x1B\[(?:[0-9]{1,2}(?:;[0-9]{1,2})?)?[m|K]/g, "");
		const c = !0 === e.fixed_width ? u - (f || o).length : u - g.config(e.wcwidth_options || {})(f || o);
		return c < 0 ? e.strip ? n ? o.substr(-1 * u) : o.substr(0, u) : o : (i += e.char.repeat(c), n ? i + o : o + i);
	}
	var require_clone = __commonJSMin(((exports, module) => {
		var clone = (function() {
			"use strict";
			function clone(parent, circular, depth, prototype) {
				if (typeof circular === "object") {
					depth = circular.depth;
					prototype = circular.prototype;
					circular.filter;
					circular = circular.circular;
				}
				var allParents = [];
				var allChildren = [];
				var useBuffer = typeof Buffer != "undefined";
				if (typeof circular == "undefined") circular = true;
				if (typeof depth == "undefined") depth = Infinity;
				function _clone(parent, depth) {
					if (parent === null) return null;
					if (depth == 0) return parent;
					var child;
					var proto;
					if (typeof parent != "object") return parent;
					if (clone.__isArray(parent)) child = [];
					else if (clone.__isRegExp(parent)) {
						child = new RegExp(parent.source, __getRegExpFlags(parent));
						if (parent.lastIndex) child.lastIndex = parent.lastIndex;
					} else if (clone.__isDate(parent)) child = new Date(parent.getTime());
					else if (useBuffer && Buffer.isBuffer(parent)) {
						if (Buffer.allocUnsafe) child = Buffer.allocUnsafe(parent.length);
						else child = new Buffer(parent.length);
						parent.copy(child);
						return child;
					} else if (typeof prototype == "undefined") {
						proto = Object.getPrototypeOf(parent);
						child = Object.create(proto);
					} else {
						child = Object.create(prototype);
						proto = prototype;
					}
					if (circular) {
						var index = allParents.indexOf(parent);
						if (index != -1) return allChildren[index];
						allParents.push(parent);
						allChildren.push(child);
					}
					for (var i in parent) {
						var attrs;
						if (proto) attrs = Object.getOwnPropertyDescriptor(proto, i);
						if (attrs && attrs.set == null) continue;
						child[i] = _clone(parent[i], depth - 1);
					}
					return child;
				}
				return _clone(parent, depth);
			}
			clone.clonePrototype = function clonePrototype(parent) {
				if (parent === null) return null;
				var c = function() {};
				c.prototype = parent;
				return new c();
			};
			function __objToStr(o) {
				return Object.prototype.toString.call(o);
			}
			clone.__objToStr = __objToStr;
			function __isDate(o) {
				return typeof o === "object" && __objToStr(o) === "[object Date]";
			}
			clone.__isDate = __isDate;
			function __isArray(o) {
				return typeof o === "object" && __objToStr(o) === "[object Array]";
			}
			clone.__isArray = __isArray;
			function __isRegExp(o) {
				return typeof o === "object" && __objToStr(o) === "[object RegExp]";
			}
			clone.__isRegExp = __isRegExp;
			function __getRegExpFlags(re) {
				var flags = "";
				if (re.global) flags += "g";
				if (re.ignoreCase) flags += "i";
				if (re.multiline) flags += "m";
				return flags;
			}
			clone.__getRegExpFlags = __getRegExpFlags;
			return clone;
		})();
		if (typeof module === "object" && module.exports) module.exports = clone;
	}));
	var require_defaults = __commonJSMin(((exports, module) => {
		var clone = require_clone();
		module.exports = function(options, defaults) {
			options = options || {};
			Object.keys(defaults).forEach(function(key) {
				if (typeof options[key] === "undefined") options[key] = clone(defaults[key]);
			});
			return options;
		};
	}));
	var require_combining = __commonJSMin(((exports, module) => {
		module.exports = [
			[768, 879],
			[1155, 1158],
			[1160, 1161],
			[1425, 1469],
			[1471, 1471],
			[1473, 1474],
			[1476, 1477],
			[1479, 1479],
			[1536, 1539],
			[1552, 1557],
			[1611, 1630],
			[1648, 1648],
			[1750, 1764],
			[1767, 1768],
			[1770, 1773],
			[1807, 1807],
			[1809, 1809],
			[1840, 1866],
			[1958, 1968],
			[2027, 2035],
			[2305, 2306],
			[2364, 2364],
			[2369, 2376],
			[2381, 2381],
			[2385, 2388],
			[2402, 2403],
			[2433, 2433],
			[2492, 2492],
			[2497, 2500],
			[2509, 2509],
			[2530, 2531],
			[2561, 2562],
			[2620, 2620],
			[2625, 2626],
			[2631, 2632],
			[2635, 2637],
			[2672, 2673],
			[2689, 2690],
			[2748, 2748],
			[2753, 2757],
			[2759, 2760],
			[2765, 2765],
			[2786, 2787],
			[2817, 2817],
			[2876, 2876],
			[2879, 2879],
			[2881, 2883],
			[2893, 2893],
			[2902, 2902],
			[2946, 2946],
			[3008, 3008],
			[3021, 3021],
			[3134, 3136],
			[3142, 3144],
			[3146, 3149],
			[3157, 3158],
			[3260, 3260],
			[3263, 3263],
			[3270, 3270],
			[3276, 3277],
			[3298, 3299],
			[3393, 3395],
			[3405, 3405],
			[3530, 3530],
			[3538, 3540],
			[3542, 3542],
			[3633, 3633],
			[3636, 3642],
			[3655, 3662],
			[3761, 3761],
			[3764, 3769],
			[3771, 3772],
			[3784, 3789],
			[3864, 3865],
			[3893, 3893],
			[3895, 3895],
			[3897, 3897],
			[3953, 3966],
			[3968, 3972],
			[3974, 3975],
			[3984, 3991],
			[3993, 4028],
			[4038, 4038],
			[4141, 4144],
			[4146, 4146],
			[4150, 4151],
			[4153, 4153],
			[4184, 4185],
			[4448, 4607],
			[4959, 4959],
			[5906, 5908],
			[5938, 5940],
			[5970, 5971],
			[6002, 6003],
			[6068, 6069],
			[6071, 6077],
			[6086, 6086],
			[6089, 6099],
			[6109, 6109],
			[6155, 6157],
			[6313, 6313],
			[6432, 6434],
			[6439, 6440],
			[6450, 6450],
			[6457, 6459],
			[6679, 6680],
			[6912, 6915],
			[6964, 6964],
			[6966, 6970],
			[6972, 6972],
			[6978, 6978],
			[7019, 7027],
			[7616, 7626],
			[7678, 7679],
			[8203, 8207],
			[8234, 8238],
			[8288, 8291],
			[8298, 8303],
			[8400, 8431],
			[12330, 12335],
			[12441, 12442],
			[43014, 43014],
			[43019, 43019],
			[43045, 43046],
			[64286, 64286],
			[65024, 65039],
			[65056, 65059],
			[65279, 65279],
			[65529, 65531],
			[68097, 68099],
			[68101, 68102],
			[68108, 68111],
			[68152, 68154],
			[68159, 68159],
			[119143, 119145],
			[119155, 119170],
			[119173, 119179],
			[119210, 119213],
			[119362, 119364],
			[917505, 917505],
			[917536, 917631],
			[917760, 917999]
		];
	}));
	var import_wcwidth = __toESM(__commonJSMin(((exports, module) => {
		var defaults = require_defaults();
		var combining = require_combining();
		var DEFAULTS = {
			nul: 0,
			control: 0
		};
		module.exports = function wcwidth(str) {
			return wcswidth(str, DEFAULTS);
		};
		module.exports.config = function(opts) {
			opts = defaults(opts || {}, DEFAULTS);
			return function wcwidth(str) {
				return wcswidth(str, opts);
			};
		};
		function wcswidth(str, opts) {
			if (typeof str !== "string") return wcwidth(str, opts);
			var s = 0;
			for (var i = 0; i < str.length; i++) {
				var n = wcwidth(str.charCodeAt(i), opts);
				if (n < 0) return -1;
				s += n;
			}
			return s;
		}
		function wcwidth(ucs, opts) {
			if (ucs === 0) return opts.nul;
			if (ucs < 32 || ucs >= 127 && ucs < 160) return opts.control;
			if (bisearch(ucs)) return 0;
			return 1 + (ucs >= 4352 && (ucs <= 4447 || ucs == 9001 || ucs == 9002 || ucs >= 11904 && ucs <= 42191 && ucs != 12351 || ucs >= 44032 && ucs <= 55203 || ucs >= 63744 && ucs <= 64255 || ucs >= 65040 && ucs <= 65049 || ucs >= 65072 && ucs <= 65135 || ucs >= 65280 && ucs <= 65376 || ucs >= 65504 && ucs <= 65510 || ucs >= 131072 && ucs <= 196605 || ucs >= 196608 && ucs <= 262141));
		}
		function bisearch(ucs) {
			var min = 0;
			var max = combining.length - 1;
			var mid;
			if (ucs < combining[0][0] || ucs > combining[max][1]) return false;
			while (max >= min) {
				mid = Math.floor((min + max) / 2);
				if (ucs > combining[mid][1]) min = mid + 1;
				else if (ucs < combining[mid][0]) max = mid - 1;
				else return true;
			}
			return false;
		}
	}))(), 1);
	function assert(condition, message) {
		if (!condition) throw new Error(message || "Assertion failed");
	}
	function attachButton(parent, onClick) {
		const button = document.createElement("a");
		button.append("导出");
		button.addEventListener("click", onClick, false);
		button.style.cursor = "pointer";
		button.style.position = "absolute";
		button.style.zIndex = "1";
		button.style.color = "white";
		button.style.opacity = ".75";
		button.style.paddingInlineStart = ".5em";
		button.style.fontSize = ".84em";
		parent?.appendChild(button);
	}
	function compareNestedStringArray(x, y) {
		if (x instanceof Array) if (x.length != y.length) return false;
		else return x.filter((v, i) => !compareNestedStringArray(v, y[i])).length == 0;
		else return x === y;
	}
	function deduplicateDays(timetable) {
		let dedup = true;
		timetable.forEach((days) => {
			if (days.length > 1) days.slice(1).forEach((day) => {
				if (!compareNestedStringArray(days[0], day)) dedup = false;
			});
		});
		if (dedup) return new Map(Array.from(timetable.entries()).map(([station, days]) => [station, [days[0]]]));
		else return timetable;
	}
	function luaifyNestedStringArray(array, padding = 0) {
		if (array instanceof Array) return `{ ${array.map((child) => luaifyNestedStringArray(child, padding)).join(", ")} }`;
		else if (array == "nil") return y(padding, `nil`);
		else return y(padding, `'${array}'`);
	}
	var Timetable = {
		reverse: function(timetable) {
			return new Map([...timetable.entries()].reverse().map(([name, times]) => [name, times.map(([first, last]) => [first.reverse(), last.reverse()])]));
		},
		luaify: function(timetable) {
			timetable = deduplicateDays(timetable);
			const padding = Math.max(...[...timetable.keys()].map((str) => (0, import_wcwidth.default)(str))) + 4;
			return `
\t\t\tstations = ${luaifyNestedStringArray([...timetable.keys()])},
\t\t\tdata = {
${Array.from(timetable).map(([key, value]) => `\t\t\t\t${y(`['${key}']`, padding)} = ${luaifyNestedStringArray(value, 7)},`).join("\n")}
\t\t\t}`;
		}
	};
	function parseCell$1(cell, closed) {
		return cell.innerText.trim().replace(/\p{Pd}+/u, closed ? "nil" : "").replace(/^0([4-9]):(\d\d)$/, "$1:$2");
	}
	function parseRow(cells, days, first, last) {
		const closed = cells.slice(1).filter((cell) => cell.innerText.trim().length > 2).length == 0;
		return days.map((dayOffset) => [first.map((i) => parseCell$1(cells[i + dayOffset], closed)), last.map((index) => index instanceof Array ? index.map((i) => parseCell$1(cells[i + dayOffset], closed)) : parseCell$1(cells[index + dayOffset], closed))]);
	}
	function parseRows(rows, days, first, last) {
		const timetable = new Map();
		for (const row of rows) {
			if (row.length == 0) break;
			const name = row[0].innerText.trim().replace("航站楼", "");
			if (!name || name == "--") break;
			timetable.set(name, parseRow(row, days, first, last));
		}
		return timetable;
	}
	var CRT = { bootstrap: function() {
		document.querySelectorAll(".schedule-card").forEach((card) => {
			const caption = [...card.querySelectorAll(".schedule-card-head")].single();
			const copyData = function() {
				const table = [...card.querySelectorAll("table")].single();
				const [thDays, thTimes, thTermini] = (() => {
					const rows = table.tHead?.rows;
					if (rows?.length == 3) return [
						0,
						1,
						2
					].map((r) => [...table.tHead.rows[r].querySelectorAll("th:not([rowspan])")].filter((th) => th.innerText.trim().length > 2));
					else if (rows?.length == 2) {
						function getCommon(left, right) {
							return left.split("").filter((char, c) => char == right[c]).join("");
						}
						let days;
						if (rows[0].cells.length == 5) {
							days = [document.createElement("th"), document.createElement("th")];
							days[0].innerText = getCommon(rows[0].cells[1].innerText.trim(), rows[0].cells[2].innerText.trim());
							days[1].innerText = getCommon(rows[0].cells[3].innerText.trim(), rows[0].cells[4].innerText.trim());
							days.forEach((th) => th.setAttribute("colspan", (rows[0].cells[1].colSpan * 2).toString()));
						} else throw rows[0].cells;
						return [days, ...[0, 1].map((r) => [...table.tHead.rows[r].querySelectorAll("th:not([rowspan])")].filter((th) => th.innerText.trim().length > 2))];
					} else throw rows?.[0]?.cells;
				})();
				if (thDays.length == 0) {
					thDays.push(document.createElement("th"));
					thDays[0].colSpan = thTimes.map((g) => g.colSpan).reduce((p, c) => p + c, 0);
				}
				assert([1, 2].includes(thDays.length), "Invalid # of days.");
				assert(thTimes.length % thDays.length == 0 && thTimes.length >= 2, "Invalid # of termini.");
				assert(thTermini.length % thDays.length == 0 && thTermini.length >= 2, "Invalid # of child termini.");
				const dayWidth = thDays[0].colSpan;
				const days = [];
				for (let i = 0; i < thDays.length; i++) {
					assert(thDays[i].colSpan == dayWidth);
					days.push(i * dayWidth);
				}
				const first = [1, 2];
				const last = [3, 4];
				const dl = [];
				const ul = [];
				if (thTimes.length / thDays.length == 2 && thTermini.length / thTimes.length == 2) {
					if (thTermini[0].innerText.trim().includes(table.tBodies[0].rows[0].cells[0].innerText.trim())) {
						first.reverse();
						last.reverse();
					}
				} else if (thTimes.length / thDays.length >= 2) {
					let i = 0;
					for (const terminus of thTimes) {
						const span = thTermini.slice(i, i + terminus.colSpan);
						if (terminus.innerText.trim().startsWith("首班车")) {
							first[0] = span.single((td) => {
								return td.innerText.trim().match(/↓|内环/u) !== null;
							}).cellIndex + 1;
							first[1] = span.single((td) => {
								return td.innerText.trim().match(/↑|外环/u) !== null;
							}).cellIndex + 1;
						} else {
							dl.push(...span.filter((td) => {
								return td.innerText.trim().match(/↓|内环/u) !== null;
							}).map((td) => td.cellIndex + 1));
							ul.push(...span.filter((td) => {
								return td.innerText.trim().match(/↑|外环/u) !== null;
							}).map((td) => td.cellIndex + 1));
						}
						i += terminus.colSpan;
						if (i >= thDays[0].colSpan) break;
					}
					[last[0], last[1]] = dl.length == 1 && ul.length == 1 ? [dl[0], ul[0]] : [dl, ul];
				} else throw thTimes.length;
				let timetable = parseRows([...table.tBodies[0].rows].map((row) => [...row.cells]), days, first, last);
				if (caption.innerText.includes("璧铜") && timetable.keys().next().value?.includes("璧山")) timetable = Timetable.reverse(timetable);
				navigator.clipboard.writeText(Timetable.luaify(timetable));
			};
			attachButton(caption, copyData);
			new MutationObserver(() => {
				if (caption.querySelector("a") == null) {
					attachButton(caption, copyData);
					const rows = [...[...card.querySelectorAll("table")].single().tBodies[0].rows].map((row) => [...row.cells]);
					const i = rows.findIndex((row) => row.every((cell) => cell.innerText.trim().length <= 2));
					if (i < 0) return;
					const j = rows.findIndex((row, r) => r > i && row.some((cell) => cell.innerText.includes("↓")));
					if (j < 0) return;
					attachButton(rows[j][0], function() {
						const d = rows[j].map((cell, c) => cell.innerText.includes("↓") ? c : null).filter((c) => c !== null);
						const u = rows[j].map((cell, c) => cell.innerText.includes("↑") ? c : null).filter((c) => c !== null);
						let days;
						assert(d.length == u.length && d.length >= 2, "Invalid # of termini.");
						const first = [d[0], u[0]];
						const last = [d[1], u[1]];
						if (d.length == 2) days = [d[0] - 1];
						else if (d.length == 4) days = [d[0] - 1, d[2] - 1];
						else throw [d, u];
						const timetable = parseRows(rows.slice(i + 2), days, first, last);
						navigator.clipboard.writeText(Timetable.luaify(timetable));
					});
				}
			}).observe(card, {
				childList: true,
				subtree: true
			});
		});
	} };
	function parseCell(cell) {
		return cell.innerText.trim().replace(/\p{Pd}+|[((]到达[))]/u, "");
	}
	var WHRT = { bootstrap: () => {
		const title = document.querySelector("h1");
		const copyData = function() {
			const timetable = new Map();
			document.querySelectorAll("table.Table").forEach((table) => {
				const termini = [...table.querySelector("tr:has(td + td)").querySelectorAll("td")];
				const sub_termini = [...table.querySelector("tr:not(:has(td[colspan]))").querySelectorAll("td")];
				assert(termini.length == 2, "Invalid # of termini.");
				const terminiSpans = termini.map((td) => td.colSpan);
				assert(terminiSpans[0] >= 3, "Invalid termini span.");
				assert(terminiSpans[1] >= 3, "Invalid termini span.");
				const offsetFirst = [sub_termini.slice(0, terminiSpans[0]).find((td) => td.innerText.trim().startsWith("首班车")).cellIndex, sub_termini.find((td) => td.innerText.trim().startsWith("首班车")).cellIndex];
				const dl = sub_termini.slice(terminiSpans[0]).filter((td) => td.innerText.trim().startsWith("末班车")).map((td) => td.cellIndex);
				const ul = sub_termini.slice(0, terminiSpans[0]).filter((td) => td.innerText.trim().startsWith("末班车")).map((td) => td.cellIndex);
				const offsetLast = dl.length == 1 && ul.length == 1 ? [dl[0], ul[0]] : [dl, ul];
				offsetLast.forEach((o) => {
					if (o instanceof Array) o.unshift(o.pop());
				});
				const nameOffset = sub_termini.slice(terminiSpans[0]).find((td) => td.innerText.trim().startsWith("车站")).cellIndex;
				assert(nameOffset > 0, "Invalid name offset.");
				const rows = [...table.querySelectorAll("tr:not(:has(td[colspan]))")].slice(1);
				for (const row of rows) {
					const name = row.cells[nameOffset].innerText.trim();
					const up_row = rows[rows.length - 1 - rows.indexOf(row)];
					assert(up_row !== void 0, "Invalid row.");
					if (!timetable.has(name)) timetable.set(name, []);
					timetable.get(name).push([[parseCell(row.cells[offsetFirst[0]]), parseCell(up_row.cells[offsetFirst[1]])], [offsetLast[0] instanceof Array ? offsetLast[0].map((i) => parseCell(row.cells[i])) : parseCell(row.cells[offsetLast[0]]), offsetLast[1] instanceof Array ? offsetLast[1].map((i) => parseCell(up_row.cells[i])) : parseCell(up_row.cells[offsetLast[1]])]]);
				}
			});
			navigator.clipboard.writeText(Timetable.luaify(timetable));
		};
		attachButton(title, copyData);
	} };
	if (!Array.prototype.single) Object.defineProperty(Array.prototype, "single", {
		value: function(predicate) {
			const target = predicate ? this.filter(predicate) : this;
			if (target.length === 0) throw new Error("Sequence contains no matching element");
			if (target.length > 1) throw new Error("Sequence contains more than one matching element");
			return target[0];
		},
		enumerable: false,
		configurable: true,
		writable: true
	});
	switch (new URL(document.URL).hostname) {
		case "www.cqmetro.cn":
			CRT.bootstrap();
			break;
		case "www.wuhanrt.com":
			WHRT.bootstrap();
			break;
	}
})();