import * as SparkMD5 from 'spark-md5';
import { cancelable } from './CancelablePromise';
import { sscanf } from '../../libs/scanf/scanf';
import { utf8ToBytes } from '../../libs/utf8-encoder';
import { LogLevelType, LayoutType } from '../const';
import { BaseUtils } from './BaseUtils';

const _defaultOptions = {};
const _emptyArray = [];

var _factories = [];
var _macros = {};
var _registeredClasses = {};
var _registeredComponents = {};
var _registeredVariables = {};
var _urlResolvers = [];
let _workPath = '';
let _globalEnvVars = {};

var _lastAttributeKeyCache = { key: "", keys: [] }

var _timer = typeof performance === 'undefined' ? Date : performance;
var _global = typeof window !== 'undefined' ? window : (typeof global !== 'undefined' ? global : null);

const _colorKeywords = {
	'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF,
	'beige': 0xF5F5DC, 'bisque': 0xFFE4C4, 'black': 0x000000, 'blanchedalmond': 0xFFEBCD, 'blue': 0x0000FF, 'blueviolet': 0x8A2BE2,
	'brown': 0xA52A2A, 'burlywood': 0xDEB887, 'cadetblue': 0x5F9EA0, 'chartreuse': 0x7FFF00, 'chocolate': 0xD2691E, 'coral': 0xFF7F50,
	'cornflowerblue': 0x6495ED, 'cornsilk': 0xFFF8DC, 'crimson': 0xDC143C, 'cyan': 0x00FFFF, 'darkblue': 0x00008B, 'darkcyan': 0x008B8B,
	'darkgoldenrod': 0xB8860B, 'darkgray': 0xA9A9A9, 'darkgreen': 0x006400, 'darkgrey': 0xA9A9A9, 'darkkhaki': 0xBDB76B, 'darkmagenta': 0x8B008B,
	'darkolivegreen': 0x556B2F, 'darkorange': 0xFF8C00, 'darkorchid': 0x9932CC, 'darkred': 0x8B0000, 'darksalmon': 0xE9967A, 'darkseagreen': 0x8FBC8F,
	'darkslateblue': 0x483D8B, 'darkslategray': 0x2F4F4F, 'darkslategrey': 0x2F4F4F, 'darkturquoise': 0x00CED1, 'darkviolet': 0x9400D3,
	'deeppink': 0xFF1493, 'deepskyblue': 0x00BFFF, 'dimgray': 0x696969, 'dimgrey': 0x696969, 'dodgerblue': 0x1E90FF, 'firebrick': 0xB22222,
	'floralwhite': 0xFFFAF0, 'forestgreen': 0x228B22, 'fuchsia': 0xFF00FF, 'gainsboro': 0xDCDCDC, 'ghostwhite': 0xF8F8FF, 'gold': 0xFFD700,
	'goldenrod': 0xDAA520, 'gray': 0x808080, 'green': 0x008000, 'greenyellow': 0xADFF2F, 'grey': 0x808080, 'honeydew': 0xF0FFF0, 'hotpink': 0xFF69B4,
	'indianred': 0xCD5C5C, 'indigo': 0x4B0082, 'ivory': 0xFFFFF0, 'khaki': 0xF0E68C, 'lavender': 0xE6E6FA, 'lavenderblush': 0xFFF0F5, 'lawngreen': 0x7CFC00,
	'lemonchiffon': 0xFFFACD, 'lightblue': 0xADD8E6, 'lightcoral': 0xF08080, 'lightcyan': 0xE0FFFF, 'lightgoldenrodyellow': 0xFAFAD2, 'lightgray': 0xD3D3D3,
	'lightgreen': 0x90EE90, 'lightgrey': 0xD3D3D3, 'lightpink': 0xFFB6C1, 'lightsalmon': 0xFFA07A, 'lightseagreen': 0x20B2AA, 'lightskyblue': 0x87CEFA,
	'lightslategray': 0x778899, 'lightslategrey': 0x778899, 'lightsteelblue': 0xB0C4DE, 'lightyellow': 0xFFFFE0, 'lime': 0x00FF00, 'limegreen': 0x32CD32,
	'linen': 0xFAF0E6, 'magenta': 0xFF00FF, 'maroon': 0x800000, 'mediumaquamarine': 0x66CDAA, 'mediumblue': 0x0000CD, 'mediumorchid': 0xBA55D3,
	'mediumpurple': 0x9370DB, 'mediumseagreen': 0x3CB371, 'mediumslateblue': 0x7B68EE, 'mediumspringgreen': 0x00FA9A, 'mediumturquoise': 0x48D1CC,
	'mediumvioletred': 0xC71585, 'midnightblue': 0x191970, 'mintcream': 0xF5FFFA, 'mistyrose': 0xFFE4E1, 'moccasin': 0xFFE4B5, 'navajowhite': 0xFFDEAD,
	'navy': 0x000080, 'oldlace': 0xFDF5E6, 'olive': 0x808000, 'olivedrab': 0x6B8E23, 'orange': 0xFFA500, 'orangered': 0xFF4500, 'orchid': 0xDA70D6,
	'palegoldenrod': 0xEEE8AA, 'palegreen': 0x98FB98, 'paleturquoise': 0xAFEEEE, 'palevioletred': 0xDB7093, 'papayawhip': 0xFFEFD5, 'peachpuff': 0xFFDAB9,
	'peru': 0xCD853F, 'pink': 0xFFC0CB, 'plum': 0xDDA0DD, 'powderblue': 0xB0E0E6, 'purple': 0x800080, 'rebeccapurple': 0x663399, 'red': 0xFF0000, 'rosybrown': 0xBC8F8F,
	'royalblue': 0x4169E1, 'saddlebrown': 0x8B4513, 'salmon': 0xFA8072, 'sandybrown': 0xF4A460, 'seagreen': 0x2E8B57, 'seashell': 0xFFF5EE,
	'sienna': 0xA0522D, 'silver': 0xC0C0C0, 'skyblue': 0x87CEEB, 'slateblue': 0x6A5ACD, 'slategray': 0x708090, 'slategrey': 0x708090, 'snow': 0xFFFAFA,
	'springgreen': 0x00FF7F, 'steelblue': 0x4682B4, 'tan': 0xD2B48C, 'teal': 0x008080, 'thistle': 0xD8BFD8, 'tomato': 0xFF6347, 'turquoise': 0x40E0D0,
	'violet': 0xEE82EE, 'wheat': 0xF5DEB3, 'white': 0xFFFFFF, 'whitesmoke': 0xF5F5F5, 'yellow': 0xFFFF00, 'yellowgreen': 0x9ACD32
};

/**
 * Parse color from hex value.
 * @param {number} value The hex value.
 * @param {Array} target The target array to store the result.
 * @returns {Array} The target array.
 * @example
 * // 将十六进制颜色值解析为RGB数组(0-1范围)
 * let color = [];
 * _parseColorFromHex(0xFF0000, color); // 红色
 * console.log(color); // [1, 0, 0]
 *
 * _parseColorFromHex(0x00FF00, color); // 绿色
 * console.log(color); // [0, 1, 0]
 */
function _parseColorFromHex(value, target) {
	let hex = Math.floor(value);

	target[0] = (hex >> 16 & 255) / 255;
	target[1] = (hex >> 8 & 255) / 255;
	target[2] = (hex & 255) / 255;

	return target;
}

/**
 * Read a file in chunks.
 * @param {Blob} buffer The file buffer.
 * @param {Function} chunkCallback The callback function for each chunk.
 * @param {Function} endCallback The callback function when reading is complete.
 * @example
 * // 分块读取大文件
 * let file = new Blob(['大文件内容...'], { type: 'text/plain' });
 *
 * _readChunked(
 *   file,
 *   function(chunk, offset, fileSize) {
 *     // 处理每个数据块
 *     console.log('已读取:', Math.round(offset / fileSize * 100) + '%');
 *   },
 *   function(error) {
 *     if (error) {
 *       console.error('读取出错:', error);
 *     } else {
 *       console.log('读取完成');
 *     }
 *   }
 * );
 */
function _readChunked(buffer, chunkCallback, endCallback) {
	const blob = new Blob([buffer]); // 将 ArrayBuffer 转为 Blob
	const chunkSize = 4 * 1024 * 1024; // 4MB
	let offset = 0;
	const fileSize = blob.size; // 使用 .size 属性

	const reader = new FileReader();
	reader.onload = function () {
		if (reader.error) {
			endCallback(reader.error || {});
			return;
		}
		offset += reader.result.byteLength; // 使用 .byteLength 获取 ArrayBuffer 长度
		chunkCallback(reader.result, offset, fileSize);
		if (offset >= fileSize) {
			endCallback(null);
			return;
		}
		readNext();
	};

	reader.onerror = function (err) {
		endCallback(err || {});
	};

	function readNext() {
		const blobSlice = blob.slice(offset, offset + chunkSize);
		reader.readAsArrayBuffer(blobSlice);
	}

	readNext();
}

// Try to ignore eval compile warning
var eval2 = eval;
var _eval = function (script) {
	try {
		return eval2(script);
	}
	catch (e) {
	}
}

var _objectKeysToLowerCase = function (input, deep, filter) {
	var idx, key, keys, last, output, self, type, value;
	self = _objectKeysToLowerCase;
	type = typeof deep;

	// Convert "deep" to a number between 0 to Infinity or keep special object.
	if (type === 'undefined' || deep === null || deep === 0 || deep === false) {
		deep = 0; // Shallow copy
	}
	else if (type === 'object') {
		if (!(deep instanceof self)) {
			throw new TypeError('Expected "deep" to be a special object');
		}
	}
	else if (deep === true) {
		deep = Infinity; // Deep copy
	}
	else if (type === 'number') {
		if (isNaN(deep) || deep < 0) {
			throw new RangeError(
				'Expected "deep" to be a positive number, got ' + deep
			);
		}
	}
	else {
		throw new TypeError(
			'Expected "deep" to be a boolean, number or object, got "' + type + '"'
		);
	}


	// Check type of input, and throw if null or not an object.
	if (input === null || typeof input !== 'object') {
		throw new TypeError('Expected "input" to be an object');
	}

	// Check type of filter
	type = typeof filter;
	if (filter === null || type === 'undefined' || type === 'function') {
		filter = filter || null;
	}
	else {
		throw new TypeError('Expected "filter" to be a function');
	}

	keys = Object.keys(input); // Get own keys from object
	last = keys.length - 1;
	output = {}; // new object

	if (deep) { // only run the deep copy if needed.
		if (typeof deep === 'number') {
			// Create special object to be used during deep copy
			deep =
				Object.seal(
					Object.create(
						self.prototype,
						{
							input: { value: [] },
							output: { value: [] },
							level: { value: -1, writable: true },
							max: { value: deep, writable: false }
						}
					)
				);
		}
		else {
			// Circle detection
			idx = deep.input.indexOf(input);
			if (~idx) {
				return deep.output[idx];
			}
		}

		deep.level += 1;
		deep.input.push(input);
		deep.output.push(output);

		idx = last + 1;
		while (idx--) {
			key = keys[last - idx]; // Using [last - idx] to preserve order.
			value = input[key];
			if (typeof value === 'object' && value && deep.level < deep.max) {
				if (value.constructor === Object) {
					value = self(value, deep, filter);
				}
			}

			var _filter = filter || function () { return true; }
			if (_filter(key, value)) {
				output[key.toLowerCase()] = value;
			}
			else {
				output[key] = value;
			}
		}
		deep.level -= 1;
	}
	else {
		// Simple shallow copy
		idx = last + 1;
		while (idx--) {
			key = keys[last - idx]; // Using [last - idx] to preserve order.

			var _filter = filter || function () { return true; }
			if (_filter(key, value)) {
				output[key.toLowerCase()] = input[key];
			}
			else {
				output[key] = input[key];
			}
		}
	}
	return output;
}

// Thanks for sharing code: http://jsfiddle.net/cattail/NYNT5/

// classify object
var classof = function (o) {
	if (o === null) { return "null" }
	if (o === undefined) { return "undefined" }
	// I suppose Object.prototype.toString use obj.constructor.name
	// to generate string
	var className = Object.prototype.toString.call(o).slice(8, -1);
	return className;
};

var _references = [];
var _handlers = {
	// Handle regexp and date even in shallow.
	'RegExp': function (reg) {
		var flags = '';
		flags += reg.global ? 'g' : '';
		flags += reg.multiline ? 'm' : '';
		flags += reg.ignoreCase ? 'i' : '';
		return new RegExp(reg.source, flags);
	},
	'Date': function (date) {
		return new Date(+date);
	},
	'Array': function (arr, shallow, filterFunc, cloneFunc) {
		var newArr = [], i;
		for (i = 0; i < arr.length; i++) {
			if (shallow) {
				newArr[i] = arr[i];
			}
			else {
				// handle circular reference
				if (_references.indexOf(arr[i]) !== -1) {
					continue;
				}

				// try to use clone function to copy value
				if (cloneFunc && arr[i]) {
					var clonedObject = cloneFunc(arr[i]);
					if (clonedObject) {
						newArr[i] = clonedObject;
						continue;
					}
				}

				var handler = _handlers[classof(arr[i])];
				if (handler) {
					_references.push(arr[i]);
					newArr[i] = handler(arr[i], false);
				}
				else {
					newArr[i] = arr[i];
				}
			}
		}
		return newArr;
	},
	'Object': function (obj, shallow, filterFunc, cloneFunc) {
		var newObj = {}, prop, handler;
		for (prop in obj) {
			if (filterFunc && !filterFunc(prop)) {
				continue;
			}

			// escape prototype properties
			if (shallow) {
				newObj[prop] = obj[prop];
			}
			else {
				// handle circular reference
				if (_references.indexOf(obj[prop]) !== -1) {
					continue;
				}

				// try to use clone function to copy value
				if (cloneFunc && obj[prop]) {
					var clonedObject = cloneFunc(obj[prop], prop);
					if (clonedObject) {
						newObj[prop] = clonedObject;
						continue;
					}
				}

				// recursive
				handler = _handlers[classof(obj[prop])];
				if (handler) {
					_references.push(obj[prop]);
					newObj[prop] = handler(obj[prop], false, filterFunc, cloneFunc);
				}
				else {
					newObj[prop] = obj[prop];
				}
			}
		}

		return newObj;
	}
};

// Thanks for sharing code: https://gist.github.com/david-risney/af6f7912ea171b9076d3ba3ebd54a355
/**
 *
 * @param {object} parent 父对象
 * @param {string[]} fullNamePath 属性路径
 * @param {object} feedback 回调函数
 * @example
 * // 为对象属性设置断点
 * let obj = { value: 10 };
 *
 * _valueBreakpoint(obj, ['value'], {
 *   onCompareValue: function(oldValue, newValue) {
 *     // 当值发生变化时触发断点
 *     return oldValue !== newValue;
 *   },
 *   onValueChanged: function(newValue) {
 *     console.log('值已更改为:', newValue);
 *   }
 * });
 *
 * obj.value = 20; // 会触发断点
 */
function _valueBreakpoint(parent, fullNamePath, feedback) {
	var name = fullNamePath[0];
	var childNamePath = fullNamePath.slice(1);
	var innerValue = parent[name];
	var childBreakpoints = [];

	function applyChildValueBreakpoints() {
		if (childNamePath.length > 0 && innerValue) {
			childBreakpoints.push(_valueBreakpoint(innerValue, childNamePath, feedback));
		}
	}
	applyChildValueBreakpoints();

	Object.defineProperty(parent, name, {
		get: (function () {
			return innerValue;
		}).bind(this),
		set: (function (newValue) {
			if (!childNamePath.length) {
				var valueChanged = false;
				var onCompareValue = feedback.onCompareValue;
				if (onCompareValue && onCompareValue(innerValue, newValue)) {
					_eval('debugger'); // use eval here to prevent optimize debugger keyword away

					valueChanged = true;
				}
			}

			innerValue = newValue;
			applyChildValueBreakpoints();

			if (valueChanged) {
				var onValueChanged = feedback.onValueChanged;
				if (onValueChanged) {
					onValueChanged(newValue);
				}
			}
		}).bind(this),
		enumerable: true,
		configurable: true
	});
}

let _originalValueOf = null;
/**
 * 启用NaN捕获。
 * @param {boolean} value 是否启用。
 * @example
 * // 启用NaN捕获
 * _enableNaNCatch(true);
 *
 * // 这将抛出错误,因为试图将非数字对象转换为数字
 * let obj = {};
 * let num = obj + 1; // 将触发错误
 *
 * // 禁用NaN捕获
 * _enableNaNCatch(false);
 */
function _enableNaNCatch(value) {
	if (value && !_originalValueOf) {
		_originalValueOf = Object.prototype.valueOf;

		Object.prototype.valueOf = function () {
			if (typeof this !== 'number') {
				throw new Error('Object is not a Number');
			}

			return _originalValueOf.call(this);
		}
	}
	else {
		Object.prototype.valueOf = _originalValueOf;
		_originalValueOf = null;
	}
}

function _clearTimeoutById(id, callbacks) {
	if (!id) {
		return;
	}

	let index = Utils.binarySearch(callbacks, (timer) => {
		return timer.id - id;
	});

	if (index === -1) {
		return;
	}

	callbacks.splice(index, 1);
}

/**
 * @class
 * The timer to replace the global setTimeout() function
 * @memberof THING
 */
class Timer {

	static id = 0;

	/**
	 * The number of batch timeout callback in one frame.
	 * @type {number}
	 * @private
	 */
	static batchNumber = 100;
	static batchTimeoutCallbacks = [];

	// Update callback functions
	static updateCallbacks = [];

	// Timeout callback functions
	static timeoutCallbacks = [];
	static directTimeoutCallbacks = [];

	/**
	 * Set timer callback function in batch mode.
	 * @param {Function} callback The callback function.
	 * @private
	 * @example
	 * // 设置批量定时器回调函数
	 * THING.Utils.setBatchTimeout(function() {
	 *   console.log('每帧执行一次');
	 * });
	 */
	static setBatchTimeout(callback) {
		Timer.batchTimeoutCallbacks.push(callback);
	}

	/**
	 * 设置定时器回调函数。
	 * @param {Function} callback 回调函数。
	 * @param {number} milliseconds 延迟时间(毫秒)。
	 * @returns {number|null} 定时器ID。
	 * @example
	 * // 设置一个延时执行的函数
	 * let timerId = THING.Utils.setTimeout(function() {
	 *   console.log('3秒后执行');
	 * }, 3000);
	 *
	 * // 可以通过返回的ID取消定时器
	 * // THING.Utils.clearTimeout(timerId);
	 */
	static setTimeout(callback, milliseconds) {
		if (milliseconds === undefined) {
			Timer.directTimeoutCallbacks.push(callback);

			// Direct timeout would return nothing, due to we can not clear it
			return null;
		}
		else {
			var id = ++Timer.id;
			Timer.timeoutCallbacks.push({ id, callback, time: milliseconds / 1000 });

			return id;
		}
	}

	/**
	 * Clear timeout callback function.
	 * @param {number} id The timer id.
	 * @example
	 * // 设置一个延时执行的函数
	 * let timerId = THING.Utils.setTimeout(function() {
	 *   console.log('这条消息不会显示,因为定时器被取消了');
	 * }, 3000);
	 *
	 * // 取消定时器
	 * THING.Utils.clearTimeout(timerId);
	 */
	static clearTimeout(id) {
		_clearTimeoutById(id, Timer.timeoutCallbacks);
	}

	/**
	 * 更新定时器。
	 * @param {number} deltaTime 时间差。
	 * @example
	 * // 更新定时器
	 * THING.Utils.update(1);
	 */
	static update(deltaTime) {
		// Direct timeout ...
		let length = Timer.directTimeoutCallbacks.length;
		if (length) {
			// To prevent dead loop calling in callback functions, so we copy callback functions here
			let directTimeoutCallbacks = Timer.directTimeoutCallbacks.slice(0);
			Timer.directTimeoutCallbacks.splice(0, length);

			for (let i = 0; i < length; i++) {
				directTimeoutCallbacks[i]();
			}
		}

		// Delay timeout ...
		var timeoutCallbacks = Timer.timeoutCallbacks;
		for (var i = 0; i < timeoutCallbacks.length; i++) {
			var info = timeoutCallbacks[i];

			info.time -= deltaTime;
			if (info.time > 0) {
				continue;
			}

			timeoutCallbacks.splice(i--, 1);

			info.callback();
		}

		// Batch timeout ...
		if (Timer.batchTimeoutCallbacks.length) {
			let number = Math.min(Timer.batchTimeoutCallbacks.length, Timer.batchNumber);
			for (let i = 0; i < number; i++) {
				Timer.batchTimeoutCallbacks[i]();
			}

			Timer.batchTimeoutCallbacks.splice(0, number);
		}

		// Update callbacks ...
		if (Timer.updateCallbacks.length) {
			Timer.updateCallbacks.forEach(callback => {
				callback(deltaTime);
			});
		}
	}

	/**
	 * 添加更新回调函数。
	 * @param {Function} callback 回调函数。
	 * @example
	 * // 添加更新回调函数
	 * THING.Utils.addUpdateCallback(function(deltaTime) {
	 *   console.log('每帧更新,时间差:', deltaTime);
	 * });
	 */
	static addUpdateCallback(callback) {
		Timer.updateCallbacks.push(callback);
	}

	/**
	 * 移除更新回调函数。
	 * @param {Function} callback 回调函数。
	 * @example
	 * // 移除更新回调函数
	 * THING.Utils.removeUpdateCallback(function(deltaTime) {
	 *   console.log('每帧更新,时间差:', deltaTime);
	 * });
	 */
	static removeUpdateCallback(callback) {
		let index = Timer.updateCallbacks.indexOf(callback);
		if (index == -1) {
			return;
		}

		Timer.updateCallbacks.splice(index, 1);
	}

}

/**
 * @class Utils
 * Useful functions.
 * @memberof THING
 */
class Utils extends BaseUtils {

	/**
	 * The log level type.
	 * @type {LogLevelType}
	 */
	static logLevelType = LogLevelType.All;

	/**
	 * 设置批量定时器数量。
	 * @param {number} value 批量定时器数量。
	 * @example
	 * // 设置批量定时器数量
	 * THING.Utils.setBatchTimeoutNumber(100);
	 */
	static setBatchTimeoutNumber(value) {
		Timer.batchNumber = value;
	}

	/**
	 * 获取批量定时器数量。
	 * @returns {number} 批量定时器数量。
	 * @example
	 * // 获取批量定时器数量
	 * const number = THING.Utils.getBatchTimeoutNumber();
	 * console.log(number); // 100
	 */
	static getBatchTimeoutNumber() {
		return Timer.batchNumber;
	}

	/**
	 * 设置批量定时器回调函数。
	 * @param {Function} callback 回调函数。
	 * @example
	 * // 设置批量定时器回调函数
	 * THING.Utils.setBatchTimeout(function() {
	 *   console.log('每帧执行一次');
	 * });
	 */
	static setBatchTimeout(callback) {
		Timer.setBatchTimeout(callback);
	}

	/**
	 * Set timeout callback function.
	 * @param {Function} callback The callback function.
	 * @param {number} milliseconds The delay time in milliseconds.
	 * @returns {number} If milliseconds is undefined then return nothing and the timer can not be clear
	 * @example
	 * // 设置一个延时执行的函数
	 * let timerId = THING.Utils.setTimeout(function() {
	 *   console.log('3秒后执行');
	 * }, 3000);
	 *
	 * // 可以通过返回的ID取消定时器
	 * // THING.Utils.clearTimeout(timerId);
	 */
	static setTimeout(callback, milliseconds) {
		return Timer.setTimeout(callback, milliseconds);
	}

	/**
	 * Clear timeout callback function.
	 * @param {number} id The timeout ID.
	 * @example
	 * // 设置一个延时执行的函数
	 * let timerId = THING.Utils.setTimeout(function() {
	 *   console.log('这条消息不会显示,因为定时器被取消了');
	 * }, 3000);
	 *
	 * // 取消定时器
	 * THING.Utils.clearTimeout(timerId);
	 */
	static clearTimeout(id) {
		Timer.clearTimeout(id);
	}

	/**
	 * Clear all timeouts.
	 * @example
	 * // 设置多个定时器
	 * THING.Utils.setTimeout(function() { console.log('定时器1'); }, 1000);
	 * THING.Utils.setTimeout(function() { console.log('定时器2'); }, 2000);
	 * THING.Utils.setTimeout(function() { console.log('定时器3'); }, 3000);
	 *
	 * // 清除所有定时器
	 * THING.Utils.clearAllTimeout();
	 */
	static clearAllTimeout() {
		Timer.timeoutCallbacks = [];
		Timer.directTimeoutCallbacks = [];
		Timer.batchTimeoutCallbacks = [];
	}

	/**
	 * Add update callback.
	 * @param {Function} callback The callback function.
	 * @example
	 * // 添加一个每帧更新的回调函数
	 * function onUpdate(deltaTime) {
	 *   console.log('每帧更新,时间差:', deltaTime);
	 * }
	 *
	 * THING.Utils.addUpdateCallback(onUpdate);
	 */
	static addUpdateCallback(callback) {
		Timer.addUpdateCallback(callback);
	}

	/**
	 * Remove update callback.
	 * @param {Function} callback The callback function.
	 * @example
	 * // 定义一个更新函数
	 * function onUpdate(deltaTime) {
	 *   console.log('每帧更新,时间差:', deltaTime);
	 * }
	 *
	 * // 添加更新回调
	 * THING.Utils.addUpdateCallback(onUpdate);
	 *
	 * // 移除更新回调
	 * THING.Utils.removeUpdateCallback(onUpdate);
	 */
	static removeUpdateCallback(callback) {
		Timer.removeUpdateCallback(callback);
	}

	/**
	 * Update the timer.
	 * @param {number} deltaTime The time difference.
	 * @example
	 * // 更新定时器
	 * THING.Utils.update(1);
	 */
	static update(deltaTime) {
		Timer.update(deltaTime);
	}

	/**
	 * Disable/Enable console debug.
	 * @type {boolean}
	 * @example
	 * // 禁用console.debug输出
	 * THING.Utils.disableDebug = true;
	 * console.debug('这条消息不会显示');
	 *
	 * // 启用console.debug输出
	 * THING.Utils.disableDebug = false;
	 * console.debug('这条消息会显示');
	 */
	static get disableDebug() {
		return console.debug != _consoleDebugFunc;
	}
	/**
	 *
	 */
	static set disableDebug(value) {
		if (value) {
			console.debug = function () { };
		}
		else {
			console.debug = _consoleDebugFunc;
		}
	}

	/**
	 * Disable/Enable console log.
	 * @type {boolean}
	 * @example
	 * // 禁用console.log输出
	 * THING.Utils.disableLog = true;
	 * console.log('这条消息不会显示');
	 *
	 * // 启用console.log输出
	 * THING.Utils.disableLog = false;
	 * console.log('这条消息会显示');
	 */
	static get disableLog() {
		return console.log != _consoleLogFunc;
	}
	/**
	 *
	 */
	static set disableLog(value) {
		if (value) {
			console.log = function () { };
		}
		else {
			console.log = _consoleLogFunc;
		}
	}

	/**
	 * Disable/Enable console warn.
	 * @type {boolean}
	 * @example
	 * // 禁用console.warn输出
	 * THING.Utils.disableWarn = true;
	 * console.warn('这条警告不会显示');
	 *
	 * // 启用console.warn输出
	 * THING.Utils.disableWarn = false;
	 * console.warn('这条警告会显示');
	 */
	static get disableWarn() {
		return console.warn != _consoleWarnFunc;
	}
	/**
	 *
	 */
	static set disableWarn(value) {
		if (value) {
			console.warn = function () { };
		}
		else {
			console.warn = _consoleWarnFunc;
		}
	}

	/**
	 * Disable/Enable console error.
	 * @type {boolean}
	 * @example
	 * // 禁用console.error输出
	 * THING.Utils.disableError = true;
	 * console.error('这条错误不会显示');
	 *
	 * // 启用console.error输出
	 * THING.Utils.disableError = false;
	 * console.error('这条错误会显示');
	 */
	static get disableError() {
		return console.error != _consoleErrorFunc;
	}
	/**
	 *
	 */
	static set disableError(value) {
		if (value) {
			console.error = function () { };
		}
		else {
			console.error = _consoleErrorFunc;
		}
	}

	/**
	 * Disable/Enable console time.
	 * @type {boolean}
	 * @example
	 * // 禁用console.time相关函数
	 * THING.Utils.disableTime = true;
	 * console.time('计时器'); // 不会生效
	 * console.timeEnd('计时器'); // 不会生效
	 *
	 * // 启用console.time相关函数
	 * THING.Utils.disableTime = false;
	 * console.time('计时器'); // 开始计时
	 * // 执行一些操作...
	 * console.timeEnd('计时器'); // 结束计时并显示耗时
	 */
	static get disableTime() {
		return console.time != _consoleTimeFunc;
	}
	/**
	 *
	 */
	static set disableTime(value) {
		if (value) {
			console.time = function () { };
			console.timeEnd = function () { };
		}
		else {
			console.time = _consoleTimeFunc;
			console.timeEnd = _consoleTimeEndFunc;
		}
	}

	/**
	 * 解析对象。
	 * @param {any} value 要解析的值。
	 * @param {any} defaultValue 默认值。
	 * @returns {any} 解析后的值。
	 * @example
	 * // 解析对象
	 * const obj = THING.Utils.parseObject({ a: 1, b: 2 });
	 * console.log(obj); // { a: 1, b: 2 }
	 */
	static parseObject(value, defaultValue = {}) {
		if (Utils.isObject(value)) {
			return Utils.mergeObject({}, value, true);
		}

		return Utils.mergeObject({}, defaultValue);
	}

	/**
	 * 解析JSON。
	 * @param {any} object 要解析的值。
	 * @returns {any} 解析后的值。
	 * @example
	 * // 解析JSON
	 * const obj = THING.Utils.parseJSON({ a: 1, b: 2 });
	 * console.log(obj); // { a: 1, b: 2 }
	 */
	static parseJSON(object) {
		try {
			if (Utils.isArrayBuffer(object)) {
				return JSON.parse(Utils.arrayBufferToString(object));
			}
			else if (Utils.isArray(object) || Utils.isUint8Array(object)) {
				return JSON.parse(Utils.bufferToString(object));
			}
			else {
				return JSON.parse(object);
			}
		}
		catch (ex) {
			//			Utils.error(ex);
			return {};
		}
	}

	/**
	 * 获取对象中的函数。
	 * @param {any} object 对象。
	 * @returns {Array<string>} 函数名数组。
	 * @example
	 * // 获取对象中的函数
	 * const functions = THING.Utils.getFunctionsFromObject({ a: 1, b: 2 });
	 * console.log(functions); // ['a', 'b']
	 */
	static getFunctionsFromObject(object) {
		var funcNames = [];

		var names_1 = Object.getOwnPropertyNames(Object.getPrototypeOf(object));
		var names_2 = Object.getOwnPropertyNames(Object.getPrototypeOf(object.__proto__));
		var names = names_1.concat(names_2);
		for (let name of names) {
			let method = object[name];

			if (!(method instanceof Function)) {
				continue;
			}

			if (name == 'constructor') {
				continue;
			}

			funcNames.push(name);
		}

		return funcNames.sort();
	}

	/**
	 * 获取类类型中的函数。
	 * @param {any} classType 类类型。
	 * @returns {Array<string>} 函数名数组。
	 * @example
	 * // 获取类类型中的函数
	 * const functions = THING.Utils.getFunctionsFromClassType(Thing);
	 * console.log(functions); // ['a', 'b']
	 */
	static getFunctionsFromClassType(classType) {
		return Utils.getFunctionsFromObject(new classType());
	}

	/**
	 * 获取类类型中的静态函数。
	 * @param {any} classType 类类型。
	 * @returns {Array<string>} 函数名数组。
	 * @example
	 * // 获取类类型中的静态函数
	 * const functions = THING.Utils.getStaticFunctionsFromClassType(Thing);
	 * console.log(functions); // ['a', 'b']
	 */
	static getStaticFunctionsFromClassType(classType) {
		return Object.getOwnPropertyNames(classType).filter(funcName => {
			return Utils.isFunction(classType[funcName]);
		});
	}

	/**
	 * 获取类类型中的类名。
	 * @param {any} proto 类类型。
	 * @returns {string} 类名。
	 * @example
	 * // 获取类类型中的类名
	 * const className = THING.Utils.getClassNameFromProto(Thing);
	 * console.log(className); // 'Thing'
	 */
	static getClassNameFromProto(proto) {
		return proto.constructor.className || proto.constructor.name;
	}

	/**
	 * 获取类类型中的类名。
	 * @param {any} proto 类类型。
	 * @returns {Array<string>} 类名数组。
	 * @example
	 * // 获取类类型中的类名
	 * const classNames = THING.Utils.getClassNamesFromProto(Thing);
	 * console.log(classNames); // ['Thing']
	 */
	static getClassNamesFromProto(proto) {
		var classNames = [];
		while (proto) {
			var className = Utils.getClassNameFromProto(proto);
			if (className != 'Object') {
				if (classNames.indexOf(className) === -1) {
					classNames.push(className);
				}
			}

			proto = proto.__proto__;
		}

		return classNames;
	}

	/**
	 * Output debug log.
	 * @example
	 * // 输出调试信息
	 * THING.Utils.debug('调试信息');
	 */
	static debug() {
		if (Utils.logLevelType & LogLevelType.Debug) {
			console.debug.apply(console, arguments);
		}
	}

	/**
	 * Output log.
	 * @example
	 * // 输出日志信息
	 * THING.Utils.log('日志信息');
	 */
	static log() {
		if (Utils.logLevelType & LogLevelType.Log) {
			console.log.apply(console, arguments);
		}
	}

	/**
	 * Output warn log.
	 * @example
	 * // 输出警告信息
	 * THING.Utils.warn('警告信息');
	 */
	static warn() {
		if (Utils.logLevelType & LogLevelType.Warn) {
			console.warn.apply(console, arguments);
		}
	}

	/**
	 * Output error log.
	 * @example
	 * // 输出错误信息
	 * THING.Utils.error('错误信息');
	 */
	static error() {
		if (Utils.logLevelType & LogLevelType.Error) {
			console.error.apply(console, arguments);
		}
	}

	/**
	 * 获取当前时间。
	 * @returns {number} 当前时间(秒)。
	 * @example
	 * // 获取当前时间
	 * const currentTime = THING.Utils.getCurrentTime();
	 * console.log(currentTime); // 当前时间(秒)
	 */
	static getCurrentTime() {
		return _timer.now() / 1000;
	}

	/**
	 * 计算从给定时间到当前时间的时间差(秒)。
	 * @param {number} time 给定的时间(秒)。
	 * @returns {number} 从给定时间到当前时间的时间差(秒)。
	 * @example
	 * // 计算从给定时间到当前时间的时间差
	 * const elapsedTime = THING.Utils.getElapsedTime(1609459200); // 假设给定的时间是2021年1月1日0时0分0秒
	 * console.log(elapsedTime); // 输出从给定时间到当前时间的时间差(秒)
	 */
	static getElapsedTime(time) {
		return Utils.getCurrentTime() - time;
	}

	/**
	 * 获取当前时间(毫秒)。
	 * @returns {number} 当前时间(毫秒)。
	 * @example
	 * // 获取当前时间(毫秒)
	 * const currentTimeMilliseconds = THING.Utils.getCurrentTimeMilliseconds();
	 * console.log(currentTimeMilliseconds); // 输出当前时间(毫秒)
	 */
	static getCurrentTimeMilliseconds() {
		return _timer.now();
	}

	/**
	 * 计算从给定时间到当前时间的时间差(毫秒)。
	 * @param {number} time 给定的时间(毫秒)。
	 * @returns {number} 从给定时间到当前时间的时间差(毫秒)。
	 * @example
	 * // 计算从给定时间到当前时间的时间差(毫秒)
	 * const elapsedTimeMilliseconds = THING.Utils.getElapsedTimeMilliseconds(1609459200000); // 假设给定的时间是2021年1月1日0时0分0秒
	 * console.log(elapsedTimeMilliseconds); // 输出从给定时间到当前时间的时间差(毫秒)
	 */
	static getElapsedTimeMilliseconds(time) {
		return Utils.getCurrentTimeMilliseconds() - time;
	}

	/**
	 * 设置数据/值断点。
	 * @param {object} object 对象。
	 * @param {string | Array<string>} attributes 对象的属性名(或属性名数组)。
	 * @param {Function} callback 值比较回调函数,true表示断点,null表示清除断点。
	 * @returns {object} 返回一个对象,包含onValueChanged方法,用于设置值变化回调函数。
	 * @example
	 * // 设置数据/值断点
	 * THING.Utils.setValueBreakpoint(obj, 'value', function(oldValue, newValue) {
	 *   return oldValue !== newValue;
	 * });
	 *
	 * // 设置多个属性断点
	 * THING.Utils.setValueBreakpoint(obj, ['value', 'name'], function(oldValue, newValue) {
	 *   return oldValue !== newValue;
	 * });
	 */
	static setValueBreakpoint(object, attributes, callback = (a, b) => { return a != b; }) {
		var feedback = {
			onCompareValue: callback,
			onValueChanged: function () { }
		};

		var reuslt = {
			onValueChanged: function (callback) {
				feedback.onValueChanged = callback;
			}
		}

		if (Utils.isArray(attributes)) {
			attributes.forEach(name => {
				_valueBreakpoint(object, [name], feedback);
			});
		}
		else if (Utils.isString(attributes)) {
			_valueBreakpoint(object, [attributes], feedback);
		}

		return reuslt;
	}

	/**
	 * 启用NaN捕获。
	 * @param {boolean} value 是否启用NaN捕获。
	 * @example
	 * // 启用NaN捕获
	 * THING.Utils.enableNaNCatch(true);
	 *
	 * // 禁用NaN捕获
	 * THING.Utils.enableNaNCatch(false);
	 */
	static enableNaNCatch(value = true) {
		_enableNaNCatch(value);
	}

	/**
	 * 获取两个对象的所有唯一键名。
	 * @param {object} obj1 第一个对象。
	 * @param {object} obj2 第二个对象。
	 * @returns {Array<string>} 返回一个包含所有唯一键名的数组。
	 * @example
	 * // 获取两个对象的所有唯一键名
	 * const obj1 = { name: 'John', age: 30 };
	 * const obj2 = { age: 25, city: 'Beijing' };
	 *
	 * const unionKeys = THING.Utils.getUnionKeys(obj1, obj2);
	 * console.log(unionKeys); // ['name', 'age', 'city']
	 *
	 * // 处理重复键
	 * const obj3 = { x: 1, y: 2 };
	 * const obj4 = { y: 3, z: 4 };
	 * const keys = THING.Utils.getUnionKeys(obj3, obj4);
	 * console.log(keys); // ['x', 'y', 'z']
	 */
	static getUnionKeys(obj1, obj2) {
		var keys1 = Object.keys(obj1);
		var keys2 = Object.keys(obj2);

		for (var i = 0, l = keys2.length; i < l; i++) {
			var key = keys2[i];
			if (keys1.indexOf(key) == -1) {
				keys1.push(key);
			}
		}

		return keys1;
	}

	/**
	 * 格式化金额。
	 * @param {number} value 金额。
	 * @param {number} fixedNumber 小数位数。
	 * @returns {string} 格式化后的金额。
	 * @example
	 * // 格式化金额
	 * const formattedValue = THING.Utils.formatMoney(1234.5678, 2);
	 * console.log(formattedValue); // "1,234.57"
	 */
	static formatMoney(value, fixedNumber = 0) {
		return value.toFixed(fixedNumber).replace(/\B(?=(\d{3})+(?!\d))/g, ",");
	}

	/**
	 * 格式化字节大小。
	 * @param {number} value 字节大小。
	 * @param {number} fixedNumber 小数位数。
	 * @param {string} suffixName 后缀名。
	 * @returns {string} 格式化后的字节大小。
	 * @example
	 * // 格式化字节大小
	 * const formattedValue = THING.Utils.formatByteSize(1234567890, 2, 'B');
	 * console.log(formattedValue); // "1.23 GB"
	 */
	static formatByteSize(value, fixedNumber = 2, suffixName = 'B') {
		if (value > 1000 * 1000 * 1000 * 1000) {
			return Utils.formatMoney(value / (1000 * 1000 * 1000 * 1000), fixedNumber) + " T" + suffixName;
		}
		else if (value > 1000 * 1000 * 1000) {
			return Utils.formatMoney(value / (1000 * 1000 * 1000), fixedNumber) + " G" + suffixName;
		}
		else if (value > 1000 * 1000) {
			return Utils.formatMoney(value / (1000 * 1000), fixedNumber) + " M" + suffixName;
		}
		else if (value > 1000) {
			return Utils.formatMoney(value / (1000), fixedNumber) + " K" + suffixName;
		}
		else {
			if (suffixName) {
				return Utils.formatMoney(value, fixedNumber) + " " + suffixName;
			}
			else {
				return Utils.formatMoney(value, fixedNumber);
			}
		}
	}

	/**
	 * Allocate an array of objects of a specific class type.
	 * @param {Function} classType The class constructor.
	 * @param {number} number The number of elements to create.
	 * @returns {Array} An array of new instances of the class.
	 * @example
	 * // 创建指定类型的对象数组
	 * class MyClass {
	 *   constructor() {
	 *     this.value = 0;
	 *   }
	 * }
	 *
	 * // 创建5个MyClass实例的数组
	 * const instances = THING.Utils.allocateArray(MyClass, 5);
	 * console.log(instances.length); // 5
	 * console.log(instances[0] instanceof MyClass); // true
	 */
	static allocateArray(classType, number) {
		if (classType) {
			return null;
		}

		var elements = [];
		for (var i = 0; i < number; i++) {
			elements.push(new classType());
		}

		return elements;
	}

	/**
	 * 获取数组长度。
	 * @param {Array} arr 数组。
	 * @returns {number} 数组长度。
	 * @example
	 * // 获取数组长度
	 * const arr = [1, 2, 3];
	 * const length = THING.Utils.getArrayLength(arr);
	 * console.log(length); // 3
	 */
	static getArrayLength(arr) {
		if (!Utils.isArray(arr)) {
			return 0;
		}

		return arr.length;
	}

	/**
	 * 检查数组是否为空。
	 * @param {Array} arr 数组。
	 * @returns {boolean} 是否为空。
	 * @example
	 * // 检查数组是否为空
	 * const emptyArr = [];
	 * const nonEmptyArr = [1, 2, 3];
	 *
	 * THING.Utils.isEmptyArray(emptyArr); // true
	 * THING.Utils.isEmptyArray(nonEmptyArr); // false
	 */
	static isEmptyArray(arr) {
		return Utils.isType('Array')(arr) && arr.length == 0;
	}

	/**
	 * Push an element to array if it doesn't exist.
	 * @param {Array} arr The array.
	 * @param {*} element The element to push.
	 * @example
	 * // 将元素添加到数组中(如果数组中不存在该元素)
	 * const arr = [1, 2, 3];
	 *
	 * // 添加不存在的元素
	 * THING.Utils.pushToArray(arr, 4);
	 * console.log(arr); // [1, 2, 3, 4]
	 *
	 * // 添加已存在的元素(不会重复添加)
	 * THING.Utils.pushToArray(arr, 3);
	 * console.log(arr); // [1, 2, 3, 4]
	 *
	 * // 添加null或undefined(不会添加)
	 * THING.Utils.pushToArray(arr, null);
	 * console.log(arr); // [1, 2, 3, 4]
	 */
	static pushToArray(arr, element) {
		if (!element) {
			return;
		}

		var index = arr.indexOf(element);
		if (index === -1) {
			arr.push(element);
		}
	}

	/**
	 * Remove an element from array.
	 * @param {Array} arr The array.
	 * @param {*} element The element to remove.
	 * @returns {boolean} True if the element was removed.
	 * @example
	 * // 从数组中移除元素
	 * const arr = [1, 2, 3, 4];
	 *
	 * // 移除存在的元素
	 * const removed = THING.Utils.removeFromArray(arr, 3);
	 * console.log(removed); // true
	 * console.log(arr); // [1, 2, 4]
	 *
	 * // 移除不存在的元素
	 * const notRemoved = THING.Utils.removeFromArray(arr, 5);
	 * console.log(notRemoved); // false
	 * console.log(arr); // [1, 2, 4]
	 *
	 * // 传入null数组
	 * const nullResult = THING.Utils.removeFromArray(null, 1);
	 * console.log(nullResult); // false
	 */
	static removeFromArray(arr, element) {
		if (!arr) {
			return false;
		}

		var index = arr.indexOf(element);
		if (index === -1) {
			return false;
		}

		arr._removeAt(index);

		return true;
	}

	/**
	 * 获取值在数组中的索引。
	 * @param {*} value 值。
	 * @param {Array} arrs 数组。
	 * @returns {number} 索引。
	 * @example
	 * // 获取值在数组中的索引
	 * const arr = [1, 2, 3];
	 * const index = THING.Utils.getIndexFromArrays(2, arr);
	 * console.log(index); // 1
	 */
	static getIndexFromArrays(value, arrs) {
		for (var i = 0; i < arrs.length; i++) {
			var index = arrs[i].indexOf(value);
			if (index !== -1) {
				return index;
			}
		}

		return -1;
	}

	/**
	 * 合并数组。
	 * @param {object} object 对象。
	 * @param {string} key 键。
	 * @param {Array} elements 元素。
	 * @example
	 * // 合并数组
	 * const obj = { items: [] };
	 * const elements = [4, 5, 6];
	 * THING.Utils.combineArray(obj, 'items', elements);
	 * console.log(obj.items); // [1, 2, 3, 4, 5, 6]
	 */
	static combineArray(object, key, elements) {
		object[key] = object[key] || [];
		if (Utils.isArray(elements)) {
			object[key].concat(elements);
		}
		else {
			object[key].push(elements);
		}
	}

	/**
	 * 将字符串转换为小写。
	 * @param {string} s 字符串。
	 * @returns {string} 小写字符串。
	 * @example
	 * // 将字符串转换为小写
	 * const str = 'Hello World';
	 * const lowerStr = THING.Utils.toLowerCase(str);
	 * console.log(lowerStr); // 'hello world'
	 *
	 * // 处理空值
	 * THING.Utils.toLowerCase(null); // ''
	 * THING.Utils.toLowerCase(undefined); // ''
	 */
	static toLowerCase(s) {
		return s ? s.toLowerCase() : '';
	}

	/**
	 * 将字符串转换为大写。
	 * @param {string} s 字符串。
	 * @returns {string} 大写字符串。
	 * @example
	 * // 将字符串转换为大写
	 * const str = 'Hello World';
	 * const upperStr = THING.Utils.toUpperCase(str);
	 * console.log(upperStr); // 'HELLO WORLD'
	 *
	 * // 处理空值
	 * THING.Utils.toUpperCase(null); // ''
	 * THING.Utils.toUpperCase(undefined); // ''
	 */
	static toUpperCase(s) {
		return s ? s.toUpperCase() : '';
	}

	/**
	 * Check if a string is a base64 URL.
	 * @param {string} s The string to check.
	 * @returns {boolean} True if the string is a base64 URL.
	 * @example
	 * // 检查字符串是否为base64编码的URL
	 * const base64Url = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA';
	 * const regularUrl = 'https://example.com/image.png';
	 *
	 * THING.Utils.isBase64Url(base64Url); // true
	 * THING.Utils.isBase64Url(regularUrl); // false
	 */
	static isBase64Url(s) {
		if (s._startsWith("data:")) {
			if (s.indexOf("base64,") !== -1) {
				return true;
			}
		}

		return false;
	}

	/**
	 * Check if a URL is a video file URL.
	 * @param {string} url The URL to check.
	 * @returns {boolean} True if the URL is a video file URL.
	 * @example
	 * // 检查URL是否为视频文件
	 * const videoUrl = 'https://example.com/video.mp4';
	 * const imageUrl = 'https://example.com/image.png';
	 *
	 * THING.Utils.isVideoUrl(videoUrl); // true
	 * THING.Utils.isVideoUrl(imageUrl); // false
	 */
	static isVideoUrl(url) {
		const videoExtensions = /\.(mp4|m4v|webm|flv|f4v|mov|avi|wmv|mpeg|mpg|mkv|ts)$/i;
		return videoExtensions.test(url);
	}

	/**
	 * Check if a URL is a WebAssembly file URL.
	 * @param {string} url The URL to check.
	 * @returns {boolean} True if the URL is a WebAssembly file URL.
	 * @example
	 * // 检查URL是否为WebAssembly文件
	 * const wasmUrl = 'https://example.com/module.wasm';
	 * const jsUrl = 'https://example.com/script.js';
	 *
	 * THING.Utils.isWASMUrl(wasmUrl); // true
	 * THING.Utils.isWASMUrl(jsUrl); // false
	 */
	static isWASMUrl(url) {
		const videoExtensions = /\.(wasm)$/i;
		return videoExtensions.test(url);
	}

	/**
	 * Check if a URL is a Blob URL.
	 * @param {string} s The URL to check.
	 * @returns {boolean} True if the URL is a Blob URL.
	 * @example
	 * // 检查URL是否为Blob URL
	 * const blobUrl = 'blob:https://example.com/1234-5678-9abc-def0';
	 * const regularUrl = 'https://example.com/image.png';
	 *
	 * THING.Utils.isBlobUrl(blobUrl); // true
	 * THING.Utils.isBlobUrl(regularUrl); // false
	 */
	static isBlobUrl(s) {
		if (s._startsWith("blob:")) {
			return true;
		}

		return false;
	}

	/**
	 * 截断长字符串并添加省略号。
	 * @param {string} str 字符串。
	 * @param {number} len 字符串限制长度。
	 * @returns {string} 截断长字符串并添加省略号。
	 * @example
	 * // 截断长字符串并添加省略号
	 * const longText = 'This is a very long text that needs to be truncated';
	 * const shortText = THING.Utils.beautySub(longText, 10);
	 * console.log(shortText); // 'This is a ...'
	 *
	 * // 处理包含中文的字符串(中文字符占用两个长度单位)
	 * const mixedText = '这是一段中英文混合的text';
	 * const truncated = THING.Utils.beautySub(mixedText, 10);
	 * console.log(truncated); // '这是一段中...'
	 */
	static beautySub(str, len) {
		var reg = /[\u4e00-\u9fa5]/g, // Match chinese
			slice = str.substring(0, len),
			chineseCharNum = (~~(slice.match(reg) && slice.match(reg).length)),
			realen = slice.length * 2 - chineseCharNum;
		return str.substr(0, realen) + (realen < str.length ? "..." : "");
	}

	/**
	 * 将对象的键名转换为小写。
	 * @param {object} input 对象。
	 * @param {boolean | number} [deep] 递归或深度级别。
	 * @param {Function} [filter] 键过滤回调函数。
	 * @returns {object} 转换后的对象。
	 * @example
	 * // 将对象的键名转换为小写
	 * var obj = { 'Name': 'GO', 'Info': { 'Year': 'Hello 2019','Verson':'xxxx' } };
	 *
	 * // 只转换第一层键名
	 * console.log(THING.Utils.objectKeysToLowerCase(obj));
	 * // {"name":"GO","info":{"Year":"Hello 2019","Verson":"xxxx"}}
	 *
	 * // 递归转换所有层级的键名
	 * console.log(THING.Utils.objectKeysToLowerCase(obj, true));
	 * // {"name":"GO","info":{"year":"Hello 2019","verson":"xxxx"}}
	 *
	 * // 使用过滤函数,排除特定键名
	 * console.log(THING.Utils.objectKeysToLowerCase(obj, true, function (key) {
	 * 	if (key == 'Year') { return false; } else { return true; }
	 * }));
	 * // {"name":"GO","info":{"Year":"Hello 2019","verson":"xxxx"}}
	 */
	static objectKeysToLowerCase(input, deep, filter) {
		return _objectKeysToLowerCase(input, deep, filter);
	}

	/**
	 * Convert font size in points (pt) to pixel size (px).
	 * @param {number} pt Font size in points.
	 * @returns {number} Font size in pixels.
	 * @example
	 * // 将字体大小从磅值(pt)转换为像素值(px)
	 * const fontSizeInPt = 12; // 12pt
	 * const fontSizeInPx = THING.Utils.fontSizeToPixelSize(fontSizeInPt);
	 * console.log(fontSizeInPx); // 16px (12pt = 16px)
	 */
	static fontSizeToPixelSize(pt) {
		return (pt / 72) * 96;
	}

	/**
	 * Convert pixel size (px) to font size in points (pt).
	 * @param {number} px Font size in pixels.
	 * @returns {number} Font size in points.
	 * @example
	 * // 将字体大小从像素值(px)转换为磅值(pt)
	 * const fontSizeInPx = 16; // 16px
	 * const fontSizeInPt = THING.Utils.pixelSizeToFontSize(fontSizeInPx);
	 * console.log(fontSizeInPt); // 12pt (16px = 12pt)
	 */
	static pixelSizeToFontSize(px) {
		return (px / 96) * 72;
	}

	/**
	 * 检查对象是否为类。
	 * @param {object} obj 对象。
	 * @returns {boolean} 是否为类。
	 * @example
	 * // 检查对象是否为类
	 * const obj = { a: 1, b: 2 };
	 * const isClass = THING.Utils.isClass(obj);
	 * console.log(isClass); // false
	 */
	static isClass(obj) {
		if (typeof obj != "function") return false;

		var str = obj.toString();

		// async function or arrow function
		if (obj.prototype === undefined) return false;
		// generator function or malformed definition
		if (obj.prototype.constructor !== obj) return false;
		// ES6 class
		if (str.slice(0, 5) == "class") return true;
		// has own prototype properties
		if (Object.getOwnPropertyNames(obj.prototype).length >= 2) return true;
		// anonymous function
		if (/^function\s+\(|^function\s+anonymous\(/.test(str)) return false;

		return false;
	}

	/**
	 * Check if a path is an image file path.
	 * @param {string} path The file path to check.
	 * @returns {boolean} True if the path is an image file path.
	 * @example
	 * // 检查文件路径是否为图片
	 * const isImage = THING.Utils.isImagePath('texture.png'); // true
	 * const isNotImage = THING.Utils.isImagePath('document.pdf'); // false
	 */
	static isImagePath(path) {
		return (/\.(tga|png|gif|jpe?g|tiff?|webp|bmp)$/i).test(path);
	}

	/**
	 * Check if an object is empty.
	 * @param {object} obj The object to check.
	 * @returns {boolean} True if the object is empty.
	 * @example
	 * // 检查对象是否为空
	 * const emptyObj = {};
	 * const nonEmptyObj = { key: 'value' };
	 * THING.Utils.isEmptyObject(emptyObj); // true
	 * THING.Utils.isEmptyObject(nonEmptyObj); // false
	 */
	static isEmptyObject(obj) {
		return !Object.keys(obj).length;
	}

	/**
	 * Compare two objects for equality.
	 * @param {object} o1 The first object.
	 * @param {object} o2 The second object.
	 * @returns {boolean} True if the objects are equal.
	 * @example
	 * // 比较两个对象是否相等
	 * const obj1 = { a: 1, b: 2 };
	 * const obj2 = { a: 1, b: 2 };
	 * const obj3 = { a: 1, b: 3 };
	 * THING.Utils.equalsObject(obj1, obj2); // true
	 * THING.Utils.equalsObject(obj1, obj3); // false
	 */
	static equalsObject(o1, o2) {
		for (var key in o1) {
			if (o1[key] != o2[key]) {
				return false;
			}
		}

		return true;
	}

	/**
	 * Clear all properties from an object.
	 * @param {object} obj The object to clear.
	 * @example
	 * // 清除对象中的所有属性
	 * const obj = { a: 1, b: 2, c: 3 };
	 * THING.Utils.clearObject(obj);
	 * console.log(obj); // {}
	 */
	static clearObject(obj) {
		for (var key in obj) {
			delete obj[key];
		}
	}

	/**
	 * 克隆JS对象。
	 * @param {object} obj 要克隆的对象。
	 * @param {boolean} [shallow=true] 是否只使用引用。
	 * @param {Function} [filterFunc=null] 过滤属性的函数。
	 * @param {Function} [cloneFunc=null] 克隆属性的函数。
	 * @returns {object} 克隆后的对象。
	 * @example
	 * // 克隆一个对象
	 * const original = { name: 'object', values: [1, 2, 3], nested: { key: 'value' } };
	 *
	 * // 浅克隆 - 嵌套对象和数组是引用
	 * const shallowClone = THING.Utils.cloneObject(original);
	 * shallowClone.nested.key = 'changed';
	 * console.log(original.nested.key); // 'changed', 因为嵌套对象是引用
	 *
	 * // 深克隆 - 嵌套对象和数组也被克隆
	 * const deepClone = THING.Utils.cloneObject(original, false);
	 * deepClone.nested.key = 'new value';
	 * console.log(original.nested.key); // 'changed', 原始对象不受影响
	 */
	static cloneObject(obj, shallow = true, filterFunc = null, cloneFunc = null) {
		// Thanks for sharing code: http://jsfiddle.net/cattail/NYNT5/
		_references.length = 0;
		var handler = _handlers[classof(obj)];
		return handler ? handler(obj, shallow, filterFunc, cloneFunc) : obj;
	}

	/**
	 * Copy JS object in referenced mode.
	 * @param {object} target The target object.
	 * @param {object} source The source object.
	 * @returns {object} The referenced of target object.
	 * @example
	 * // 将源对象的属性复制到目标对象
	 * const target = { a: 1 };
	 * const source = { b: 2, c: 3 };
	 *
	 * THING.Utils.copyObject(target, source);
	 * console.log(target); // { a: 1, b: 2, c: 3 }
	 *
	 * // 如果源对象和目标对象有相同的属性,源对象的值会覆盖目标对象的值
	 * const target2 = { x: 10, y: 20 };
	 * const source2 = { y: 30, z: 40 };
	 *
	 * THING.Utils.copyObject(target2, source2);
	 * console.log(target2); // { x: 10, y: 30, z: 40 }
	 */
	static copyObject(target, source) {
		if (target === source) {
			return target;
		}

		if (source) {
			Utils.clearObject(target);

			for (var key in source) {
				var value = source[key];

				if (value) {
					if (Utils.isObject(value)) {
						target[key] = {};
						Utils.copyObject(target[key], value);
					}
					else {
						target[key] = value;
					}
				}
				else {
					target[key] = value;
				}
			}
		}

		return target;
	}

	/**
	 * 复制Uint8Array。
	 * @param {Uint8Array} source 源Uint8Array。
	 * @returns {Uint8Array} 复制后的Uint8Array。
	 * @example
	 * // 复制Uint8Array
	 * const source = new Uint8Array([1, 2, 3]);
	 * const copied = THING.Utils.copyUint8Array(source);
	 * console.log(copied); // Uint8Array [1, 2, 3]
	 */
	static copyUint8Array(source) {
		var dst = new ArrayBuffer(source.byteLength);
		return new Uint8Array(dst).set(new Uint8Array(source));
	}

	/**
	 * Merge object.
	 * @param {object} target The target object.
	 * @param {object} source The source object.
	 * @param {boolean} [overwrite=false] True indicates overwrite values.
	 * @returns {object} The merged object.
	 * @example
	 * // 合并两个对象
	 * var obj1 = { 'name': 'JS', 'year': '2018' };
	 * var obj2 = { 'version': 'xxx', 'year': '2019' };
	 *
	 * // 不覆盖已有属性
	 * var merged1 = THING.Utils.mergeObject(obj1, obj2);
	 * console.log(merged1); // {"name":"JS","year":"2018","version":"xxx"}
	 *
	 * // 覆盖已有属性
	 * var merged2 = THING.Utils.mergeObject(obj1, obj2, true);
	 * console.log(merged2); // {"name":"JS","year":"2019","version":"xxx"}
	 */
	static mergeObject(target, source, overwrite) {
		if (!source) {
			return Utils.cloneObject(target);
		}

		if (!Utils.isObject(source) || !Utils.isObject(target)) {
			return overwrite ? Utils.cloneObject(source) : target;
		}

		for (var key in source) {
			var targetProp = target[key];
			var sourceProp = source[key];

			// Continue to merge sub objects
			if (Utils.isObject(sourceProp) && Utils.isObject(targetProp)) {
				Utils.mergeObject(targetProp, sourceProp, overwrite);
			}
			// Overwrite attribute of target when it's not exist
			else if (overwrite || !(key in target)) {
				target[key] = Utils.cloneObject(source[key], true);
			}
		}

		return target;
	}

	/**
	 * 将源对象的值赋值给目标对象。
	 * @param {object} target 目标对象。
	 * @param {object} source 源对象。
	 * @example
	 * // 将源对象的值赋值给目标对象
	 * const target = { a: 1 };
	 * const source = { b: 2, c: 3 };
	 *
	 * THING.Utils.assignValues(target, source);
	 * console.log(target); // { a: 1, b: 2, c: 3 }
	 */
	static assignValues(target, source) {
		if (Utils.isArray(source)) {
			source.forEach(src => {
				Utils.assignValues(target, src);
			});
		}
		else {
			for (var key in source) {
				if (target[key] !== undefined) {
					continue;
				}

				target[key] = source[key];
			}
		}
	}

	/**
	 * 将颜色数组转换为十六进制数字。
	 * @param {Array<number>} value 颜色数组 [r, g, b],范围为 [0, 1]。
	 * @returns {number} 十六进制数字。
	 * @example
	 * let color = [1, 0, 0]; // 红色
	 * let hex = THING.Utils.colorToHex(color);
	 * // @expect(hex === 0xFF0000);
	 * @public
	 */
	static colorToHex(value) {
		return (value[0] * 255) << 16 ^ (value[1] * 255) << 8 ^ (value[2] * 255) << 0;
	}

	/**
	 * 将颜色数组转换为十六进制字符串。
	 * @param {Array<number>} value 颜色数组 [r, g, b],范围为 [0, 1]。
	 * @returns {string} 十六进制字符串,如 '#FF0000'。
	 * @example
	 * let color = [1, 0, 0]; // 红色
	 * let hexString = THING.Utils.colorToHexString(color);
	 * // @expect(hexString === '#ff0000');
	 * @public
	 */
	static colorToHexString(value) {
		if (!value) {
			return null;
		}

		return '#' + ('000000' + Utils.colorToHex(value).toString(16)).slice(-6);
	}

	/**
	 * 检查两个颜色在 epsilon 范围内是否相等。
	 * @param {Array<number>} c1 第一个颜色数组 [r, g, b],范围为 [0, 1]。
	 * @param {Array<number>} c2 第二个颜色数组 [r, g, b],范围为 [0, 1]。
	 * @param {number} [epsilon] epsilon 值。
	 * @returns {boolean} 如果颜色相等则返回 true。
	 * @example
	 * let color1 = [1, 0, 0];
	 * let color2 = [1, 0, 0];
	 * let equal = THING.Utils.equalsColor(color1, color2);
	 * // @expect(equal === true);
	 * @public
	 */
	static equalsColor(c1, c2, epsilon = 0.0001) {
		if (!Utils.isArray(c1) || !Utils.isArray(c2)) {
			return false;
		}

		if (Math.abs(c1[0] - c2[0]) > epsilon) {
			return false;
		}

		if (Math.abs(c1[1] - c2[1]) > epsilon) {
			return false;
		}

		if (Math.abs(c1[2] - c2[2]) > epsilon) {
			return false;
		}

		return true;
	}

	/**
	 * 检查值是否为有效的颜色格式。
	 * @param {*} value 要检查的值。
	 * @returns {boolean} 如果值是有效的颜色格式则返回 true。
	 * @example
	 * // 数组格式
	 * THING.Utils.isColorString([1, 0, 0]); // true
	 * // 十六进制数字
	 * THING.Utils.isColorString(0xFF0000); // true
	 * // 十六进制字符串
	 * THING.Utils.isColorString('#FF0000'); // true
	 * // RGB 字符串
	 * THING.Utils.isColorString('rgb(255,0,0)'); // true
	 * // RGBA 字符串
	 * THING.Utils.isColorString('rgba(255,0,0,1)'); // true
	 * // 颜色关键字
	 * THING.Utils.isColorString('red'); // true
	 * @public
	 */
	static isColorString(value) {
		// [0~1, 0~1, 0~1]
		if (Utils.isArray(value)) {
			return true;
		}

		// 0x000000~0xFFFFFF
		if (Utils.isNumber(value)) {
			return true;
		}

		// 字符串格式
		if (Utils.isString(value)) {
			// '#FFFFFF'
			if (value[0] == '#') {
				return true;
			}
			// rgb(r, g, b)
			else if (value.startsWith('rgb(')) {
				return true;
			}
			// rgba(r, g, b, a)
			else if (value.startsWith('rgba(')) {
				return true;
			}
		}

		if (_colorKeywords[value.toLowerCase()] !== undefined) {
			return true;
		}

		return false;
	}

	/**
	 * Convert HSL color values to RGB color values
	 * @param {number} h Hue value (0-360)
	 * @param {number} s Saturation value (0-100)
	 * @param {number} l Lightness value (0-100)
	 * @returns {Array} RGB color values array [r, g, b] in range [0-1]
	 * @example
	 * let rgb = THING.Utils._hslToRgb(120, 100, 50);
	 * console.log(rgb); // [0, 1, 0]
	 * @private
	 */
	static _hslToRgb(h, s, l) {
		s /= 100;
		l /= 100;
		const k = n => (n + h / 30) % 12;
		const a = s * Math.min(l, 1 - l);
		const f = n => l - a * Math.max(-1, Math.min(k(n) - 3, Math.min(9 - k(n), 1)));
		return [f(0), f(8), f(4)];
	}

	/**
	 * 解析颜色值并返回 RGBA 数组。
	 * @param {Array | number | string} value 颜色值,可以是数组、十六进制数字或字符串格式。
	 * @param {Array} defaultValue 默认返回值,当解析失败时返回。
	 * @param {Array} [target] 目标数组,用于存储解析后的颜色值。
	 * @returns {Array} 返回 RGBA 数组,范围为 [0~1],如果解析失败则返回 defaultValue。
	 * @public
	 * @example
	 * // 解析颜色值
	 * let color = THING.Utils.parseColor('#FF0000');
	 * // @expect(color === [1, 0, 0]);
	 * // 解析颜色值
	 * let color = THING.Utils.parseColor('rgb(255,0,0)');
	 * // @expect(color === [1, 0, 0]);
	 * // 解析颜色值
	 * let color = THING.Utils.parseColor('hsl(120, 100%, 50%)');
	 * // @expect(color === [0, 1, 0]);
	 */
	static parseColor(value, defaultValue, target) {
		target = target || [];

		// [0~1, 0~1, 0~1, 0~1(optional)]
		if (Utils.isArray(value)) {
			target[0] = value[0];
			target[1] = value[1];
			target[2] = value[2];

			if (value[3] !== undefined) {
				target[3] = value[3];
			}

			return target;
		}
		// 0x000000~0xFFFFFF
		else if (Utils.isNumber(value)) {
			return _parseColorFromHex(value, target);
		}
		// String: '#FFFFFF'/'rgb(r, g, b)'/'hsl(h, s%, l%)'
		else if (Utils.isString(value)) {
			// '#FFFFFF'
			if (value[0] == '#') {
				return _parseColorFromHex(parseInt(value.substr(1), 16), target);
			}
			// rgb(r, g, b)
			else if (value.startsWith('rgb(')) {
				var colors = value.substring(4).split(',');
				if (colors.length === 3) {
					let r = parseInt(colors[0]);
					let g = parseInt(colors[1]);
					let b = parseInt(colors[2]._trimRight(' )'));

					target[0] = r / 255;
					target[1] = g / 255;
					target[2] = b / 255;

					return target;
				}
			}
			// rgba(r, g, b, a)
			else if (value.startsWith('rgba(')) {
				var colors = value.substring(5).split(',');
				if (colors.length === 4) {
					var r = parseInt(colors[0]);
					var g = parseInt(colors[1]);
					var b = parseInt(colors[2]);
					// Alpha range is [0, 1]
					var a = parseFloat(colors[3]._trimRight(' )'));

					target[0] = r / 255;
					target[1] = g / 255;
					target[2] = b / 255;
					target[3] = a;

					return target;
				}
			}
			// hsl(h, s%, l%)
			else if (value.startsWith('hsl(')) {
				var colors = value.substring(4).split(',');
				if (colors.length === 3) {
					let h = parseFloat(colors[0]);
					let s = parseFloat(colors[1]);
					let l = parseFloat(colors[2]);

					// Remove '%' and ')' from s and l values
					s = parseFloat(s.toString().replace('%', ''));
					l = parseFloat(l.toString().replace('%', '').replace(')', ''));

					const [r, g, b] = Utils._hslToRgb(h, s, l);
					target[0] = r;
					target[1] = g;
					target[2] = b;

					return target;
				}
			}
			// Other string, try to convert it
			else {
				if (isNaN(value)) {
					var hexValue = _colorKeywords[value.toLowerCase()];
					if (hexValue !== undefined) {
						return _parseColorFromHex(hexValue, target);
					}
				}
				else {
					return _parseColorFromHex(parseInt(value), target);
				}
			}
		}

		return defaultValue;
	}

	/**
	 * 从多种类型中解析值。
	 * @param {object} types 类型映射对象。
	 * @param {any} value 要解析的值。
	 * @param {any} defaultValue 默认返回值,当解析失败时返回。
	 * @returns {any} 解析后的值。
	 * @example
	 * // 解析值
	 * const types = { 'red': 1, 'blue': 2, 'green': 3 };
	 * const value = 'blue';
	 * const result = THING.Utils.parseValueFromTypes(types, value);
	 * console.log(result); // 2
	 */
	static parseValueFromTypes(types, value, defaultValue) {
		var keys = Object.keys(types);
		for (var i = 0; i < keys.length; i++) {
			var key = keys[i];
			if (types[key] == value) {
				return key;
			}
		}

		if (defaultValue !== undefined) {
			return defaultValue;
		}

		return value;
	}

	/**
	 * 将颜色值转换为十六进制字符串。
	 * @param {Array | number | string} value 颜色值,可以是数组、十六进制数字或字符串格式。
	 * @param {Array} defaultValue 默认返回值,当解析失败时返回。
	 * @returns {string} 十六进制字符串。
	 * @example
	 * // 将颜色值转换为十六进制字符串
	 * const value = [1, 0, 0];
	 * const result = THING.Utils.toColorHexString(value);
	 * console.log(result); // '#FF0000'
	 */
	static toColorHexString(value, defaultValue) {
		var color = Utils.parseColor(value, defaultValue);

		var r = Number(Math.round(color[0] * 255)).toString(16).padStart(2, '0');
		var g = Number(Math.round(color[1] * 255)).toString(16).padStart(2, '0');
		var b = Number(Math.round(color[2] * 255)).toString(16).padStart(2, '0');

		return '#' + r + g + b;
	}

	/**
	 * 检查对象是否具有指定属性。
	 * @param {object} object 要检查的对象。
	 * @param {string} key 要检查的属性名。
	 * @param {string} [separator='/'] 属性分隔符。
	 * @returns {boolean} 如果对象具有指定属性,则返回 true,否则返回 false。
	 * @example
	 * // 检查对象是否具有指定属性
	 * const obj = { a: { b: { c: 'value' } } };
	 * const result = THING.Utils.hasAttribute(obj, 'a/b/c');
	 * console.log(result); // true
	 */
	static hasAttribute(object, key, separator = '/') {
		return Utils.getAttribute(object, key, separator) !== undefined;
	}

	/**
	 * 获取对象的指定属性。
	 * @param {object} object 要获取属性的对象。
	 * @param {string} key 要获取的属性名。
	 * @param {string} [separator='/'] 属性分隔符。
	 * @returns {any} 获取的属性值。
	 * @example
	 * // 获取对象的指定属性
	 * const obj = { a: { b: { c: 'value' } } };
	 * const result = THING.Utils.getAttribute(obj, 'a/b/c');
	 */
	static getAttribute(object, key, separator = '/') {
		if (!object || !key) {
			return undefined;
		}
		let keys = [];

		if (key === _lastAttributeKeyCache.key) {
			keys = _lastAttributeKeyCache.keys;
		}
		else {
			keys = key.split(separator);
			_lastAttributeKeyCache.key = key;
			_lastAttributeKeyCache.keys = keys;
		}

		// Try to find attribute from object
		if (keys.length) {
			for (let i = 0, l = keys.length; i < l; i++) {
				let value = object[keys[i]];
				if (value === undefined) {
					return undefined;
				}

				object = value;
			}
		}
		return object;
	}

	/**
	 * 设置对象的指定属性。
	 * @param {object} object 要设置属性的对象。
	 * @param {string} key 要设置的属性名。
	 * @param {any} value 要设置的属性值。
	 * @param {string} [separator='/'] 属性分隔符。
	 * @returns {object} 设置后的对象。
	 * @example
	 * // 设置对象的指定属性
	 * const obj = { a: { b: { c: 'value' } } };
	 * const result = THING.Utils.setAttribute(obj, 'a/b/c', 'newValue');
	 * console.log(result); // { a: { b: { c: 'newValue' } } }
	 */
	static setAttribute(object, key, value, separator = '/') {
		if (!object || !key) {
			return null;
		}

		var keys = key.split(separator);
		for (var i = 0; i < keys.length; i++) {
			var key = keys[i];
			if (i == keys.length - 1) {
				object[key] = value;
				break;
			}

			if (Utils.isNull(object[key])) {
				object[key] = {};
			}

			object = object[key];
		}

		return value;
	}

	/**
	 * 设置对象的多个属性。
	 * @param {object} object 要设置属性的对象。
	 * @param {object} attributes 要设置的属性对象。
	 * @param {boolean} [overwrite=true] 是否覆盖已存在的属性。
	 * @returns {object} 设置前的属性对象。
	 * @example
	 * // 设置对象的多个属性
	 * const obj = { a: 1, b: 2 };
	 * const attributes = { b: 3, c: 4 };
	 * const result = THING.Utils.setAttributes(obj, attributes);
	 * console.log(result); // { a: 1, b: 3, c: 4 }
	 */
	static setAttributes(object, attributes, overwrite = true) {
		var prevAttributes = {};
		for (var key in attributes) {
			var objectValue = object[key];
			if (objectValue !== undefined) {
				if (!overwrite) {
					continue;
				}

				prevAttributes[key] = objectValue;
			}

			object[key] = attributes[key];
		}

		return prevAttributes;
	}

	/**
	 * 设置对象的指定属性,如果属性不存在则不设置。
	 * @param {object} target 目标对象。
	 * @param {string} targetKey 目标属性名。
	 * @param {object} source 源对象。
	 * @param {Function} [compareFunc] 比较函数。
	 * @param {string} [sourceKey] 源属性名。
	 * @returns {void}
	 * @example
	 * // 设置对象的指定属性,如果属性不存在则不设置。
	 * const target = { a: 1 };
	 * const source = { b: 2 };
	 * THING.Utils.setAttributeIfExist(target, 'a', source);
	 * console.log(target); // { a: 1 }
	 */
	static setAttributeIfExist(target, targetKey, source, compareFunc = (v) => { return v !== undefined; }, sourceKey = targetKey) {
		var sourceValue = source[sourceKey];
		if (sourceValue === undefined) {
			return;
		}

		if (!compareFunc(sourceValue)) {
			return;
		}

		target[targetKey] = sourceValue;
	}

	/**
	 * 交换对象的指定属性。
	 * @param {object} object 要交换属性的对象。
	 * @param {string} key1 要交换的第一个属性名。
	 * @param {string} key2 要交换的第二个属性名。
	 * @returns {object} 交换后的对象。
	 * @example
	 * // 交换对象的指定属性
	 * const obj = { a: 1, b: 2 };
	 * const result = THING.Utils.swapObjectAttribute(obj, 'a', 'b');
	 * console.log(result); // { a: 2, b: 1 }
	 */
	static swapObjectAttribute(object, key1, key2) {
		var v1 = object[key1];
		object[key1] = object[key2];
		object[key2] = v1;

		return object;
	}

	/**
	 * 二分查找。
	 * @param {Array} array 要查找的数组。
	 * @param {any} target 要查找的值。
	 * @returns {number} 查找的索引。
	 * @example
	 * // 二分查找
	 * const array = [1, 2, 3, 4, 5];
	 * const result = THING.Utils.binarySearch(array, 3);
	 * console.log(result); // 2
	 */
	static binarySearch(array, target) {
		var l = 0, r = array.length - 1;

		if (Utils.isFunction(target)) {
			while (l <= r) {
				var mid = Math.floor((l + r) / 2);
				if (target(array[mid]) === 0) {
					return mid;
				}
				else if (target(array[mid]) > 0) {
					r = mid - 1;
				}
				else {
					l = mid + 1;
				}
			}
		}
		else {
			while (l <= r) {
				var mid = Math.floor((l + r) / 2);
				if (target === array[mid]) {
					return mid;
				}
				else if (target < array[mid]) {
					r = mid - 1;
				}
				else {
					l = mid + 1;
				}
			}
		}

		return -1;
	}

	/**
	 * 二分查找边界。
	 * @param {Array} array 要查找的数组。
	 * @param {any} target 要查找的值。
	 * @param {Function} compareFunc 比较函数。
	 * @returns {number} 查找的索引。
	 * @example
	 * // 二分查找边界
	 * const array = [1, 2, 3, 4, 5];
	 * const result = THING.Utils.binaryBound(array, 3);
	 * console.log(result); // 2
	 */
	static binaryBound(array, target, compareFunc) {
		if (!array.length) {
			return 0;
		}

		var i = 0, j = array.length - 1;

		if (compareFunc) {
			while (i < j - 1) {
				var m = Math.floor((i + j) / 2);

				var ret = compareFunc(array[m], target);
				if (ret == 0) { return m; }

				if (ret < 0) { i = m; }
				else { j = m; }
			}

			if (compareFunc(array[i], target) > 0) { return i; }
			else if (compareFunc(array[j], target) > 0) { return j; }
		}
		else {
			while (i < j - 1) {
				var m = Math.floor((i + j) / 2);

				if (array[m] === target) {
					return m;
				}
				if (array[m] < target) {
					i = m;
				}
				else {
					j = m;
				}
			}

			if (array[i] > target) { return i; }
			else if (array[j] > target) { return j; }
		}

		return -1;
	}

	/**
	 * 二分查找边界插入。
	 * @param {Array} array 要插入的数组。
	 * @param {any} target 要插入的值。
	 * @param {Function} compareFunc 比较函数。
	 * @returns {Array} 插入后的数组。
	 * @example
	 * // 二分查找边界插入
	 * const array = [1, 2, 3, 4, 5];
	 * const result = THING.Utils.insertBinaryBound(array, 3);
	 * console.log(result); // [1, 2, 3, 3, 4, 5]
	 */
	static insertBinaryBound(array, target, compareFunc) {
		var index = Utils.binaryBound(array, target, compareFunc);
		if (index === -1) {
			array.push(target);
		}
		else {
			array.splice(index, 0, target);
		}

		return array;
	}

	// Thanks for sharing code: https://blog.csdn.net/hupian1989/article/details/80920324
	/**
	 * 节流。
	 * @param {Function} fn 要节流的函数。
	 * @param {number} wait 节流时间。
	 * @returns {Function} 节流后的函数。
	 * @example
	 * // 节流
	 * const throttledFn = THING.Utils.throttling(function() {
	 *   console.log('节流执行');
	 * }, 1000);
	 * throttledFn(); // 每1秒执行一次
	 */
	static throttling(fn, wait) {
		let timer;
		let context, args;

		let run = () => {
			let waitTime = Utils.isFunction(wait) ? wait() : wait;

			timer = setTimeout(() => {
				fn.apply(context, args);
				clearTimeout(timer);
				timer = null;
			}, waitTime);
		}

		return function () {
			let waitTime = Utils.isFunction(wait) ? wait() : wait;
			if (!waitTime) {
				fn.apply(context, args);
				return;
			}

			context = this;
			args = arguments;
			if (!timer) {
				run();
			}
		}
	}

	/**
	 * 获取字符串的MD5码。
	 * @param {string} string 要获取MD5码的字符串。
	 * @returns {string} MD5码。
	 * @example
	 * // 获取字符串的MD5码
	 * const md5Code = THING.Utils.getMD5CodeFromString('hello');
	 * console.log(md5Code); // '5d41402abc4b2a76b9719d911017c592'
	 */
	static getMD5CodeFromString(string) {
		return SparkMD5.hash(string);
	}

	/**
	 * 获取缓冲区的MD5码。
	 * @param {ArrayBuffer} buffer 要获取MD5码的缓冲区。
	 * @param {Function} progress 进度回调函数。
	 * @returns {Promise} 获取MD5码的Promise。
	 * @example
	 * // 获取缓冲区的MD5码
	 * const buffer = new ArrayBuffer(1024);
	 * const md5Code = await THING.Utils.getMD5CodeFromBuffer(buffer);
	 * console.log(md5Code); // '5d41402abc4b2a76b9719d911017c592'
	 */
	static getMD5CodeFromBuffer(buffer, progress) {
		return new Promise((resolve, reject) => {
			const spark = new SparkMD5.ArrayBuffer();
			_readChunked(buffer,
				// Reading
				(chunk, offs, total) => {
					spark.append(chunk);
					if (progress) {
						progress(offs / total);
					}
				},
				// Error
				err => {
					if (err) {
						reject(err);
					}
					else {
						// TODO: Handle errors
						var hash = spark.end();
						resolve(hash);
					}
				}
			);
		});
	}

	/**
	 * 应用新的构造函数。
	 * @param {Function} ctor 要应用的构造函数。
	 * @param {Array} args 要传递的参数。
	 * @returns {object} 应用后的对象。
	 * @example
	 * // 应用新的构造函数
	 * const newObj = THING.Utils.applyNew(Object, ['foo', 'bar']);
	 * console.log(newObj); // { foo: 'foo', bar: 'bar' }
	 */
	static applyNew(ctor, args) {
		if (!ctor) {
			return null;
		}

		var applyArgs = ([{}]).concat(args || []);
		var f = Function.prototype.bind.apply(ctor, applyArgs);

		return new f();
	}

	/**
	 * 将数字转换为字符串。
	 * @param {number} i 要转换的数字。
	 * @returns {string} 转换后的字符串。
	 * @example
	 * // 将数字转换为字符串
	 * const str = THING.Utils.itoa(123);
	 * console.log(str); // '123'
	 */
	static itoa(i) {
		return String.fromCharCode(i);
	}

	/**
	 * 将字符串转换为数字。
	 * @param {string} a 要转换的字符串。
	 * @returns {number} 转换后的数字。
	 * @example
	 * // 将字符串转换为数字
	 * const num = THING.Utils.atoi('123');
	 * console.log(num); // 123
	 */
	static atoi(a) {
		return a.charCodeAt();
	}

	/**
	 * 将Base64字符串转换为Blob。
	 * @param {string} base64Str 要转换的Base64字符串。
	 * @returns {Blob} 转换后的Blob。
	 * @example
	 * // 将Base64字符串转换为Blob
	 * const blob = THING.Utils.base64ToBlob('base64Str');
	 * console.log(blob); // Blob { size: 1024, type: 'image/png' }
	 */
	static base64ToBlob(base64Str) {
		var bString = atob(base64Str);
		var len = bString.length;
		var arr = new Uint8Array(len);
		while (len--) {
			arr[len] = bString.charCodeAt(len);
		}

		return arr;
	}

	/**
	 * 将Blob转换为Base64字符串。
	 * @param {Blob} bytes 要转换的Blob。
	 * @returns {string} 转换后的Base64字符串。
	 * @example
	 * // 将Blob转换为Base64字符串
	 * const base64Str = THING.Utils.blobToBase64(blob);
	 * console.log(base64Str); // 'base64Str'
	 */
	static blobToBase64(bytes) {
		var bString = "";
		for (var i = 0, len = bytes.length; i < len; ++i) {
			bString += String.fromCharCode(bytes[i]);
		}

		return btoa(bString);
	}

	/**
	 * 将缓冲区转换为字符串。
	 * @param {ArrayBuffer} buffer 要转换的缓冲区。
	 * @returns {string} 转换后的字符串。
	 * @example
	 * // 将缓冲区转换为字符串
	 * const str = THING.Utils.arrayBufferToString(buffer);
	 * console.log(str); // 'base64Str'
	 */
	static arrayBufferToString(buffer) {
		var string = String.fromCharCode.apply(null, new Uint8Array(buffer));

		return decodeURIComponent(escape(string));
	}

	/**
	 * 将Uint8Array转换为字符串。
	 * @param {Uint8Array} buffer 要转换的Uint8Array。
	 * @returns {string} 转换后的字符串。
	 * @example
	 * // 将Uint8Array转换为字符串
	 * const str = THING.Utils.uint8ArrayToString(new Uint8Array([1, 2, 3]));
	 * console.log(str); // '123'
	 */
	static uint8ArrayToString(buffer) {
		const CHUNK_SIZE = 128 * 1024; // Chunk size for processing
		const decoder = new TextDecoder();
		let offset = 0;
		let result = '';

		while (offset < buffer.length) {
			const chunk = buffer.subarray(offset, offset + CHUNK_SIZE);
			const str = decoder.decode(chunk, { stream: true });
			result += str;
			offset += CHUNK_SIZE;
		}

		// Decode any remaining bytes
		result += decoder.decode();

		return result;
	}

	/**
	 * 将字符串转换为缓冲区。
	 * @param {string} string 要转换的字符串。
	 * @returns {ArrayBuffer} 转换后的缓冲区。
	 * @example
	 * // 将字符串转换为缓冲区
	 * const buffer = THING.Utils.stringToArrayBuffer('123');
	 * console.log(buffer); // ArrayBuffer { byteLength: 3 }
	 */
	static stringToArrayBuffer(string) {
		var buf = new ArrayBuffer(string.length);
		var bufView = new Uint8Array(buf);
		for (var i = 0, strLen = string.length; i < strLen; i++) {
			bufView[i] = string.charCodeAt(i);
		}

		return buf;
	}

	/**
	 * 将缓冲区转换为UTF-16字符串。
	 * @param {ArrayBuffer} buffer 要转换的缓冲区。
	 * @returns {string} 转换后的UTF-16字符串。
	 * @example
	 * // 将缓冲区转换为UTF-16字符串
	 * const str = THING.Utils.arrayBufferToUtf16(new ArrayBuffer(3));
	 * console.log(str); // '123'
	 */
	static arrayBufferToUtf16(buffer) {
		return String.fromCharCode.apply(null, new Uint16Array(buffer));
	}

	/**
	 * 将UTF-16字符串转换为缓冲区。
	 * @param {string} string 要转换的UTF-16字符串。
	 * @returns {ArrayBuffer} 转换后的缓冲区。
	 * @example
	 * // 将UTF-16字符串转换为缓冲区
	 * const buffer = THING.Utils.utf16ToArrayBuffer('123');
	 * console.log(buffer); // ArrayBuffer { byteLength: 6 }
	 */
	static utf16ToArrayBuffer(string) {
		var buf = new ArrayBuffer(string.length * 2);
		var bufView = new Uint16Array(buf);
		for (var i = 0, strLen = string.length; i < strLen; i++) {
			bufView[i] = string.charCodeAt(i);
		}

		return buf;
	}

	/**
	 * 将缓冲区转换为Blob。
	 * @param {ArrayBuffer} buffer 要转换的缓冲区。
	 * @param {object} options 选项。
	 * @returns {Blob} 转换后的Blob。
	 * @example
	 * // 将缓冲区转换为Blob
	 * const blob = THING.Utils.arrayBufferToBlob(new ArrayBuffer(3));
	 * console.log(blob); // Blob { size: 3, type: 'application/octet-stream' }
	 */
	static arrayBufferToBlob(buffer, options) {
		return new Blob([new Uint8Array(buffer, 0, buffer.byteLength)], options);
	}

	/**
	 * 将Blob转换为缓冲区。
	 * @param {Blob} blob 要转换的Blob。
	 * @returns {Promise<ArrayBuffer>} 转换后的缓冲区。
	 * @example
	 * // 将Blob转换为缓冲区
	 * const buffer = await THING.Utils.blobToArrayBuffer(blob);
	 * console.log(buffer); // ArrayBuffer { byteLength: 3 }
	 */
	static blobToArrayBuffer(blob) {
		return new Response(blob).arrayBuffer();
	}

	/**
	 * 将缓冲区转换为Blob。
	 * @param {ArrayBuffer} buffer 要转换的缓冲区。
	 * @param {object} options 选项。
	 * @returns {Blob} 转换后的Blob。
	 * @example
	 * // 将缓冲区转换为Blob
	 * const blob = THING.Utils.bufferToBlob(new ArrayBuffer(3));
	 * console.log(blob); // Blob { size: 3, type: 'application/octet-stream' }
	 */
	static bufferToBlob(buffer, options) {
		return new Blob([buffer], options);
	}

	/**
	 * 将Blob转换为缓冲区。
	 * @param {Blob} blob 要转换的Blob。
	 * @returns {Promise<Uint8Array>} 转换后的缓冲区。
	 * @example
	 * // 将Blob转换为缓冲区
	 * const buffer = await THING.Utils.blobToBuffer(blob);
	 * console.log(buffer); // Uint8Array { length: 3 }
	 */
	static blobToBuffer(blob) {
		return new Promise((resolve, reject) => {
			new Response(blob).arrayBuffer().then((buffer) => {
				resolve(new Uint8Array(buffer));
			});
		})
	}

	/**
	 * 将字符串转换为缓冲区。
	 * @param {string} string 要转换的字符串。
	 * @returns {Uint8Array} 转换后的缓冲区。
	 * @example
	 * // 将字符串转换为缓冲区
	 * const buffer = THING.Utils.stringToBuffer('123');
	 * console.log(buffer); // Uint8Array { length: 3 }
	 */
	static stringToBuffer(string) {
		var result;

		if ('undefined' === typeof Uint8Array) {
			result = utf8ToBytes(string);
		}
		else {
			result = new Uint8Array(utf8ToBytes(string));
		}

		return result;
	}

	/**
	 * 将缓冲区转换为字符串。
	 * @param {Uint8Array} buffer 要转换的缓冲区。
	 * @returns {string} 转换后的字符串。
	 * @example
	 * // 将缓冲区转换为字符串
	 * const str = THING.Utils.bufferToString(new Uint8Array([1, 2, 3]));
	 * console.log(str); // '123'
	 */
	static bufferToString(buffer) {
		return Utils.uint8ArrayToString(buffer);
	}

	/**
	 * 同步选项。
	 * @param {object} target 目标对象。
	 * @param {object} options 选项。
	 * @param {object} values 值。
	 * @returns {boolean} 是否同步成功。
	 * @example
	 * // 同步选项
	 * const target = {};
	 * const options = { a: 1, b: 2 };
	 * const values = { a: 3, c: 4 };
	 * const result = THING.Utils.syncOptions(target, options, values);
	 */
	static syncOptions(target, options, values = {}) {
		if (!options) {
			return false;
		}

		for (var key in values) {
			var value = Utils.parseValue(options[key], values[key]);
			if (Utils.isNull(value)) {
				continue;
			}

			target[key] = value;
		}

		return true;
	}

	/**
	 * 断点。
	 * @example
	 * // 断点
	 * THING.Utils._break();
	 */
	static _break() {
		_eval('debugger')
	}

	/**
	 * 执行脚本。
	 * @param {string} script 要执行的脚本。
	 * @example
	 * // 执行脚本
	 * THING.Utils.eval('console.log("Hello, world!");');
	 */
	static eval(script) {
		_eval(script);
	}

	/**
	 * 格式化字符串。
	 * @param {string} string 要格式化的字符串。
	 * @param {string} format 格式。
	 * @returns {string} 格式化后的字符串。
	 * @example
	 * // 格式化字符串
	 * const result = THING.Utils.scanf('Hello, world!', '%s');
	 * console.log(result); // 'Hello, world!'
	 */
	static scanf(string, format) {
		return sscanf(string, format);
	}

	/**
	 * 获取宏。
	 * @returns {Array<object>} 宏。
	 * @example
	 * // 获取宏
	 * const macros = THING.Utils.getMacros();
	 * console.log(macros); // [{ name: 'macro1', value: 'value1' }, { name: 'macro2', value: 'value2' }]
	 */
	static getMacros() {
		return _macros;
	}

	/**
	 * 添加工厂。
	 * @param {object} factory 工厂。
	 * @param {string} name 唯一名称,可以稍后通过名称替换工厂。
	 * @param {number} priority 优先级,从高到低创建对象。
	 * @example
	 * // 创建一个简单的工厂对象
	 * const myFactory = {
	 *   createObject: function(type, options) {
	 *     if (type === 'button') {
	 *       return new Button(options);
	 *     }
	 *     return null;
	 *   }
	 * };
	 *
	 * // 添加工厂,设置名称和优先级
	 * THING.Utils.addFactory(myFactory, 'buttonFactory', 1);
	 *
	 * // 添加另一个低优先级的工厂
	 * const defaultFactory = {
	 *   createObject: function(type, options) {
	 *     return new DefaultObject(options);
	 *   }
	 * };
	 * THING.Utils.addFactory(defaultFactory, 'defaultFactory', 0);
	 */
	static addFactory(factory, name = '', priority = 0) {
		if (!factory) {
			return;
		}

		_factories.push({ factory, name, priority, index: _factories.length });
		_factories.sort((a, b) => {
			if (a.priority != b.priority) {
				return a.priority > b.priority;
			}

			return a.index > b.index;
		});
	}

	/**
	 * Add factories.
	 * @param {Array<object>} factories The factories.
	 * @example
	 * // 创建多个工厂对象
	 * const factories = [
	 *   {
	 *     createObject: function(type, options) {
	 *       if (type === 'button') {
	 *         return new Button(options);
	 *       }
	 *       return null;
	 *     }
	 *   },
	 *   {
	 *     createObject: function(type, options) {
	 *       if (type === 'input') {
	 *         return new Input(options);
	 *       }
	 *       return null;
	 *     }
	 *   }
	 * ];
	 *
	 * // 批量添加工厂
	 * THING.Utils.addFactories(factories);
	 */
	static addFactories(factories) {
		factories.forEach(factory => {
			Utils.addFactory(factory);
		});
	}

	/**
	 * Get the factories.
	 * @type {Array<object>}
	 * @example
	 * // 获取所有已注册的工厂
	 * const factories = THING.Utils.getFactories();
	 *
	 * // 遍历所有工厂
	 * factories.forEach(factory => {
	 *   console.log('工厂对象:', factory);
	 *   // 可以调用工厂的createObject方法创建对象
	 *   const options = {};
	 *   const obj = factory.createObject('someType', options);
	 * });
	 *
	 * // 检查是否存在特定类型的工厂
	 * const hasButtonFactory = factories.some(factory => {
	 *   return factory.createObject('button') !== null;
	 * });
	 */
	static getFactories() {
		return _factories.map(info => {
			return info.factory;
		});
	}

	/**
	 * 设置工厂。
	 * @param {object} factory 工厂。
	 * @param {string} name 唯一名称。
	 * @returns {boolean} 是否设置成功。
	 * @example
	 * // 创建一个新的工厂对象
	 * const newButtonFactory = {
	 *   createObject: function(type, options) {
	 *     if (type === 'button') {
	 *       return new ModernButton(options); // 返回新版本的按钮
	 *     }
	 *     return null;
	 *   }
	 * };
	 *
	 * // 替换现有的按钮工厂
	 * const success = THING.Utils.setFactory(newButtonFactory, 'buttonFactory');
	 * if (success) {
	 *   console.log('成功更新按钮工厂');
	 * } else {
	 *   console.log('未找到指定名称的工厂');
	 * }
	 */
	static setFactory(factory, name) {
		for (var i = 0; i < _factories.length; i++) {
			if (_factories[i].name == name) {
				_factories[i].factory = factory;
				return true;
			}
		}

		return false;
	}

	/**
	 * 从工厂创建对象。
	 * @param {string} type 类型名称。
	 * @param {object} options 选项。
	 * @returns {object} 对象。
	 * @example
	 * // 创建一个按钮对象
	 * const buttonOptions = {
	 *   text: '点击我',
	 *   style: {
	 *     width: '100px',
	 *     height: '30px'
	 *   }
	 * };
	 * const button = THING.Utils.createObject('button', buttonOptions);
	 *
	 * // 创建一个输入框对象
	 * const inputOptions = {
	 *   placeholder: '请输入内容',
	 *   type: 'text'
	 * };
	 * const input = THING.Utils.createObject('input', inputOptions);
	 *
	 * // 处理创建失败的情况
	 * const unknownObject = THING.Utils.createObject('unknownType');
	 * if (!unknownObject) {
	 *   console.error('创建对象失败:未知类型');
	 * }
	 */
	static createObject(type, options = _defaultOptions) {
		for (var i = 0, l = _factories.length; i < l; i++) {
			var factory = _factories[i].factory;

			var object = factory.createObject(type, options);
			if (object) {
				return object;
			}
		}

		Utils.error(`Create (type: '${type}') object failed`, options);
		return null;
	}

	/**
	 * 获取全局对象。
	 * @returns {object} 全局对象 (window in browser, global in Node.js)
	 * @example
	 * // 获取全局对象
	 * const globalObj = THING.Utils.getGlobal();
	 *
	 * // 在浏览器环境中
	 * console.log(globalObj === window); // true
	 *
	 * // 使用全局对象添加全局变量
	 * globalObj.myGlobalVar = 'Hello World';
	 * console.log(window.myGlobalVar); // 'Hello World'
	 *
	 * // 获取全局函数
	 * console.log(globalObj.setTimeout === window.setTimeout); // true
	 */
	static getGlobal() {
		return _global;
	}

	/**
	 * 注册类到对象。
	 * @param {object} object 对象。
	 * @param {string} clsName 类名。
	 * @param {*} cls 类型。
	 * @param {*} out 附加对象。
	 * @param {boolean} force 是否强制覆盖已存在的类。
	 * @returns {boolean} 是否注册成功。
	 * @example
	 * // 注册类到对象
	 * const obj = {};
	 * const cls = {};
	 * const out = {};
	 * const force = true;
	 * const result = THING.Utils.registerClassToObject(obj, 'clsName', cls, out, force);
	 * console.log(result); // true
	 */
	static registerClassToObject(object, clsName, cls, out, force = true) {
		if (!clsName) {
			return false;
		}

		if (Utils.isClass(cls)) {
			if (force) {
				cls.className = clsName;
				object[clsName] = cls;
			}
			else {
				if (cls.className === undefined) {
					cls.className = clsName;
				}

				if (!object[clsName]) {
					object[clsName] = cls;
				}
			}
		}

		if (out) {
			if (force || !out[clsName]) {
				out[clsName] = cls;
			}
		}

		return true;
	}

	/**
	 * 注册类。
	 * @param {string} clsName 类名。
	 * @param {*} cls 类型。
	 * @param {*} out 附加对象。
	 * @param {boolean} force 是否强制覆盖已存在的类。
	 * @returns {boolean} 是否注册成功。
	 * @example
	 * 	class MyClass {};
	 * 	THING.Utils.registerClass('MyClass', MyClass);
	 * 	let cls = THING.Utils.getRegisteredClass('MyClass');
	 * 	// @expect(cls != null);
	 * @public
	 */
	static registerClass(clsName, cls, out, force = true) {
		return Utils.registerClassToObject(_registeredClasses, clsName, cls, out, force);
	}

	/**
	 * 注册类。
	 * @param {object} classes 类。
	 * @param {*} out 附加对象。
	 * @param {boolean} force 是否强制覆盖已存在的类。
	 * @example
	 * 	class MyClass {};
	 * 	THING.Utils.registerClass('MyClass', MyClass);
	 * 	let cls = THING.Utils.getRegisteredClass('MyClass');
	 * 	// @expect(cls != null);
	 */
	static registerClasses(classes, out, force) {
		for (var key in classes) {
			this.registerClass(key, classes[key], out, force);
		}
	}

	/**
	 * 获取已注册的类。
	 * @param {string} name 类名。
	 * @returns {*} 类。
	 * @example
	 * 	class MyClass {};
	 * 	THING.Utils.registerClass('MyClass', MyClass);
	 * 	let cls = THING.Utils.getRegisteredClass('MyClass');
	 * 	// @expect(cls != null);
	 * 	let cls2 = THING.Utils.getRegisteredClass('MyClass_not');
	 * 	// @expect(cls2 == null);
	 */
	static getRegisteredClass(name) {
		let cls = _registeredClasses[name];
		if (cls) {
			return cls;
		}

		return null;
	}

	/**
	 * 获取已注册的类。
	 * @returns {object} 类。
	 * @example
	 * 	class MyClass {};
	 * 	THING.Utils.registerClass('MyClass', MyClass);
	 * 	let cls = THING.Utils.getRegisteredClass('MyClass');
	 * 	// @expect(cls != null);
	 * 	let cls2 = THING.Utils.getRegisteredClass('MyClass_not');
	 * 	// @expect(cls2 == null);
	 */
	static getRegisteredClasses() {
		return _registeredClasses;
	}

	/**
	 * 移除已注册的类。
	 * @param {string} name 类名。
	 * @example
	 * 	class MyClass {};
	 * 	THING.Utils.registerClass('MyClass', MyClass);
	 * 	THING.Utils.unregisterClass('MyClass');
	 * 	let cls = THING.Utils.getRegisteredClass('MyClass');
	 * 	// @expect(cls == null);
	 */
	static unregisterClass(name) {
		delete _registeredClasses[name];
	}

	/**
	 * 注册组件。
	 * @param {string} clsName 类名。
	 * @param {*} cls 类型。
	 * @param {object} out 附加对象。
	 * @param {boolean} force 是否强制覆盖已存在的组件。
	 * @returns {boolean} 是否注册成功。
	 * @public
	 * @example
	 * // 定义一个自定义组件类
	 * class ColorComponent {
	 *   constructor() {
	 *     this.type = 'color';
	 *     this.value = '#000000';
	 *   }
	 *
	 *   setColor(color) {
	 *     this.value = color;
	 *   }
	 * }
	 *
	 * // 注册组件
	 * THING.Utils.registerComponent('ColorComponent', ColorComponent);
	 *
	 * // 使用注册的组件
	 * const ColorClass = THING.Utils.getRegisteredComponent('ColorComponent');
	 * const colorComp = new ColorClass();
	 * colorComp.setColor('#FF0000');
	 */
	static registerComponent(clsName, cls, out, force = true) {
		var success1 = Utils.registerClass(clsName, cls, out, force);
		var success2 = Utils.registerClassToObject(_registeredComponents, clsName, cls, out, force);
		return success1 && success2;
	}

	/**
	 * 注销组件
	 * @param {string} name 组件名称
	 * @public
	 * @example
	 * // 注册一个测试组件
	 * class TestComponent {
	 *   constructor() {
	 *     this.name = 'TestComponent';
	 *   }
	 * }
	 * THING.Utils.registerComponent('TestComponent', TestComponent);
	 *
	 * // 注销组件
	 * THING.Utils.unregisterComponent('TestComponent');
	 *
	 * // 尝试获取已注销的组件
	 * const comp = THING.Utils.getRegisteredComponent('TestComponent');
	 * console.log(comp); // undefined
	 */
	static unregisterComponent(name) {
		Utils.unregisterClass(name);
		delete _registeredComponents[name];
	}

	/**
	 * 根据名称获取已注册的组件
	 * @param {string} name 组件名称
	 * @returns {object} 组件类
	 * @public
	 * @example
	 * // 注册一个按钮组件
	 * class ButtonComponent {
	 *   constructor() {
	 *     this.type = 'button';
	 *     this.text = '点击我';
	 *   }
	 *
	 *   onClick() {
	 *     console.log('按钮被点击');
	 *   }
	 * }
	 * THING.Utils.registerComponent('ButtonComponent', ButtonComponent);
	 *
	 * // 获取注册的组件
	 * const ButtonClass = THING.Utils.getRegisteredComponent('ButtonComponent');
	 * if (ButtonClass) {
	 *   const button = new ButtonClass();
	 *   button.onClick(); // 输出: 按钮被点击
	 * }
	 */
	static getRegisteredComponent(name) {
		return _registeredComponents[name];
	}

	/**
	 * 获取已注册的组件
	 * @returns {object} 组件。
	 * @public
	 * @example
	 * // 获取所有已注册的组件
	 * const components = THING.Utils.getRegisteredComponents();
	 *
	 * // 遍历所有组件
	 * for (const name in components) {
	 *   console.log('组件名称:', name);
	 *   console.log('组件类:', components[name]);
	 *
	 *   // 创建组件实例
	 *   const instance = new components[name]();
	 * }
	 *
	 * // 检查特定组件是否已注册
	 * if (components['ButtonComponent']) {
	 *   console.log('按钮组件已注册');
	 * }
	 *
	 * // 获取已注册组件的数量
	 * const count = Object.keys(components).length;
	 * console.log('已注册组件数量:', count);
	 */
	static getRegisteredComponents() {
		return _registeredComponents;
	}

	/**
	 * Register a variable.
	 * @param {string} key The variable key.
	 * @param {*} value The variable value.
	 * @example
	 * // 注册全局变量
	 * THING.Utils.registerVariable('config', {
	 *   apiUrl: 'https://api.example.com',
	 *   timeout: 5000
	 * });
	 *
	 * // 注册简单变量
	 * THING.Utils.registerVariable('maxRetries', 3);
	 *
	 * // 注册函数
	 * THING.Utils.registerVariable('formatDate', function(date) {
	 *   return date.toLocaleDateString();
	 * });
	 */
	static registerVariable(key, value) {
		_registeredVariables[key] = value;
	}

	/**
	 * 注销变量。
	 * @param {string} key 变量键。
	 * @example
	 * // 注销变量
	 * THING.Utils.unregisterVariable('config');
	 */
	static unregisterVariable(key) {
		delete _registeredVariables[key];
	}

	/**
	 * Get registered variable by key.
	 * @param {string} key The variable key.
	 * @returns {*} The registered variable value.
	 * @example
	 * // 获取之前注册的变量
	 * const config = THING.Utils.getRegisteredVariable('config');
	 * console.log(config.apiUrl); // 'https://api.example.com'
	 *
	 * const maxRetries = THING.Utils.getRegisteredVariable('maxRetries');
	 * console.log(maxRetries); // 3
	 *
	 * // 使用注册的函数
	 * const formatDate = THING.Utils.getRegisteredVariable('formatDate');
	 * console.log(formatDate(new Date())); // 例如: '2024/3/15'
	 *
	 * // 处理未注册的变量
	 * const notExist = THING.Utils.getRegisteredVariable('notExist');
	 * console.log(notExist); // undefined
	 */
	static getRegisteredVariable(key) {
		return _registeredVariables[key];
	}

	/**
	 * Make a promise cancelable.
	 * @param {Promise} promise The promise to make cancelable.
	 * @returns {object} An object with the promise and a cancel function.
	 * @example
	 * // 创建一个可取消的异步操作
	 * const asyncOperation = new Promise(resolve => {
	 *   setTimeout(() => {
	 *     resolve('操作完成');
	 *   }, 5000);
	 * });
	 *
	 * // 将Promise转换为可取消的
	 * const cancelable = THING.Utils.makeCancelablePromise(asyncOperation);
	 *
	 * // 使用Promise
	 * cancelable.promise
	 *   .then(result => {
	 *     console.log(result); // 如果没有取消,将输出: '操作完成'
	 *   })
	 *   .catch(error => {
	 *     if (error.isCanceled) {
	 *       console.log('操作被取消');
	 *     } else {
	 *       console.error('操作出错:', error);
	 *     }
	 *   });
	 *
	 * // 在某个时刻取消操作
	 * setTimeout(() => {
	 *   cancelable.cancel();
	 * }, 2000);
	 */
	static makeCancelablePromise(promise) {
		return cancelable(promise);
	}

	/**
	 * 判断是否为原生函数。
	 * @param {Function} func 函数。
	 * @returns {boolean} 是否为原生函数。
	 * @example
	 * // 判断是否为原生函数
	 * const isNative = THING.Utils.isNativeFunction(Math.random);
	 * console.log(isNative); // true
	 */
	static isNativeFunction(func) {
		if (!Utils.isFunction(func)) {
			return false;
		}

		return func.toString() === 'function toString() { [native code] }';
	}

	/**
	 * 绑定对象属性。
	 * @param {object} object 对象。
	 * @param {object} accessor 访问器。
	 * @param {string} name 属性名。
	 * @example
	 * // 绑定对象属性
	 * const obj = {};
	 * const accessor = { value: 10 };
	 * THING.Utils.bindObjectProperty(obj, accessor, 'value');
	 * console.log(obj.value); // 10
	 */
	static bindObjectProperty(object, accessor, name) {
		Object.defineProperty(object, name,
			{
				get: function () {
					return accessor[name];
				},
				set: function (value) {
					accessor[name] = value;
				}
			}
		);
	}

	/**
	 * 获取布局进度。
	 * @param {string|number} type 布局类型。
	 * @returns {number} 布局进度。
	 * @example
	 * // 获取布局进度
	 * const progress = THING.Utils.getProgressByLayout('left');
	 * console.log(progress); // 0
	 */
	static getProgressByLayout(type) {
		let progress = 0;
		if (Utils.isString(type)) {
			switch (type) {
				case LayoutType.Left:
				case LayoutType.Bottom:
				case LayoutType.Back:
					progress = 0;
					break;

				case LayoutType.Right:
				case LayoutType.Top:
				case LayoutType.Front:
					progress = 1;
					break;

				case LayoutType.Center:
					progress = 0.5;
					break;

				default:
					break;
			}
		}
		else if (Utils.isNumber(type)) {
			progress = type;
		}

		return progress;
	}

	/**
	 * Merge set.
	 * @param {Set|Array} a The a array or set.
	 * @param {Set|Array} b The b array or set.
	 * @returns {Set} 合并后的集合。
	 * @example
	 * var a = new Set(['one','two']);
	 * var b = new Set(['three','four']);
	 * // Set(4) {'one', 'two', 'three', 'four'}
	 * console.log(THING.Utils.mergeSet(a,b));
	 */
	static mergeSet(a, b) {
		if (!Utils.isSet(a) && !Utils.isArray(a)) {
			a = _emptyArray;
		}
		if (!Utils.isSet(b) && !Utils.isArray(b)) {
			b = _emptyArray;
		}
		const array = [...a, ...b];
		return new Set(array);
	}

	/**
	 * 解析URL。
	 * @param {string} url 要解析的URL。
	 * @returns {string} 解析后的URL。
	 * @example
	 * // 解析URL
	 * const url = THING.Utils.resolveURL('http://example.com/path/to/resource');
	 * console.log(url); // 'http://example.com/path/to/resource'
	 */
	static resolveURL(url) {
		for (let i = 0; i < _urlResolvers.length; i++) {
			const resolver = _urlResolvers[i];
			let result = resolver(url);
			if (result && result !== url) {
				return result;
			}
		}
		return url;
	}

	/**
	 * 添加URL解析器。
	 * @param {Function} resolver 解析器。
	 * @example
	 * // 添加URL解析器
	 * THING.Utils.addURLResolver(function (url) {
	 *   return url;
	 * });
	 */
	static addURLResolver(resolver) {
		_urlResolvers.push(resolver);
	}

	/**
	 * 移除URL解析器。
	 * @param {Function} target 解析器。
	 * @example
	 * // 移除URL解析器
	 * THING.Utils.removeURLResolver(function (url) {
	 *   return url;
	 * });
	 */
	static removeURLResolver(target) {
		for (let i = _urlResolvers.length - 1; i >= 0; i--) {
			const resolver = _urlResolvers[i];
			if (target === resolver) {
				_urlResolvers._removeAt(i);
			}
		}
	}

	/**
	 * 获取工作路径。
	 * @returns {string} 工作路径。
	 * @example
	 * // 获取工作路径
	 * const workPath = THING.Utils.workPath;
	 * console.log(workPath); // 'http://example.com/path/to/resource'
	 */
	static get workPath() {
		return _workPath;
	}
	/**
	 * 设置工作路径。
	 * @param {string} val 工作路径。
	 * @example
	 * // 设置工作路径
	 * THING.Utils.workPath = 'http://example.com/path/to/resource';
	 */
	static set workPath(val) {
		_workPath = val;
	}

	/**
	 * 获取全局环境变量。
	 * @returns {object} 全局环境变量。
	 * @example
	 * // 获取全局环境变量
	 * const globalEnvVars = THING.Utils.getGlobalEnvVars();
	 * console.log(globalEnvVars); // { a: 1, b: 2 }
	 */
	static getGlobalEnvVars() {
		return Utils.cloneObject(_globalEnvVars, false)
	}

	/**
	 * 设置全局环境变量。
	 * @param {object} vars 环境变量。
	 * @example
	 * // 设置全局环境变量
	 * THING.Utils.setGlobalEnvVars({ a: 1, b: 2 });
	 */
	static setGlobalEnvVars(vars) {
		if (!vars) {
			_globalEnvVars = {}
		}
		else {
			_globalEnvVars = Utils.cloneObject(vars, false)
		}
	}

	/**
	 * 获取全局环境变量。
	 * @param {string} key 环境变量键。
	 * @returns {any} 环境变量值。
	 * @example
	 * // 获取全局环境变量
	 * const globalEnvVar = THING.Utils.getGlobalEnvVar('a');
	 * console.log(globalEnvVar); // 1
	 */
	static getGlobalEnvVar(key) {
		return _globalEnvVars[key]
	}

	/**
	 * 设置全局环境变量。
	 * @param {string} key 环境变量键。
	 * @param {any} val 环境变量值。
	 * @example
	 * // 设置全局环境变量
	 * THING.Utils.setGlobalEnvVar('a', 1);
	 */
	static setGlobalEnvVar(key, val) {
		_globalEnvVars[key] = val
	}

	// 字符串排序,如果字符串中包含数字,则按照数字大小排序,否则按照字典顺序排序
	/**
	 * 字符串排序。
	 * @param {string} a 字符串a。
	 * @param {string} b 字符串b。
	 * @returns {number} 排序结果。
	 * @example
	 * // 字符串排序
	 * const result = THING.Utils.stringSort('a10', 'a2');
	 * console.log(result); // -1
	 */
	static stringSort(a, b) {
		let i = 0;
		let lenA = a.length;
		let lenB = b.length;

		while (i < lenA && i < lenB) {
			const charA = a[i];
			const charB = b[i];
			// 检查当前字符是否可能是数字的开始
			const isDigitStartA = !isNaN(parseInt(charA, 10));
			const isDigitStartB = !isNaN(parseInt(charB, 10));

			if (isDigitStartA && isDigitStartB) {
				// 找到数字部分的结束位置
				let numStartA = i;
				let numStartB = i;
				while (numStartA < lenA && !isNaN(parseInt(a[numStartA], 10))) {
					numStartA++;
				}
				while (numStartB < lenB && !isNaN(parseInt(b[numStartB], 10))) {
					numStartB++;
				}
				// 提取数字部分并进行比较
				const numA = parseInt(a.slice(i, numStartA), 10);
				const numB = parseInt(b.slice(i, numStartB), 10);
				if (numA !== numB) {
					return numA - numB;
				}
				// 如果数字相同,则继续比较后面的字符
				i = numStartA - 1; // 减1是因为循环会自增i
			}
			else if (isDigitStartA !== isDigitStartB) {
				// 如果一个字符是数字的开始,另一个不是,则根据需求决定顺序
				// 这里假设非数字部分排在数字部分前面(如果需要调整,可以交换返回值)
				return isDigitStartA ? 1 : -1;
			}
			else {
				// 如果两个字符都不是数字的开始,则按字典顺序比较
				if (charA !== charB) {
					return charA.localeCompare(charB);
				}
			}
			i++;
		}

		// 如果到这里还没有返回,说明前面的字符(包括数字整体)都相同
		// 比较剩余字符串的长度(处理例如 "Boxv" 和 "Box10vxx" 的情况)
		return lenA - lenB;
	}


	/**
	 * Compare two values for equality.
	 * @param {*} o1 The first value.
	 * @param {*} o2 The second value.
	 * @returns {boolean} True if the objects are equal.
	 * @example
	 * // 比较两个变量是否相等
	 * THING.Utils.equals([0,1,2], [0,1,2]); // true
	 * THING.Utils.equals('a', 'a'); // true
	 * THING.Utils.equals(1, 1); // true
	 * THING.Utils.equals('1', 1); // false
	 * THING.Utils.equals({a:'a'}, {}); // false
	 */
	static equals(o1, o2) {
		const o1Type = getBaseType(o1);
		const o2Type = getBaseType(o2);
		if (o1Type !== o2Type) {
			return false
		}

		if (o1Type === 'array') {
			if (o1.length !== o2.length) {
				return false;
			}

			for (let i = 0; i < o1.length; i++) {
				if (o1[i] !== o2[i]) {
					return false
				}
			}
			return true;
		}

		if (this.isPlainObject(o1) && this.isPlainObject(o2)) {
			return this.equalsObject(o1, o2)
		}

		if (o1 !== o2) {
			return false;
		}

		return true;
	}

}

function getBaseType(value) {
	if (Array.isArray(value)) {
		return 'array'
	}
	else if (value === null) {
		return 'null'
	}
	else if (value === undefined) {
		return 'undefined'
	}
	else {
		return typeof (value);
	}
}

Utils.addURLResolver(function (url) {
	if (!url._startsWith('/')) {
		return url;
	}

	if (url._startsWith(_workPath)) {
		return url;
	}

	if (_workPath) {
		return _workPath._appendURL(url);
	}

	return url;
});

/**
 * Resolve protocol-relative URL (starts with '//') to absolute URL using current window protocol.
 * If the input does not start with "//", it will be returned unchanged.
 * @param {string} url The url string.
 * @returns {string} The resolved url.
 * @example
 * // In browser environment with https protocol
 * BaseUtils.resolveURL('//example.com/img.png'); // returns 'https://example.com/img.png'
 */
Utils.addURLResolver(function (url) {
	if (BaseUtils.isNull(url) || !BaseUtils.isString(url)) {
		return url;
	}

	if (url.startsWith('//')) {
		if (typeof window !== 'undefined' && window.location && window.location.protocol) {
			return window.location.protocol + url;
		}
		// Fallback to https when window is unavailable (e.g. in node env)
		return 'https:' + url;
	}

	return url;
});

var _consoleDebugFunc = console.debug;
var _consoleLogFunc = console.log;
var _consoleWarnFunc = console.warn;
var _consoleErrorFunc = console.error;
var _consoleTimeFunc = console.time;
var _consoleTimeEndFunc = console.timeEnd;

// Define other useful attributes.
Object.defineProperties(Utils, {

});

export { Utils };