mirror of
				https://scm.univ-tours.fr/22107988t/rappaurio-sae501_502.git
				synced 2025-11-04 10:45:22 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			1766 lines
		
	
	
		
			51 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			1766 lines
		
	
	
		
			51 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
/**
 | 
						||
 * @name CeL data function
 | 
						||
 * @fileoverview 本檔案包含了 data 處理的 functions。
 | 
						||
 * @since
 | 
						||
 */
 | 
						||
 | 
						||
'use strict';
 | 
						||
// 'use asm';
 | 
						||
 | 
						||
// --------------------------------------------------------------------------------------------
 | 
						||
 | 
						||
typeof CeL === 'function' && CeL.run({
 | 
						||
	// module name
 | 
						||
	name : 'data',
 | 
						||
 | 
						||
	require : 'data.code.compatibility.|data.native.to_fixed',
 | 
						||
 | 
						||
	// 設定不匯出的子函式。
 | 
						||
	// no_extend : '*',
 | 
						||
 | 
						||
	// 為了方便格式化程式碼,因此將 module 函式主體另外抽出。
 | 
						||
	code : module_code
 | 
						||
});
 | 
						||
 | 
						||
function module_code(library_namespace) {
 | 
						||
 | 
						||
	// requiring
 | 
						||
	var to_fixed = this.r('to_fixed'),
 | 
						||
	/** {Number}未發現之index。 const: 基本上與程式碼設計合一,僅表示名義,不可更改。(=== -1) */
 | 
						||
	NOT_FOUND = ''.indexOf('_');
 | 
						||
 | 
						||
	/**
 | 
						||
	 * null module constructor
 | 
						||
	 * 
 | 
						||
	 * @class data 處理的 functions
 | 
						||
	 */
 | 
						||
	var _// JSDT:_module_
 | 
						||
	= function() {
 | 
						||
		// null module constructor
 | 
						||
	};
 | 
						||
 | 
						||
	/**
 | 
						||
	 * for JSDT: 有 prototype 才會將之當作 Class
 | 
						||
	 */
 | 
						||
	_// JSDT:_module_
 | 
						||
	.prototype = {};
 | 
						||
 | 
						||
	/**
 | 
						||
	 * <code>
 | 
						||
	eval(uneval(o)): IE 沒有 uneval
 | 
						||
	http://keithdevens.com/weblog/archive/2007/Jun/07/javascript.clone
 | 
						||
 | 
						||
	way1:
 | 
						||
	return YAHOO.lang.JSON.parse( YAHOO.lang.JSON.stringify( obj ) );
 | 
						||
 | 
						||
	TODO:
 | 
						||
	1.
 | 
						||
	防止交叉參照版: try
 | 
						||
	var a=function(){this.a=1,this.b={a:this.a},this.a={b:this.b};},b=cloneObject(a);
 | 
						||
	.or.
 | 
						||
	var a={},b;
 | 
						||
	a.a={a:1};
 | 
						||
	a.b={a:a.a};
 | 
						||
	a.a={b:a.b};
 | 
						||
	b=cloneObject(a);
 | 
						||
 | 
						||
	恐須改成
 | 
						||
	=new cloneObject();
 | 
						||
 | 
						||
 | 
						||
	2.
 | 
						||
	equal()
 | 
						||
 | 
						||
	 </code>
 | 
						||
	 */
 | 
						||
	/**
 | 
						||
	 * clone object
 | 
						||
	 * 
 | 
						||
	 * @param object
 | 
						||
	 * @param {Boolean}deep
 | 
						||
	 *            deep / with trivial
 | 
						||
	 * @return
 | 
						||
	 * 
 | 
						||
	 * @see Object.clone() @ data.native
 | 
						||
	 * @since 2008/7/19 11:13:10, 2012/10/16 22:01:12, 2014/5/30 19:35:59.
 | 
						||
	 */
 | 
						||
	function clone(object, deep) {
 | 
						||
		if (!object || typeof object !== 'object')
 | 
						||
			// assert: is 純量 / function
 | 
						||
			return object;
 | 
						||
 | 
						||
		if (Array.isArray(object))
 | 
						||
			if (deep) {
 | 
						||
				var target = [];
 | 
						||
				object.forEach(function(o, index) {
 | 
						||
					target[index] = clone(o, deep);
 | 
						||
				});
 | 
						||
				return target;
 | 
						||
			} else
 | 
						||
				// Array.clone: data.native.clone_Array()
 | 
						||
				return Array.clone(object);
 | 
						||
 | 
						||
		var key = ('clone' in object)
 | 
						||
		// test 物件自帶的 clone().
 | 
						||
		&& typeof object.clone === 'function';
 | 
						||
 | 
						||
		if (key)
 | 
						||
			// object.clone(deep);
 | 
						||
			return object.clone();
 | 
						||
 | 
						||
		key = library_namespace.is_type(object);
 | 
						||
		if (key === 'Date')
 | 
						||
			return new Date(object.getTime());
 | 
						||
 | 
						||
		if (key === 'RegExp')
 | 
						||
			// new object.constructor(object)
 | 
						||
			return new RegExp(object);
 | 
						||
 | 
						||
		var value, target = {};
 | 
						||
		for (key in object)
 | 
						||
			// 不加入非本 instance,為 prototype 的東西。
 | 
						||
			if (Object.hasOwn(object, key)) {
 | 
						||
				value = object[key];
 | 
						||
				// TODO: 預防 loop, 防止交叉參照/循環參照。
 | 
						||
				target[key] = deep ? clone(value, deep) : value;
 | 
						||
			}
 | 
						||
		return target;
 | 
						||
	}
 | 
						||
 | 
						||
	_// JSDT:_module_
 | 
						||
	.clone = clone;
 | 
						||
 | 
						||
	// merge `new_data` to `old_data`, and return merged old_data
 | 
						||
	// merge 時,各屬性值以 `old_data` 為基礎,`new_data` 後設定者為準。
 | 
						||
	// Will modify old_data!
 | 
						||
	function deep_merge_object(old_data, options) {
 | 
						||
		var new_data;
 | 
						||
		if (Array.isArray(old_data)) {
 | 
						||
			// deep_merge_object([old_data, new_data, newer_data, ...,
 | 
						||
			// latest data ], options);
 | 
						||
			old_data.forEach(function(data, index) {
 | 
						||
				if (index === 0) {
 | 
						||
					old_data = data;
 | 
						||
				} else if (index === this.length - 1) {
 | 
						||
					new_data = data;
 | 
						||
				} else {
 | 
						||
					old_data = deep_merge_object([ old_data, data ], options);
 | 
						||
				}
 | 
						||
			});
 | 
						||
		} else {
 | 
						||
			// deep_merge_object(old_data, new_data);
 | 
						||
			new_data = options;
 | 
						||
		}
 | 
						||
 | 
						||
		// ----------------------------
 | 
						||
 | 
						||
		if (typeof old_data !== 'object' || old_data === null || !new_data) {
 | 
						||
			return new_data || old_data;
 | 
						||
		}
 | 
						||
 | 
						||
		// ----------------------------
 | 
						||
 | 
						||
		function merge_property_of_object(sub_new_data, sub_old_data) {
 | 
						||
			for ( var property in sub_new_data) {
 | 
						||
				// 將 property in sub_new_data 設定至
 | 
						||
				// old_value=sub_old_data[property];
 | 
						||
				merge_property(property, sub_new_data, sub_old_data);
 | 
						||
			}
 | 
						||
			return sub_old_data;
 | 
						||
		}
 | 
						||
 | 
						||
		// 以 sub_old_data[property] 為基礎,將 sub_new_data[property] merge/overwrite
 | 
						||
		// 到 sub_old_data[property]
 | 
						||
		// 最終指定 sub_new_data[property] = old_value;
 | 
						||
		function merge_property(property, sub_new_data, sub_old_data) {
 | 
						||
			// assert: property in sub_new_data
 | 
						||
			var new_value = sub_new_data[property];
 | 
						||
 | 
						||
			// assert: typeof old_value === 'object'
 | 
						||
			if (typeof new_value !== 'object' || !(property in sub_old_data)) {
 | 
						||
				// using new_value, overwrite old value
 | 
						||
				sub_old_data[property] = new_value;
 | 
						||
				return;
 | 
						||
			}
 | 
						||
 | 
						||
			// assert: property in sub_old_data
 | 
						||
			var old_value = sub_old_data[property];
 | 
						||
 | 
						||
			if (Array.isArray(new_value)) {
 | 
						||
				if (Array.isArray(old_value)) {
 | 
						||
					// 對於 {Object}old_value 先複製到 `old_value`
 | 
						||
					Object.keys(new_value).forEach(
 | 
						||
					// merge 像 new_value.a=1
 | 
						||
					function(sub_property) {
 | 
						||
						if (!library_namespace.is_digits(sub_property)) {
 | 
						||
							merge_property(sub_property, new_value, old_value);
 | 
						||
						}
 | 
						||
					});
 | 
						||
 | 
						||
					old_value.append(new_value);
 | 
						||
				} else if (typeof old_value === 'object') {
 | 
						||
					// assert: library_namespace.is_Object(old_value)
 | 
						||
					merge_property_of_object(new_value, old_value);
 | 
						||
				} else {
 | 
						||
					// new_value.push(old_value);
 | 
						||
					sub_old_data[property] = new_value;
 | 
						||
				}
 | 
						||
				return;
 | 
						||
			}
 | 
						||
 | 
						||
			// assert: library_namespace.is_Object(old_value) &&
 | 
						||
			// library_namespace.is_Object(new_value)
 | 
						||
 | 
						||
			if (typeof old_value !== 'object') {
 | 
						||
				// 考慮 new_value 與 old_value 型態不同的情況。
 | 
						||
				sub_old_data[property] = new_value;
 | 
						||
			} else {
 | 
						||
				merge_property_of_object(new_value, old_value);
 | 
						||
			}
 | 
						||
		}
 | 
						||
 | 
						||
		// assert: library_namespace.is_Object(old_data)
 | 
						||
		return merge_property_of_object(new_data, old_data);
 | 
						||
	}
 | 
						||
 | 
						||
	_.deep_merge_object = deep_merge_object;
 | 
						||
 | 
						||
	/**
 | 
						||
	 * get the quote index of specified string.<br />
 | 
						||
	 * 輸入('"','dh"fdgfg')得到2:指向"的位置.
 | 
						||
	 * 
 | 
						||
	 * @param {String}string
 | 
						||
	 * @param {String}quote
 | 
						||
	 *            ['"/],[/]可能不太適用,除非將/[/]/→/[\/]/
 | 
						||
	 * @returns
 | 
						||
	 * @since 2004/5/5
 | 
						||
	 */
 | 
						||
	function index_of_quote(string, quote) {
 | 
						||
		var i, l = 0, m;
 | 
						||
		if (!quote)
 | 
						||
			quote = '"';
 | 
						||
		while ((i = string.indexOf(quote, l)) > 0
 | 
						||
				&& string.charAt(i - 1) === '\\') {
 | 
						||
			m = string.slice(l, i - 2).match(/(\\+)$/);
 | 
						||
			if (m && m[1].length % 2)
 | 
						||
				break;
 | 
						||
			else
 | 
						||
				l = i + 1;
 | 
						||
		}
 | 
						||
		return i;
 | 
						||
	}
 | 
						||
 | 
						||
	/**
 | 
						||
	 * <code>
 | 
						||
	 {var a=[],b,t='',i;a[20]=4,a[12]=8,a[27]=4,a[29]=4,a[5]=6,a.e=60,a.d=17,a.c=1;alert(a);b=sortValue(a);alert(a+'\n'+b);for(i in b)t+='\n'+b[i]+'	'+a[b[i]];alert(t);}
 | 
						||
	 </code>
 | 
						||
	 */
 | 
						||
	// 依值排出key array…起碼到現在,我還看不出此函數有啥大功用。
 | 
						||
	// array,否則會出現error! mode=1:相同value的以','合併,mode=2:相同value的以array填入
 | 
						||
	function sortValue(a, mode) {
 | 
						||
		var s = [], r = [], i, j, b, k = [];
 | 
						||
		// 使用(i in n)的方法,僅有數字的i會自動排序;這樣雖不必用sort(),但數字亦會轉成字串。
 | 
						||
		for (i in a)
 | 
						||
			if ((b = isNaN(i) ? i : parseFloat(i)),
 | 
						||
			//
 | 
						||
			typeof s[j = isNaN(j = a[i]) ? j : parseFloat(j)] === 'undefined')
 | 
						||
				k.push(j), s[j] = b;
 | 
						||
			else if (typeof s[j] === 'object')
 | 
						||
				s[j].push(b);
 | 
						||
			else
 | 
						||
				s[j] = [ s[j], b ];
 | 
						||
		// 注意:sort 方法會在原地排序 Array 物件。
 | 
						||
		for (i = 0, k.sort(library_namespace.ascending); i < k.length; i++)
 | 
						||
			if (typeof (b = s[k[i]]) === 'object')
 | 
						||
				if (mode === 1)
 | 
						||
					// b.join(',')與''+b效能相同
 | 
						||
					r.push(b.join(','));
 | 
						||
				else if (mode === 2)
 | 
						||
					r.push(b);
 | 
						||
				else
 | 
						||
					for (j in b)
 | 
						||
						r.push(b[j]);
 | 
						||
			else
 | 
						||
				r.push(b);
 | 
						||
		return r;
 | 
						||
	}
 | 
						||
 | 
						||
	/**
 | 
						||
	 * <code>
 | 
						||
	 2005/7/18 21:26
 | 
						||
	 依照所要求的index(sortByIndex_I)對array排序。
 | 
						||
	 sortByIndex_Datatype表某index為數字/字串或function
 | 
						||
	 先設定sortByIndex_I,sortByIndex_Datatype再使用array.sort(sortByIndex);
 | 
						||
 | 
						||
	 example:
 | 
						||
	var array=[
 | 
						||
	'123	avcf	334',
 | 
						||
	'131	hj	562',
 | 
						||
	'657	gfhj	435',
 | 
						||
	'131	ajy	52',
 | 
						||
	'345	fds	562',
 | 
						||
	'52	gh	435',
 | 
						||
	];
 | 
						||
	sortByIndex_I=[0,1],sortByIndex_Datatype={0:1,2:1};
 | 
						||
	for(i in array)array[i]=array[i].split('	');
 | 
						||
	array.sort(sortByIndex);
 | 
						||
	alert(array.join('\n'));
 | 
						||
	 </code>
 | 
						||
	 */
 | 
						||
	var sortByIndex_I, sortByIndex_Datatype;
 | 
						||
	function sortByIndex(a, b) {
 | 
						||
		// alert(a+'\n'+b);
 | 
						||
		for (var i = 0, n; i < sortByIndex_I.length; i++)
 | 
						||
			if (sortByIndex_Datatype[n = sortByIndex_I[i]]) {
 | 
						||
				if (typeof sortByIndex_Datatype[n] === 'function') {
 | 
						||
					if (n = sortByIndex_Datatype[n](a[n], b[n]))
 | 
						||
						return n;
 | 
						||
				} else if (n = a[n] - b[n])
 | 
						||
					return n;
 | 
						||
			} else if (a[n] != b[n])
 | 
						||
				return a[n] > b[n] ? 1 : -1;
 | 
						||
		return 0;
 | 
						||
	}
 | 
						||
 | 
						||
	/**
 | 
						||
	 * <code>
 | 
						||
	 2005/7/18 21:26
 | 
						||
	 依照所要求的 index 對 array 排序,傳回排序後的 index array。
 | 
						||
	 **假如設定了 separator,array 的元素會先被 separator 分割!
 | 
						||
 | 
						||
	 example:
 | 
						||
	 var array=[
 | 
						||
	 '123	avcf	334',
 | 
						||
	 '131	hj	562',
 | 
						||
	 '657	gfhj	435',
 | 
						||
	 '131	ajy	52',
 | 
						||
	 '345	fds	562',
 | 
						||
	 '52	gh	435',
 | 
						||
	 ];
 | 
						||
	 alert(getIndexSortByIndex(array,'	',[0,1],[0,2]));
 | 
						||
	 alert(array.join('\n'));	//	已被 separator 分割!
 | 
						||
 | 
						||
	 </code>
 | 
						||
	 */
 | 
						||
	function getIndexSortByIndex(array, separator, indexArray, isNumberIndex) {
 | 
						||
		// 判定與事前準備(設定sortByIndex_I,sortByIndex_Datatype)
 | 
						||
		if (typeof indexArray === 'number')
 | 
						||
			sortByIndex_I = [ indexArray ];
 | 
						||
		else if (typeof indexArray !== 'object'
 | 
						||
				|| indexArray.constructor !== Array)
 | 
						||
			sortByIndex_I = [ 0 ];
 | 
						||
		else
 | 
						||
			sortByIndex_I = indexArray;
 | 
						||
		var i, sortByIndex_A = [];
 | 
						||
		sortByIndex_Datatype = Object.create(null);
 | 
						||
		if (typeof isNumberIndex === 'object') {
 | 
						||
			if (isNumberIndex.constructor === Array) {
 | 
						||
				sortByIndex_Datatype = Object.create(null);
 | 
						||
				for (i = 0; i < isNumberIndex.length; i++)
 | 
						||
					sortByIndex_Datatype[isNumberIndex[i]] = 1;
 | 
						||
			} else
 | 
						||
				sortByIndex_Datatype = isNumberIndex;
 | 
						||
			for (i in sortByIndex_Datatype)
 | 
						||
				if (isNaN(sortByIndex_Datatype[i])
 | 
						||
						|| parseInt(sortByIndex_Datatype[i]) !== sortByIndex_Datatype[i])
 | 
						||
					delete sortByIndex_Datatype[i];
 | 
						||
		}
 | 
						||
		if (typeof array !== 'object')
 | 
						||
			return;
 | 
						||
 | 
						||
		// main work: 可以不用重造 array 資料的話..
 | 
						||
		for (i in array) {
 | 
						||
			if (separator)
 | 
						||
				array[i] = array[i].split(separator);
 | 
						||
			sortByIndex_A.push(i);
 | 
						||
		}
 | 
						||
		sortByIndex_A.sort(function(a, b) {
 | 
						||
			return sortByIndex(array[a], array[b]);
 | 
						||
		});
 | 
						||
 | 
						||
		/**
 | 
						||
		 * <code>
 | 
						||
		for: 重造array資料
 | 
						||
		var getIndexSortByIndexArray=array;
 | 
						||
		for(i in getIndexSortByIndexArray){
 | 
						||
			if(separator)getIndexSortByIndexArray[i]=getIndexSortByIndexArray[i].split(separator);
 | 
						||
			sortByIndex_A.push(i);
 | 
						||
		}
 | 
						||
		sortByIndex_A.sort(function (a,b){return sortByIndex(getIndexSortByIndexArray[a],getIndexSortByIndexArray[b]);});
 | 
						||
		</code>
 | 
						||
		 */
 | 
						||
 | 
						||
		return sortByIndex_A;
 | 
						||
	}
 | 
						||
 | 
						||
	/**
 | 
						||
	 * <code>
 | 
						||
	 simpleWrite('char_frequency report3.txt',char_frequency(simpleRead('function.js')+simpleRead('accounts.js')));
 | 
						||
	 {var t=reduceCode(simpleRead('function.js')+simpleRead('accounts.js'));simpleWrite('char_frequency source.js',t),simpleWrite('char_frequency report.txt',char_frequency(t));}	//	所費時間:十數秒(…太扯了吧!)
 | 
						||
	 </code>
 | 
						||
	 */
 | 
						||
	_// JSDT:_module_
 | 
						||
	.
 | 
						||
	/**
 | 
						||
	 * 測出各字元的出現率。 普通使用字元@0-127:9-10,13,32-126,reduce後常用:9,32-95,97-125
 | 
						||
	 * 
 | 
						||
	 * @param {String}
 | 
						||
	 *            text 文檔
 | 
						||
	 * @return
 | 
						||
	 * @_memberOf _module_
 | 
						||
	 */
 | 
						||
	char_frequency = function char_frequency(text) {
 | 
						||
		var i, a, c = [], d, t = '' + text, l = t.length, used = '', unused = '', u1 = -1, u2 = u1;
 | 
						||
		for (i = 0; i < l; i++)
 | 
						||
			if (c[a = t.charCodeAt(i)])
 | 
						||
				c[a]++;
 | 
						||
			else
 | 
						||
				c[a] = 1;
 | 
						||
		for (i = u1; i < 256; i++)
 | 
						||
			if (c[i]) {
 | 
						||
				if (u2 + 1 === i)
 | 
						||
					used += ',' + i, unused += (u2 < 0 ? '' : '-' + u2);
 | 
						||
				u1 = i;
 | 
						||
			} else {
 | 
						||
				if (u1 + 1 === i)
 | 
						||
					unused += ',' + i, used += (u1 < 0 ? '' : '-' + u1);
 | 
						||
				u2 = i;
 | 
						||
			}
 | 
						||
		// 若是reduceCode()的程式,通常在120項左右。
 | 
						||
		for (i = 0, t = 'used:' + used.substr(1) + '\nunused:'
 | 
						||
				+ unused.substr(1) + '\n', d = sortValue(c, 2).reverse(); i < d.length; i++) {
 | 
						||
			t += NewLine
 | 
						||
					+ (a = d[i])
 | 
						||
					+ '['
 | 
						||
					+ fromCharCode(a).replace(/\0/g, '\\0').replace(/\r/g,
 | 
						||
							'\\r').replace(/\n/g, '\\n').replace(/\t/g, '\\t')
 | 
						||
					+ ']' + ':	' + (a = c[typeof a === 'object' ? a[0] : a])
 | 
						||
					+ '	' + (100 * a / l);
 | 
						||
			// .5%以上者←選購
 | 
						||
			// if(200*v<l)break;
 | 
						||
		}
 | 
						||
		alert(t);
 | 
						||
		return t;
 | 
						||
	};
 | 
						||
 | 
						||
	/**
 | 
						||
	 * <code>
 | 
						||
	 flag:
 | 
						||
	 (flag&1)==0	HTML tag, 表情符號等不算一個字
 | 
						||
	 (flag&1)==1	將 HTML tag 全部消掉
 | 
						||
	 (flag&2)==1	連表情符號等也算一個字
 | 
						||
 | 
						||
	 可讀性/適讀性
 | 
						||
	 http://en.wikipedia.org/wiki/Flesch-Kincaid_Readability_Test
 | 
						||
	 http://en.wikipedia.org/wiki/Gunning_fog_index
 | 
						||
	 Gunning-Fog Index:簡單的來說就是幾年的學校教育才看的懂你的文章,數字越低代表越容易閱讀,若是高於17那表示你的文章太難囉,需要研究生才看的懂,我是6.08,所以要受過6.08年的學校教育就看的懂囉。
 | 
						||
	 Flesch Reading Ease:這個指數的分數越高,表示越容易了解,一般標準的文件大約介於60~70分之間。
 | 
						||
	 Flesch-Kincaid grade level:和Gunning-Fog Index相似,分數越低可讀性越高,越容易使閱讀者了解,至於此指數和Gunning-Fog Index有何不同,網站上有列出計算的演算法,有興趣的人可以比較比較。
 | 
						||
 | 
						||
	 DO.normalize(): 合併所有child成一String, may crash IE6 Win!	http://www.quirksmode.org/dom/tests/splittext.html
 | 
						||
	 </code>
 | 
						||
	 */
 | 
						||
	_// JSDT:_module_
 | 
						||
	.
 | 
						||
	/**
 | 
						||
	 * 計算字數 count words. word_count
 | 
						||
	 * 
 | 
						||
	 * @param {String}
 | 
						||
	 *            text 文檔
 | 
						||
	 * @param {Number}
 | 
						||
	 *            flag 文檔格式/處理方法
 | 
						||
	 * 
 | 
						||
	 * @return {Number} 字數
 | 
						||
	 * 
 | 
						||
	 * @see https://zh.wikipedia.org/wiki/User:%E5%B0%8F%E8%BA%8D/Wordcount.js
 | 
						||
	 * 
 | 
						||
	 * @_memberOf _module_
 | 
						||
	 */
 | 
						||
	count_word = function count_word(text, flag) {
 | 
						||
		var is_HTML = flag & 1;
 | 
						||
 | 
						||
		// is HTML object
 | 
						||
		if (typeof text === 'object')
 | 
						||
			if (text.innerText)
 | 
						||
				text = text.innerText, is_HTML = false;
 | 
						||
			else if (text.innerHTML)
 | 
						||
				text = text.innerHTML, is_HTML = true;
 | 
						||
 | 
						||
		if (typeof text !== 'string')
 | 
						||
			return 0;
 | 
						||
 | 
						||
		// 和perl不同,JScript常抓不到(.*?)之後還接特定字串的東西,大概因為沒有s。(.*?)得改作([\s\S]*?)?
 | 
						||
		// 或者該加/img?
 | 
						||
		if (is_HTML)
 | 
						||
			text = text.replace(/<!--([\s\S]*?)-->/g, '').replace(
 | 
						||
					/<[\s\n]*\/?[\s\n]*[a-z][^<>]*>/gi, '');
 | 
						||
 | 
						||
		if (flag & 2)
 | 
						||
			text = text.replace(
 | 
						||
			// 連表情符號或 '(~。),' / 破折號 '——' / 刪節號 '……' 等標點符號也算一個字
 | 
						||
			/[\+\-–*\\\/?!,;.<>{}\[\]@#$%^&_|"'~`—…、,;。!?:()()「」『』“”‘’]{2,}/g,
 | 
						||
					';');
 | 
						||
 | 
						||
		return text
 | 
						||
		// 去掉注解用的括弧、書名號、專名號、印刷符號等
 | 
						||
		.replace(/[()()《》〈〉*#]+/g, '')
 | 
						||
 | 
						||
		// 將數字改成單一字母。
 | 
						||
		.replace(/\d*\.?\d+([^.]|$)/g, '0$1')
 | 
						||
		/**
 | 
						||
		 * 將整組物理量值加計量單位略縮成單一字母。<br />
 | 
						||
		 * The general rule of the International Bureau of Weights and Measures
 | 
						||
		 * (BIPM) is that the numerical value always precedes the unit, and a
 | 
						||
		 * space is always used to separate the unit from the number, e.g., "23
 | 
						||
		 * °C" (not "23°C" or "23° C").
 | 
						||
		 * 
 | 
						||
		 * @see <a href="http://en.wikipedia.org/wiki/ISO_31-0#Expressions"
 | 
						||
		 *      accessdate="2012/7/28 0:42">ISO 31-0</a>, <a
 | 
						||
		 *      href="http://lamar.colostate.edu/~hillger/faq.html#spacing"
 | 
						||
		 *      accessdate="2012/7/28 0:42">FAQ: Frequently Asked Questions
 | 
						||
		 *      about the metric system</a>.
 | 
						||
		 */
 | 
						||
		.replace(/\d+\s*[a-zA-Z°]+(\s*\/\s*(\d+\s*)?[a-zA-Z°]+)?/g, '0')
 | 
						||
		// 長度過長時,極耗時間。e.g., ...\d{500000}...
 | 
						||
		// .replace(/\d*\.?\d+\s*[a-zA-Z°]+(\s*\/\s*(\d*\.?\d+\s*)?[a-zA-Z°]+)?/g,'0')
 | 
						||
 | 
						||
		// https://en.wikipedia.org/wiki/Punctuation_of_English
 | 
						||
		// Do not count punctuations of English.
 | 
						||
		.replace(/[,;:.?!\-–"'()⟨⟩«»\[\]{}<>$%#@~`^&*\\\/⁄+=|]+/g, '')
 | 
						||
		// 將英文、數字、單位等改成單一字母。[.]: 縮寫。[\/]: m/s 之類。
 | 
						||
		// a's: 1
 | 
						||
		// http://en.wikibooks.org/wiki/Unicode/Character_reference/0000-0FFF
 | 
						||
		// http://zh.wikipedia.org/wiki/Unicode%E5%AD%97%E7%AC%A6%E5%88%97%E8%A1%A8
 | 
						||
		.replace(/[\wÀ-ÖØ-öø-ȳ]{2,}/g, 'w')
 | 
						||
 | 
						||
		// date/time or number
 | 
						||
		.replace(/[\d:+\-–\.\/,]{2,}/g, '0')
 | 
						||
		// 再去掉*全部*空白
 | 
						||
		.replace(/[\s\n]+/g, '')
 | 
						||
		// return text.length;
 | 
						||
		.length;
 | 
						||
	};
 | 
						||
 | 
						||
	_// JSDT:_module_
 | 
						||
	.
 | 
						||
	/**
 | 
						||
	 * 運算式值的二進位表示法
 | 
						||
	 * 已最佳化:5.82s/100000次dec_to_bin(20,8)@300(?)MHz,2.63s/100000次dec_to_bin(20)@300(?)MHz
 | 
						||
	 * 
 | 
						||
	 * @param {Number}
 | 
						||
	 *            number number
 | 
						||
	 * @param places
 | 
						||
	 *            places,字元數,使用前置0來填補回覆值
 | 
						||
	 * @return
 | 
						||
	 * @example<code>
 | 
						||
	{var d=new Date,i,b;for(i=0;i<100000;i++)b=dec_to_bin(20);alert(gDate(new Date-d));}
 | 
						||
	</code>
 | 
						||
	 * @_memberOf _module_
 | 
						||
	 */
 | 
						||
	dec_to_bin = function dec_to_bin(number, places) {
 | 
						||
		if (places && number + 1 < (1 << places)) {
 | 
						||
			var h = '', b = number.toString(2), i = b.length;
 | 
						||
			for (; i < places; i++)
 | 
						||
				h += '0';
 | 
						||
			return h + b;
 | 
						||
		}
 | 
						||
		// native code 還是最快!
 | 
						||
		return number.toString(2);
 | 
						||
 | 
						||
		if (false) {
 | 
						||
			// 上兩代:慢
 | 
						||
			// 不用'1:0',型別轉換比較慢.不用i,多一個變數會慢很多
 | 
						||
			var b = '', c = 1;
 | 
						||
			for (p = p && n < (p = 1 << p) ? p : n + 1; c < p; c <<= 1)
 | 
						||
				b = (c & n ? '1' : '0') + b;
 | 
						||
			return b;
 | 
						||
 | 
						||
			// 上一代:慢
 | 
						||
			if (p && n + 1 < (1 << p)) {
 | 
						||
				var h = '', c = 1, b = n.toString(2);
 | 
						||
				while (c <= n)
 | 
						||
					c <<= 1;
 | 
						||
				while (c < p)
 | 
						||
					c <<= 1, h += '0';
 | 
						||
				return h + (n ? n.toString(2) : '');
 | 
						||
			}
 | 
						||
		}
 | 
						||
	};
 | 
						||
 | 
						||
	/**
 | 
						||
	 * <code>
 | 
						||
	value	(Array)=value,(Object)value=
 | 
						||
	[null]=value	累加=value
 | 
						||
	value=[null]	value=''
 | 
						||
 | 
						||
	type: value type	['=','][int|float|_num_]
 | 
						||
	: 前段
 | 
						||
		以[']或["]作分隔重定義指定號[=]與分隔號[,]
 | 
						||
	: 後段
 | 
						||
		數字表累加
 | 
						||
		'int'表整數int,累加1
 | 
						||
		'float'表示浮點數float,累加.1	bug:應該用.to_fixed()
 | 
						||
		不輸入或非數字表示string
 | 
						||
 | 
						||
	mode
 | 
						||
	_.set_Object_value.F.object
 | 
						||
	_.set_Object_value.F.array(10進位/當做數字)
 | 
						||
	number: key部分之base(10進位,16進位等)
 | 
						||
 | 
						||
	example:
 | 
						||
	set_Object_value('UTCDay','Sun,Mon,Tue,Wed,Thu,Fri,Sat','int');	//	自動從0開始設,UTCDay.Tue=2
 | 
						||
	set_Object_value('UTCDay','Sun,Mon,Tue,Wed,Thu,Fri,Sat');	//	UTCDay.Sun=UTCDay.Fri=''
 | 
						||
	set_Object_value('add','a=3,b,c,d',2);	//	累加2。add.b=5
 | 
						||
	set_Object_value('add','a,b,c,d',1,_.set_Object_value.F.array);	//	add[2]='c'
 | 
						||
	set_Object_value('add','4=a,b,c,d',2,_.set_Object_value.F.array);	//	累加2。add[8]='c'
 | 
						||
 | 
						||
	 </code>
 | 
						||
	 */
 | 
						||
	_// JSDT:_module_
 | 
						||
	.
 | 
						||
	/**
 | 
						||
	 * 設定object之值,輸入item=[value][,item=[value]..]。<br />
 | 
						||
	 * value未設定會自動累加。<br />
 | 
						||
	 * 使用前不必需先宣告…起碼在現在的JS版本中
 | 
						||
	 * 
 | 
						||
	 * @param obj
 | 
						||
	 *            object name that need to operate at
 | 
						||
	 * @param value
 | 
						||
	 *            valueto set
 | 
						||
	 * @param type
 | 
						||
	 *            累加 / value type
 | 
						||
	 * @param mode
 | 
						||
	 *            mode / value type
 | 
						||
	 * @return
 | 
						||
	 * @_memberOf _module_
 | 
						||
	 */
 | 
						||
	set_Object_value = function set_Object_value(obj, value, type, mode) {
 | 
						||
		if (!value || typeof obj !== 'string')
 | 
						||
			return;
 | 
						||
 | 
						||
		var a, b, i = 0, p = '=', sp = ',', e = "if(typeof " + obj
 | 
						||
				+ "!='object')" + obj + "=new " + (mode ?
 | 
						||
				// "[]":"{}"
 | 
						||
				// Array之另一種表示法:[value1,value2,..],
 | 
						||
				// Object之另一種表示法:{key1:value1,key2:value2,..}
 | 
						||
				"Array" : "Object") + ";",
 | 
						||
		// l: item, n: value to 累加
 | 
						||
		n, Tint = false, cmC = '\\u002c', eqC = '\\u003d';
 | 
						||
		if (type) {
 | 
						||
			if (typeof a === 'string') {
 | 
						||
				a = type.charAt(0);
 | 
						||
				if (a === '"' || a === "'") {
 | 
						||
					a = type.split(a);
 | 
						||
					p = a[1], sp = a[2], type = a[3];
 | 
						||
				}
 | 
						||
			}
 | 
						||
			if (type === 'int')
 | 
						||
				type = 1, Tint = true;
 | 
						||
			else if (type === 'float')
 | 
						||
				type = .1;
 | 
						||
			else if (isNaN(type))
 | 
						||
				type = 0;
 | 
						||
			else if (type === parseInt(type))
 | 
						||
				type = parseInt(type), Tint = true;
 | 
						||
			else
 | 
						||
				// t被設成累加數
 | 
						||
				type = parseFloat(type);
 | 
						||
		}
 | 
						||
		// else t = 1;
 | 
						||
 | 
						||
		if (typeof value === 'string')
 | 
						||
			value = value.split(sp);
 | 
						||
		// escape regex characters from jQuery
 | 
						||
		cmC = new RegExp(cmC.replace(
 | 
						||
				/([\.\\\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:])/g, "\\$1"), 'g'),
 | 
						||
				eqC = new RegExp(eqC.replace(
 | 
						||
						/([\.\\\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:])/g, "\\$1"),
 | 
						||
						'g');
 | 
						||
 | 
						||
		if (type)
 | 
						||
			// n: 現在count到..
 | 
						||
			n = -type;
 | 
						||
 | 
						||
		for (; i < value.length; i++) {
 | 
						||
			if (value[i].indexOf(p) === NOT_FOUND)
 | 
						||
				// if(v[i].indexOf(p)==NOT_FOUND&&m)v[i]=p+v[i];
 | 
						||
				value[i] = mode ? p + value[i] : value[i] + p;
 | 
						||
			if (mode && value[i] === p) {
 | 
						||
				n += type;
 | 
						||
				continue;
 | 
						||
			}
 | 
						||
			a = value[i].split(p);
 | 
						||
			if (!mode && !a[0])
 | 
						||
				// 去掉不合理的(Array可能有NaN index,所以不設條件。)
 | 
						||
				continue;
 | 
						||
			a[0] = a[0].replace(cmC, ',').replace(eqC, '='), a[1] = a[1]
 | 
						||
					.replace(cmC, ',').replace(eqC, '=');
 | 
						||
			if (type)
 | 
						||
				if (mode) {
 | 
						||
					if (!a[0])
 | 
						||
						a[0] = (n += type);
 | 
						||
					else if (!isNaN(b = mode > 0 ? parseInt(a[0], mode) : a[0]))
 | 
						||
						n = Tint ? (a[0] = parseInt(b)) : parseFloat(b);
 | 
						||
				} else if (!a[1])
 | 
						||
					a[1] = (n += type);
 | 
						||
				else if (!isNaN(a[1]))
 | 
						||
					n = Tint ? parseInt(a[1]) : parseFloat(a[1]);
 | 
						||
			if (!type || Tint && isNaN(b = parseInt(a[1]))
 | 
						||
					|| isNaN(b = parseFloat(a[1])))
 | 
						||
				b = a[1];
 | 
						||
			a = a[0];
 | 
						||
			e += obj + '['
 | 
						||
					+ (!type || isNaN(a) ? library_namespace.dQuote(a) : a)
 | 
						||
					+ ']='
 | 
						||
					+ (!type || isNaN(b) ? library_namespace.dQuote(b) : b)
 | 
						||
					+ ';';
 | 
						||
		}
 | 
						||
 | 
						||
		try {
 | 
						||
			// if(o=='kk')alert(e.slice(0,500));
 | 
						||
			// 因為沒想到其他方法可存取Global的object,只好使用eval...
 | 
						||
			// 可以試試obj=set_Object_value(0,..){this=new Aaaray/Object}
 | 
						||
			return library_namespace.eval_code(e);
 | 
						||
		} catch (e) {
 | 
						||
			library_namespace.error('Error @ ' + obj);
 | 
						||
			library_namespace.error(e);
 | 
						||
			return;
 | 
						||
		}
 | 
						||
	};
 | 
						||
 | 
						||
	_.set_Object_value.F = {
 | 
						||
		// object is default
 | 
						||
		'object' : 0,
 | 
						||
		'array' : -1
 | 
						||
	};
 | 
						||
 | 
						||
	_// JSDT:_module_
 | 
						||
	.
 | 
						||
	/**
 | 
						||
	 * 將字串組分作 Object
 | 
						||
	 * 
 | 
						||
	 * @param {String}
 | 
						||
	 *            value_set 字串組, e.g., 'a=12,b=34'
 | 
						||
	 * @param assignment_char
 | 
						||
	 *            char to assign values, e.g., '='
 | 
						||
	 * @param end_char
 | 
						||
	 *            end char of assignment
 | 
						||
	 * @return
 | 
						||
	 * @since 2006/9/6 20:55, 2010/4/12 23:06:04
 | 
						||
	 * @_memberOf _module_
 | 
						||
	 */
 | 
						||
	split_String_to_Object = function split_String_to_Object(value_set,
 | 
						||
			assignment_char, end_char) {
 | 
						||
		if (typeof value_set !== 'string' || !value_set)
 | 
						||
			return {};
 | 
						||
 | 
						||
		value_set = value_set.split(end_char || /[,;]/);
 | 
						||
 | 
						||
		if (!assignment_char)
 | 
						||
			assignment_char = /[=:]/;
 | 
						||
 | 
						||
		var a, o = {}, _e = 0, l = value_set.length;
 | 
						||
		for (; _e < l; _e++) {
 | 
						||
			// http://msdn.microsoft.com/library/en-us/jscript7/html/jsmthsplit.asp
 | 
						||
			a = value_set[_e].split(assignment_char, 2);
 | 
						||
			if (false)
 | 
						||
				library_namespace.debug(value_set[_e] + '\n' + a[0] + ' '
 | 
						||
						+ a[1], 2);
 | 
						||
			if (a[0] !== '')
 | 
						||
				o[a[0]] = a[1];
 | 
						||
		}
 | 
						||
		return o;
 | 
						||
	};
 | 
						||
 | 
						||
	/**
 | 
						||
	 * <code>
 | 
						||
	2003/10/1 15:46
 | 
						||
	比較string:m,n從起頭開始相同字元數
 | 
						||
	return null: 格式錯誤,-1: !m||!n
 | 
						||
	若一開始就不同:0
 | 
						||
 | 
						||
 | 
						||
	TODO:
 | 
						||
	
 | 
						||
	test starting with
 | 
						||
	
 | 
						||
	2009/2/7 7:51:58
 | 
						||
	看來測試 string 的包含,以 .indexOf() 最快。
 | 
						||
	即使是比較 s.length 為極小常數的情況亦復如此
 | 
						||
	
 | 
						||
	下面是快到慢:
 | 
						||
	
 | 
						||
	//	long, short
 | 
						||
	var contain_substring = [ function(l, s) {
 | 
						||
		var a = 0 == l.indexOf(s);
 | 
						||
		return a;
 | 
						||
	}, function(l, s) {
 | 
						||
		return 0 == l.indexOf(s);
 | 
						||
	}, function(l, s) {
 | 
						||
		return s == l.slice(0, s.length);
 | 
						||
	}, function(l, s) {
 | 
						||
		return l.match(s);
 | 
						||
	}, function(l, s) {
 | 
						||
		for (var i = 0; i < s.length; i++)
 | 
						||
			if (s.charAt(i) != l.charAt(i))
 | 
						||
				return 0;
 | 
						||
		return 1;
 | 
						||
	} ];
 | 
						||
 | 
						||
	function test_contain_substring() {
 | 
						||
		for (var i = 0; i < contain_substring.length; i++) {
 | 
						||
			var t = new Date;
 | 
						||
			for (var j = 0; j < 50000; j++) {
 | 
						||
				contain_substring[i]('sdfgjk;sh*dn\\fj;kgsamnd nwgu!eoh;nfgsj;g',
 | 
						||
						'sdfgjk;sh*dn\\fj;kgsamnd nwgu!');
 | 
						||
				contain_substring[i]('sdbf6a89* /23hsauru', 'sdbf6a89* /23');
 | 
						||
			}
 | 
						||
			sl(i + ': ' + (new Date - t));
 | 
						||
		}
 | 
						||
	}
 | 
						||
	
 | 
						||
	
 | 
						||
	//	極小常數的情況:
 | 
						||
	//	long,short
 | 
						||
	var contain_substring = [ function(l, s) {
 | 
						||
		var a = 0 == l.indexOf(s);
 | 
						||
		return a;
 | 
						||
	}, function(l, s) {
 | 
						||
		return 0 == l.indexOf(s);
 | 
						||
	}, function(l, s) {
 | 
						||
		return s == l.slice(0, 1);
 | 
						||
	}, function(l, s) {
 | 
						||
		return s.charAt(0) == l.charAt(0);
 | 
						||
	}, function(l, s) {
 | 
						||
		return l.match(/^\//);
 | 
						||
	} ];
 | 
						||
 | 
						||
	function test_contain_substring() {
 | 
						||
		for (var i = 0; i < contain_substring.length; i++) {
 | 
						||
			var t = new Date;
 | 
						||
			for (var j = 0; j < 50000; j++) {
 | 
						||
				contain_substring[i]('a:\\sdfg.dfg\\dsfg\\dsfg', '/');
 | 
						||
				contain_substring[i]('/dsfg/adfg/sadfsdf', '/');
 | 
						||
			}
 | 
						||
			sl(i + ': ' + (new Date - t));
 | 
						||
		}
 | 
						||
	}
 | 
						||
 | 
						||
	</code>
 | 
						||
	 */
 | 
						||
 | 
						||
	_// JSDT:_module_
 | 
						||
	.
 | 
						||
	/**
 | 
						||
	 * test if 2 string is at the same length.<br />
 | 
						||
	 * strcmp: String.prototype.localeCompare
 | 
						||
	 * 
 | 
						||
	 * @param s1
 | 
						||
	 *            string 1
 | 
						||
	 * @param s2
 | 
						||
	 *            string 2
 | 
						||
	 * @return
 | 
						||
	 * @_memberOf _module_
 | 
						||
	 */
 | 
						||
	same_length = function same_length(s1, s2) {
 | 
						||
		if (typeof m !== 'string' || typeof n !== 'string')
 | 
						||
			return;
 | 
						||
		if (!s1 || !s2)
 | 
						||
			return 0;
 | 
						||
 | 
						||
		var i = s1.length, b = 0, s = s2.length;
 | 
						||
		if (i < s) {
 | 
						||
			if (
 | 
						||
			// m === n.slice(0, i = m.length)
 | 
						||
			0 === s2.indexOf(s1))
 | 
						||
				return i;
 | 
						||
		} else if (
 | 
						||
		// s2==s1.slice(0,i=s2.length)
 | 
						||
		i = s, 0 === s1.indexOf(s2))
 | 
						||
			return i;
 | 
						||
 | 
						||
		// sl('*same_length: start length: '+i);
 | 
						||
		while ((i = (i + 1) >> 1) > 1 && (s = s2.substr(b, i))) {
 | 
						||
			if (false)
 | 
						||
				sl('same_length: ' + i + ',' + b + '; [' + m.substr(b) + '], ['
 | 
						||
						+ s + '] of [' + n + ']');
 | 
						||
			if (s1.indexOf(s, b) === b)
 | 
						||
				b += i;
 | 
						||
			if (false) {
 | 
						||
				sl('*same_length: ' + i + ',' + b + '; [' + m.charAt(b)
 | 
						||
						+ '], [' + n.charAt(b) + '] of [' + n + ']');
 | 
						||
				var s_l = i && m.charAt(b) == n.charAt(b) ? b + 1 : b;
 | 
						||
				sl('*same_length: ' + s_l + ':' + m.slice(0, s_l) + ',<em>'
 | 
						||
						+ m.slice(s_l) + '</em>; ' + n.slice(0, s_l) + ',<em>'
 | 
						||
						+ n.slice(s_l) + '</em>');
 | 
						||
			}
 | 
						||
		}
 | 
						||
		return i && s1.charAt(b) === s2.charAt(b) ? b + 1 : b;
 | 
						||
	};
 | 
						||
 | 
						||
	/**
 | 
						||
	 * 去除指定字串中重複字元。 remove duplicate characters in a string.
 | 
						||
	 * 
 | 
						||
	 * @param {String}string
 | 
						||
	 *            指定字串。
 | 
						||
	 * 
 | 
						||
	 * @returns 去除重複字元後之字串。
 | 
						||
	 */
 | 
						||
	function remove_duplicate_characters(string) {
 | 
						||
		string = String(string);
 | 
						||
		if (!string)
 | 
						||
			return '';
 | 
						||
 | 
						||
		string = string.split('');
 | 
						||
		var i = 0, length = string.length, code_array = [], code;
 | 
						||
		for (; i < length; i++) {
 | 
						||
			code = string[i].charCodeAt(0);
 | 
						||
			if (code in code_array) {
 | 
						||
				string[i] = '';
 | 
						||
			} else {
 | 
						||
				code_array[code] = 1;
 | 
						||
			}
 | 
						||
		}
 | 
						||
 | 
						||
		return string.join('');
 | 
						||
	}
 | 
						||
 | 
						||
	_// JSDT:_module_
 | 
						||
	.remove_duplicate_characters = remove_duplicate_characters;
 | 
						||
 | 
						||
	// -----------------------------------------------------------------------------
 | 
						||
 | 
						||
	/**
 | 
						||
	 * 產生將數字轉為 K, M, G 等數量級(order of magnitude)表示方式的轉換器。<br />
 | 
						||
	 * 原理:先設好各 symbol 使用之下限,比完大小後使用此 symbol。
 | 
						||
	 * 
 | 
						||
	 * TODO: full test
 | 
						||
	 * 
 | 
						||
	 * @param {Array}symbol
 | 
						||
	 *            array of {String}symbol
 | 
						||
	 * @param {Integer}[base]
 | 
						||
	 *            define what power
 | 
						||
	 * @param {Integer}[index_of_1]
 | 
						||
	 *            純量的 index。no prefix. 這之前的算做小數。
 | 
						||
	 * @param {String}intervening
 | 
						||
	 *            intervening string, 將插入於數字與 symbol 間。e.g.,  
 | 
						||
	 * @return {Function} 改變表示方式之轉換器。
 | 
						||
	 * @return {undefined} 輸入有問題。
 | 
						||
	 * @requires to_fixed
 | 
						||
	 * @see <a href="http://www.merlyn.demon.co.uk/js-maths.htm#DTS"
 | 
						||
	 *      accessdate="2012/8/18 12:17">JRS - JavaScript Maths - J R Stockton</a>
 | 
						||
	 * @_memberOf _module_
 | 
						||
	 */
 | 
						||
	function set_order_prefix(symbol, base, index_of_1, intervening) {
 | 
						||
		if (!Array.isArray(symbol) || !symbol.length)
 | 
						||
			return;
 | 
						||
 | 
						||
		if (!base)
 | 
						||
			base = 10;
 | 
						||
		if (!index_of_1) {
 | 
						||
			index_of_1 = 0;
 | 
						||
			if (symbol[0])
 | 
						||
				symbol.unshift('');
 | 
						||
		}
 | 
						||
 | 
						||
		var magnitude = 1, length = symbol.length, value = new Array(length), index = index_of_1;
 | 
						||
 | 
						||
		// 先設定好各數量級(order of magnitude)之大小。
 | 
						||
		while (++index < length) {
 | 
						||
			magnitude *= base;
 | 
						||
			value[index] = magnitude;
 | 
						||
		}
 | 
						||
		if (index_of_1) {
 | 
						||
			index = index_of_1;
 | 
						||
			magnitude = 1;
 | 
						||
			while (index--) {
 | 
						||
				magnitude /= base;
 | 
						||
				value[index] = magnitude;
 | 
						||
			}
 | 
						||
		}
 | 
						||
		value[index_of_1] = 1;
 | 
						||
 | 
						||
		if (intervening) {
 | 
						||
			for (index = 0; index < length; index++) {
 | 
						||
				symbol[index] = intervening + symbol[index];
 | 
						||
			}
 | 
						||
		}
 | 
						||
 | 
						||
		library_namespace.debug('magnitude array of base ' + base + ': ['
 | 
						||
				+ value + ']', 1, 'set_order_prefix');
 | 
						||
		library_namespace.debug('prefixes of base ' + base + ': [' + symbol
 | 
						||
				+ ']', 1, 'set_order_prefix');
 | 
						||
 | 
						||
		// cache 引入: symbol, value, length.
 | 
						||
 | 
						||
		return (
 | 
						||
		/**
 | 
						||
		 * 將數字轉為 K, M, G 等數量級(order of magnitude)表示方式。
 | 
						||
		 * 
 | 
						||
		 * @param {Number}number
 | 
						||
		 *            數字純量
 | 
						||
		 * @param {Number}digits
 | 
						||
		 *            to fixed digit
 | 
						||
		 * @type {String}
 | 
						||
		 * @return {String} 指定數量級(order of magnitude)表示方式
 | 
						||
		 * @requires to_fixed
 | 
						||
		 */
 | 
						||
		function(number, digits) {
 | 
						||
			if (typeof number === 'string')
 | 
						||
				number = parseFloat(number.replace(/[, ]/g, ''));
 | 
						||
			if (!number || isNaN(number))
 | 
						||
				return 0;
 | 
						||
 | 
						||
			var l = 0, r = length, i;
 | 
						||
			// 直接用比的。 inline binary search.
 | 
						||
			// while (l < (i = Math.floor((l + r) / 2))) {
 | 
						||
			while (l < (i = (l + r) >> 1)) {
 | 
						||
				library_namespace.debug('compare: ' + number + ', [' + i + ']'
 | 
						||
						+ value[i], 3, 'set_order_prefix');
 | 
						||
				if (number < value[i]) {
 | 
						||
					r = i;
 | 
						||
				} else {
 | 
						||
					l = i;
 | 
						||
				}
 | 
						||
			}
 | 
						||
			library_namespace.debug('index: [' + i + '] ' + value[i] + ', '
 | 
						||
					+ symbol[i], 2, 'set_order_prefix');
 | 
						||
 | 
						||
			l = number / value[i];
 | 
						||
			return to_fixed.call(l, isNaN(digits) || digits < 0 ? (r = Math
 | 
						||
					.floor(l)) < 10 ? 2 : r < 100 ? 1 : 0 : digits)
 | 
						||
					+ symbol[i];
 | 
						||
		});
 | 
						||
	}
 | 
						||
 | 
						||
	/**
 | 
						||
	 * 將數字轉為 K, M, G 等 metric prefix / SI prefix 表示方式,例如 6458 轉成 6.31 K。
 | 
						||
	 * 
 | 
						||
	 * @example <code>
 | 
						||
 | 
						||
	CeL.to_1000_prefix(12343454345);
 | 
						||
	CeL.to_1000_prefix('12,343,454,345');
 | 
						||
 | 
						||
	</code>
 | 
						||
	 * 
 | 
						||
	 * @returns
 | 
						||
	 * @see <a href="http://en.wikipedia.org/wiki/Metric_prefix"
 | 
						||
	 *      accessdate="2012/8/18 12:9">Metric prefix</a>, <a
 | 
						||
	 *      href="http://en.wikipedia.org/wiki/International_System_of_Units"
 | 
						||
	 *      accessdate="2012/8/18 12:11">International System of Units</a>, <a
 | 
						||
	 *      href="http://www.bipm.org/en/si/si_brochure/chapter3/prefixes.html"
 | 
						||
	 *      accessdate="2012/8/18 12:10">BIPM - SI prefixes</a>, <a
 | 
						||
	 *      href="http://bmanolov.free.fr/numbers_names.php"
 | 
						||
	 *      accessdate="2012/8/18 12:19">Names of LARGE and small Numbers</a>
 | 
						||
	 */
 | 
						||
	function to_1000_prefix() {
 | 
						||
		var s = 'yzafpnμm kMGTPEZY', i = s.indexOf(' ');
 | 
						||
		s = s.split('');
 | 
						||
		s[i] = '';
 | 
						||
		return set_order_prefix(s, 1000, i, ' ');
 | 
						||
	}
 | 
						||
 | 
						||
	/**
 | 
						||
	 * 將數字轉為 Ki, Mi, Gi 等 binary prefix 表示方式,例如 1024 轉成 1Ki。
 | 
						||
	 * 
 | 
						||
	 * @example <code>
 | 
						||
 | 
						||
	CeL.to_1024_prefix(12343454345);
 | 
						||
 | 
						||
	</code>
 | 
						||
	 * 
 | 
						||
	 * @returns
 | 
						||
	 * @see <a
 | 
						||
	 *      href="http://en.wikipedia.org/wiki/Binary_prefix#IEC_standard_prefixes"
 | 
						||
	 *      accessdate="2012/8/18 11:53">Binary prefix</a>
 | 
						||
	 */
 | 
						||
	function to_1024_prefix() {
 | 
						||
		return set_order_prefix(',Ki,Mi,Gi,Ti,Pi,Ei,Zi,Yi'.split(','), 1024, 0,
 | 
						||
				' ');
 | 
						||
	}
 | 
						||
 | 
						||
	// 不可以 `byte` 為變數名: JsDoc 會失會失效。
 | 
						||
	function to_KiB(bytes, type, use_KB) {
 | 
						||
		var expression = use_KB ? library_namespace.to_1000_prefix
 | 
						||
				: library_namespace.to_1024_prefix, b = bytes + ' byte'
 | 
						||
				+ (bytes > 1 ? 's' : '');
 | 
						||
		expression = expression(bytes) + 'B';
 | 
						||
 | 
						||
		if (type && type.toLowerCase() === 'html') {
 | 
						||
			expression = '<span title="' + b + '">' + expression + '</span>';
 | 
						||
		} else if (library_namespace.is_Object(type)) {
 | 
						||
			expression = {
 | 
						||
				span : expression,
 | 
						||
				title : b
 | 
						||
			};
 | 
						||
		} else if (type === '()') {
 | 
						||
			expression += ' (' + b + ')';
 | 
						||
		}
 | 
						||
 | 
						||
		return expression;
 | 
						||
	}
 | 
						||
	function to_KB(bytes, type) {
 | 
						||
		return to_KiB(bytes, type, true);
 | 
						||
	}
 | 
						||
 | 
						||
	// old alias: CeL.show_KiB(), CeL.show_KB()
 | 
						||
	_.to_KiB = to_KiB;
 | 
						||
	_.to_KB = to_KB;
 | 
						||
 | 
						||
	// TODO: accept '300K' as 300 KiB
 | 
						||
 | 
						||
	// 設定 lazy evaluation。
 | 
						||
	library_namespace.set_initializor(to_1000_prefix);
 | 
						||
	library_namespace.set_initializor(to_1024_prefix);
 | 
						||
 | 
						||
	// -----------------------------------------------------------------------------
 | 
						||
 | 
						||
	/**
 | 
						||
	 * for IE3: mode=1:不取空字串<br />
 | 
						||
	 * .split() appears from Internet Explorer 4.0
 | 
						||
	 * 
 | 
						||
	 * @see <a
 | 
						||
	 *      href="http://msdn.microsoft.com/en-us/library/s4esdbwz%28v=VS.85%29.aspx"
 | 
						||
	 *      accessdate="2010/4/16 20:4">Version Information (Windows Scripting -
 | 
						||
	 *      JScript)</a>
 | 
						||
	 */
 | 
						||
	function StringToArray(s, mode) {
 | 
						||
		var a = [], last = 0, i;
 | 
						||
		while ((i = s.indexOf(sp, last)) !== NOT_FOUND) {
 | 
						||
			if (mode === 0 || last !== i)
 | 
						||
				a[a.length] = s.slice(last, i);
 | 
						||
			last = i + 1;
 | 
						||
		}
 | 
						||
		if (mode === 0 || last !== s.length)
 | 
						||
			a[a.length] = s.slice(last);
 | 
						||
		return a;
 | 
						||
	}
 | 
						||
 | 
						||
	// for IE3: 去除s之空白,包括字與字之間的
 | 
						||
	function disposeSpace(s) {
 | 
						||
		if (!s)
 | 
						||
			return s;
 | 
						||
		var r = "", i, last;
 | 
						||
		while ((i = s.indexOf(' ', last)) !== NOT_FOUND)
 | 
						||
			r += s.slice(last, i), last = i + 1;
 | 
						||
		r += s.slice(last);
 | 
						||
		return r;
 | 
						||
	}
 | 
						||
 | 
						||
	// for IE3: 以label,mode:m置換s,先找到先贏
 | 
						||
	// 輸入t['$k']=..會有問題,需用t['\\$k']=..
 | 
						||
	function changeV(s, l, m) {
 | 
						||
		var i, r, re, t; // var I='';
 | 
						||
		if (!m)
 | 
						||
			m = 'g';
 | 
						||
		if (s && (t = l ? l : label))
 | 
						||
			for (i in t) {
 | 
						||
				// I+=', '+i+'='+t[i];
 | 
						||
				re = new RegExp(i, m);
 | 
						||
				// r=s.replace(re,t[i]);s=r;
 | 
						||
				s = s.replace(re, t[i]);
 | 
						||
			}
 | 
						||
		// pLog(I.substr(2));
 | 
						||
		// pLog('changeV:'+s);
 | 
						||
		return s;
 | 
						||
	}
 | 
						||
 | 
						||
	/**
 | 
						||
	 * <code>
 | 
						||
	// 以label置換s,先找到先贏
 | 
						||
	function changeV(s) {
 | 
						||
		for (var i, j = 0; j < labelN.length; j++)
 | 
						||
			if ((i = s.indexOf(labelN[j])) != NOT_FOUND)
 | 
						||
				s = s.slice(0, i) + labelV[j] + s.slice(i + labelN[j].length)
 | 
						||
				, j = 0; // search again from beginning
 | 
						||
		return s;
 | 
						||
	}
 | 
						||
	 </code>
 | 
						||
	 */
 | 
						||
 | 
						||
	_// JSDT:_module_
 | 
						||
	.get_Object_value = function(o) {
 | 
						||
		// if (Array.isArray(o)) return o;
 | 
						||
 | 
						||
		// if (!library_namespace.is_Object(o)) return;
 | 
						||
		var i, l = [];
 | 
						||
		for (i in o)
 | 
						||
			l.push(o[i]);
 | 
						||
		return l;
 | 
						||
	};
 | 
						||
 | 
						||
	_// JSDT:_module_
 | 
						||
	.
 | 
						||
	/**
 | 
						||
	 * 互換/reverse key/value pairs.
 | 
						||
	 * 
 | 
						||
	 * @example <code>
 | 
						||
	swap_key_value({A:1,B:2,s:4,t:[]}, [], /^[A-Z_\-\d]+$/) === [,'A','B']
 | 
						||
	</code>
 | 
						||
	 * @param {Object|object}pairs
 | 
						||
	 *            key/value pairs
 | 
						||
	 * @param {Object|Array}[base]
 | 
						||
	 *            把互換結果放在 base
 | 
						||
	 * @param {RegExp}[key_filter]
 | 
						||
	 *            僅放入符合的 key
 | 
						||
	 * @returns
 | 
						||
	 */
 | 
						||
	swap_key_value = function(pairs, base, key_filter) {
 | 
						||
		if (!base)
 | 
						||
			base = {};
 | 
						||
 | 
						||
		var k;
 | 
						||
		if (library_namespace.is_type(key_filter, 'RegExp')) {
 | 
						||
			for (k in pairs)
 | 
						||
				if (key_filter.test(k))
 | 
						||
					base[pairs[k]] = k;
 | 
						||
		} else
 | 
						||
			for (k in pairs)
 | 
						||
				base[pairs[k]] = k;
 | 
						||
 | 
						||
		return base;
 | 
						||
	};
 | 
						||
 | 
						||
	if (library_namespace.dependency_chain)
 | 
						||
		_.dependency_chain = library_namespace.dependency_chain;
 | 
						||
 | 
						||
	/**
 | 
						||
	 * new_Array=[,,]: 可以使用 Array 常值中的空白元素來建立零星稀疏的陣列。
 | 
						||
	 */
 | 
						||
 | 
						||
	// ---------------------------------------------------------------------//
 | 
						||
	// UTF-8 char and bytes.
 | 
						||
	/**
 | 
						||
	 * 計算指定 UTF-8 char code 之 bytes。
 | 
						||
	 * 
 | 
						||
	 * TODO:<br />
 | 
						||
	 * 加快速度。
 | 
						||
	 * 
 | 
						||
	 * @param {Number}code
 | 
						||
	 *            指定之 UTF-8 char code。
 | 
						||
	 * @returns {Number} 指定 UTF-8 char code 之 bytes。
 | 
						||
	 * @see https://en.wikipedia.org/wiki/UTF-8#Description
 | 
						||
	 */
 | 
						||
	function bytes_of_UTF8_char_code(code) {
 | 
						||
		return code < 0x0080 ? 1 : code < 0x0800 ? 2 : code < 0x10000 ? 3
 | 
						||
				: code < 0x200000 ? 4 : code < 0x4000000 ? 5
 | 
						||
						: code < 0x80000000 ? 6 : 7;
 | 
						||
	}
 | 
						||
 | 
						||
	/**
 | 
						||
	 * 計算指定 UTF-8 text 之 bytes。
 | 
						||
	 * 
 | 
						||
	 * TODO:<br />
 | 
						||
	 * use Buffer.byteLength
 | 
						||
	 * 
 | 
						||
	 * @param {String}text
 | 
						||
	 *            指定之 UTF-8 text。
 | 
						||
	 * @returns {Number} 指定 UTF-8 text 之 bytes。
 | 
						||
	 */
 | 
						||
	function byte_count_of_UTF8(text) {
 | 
						||
		var i = 0, length = text.length, bytes = 0;
 | 
						||
		for (; i < length; i++)
 | 
						||
			bytes += bytes_of_UTF8_char_code(text.charCodeAt(i));
 | 
						||
		return bytes;
 | 
						||
	}
 | 
						||
 | 
						||
	/**
 | 
						||
	 * 將 UTF-8 text 截成指定 byte 長度。
 | 
						||
	 * 
 | 
						||
	 * @param {String}text
 | 
						||
	 *            指定之 UTF-8 text。
 | 
						||
	 * @param {Number}byte_length
 | 
						||
	 *            指定之 byte 長度。
 | 
						||
	 * @returns {String} UTF-8 text, length <= byte_length.
 | 
						||
	 */
 | 
						||
	function cut_UTF8_by_bytes(text, byte_length) {
 | 
						||
		var i = 0, length = text.length;
 | 
						||
		for (; byte_length > 0 && i < length; i++) {
 | 
						||
			byte_length -= bytes_of_UTF8_char_code(text.charCodeAt(i));
 | 
						||
			if (byte_length < 0)
 | 
						||
				i--;
 | 
						||
		}
 | 
						||
		return i === length ? text : text.slice(0, i);
 | 
						||
	}
 | 
						||
 | 
						||
	_.bytes_of_char_code = bytes_of_UTF8_char_code;
 | 
						||
	_.byte_count = byte_count_of_UTF8;
 | 
						||
	_.cut_by_bytes = cut_UTF8_by_bytes;
 | 
						||
 | 
						||
	// ---------------------------------------------------------------------//
 | 
						||
	// for bencode & torrent file data.
 | 
						||
 | 
						||
	/**
 | 
						||
	 * [ key_1, value_1, key_2, value_2, key_3, value_3 ]<br /> →<br /> {
 | 
						||
	 * key_1: value_1, key_2: value_2, key_3: value_3 }
 | 
						||
	 * 
 | 
						||
	 * @param {Array}list
 | 
						||
	 *            list to convert
 | 
						||
	 * 
 | 
						||
	 * @returns {Object} pair Object converted
 | 
						||
	 * @since 2014/7/21 23:17:32
 | 
						||
	 */
 | 
						||
	function list_to_Object(list) {
 | 
						||
		var i = 0, length = list.length, pair = Object.create(null);
 | 
						||
		if (length % 2 !== 0)
 | 
						||
			library_namespace.warn('list_to_Object: The length (' + length
 | 
						||
					+ ') of list is not an even number!');
 | 
						||
 | 
						||
		for (; i < length; i += 2) {
 | 
						||
			if (typeof list[i] !== 'string')
 | 
						||
				library_namespace.warn(
 | 
						||
				// Set key to non-string type. e.g., integer
 | 
						||
				'Set (' + (typeof list[i]) + ') [' + list[i] + '] as key.');
 | 
						||
			if (list[i] in pair)
 | 
						||
				library_namespace.warn('Duplicated key: [' + list[i] + ']');
 | 
						||
 | 
						||
			library_namespace.debug('pair[' + list[i] + '] = [' + list[i + 1]
 | 
						||
					+ ']', 3);
 | 
						||
			pair[list[i]] = list[i + 1];
 | 
						||
		}
 | 
						||
 | 
						||
		return pair;
 | 
						||
	}
 | 
						||
 | 
						||
	/**
 | 
						||
	 * parse bencode data
 | 
						||
	 * 
 | 
						||
	 * @param {String}data
 | 
						||
	 *            bencode data
 | 
						||
	 * @param {Object}[status]
 | 
						||
	 *            get the parse status
 | 
						||
	 * @param {Boolean}[is_ASCII]
 | 
						||
	 *            若設定為真,則當作 ASCII 處理。若設定為假,則當作 UTF-8 處理。
 | 
						||
	 * 
 | 
						||
	 * @returns
 | 
						||
	 * 
 | 
						||
	 * @see https://zh.wikipedia.org/wiki/Bencode
 | 
						||
	 * 
 | 
						||
	 * @since 2014/7/21 23:17:32
 | 
						||
	 */
 | 
						||
	function parse_bencode(data, status, is_ASCII) {
 | 
						||
 | 
						||
		function make_end() {
 | 
						||
			// assert: object_now === queue.pop()
 | 
						||
			if ((tmp = object_now) !== queue.pop()) {
 | 
						||
				library_namespace.error('Bad data structure!');
 | 
						||
				// assert: queue.length === 0
 | 
						||
				if (queue !== object_now)
 | 
						||
					// 回存。
 | 
						||
					queue.push(object_now);
 | 
						||
			} else {
 | 
						||
				if (tmp.d)
 | 
						||
					tmp = list_to_Object(tmp);
 | 
						||
				// assert: queue.length > 0
 | 
						||
				(object_now = queue.at(-1)).push(tmp);
 | 
						||
			}
 | 
						||
		}
 | 
						||
 | 
						||
		// 盡可能不動到 data,因為 data 可能很大。
 | 
						||
		var index = 0, tmp, queue = [],
 | 
						||
		// 即使在 data 有缺陷的情況下,也盡可能解析出資料。
 | 
						||
		// 因此先將 data 設定成 list。
 | 
						||
		object_now = queue,
 | 
						||
		// 為了多行程,因此這些 pattern 應該放在函數內,不可為 global 為其他行程存取。
 | 
						||
		PATTERN_controller = /(.*?)([ldei\d])/g,
 | 
						||
		// 為了盡快 match,所以盡可能選擇可能 match 的 pattern,之後再來檢查是否相符。
 | 
						||
		PATTERN_integer = /(-?\d*)(\D)/g, PATTERN_string_length = /(\d*)(\D)/g;
 | 
						||
 | 
						||
		for (;;) {
 | 
						||
			PATTERN_controller.lastIndex = index;
 | 
						||
			if (!(tmp = PATTERN_controller.exec(data))) {
 | 
						||
				if (index < data.length)
 | 
						||
					library_namespace.error('Last data skipped! ('
 | 
						||
							+ data.slice(index) + ')');
 | 
						||
				break;
 | 
						||
			}
 | 
						||
 | 
						||
			if (tmp[1]) {
 | 
						||
				index += tmp[1].length;
 | 
						||
				// control char should be next char.
 | 
						||
				library_namespace.error('Some data skipped! (' + tmp[1] + ')');
 | 
						||
			}
 | 
						||
 | 
						||
			switch (tmp[2]) {
 | 
						||
			case 'l':
 | 
						||
				// list 列表
 | 
						||
			case 'd':
 | 
						||
				// dictionary 關聯數組
 | 
						||
				++index;
 | 
						||
				queue.push(object_now = []);
 | 
						||
				if (tmp[2] === 'd')
 | 
						||
					object_now.d = true;
 | 
						||
				break;
 | 
						||
			case 'e':
 | 
						||
				// ending
 | 
						||
				++index;
 | 
						||
				make_end();
 | 
						||
				break;
 | 
						||
 | 
						||
			case 'i':
 | 
						||
				// integer 整數
 | 
						||
				PATTERN_integer.lastIndex = ++index;
 | 
						||
				tmp = PATTERN_integer.exec(data);
 | 
						||
				if (tmp && tmp[2] === 'e') {
 | 
						||
					// 確定為 /i\d+e/
 | 
						||
					if (!tmp[1])
 | 
						||
						library_namespace
 | 
						||
								.error('No integer specified ("ie" instead of /i\d+e/)!');
 | 
						||
					else if (PATTERN_integer.lastIndex !== index
 | 
						||
							+ tmp[0].length)
 | 
						||
						library_namespace.error('Some integer data skipped! ('
 | 
						||
								+ data.slice(index, PATTERN_integer.lastIndex
 | 
						||
										- tmp[0].length) + ')');
 | 
						||
					object_now.push(parseInt(tmp[1]));
 | 
						||
					index = PATTERN_integer.lastIndex;
 | 
						||
				} else {
 | 
						||
					// fatal error
 | 
						||
					library_namespace.error('Bad integer format! Exit parse!');
 | 
						||
					index = data.length;
 | 
						||
				}
 | 
						||
				break;
 | 
						||
 | 
						||
			default:
 | 
						||
				// assert: 接下來是 string (\d+:.+) 字串
 | 
						||
				PATTERN_string_length.lastIndex = index;
 | 
						||
				tmp = PATTERN_string_length.exec(data);
 | 
						||
				if (tmp && tmp[2] === ':') {
 | 
						||
					// 確定為 /\d+:/
 | 
						||
					if (!tmp[1] || !(tmp[1] | 0))
 | 
						||
						library_namespace.error('No string length specified! ('
 | 
						||
								+ tmp[1] + ')');
 | 
						||
					else if (PATTERN_string_length.lastIndex !== index
 | 
						||
							+ tmp[0].length)
 | 
						||
						library_namespace.error('Some string data skipped! ('
 | 
						||
								+ data.slice(index,
 | 
						||
										PATTERN_string_length.lastIndex
 | 
						||
												- tmp[0].length) + ')');
 | 
						||
					if ((index = PATTERN_string_length.lastIndex)
 | 
						||
							+ (tmp = tmp[1] | 0) > data.length)
 | 
						||
						library_namespace.error(
 | 
						||
						//
 | 
						||
						'The end of string is beyond the end of data! (ask '
 | 
						||
						// remaining
 | 
						||
						+ (index + tmp) + ' - data left ' + data.length
 | 
						||
								+ ' = lost ' + (index + tmp - data.length)
 | 
						||
								+ ')');
 | 
						||
					// tmp: length of string.
 | 
						||
					library_namespace.debug(index + '+' + tmp, 3);
 | 
						||
					if (is_ASCII) {
 | 
						||
						object_now.push(data.substr(index, tmp));
 | 
						||
						index += tmp;
 | 
						||
					} else {
 | 
						||
						// 對 UTF-8 (non-ASCII string) 特別處理:
 | 
						||
						// 此時因取得 Unicode,所指定之 length >= 實際 length。
 | 
						||
						tmp = cut_UTF8_by_bytes(data.substr(index, tmp), tmp);
 | 
						||
						object_now.push(tmp);
 | 
						||
						index += tmp.length;
 | 
						||
					}
 | 
						||
				} else {
 | 
						||
					// fatal error
 | 
						||
					library_namespace.error('Bad string format! Exit parse!');
 | 
						||
					index = data.length;
 | 
						||
				}
 | 
						||
			}
 | 
						||
		}
 | 
						||
 | 
						||
		if (queue.length > 1)
 | 
						||
			library_namespace.warn('Illegal data: 有錯誤或缺陷!');
 | 
						||
		while (queue.length > 1 && Array.isArray(queue.at(-1)))
 | 
						||
			make_end();
 | 
						||
 | 
						||
		if (status)
 | 
						||
			if (queue.length !== 1)
 | 
						||
				status.error = true;
 | 
						||
 | 
						||
		return queue.length === 1 ? queue[0] : queue;
 | 
						||
	}
 | 
						||
 | 
						||
	/**
 | 
						||
	 * parse torrent file data
 | 
						||
	 * 
 | 
						||
	 * @example <code>
 | 
						||
 | 
						||
	 // @ JScript
 | 
						||
	CeL.run('data', function () {
 | 
						||
		// http://www.ubuntu.com/download/alternative-downloads
 | 
						||
		CeL.log(CeL.parse_torrent('http://releases.ubuntu.com/14.04/ubuntu-14.04-desktop-i386.iso.torrent', true));
 | 
						||
	});
 | 
						||
 | 
						||
	 * </code>
 | 
						||
	 * 
 | 
						||
	 * @param {String}path
 | 
						||
	 *            torrent file path.
 | 
						||
	 * @param {Boolean}name_only
 | 
						||
	 *            get the torrent name only.
 | 
						||
	 * 
 | 
						||
	 * @returns {Object} torrent file data
 | 
						||
	 * @since 2014/7/21 23:17:32
 | 
						||
	 */
 | 
						||
	function parse_torrent(path, name_only) {
 | 
						||
		// 注意:此方法不可跨 domain!
 | 
						||
		// JScript 下,XMLHttpRequest 會將檔案當作 UTF-8 讀取。
 | 
						||
		var data = library_namespace.get_file(path);
 | 
						||
		var status = Object.create(null);
 | 
						||
		if (!data || data.charAt(0) !== 'd') {
 | 
						||
			library_namespace.error((data ? 'Illegal' : 'Cannot get')
 | 
						||
					+ ' torrent data of [' + path + ']!');
 | 
						||
			return;
 | 
						||
		}
 | 
						||
		library_namespace.debug(data, 4);
 | 
						||
 | 
						||
		if (name_only) {
 | 
						||
			// a fast way to get torrent name.
 | 
						||
			var PATTERN_name = /4:name(\d{1,4}):/, matched = data
 | 
						||
					.match(PATTERN_name), index;
 | 
						||
			if (matched && (matched = matched[1] | 0) > 0) {
 | 
						||
				library_namespace.debug('[' + path + '] length: ' + matched, 3);
 | 
						||
				// fix for non-ASCII chars, it will be change to Unicode,
 | 
						||
				// and the real length <= length specified.
 | 
						||
				if (false) {
 | 
						||
					// assert: 'piece length' 恰好在 PATTERN_name 之後。
 | 
						||
					index = data.indexOf('12:piece lengthi')
 | 
						||
							- PATTERN_name.lastIndex;
 | 
						||
					return data.substr(PATTERN_name.lastIndex, index > 0 ? Math
 | 
						||
							.min(index, matched) : matched);
 | 
						||
				}
 | 
						||
				return cut_UTF8_by_bytes(data.substr(PATTERN_name.lastIndex,
 | 
						||
						matched), matched);
 | 
						||
			}
 | 
						||
			return;
 | 
						||
		}
 | 
						||
 | 
						||
		data = parse_bencode(data, status);
 | 
						||
 | 
						||
		return data;
 | 
						||
	}
 | 
						||
 | 
						||
	_.list_to_Object = list_to_Object;
 | 
						||
	_.parse_bencode = parse_bencode;
 | 
						||
	_.parse_torrent = parse_torrent;
 | 
						||
 | 
						||
	// ---------------------------------------------------------------------//
 | 
						||
 | 
						||
	function is_natural(value) {
 | 
						||
		return value >= 1 && Math.floor(value) === value;
 | 
						||
	}
 | 
						||
	// is_non_negative
 | 
						||
	function is_natural_or_0(value) {
 | 
						||
		return value >= 0 && Math.floor(value) === value;
 | 
						||
	}
 | 
						||
	function is_integer(value) {
 | 
						||
		return Math.floor(value) === value;
 | 
						||
	}
 | 
						||
	import_options.filters = {
 | 
						||
		number : {
 | 
						||
			range : function in_range(value) {
 | 
						||
				return (typeof this[0] !== 'number' || this[0] <= value)
 | 
						||
						&& (typeof this[1] !== 'number' || value <= this[1]);
 | 
						||
			},
 | 
						||
 | 
						||
			// 自然數 natural numbers ℕ*, ℕ+, ℕ>0, ℤ+
 | 
						||
			natural : is_natural,
 | 
						||
			'ℕ' : is_natural,
 | 
						||
			'natural+0' : is_natural_or_0,
 | 
						||
			// 'ℕ0'
 | 
						||
			'ℕ+0' : is_natural_or_0,
 | 
						||
			// 整數
 | 
						||
			integer : is_integer,
 | 
						||
			'ℤ' : is_integer
 | 
						||
		},
 | 
						||
		string : {
 | 
						||
			IPv4 : /^[12]?\d{1,2}\.[12]?\d{1,2}\.[12]?\d{1,2}\.[12]?\d{1,2}$/,
 | 
						||
 | 
						||
			// RFC2822 :
 | 
						||
			// http://regexlib.com/DisplayPatterns.aspx
 | 
						||
			// /^(?:[a-z0-9!#$%&'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+\/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])$/,
 | 
						||
			email :
 | 
						||
			// http://www.regular-expressions.info/email.html
 | 
						||
			// /^[a-z0-9!#$%&'*+\/=?^_`{|}~-]+(\.[a-z0-9!#$%&'*+\/=?^_`{|}~-]+)*@([a-z0-9]([a-z0-9-]*[a-z0-9])?\.)+([a-z]{2}|com|org|net|gov|mil|biz|info|mobi|name|aero|jobs|museum)\b$/i,
 | 
						||
			/^[a-z0-9+_~-]+(\.[a-z0-9+_~-]+)*@([a-z\d]([a-z\d-]*[a-z\d])?\.)+([a-z]{2}|com|org|net)\b$/i,
 | 
						||
 | 
						||
			// 十進位小數
 | 
						||
			decimal : /^[+\-]?(?:\d+|\d*\.\d+)$/,
 | 
						||
			// 數字
 | 
						||
			digits : library_namespace.is_digits
 | 
						||
		}
 | 
						||
	};
 | 
						||
 | 
						||
	/**
 | 
						||
	 * @inner
 | 
						||
	 */
 | 
						||
	function string_options_to_normalizer(string_normalizer) {
 | 
						||
		var normalizer = Object.create(null);
 | 
						||
 | 
						||
		string_normalizer.split('|').forEach(function(type) {
 | 
						||
			var matched = type.match(/^([a-z]+):([\s\S]+)$/);
 | 
						||
			if (!matched) {
 | 
						||
				normalizer[type] = true;
 | 
						||
				return;
 | 
						||
			}
 | 
						||
 | 
						||
			type = matched[1];
 | 
						||
			// condition
 | 
						||
			var _normalizer = matched[2];
 | 
						||
			if (_normalizer in import_options.filters[type]) {
 | 
						||
				_normalizer = import_options.filters[type][_normalizer];
 | 
						||
 | 
						||
			} else if (type === 'number' && (matched = _normalizer.match(
 | 
						||
			// @see CeL.date.parse_period.PATTERN
 | 
						||
			// [ all, min, max ]
 | 
						||
			/([+\-]?\d+(?:\.\d+)?)?\s*[–~-—─~〜﹣至]\s*([+\-]?\d+(?:\.\d+)?)?/))) {
 | 
						||
				_normalizer = import_options.filters[type]
 | 
						||
				// this: [ min, max ]
 | 
						||
				.range.bind([ matched[1] && +matched[1],
 | 
						||
				//
 | 
						||
				matched[2] && +matched[2] ]);
 | 
						||
 | 
						||
			} else if (type === 'string') {
 | 
						||
				matched = _normalizer.match(library_namespace.PATTERN_RegExp);
 | 
						||
				if (matched) {
 | 
						||
					_normalizer = new RegExp(matched[1], matched[2]);
 | 
						||
				} else {
 | 
						||
					_normalizer = _normalizer.split(';');
 | 
						||
				}
 | 
						||
 | 
						||
			} else {
 | 
						||
				library_namespace.warn('import_options: Invalid normalizer: '
 | 
						||
				//
 | 
						||
				+ _normalizer);
 | 
						||
			}
 | 
						||
 | 
						||
			normalizer[type] = _normalizer;
 | 
						||
		});
 | 
						||
 | 
						||
		return normalizer;
 | 
						||
	}
 | 
						||
 | 
						||
	/**
 | 
						||
	 * 將 options 裡面可使用之選項(依照 options_normalizer 之定義),篩選、正規化並提取至 target。
 | 
						||
	 * 
 | 
						||
	 * @param {Object}options
 | 
						||
	 * @param {Object|String|Function}options_normalizer
 | 
						||
	 *            options allowed
 | 
						||
	 * @param {Object}[target]
 | 
						||
	 *            target options to modify
 | 
						||
	 * @returns
 | 
						||
	 * 
 | 
						||
	 * @see function verify_arg(key, value)
 | 
						||
	 * @see function generate_argument_condition(condition) @ CeL.application.net.work_crawler.arguments
 | 
						||
	 * @see _.default_verify_pattern @ CeL.interact.form.select_input
 | 
						||
	 */
 | 
						||
	function import_options(options, options_normalizer, target) {
 | 
						||
		options = library_namespace.setup_options(options);
 | 
						||
		if (!target) {
 | 
						||
			target = Object.create(null);
 | 
						||
		}
 | 
						||
 | 
						||
		for ( var key in options) {
 | 
						||
			var value = options[key];
 | 
						||
			var normalizer = options_normalizer && options_normalizer[key];
 | 
						||
			if (typeof normalizer === 'string') {
 | 
						||
				// e.g., 'boolean|string:changed;multi_parts_changed'
 | 
						||
				normalizer = string_options_to_normalizer(normalizer);
 | 
						||
				// console.trace(normalizer);
 | 
						||
			}
 | 
						||
 | 
						||
			if (typeof normalizer === 'object') {
 | 
						||
				var type = Array.isArray(value) ? 'Array'
 | 
						||
				//
 | 
						||
				: library_namespace.is_RegExp(value) ? 'RegExp'
 | 
						||
				//
 | 
						||
				: library_namespace.is_Date(value) ? 'Date' : null;
 | 
						||
				if (!type || !(type in normalizer)
 | 
						||
						&& !((type = type.toLowerCase()) in normalizer)) {
 | 
						||
					type = typeof value;
 | 
						||
				}
 | 
						||
 | 
						||
				if (type in normalizer) {
 | 
						||
					normalizer = normalizer[type];
 | 
						||
				} else {
 | 
						||
					// invalid value type
 | 
						||
					continue;
 | 
						||
				}
 | 
						||
			}
 | 
						||
 | 
						||
			if (normalizer === undefined && options_normalizer) {
 | 
						||
				// invalid key / parameter name
 | 
						||
				continue;
 | 
						||
			}
 | 
						||
 | 
						||
			if (typeof normalizer === 'function') {
 | 
						||
				value = normalizer(value);
 | 
						||
			} else if (!fit_filter(normalizer, value)) {
 | 
						||
				// treat normalizer as filter
 | 
						||
				// invalid value
 | 
						||
				continue;
 | 
						||
			}
 | 
						||
 | 
						||
			if (value !== import_options.INVALID
 | 
						||
			// && value !== undefined
 | 
						||
			) {
 | 
						||
				target[key] = value;
 | 
						||
			}
 | 
						||
		}
 | 
						||
 | 
						||
		// console.trace(target);
 | 
						||
		return target;
 | 
						||
	}
 | 
						||
 | 
						||
	import_options.INVALID = {
 | 
						||
		invalid_value : true
 | 
						||
	};
 | 
						||
 | 
						||
	_.import_options = import_options;
 | 
						||
 | 
						||
	/**
 | 
						||
	 * validity value
 | 
						||
	 * 
 | 
						||
	 * generate_filter: fit_filter.bind(null, filter)
 | 
						||
	 * 
 | 
						||
	 * @param {Function|RegExp|Array}filter
 | 
						||
	 * @param value
 | 
						||
	 *            value to test
 | 
						||
	 * 
 | 
						||
	 * @returns value fits the filter
 | 
						||
	 * 
 | 
						||
	 * @see function receive() @ CeL.application.net.wiki.page
 | 
						||
	 * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/text#pattern
 | 
						||
	 */
 | 
						||
	function fit_filter(filter, value) {
 | 
						||
		// if (filter === true) return true;
 | 
						||
		if (typeof filter === 'boolean' || filter === null
 | 
						||
				|| typeof filter === 'undefined')
 | 
						||
			return filter;
 | 
						||
 | 
						||
		// 驗證 pattern
 | 
						||
		if (library_namespace.is_RegExp(filter))
 | 
						||
			return filter.test(value);
 | 
						||
 | 
						||
		if (typeof filter === 'function')
 | 
						||
			return filter(value);
 | 
						||
 | 
						||
		if (typeof filter === 'string') {
 | 
						||
			return filter === value;
 | 
						||
			// return filter.includes(value);
 | 
						||
			// return String(value).includes(filter);
 | 
						||
		}
 | 
						||
 | 
						||
		// e.g., ['A','B','C']
 | 
						||
		if (Array.isArray(filter))
 | 
						||
			return filter.includes(value);
 | 
						||
 | 
						||
		if (false && library_namespace.is_Object(filter))
 | 
						||
			return value in filter;
 | 
						||
 | 
						||
		throw new TypeError('Invalid filter');
 | 
						||
	}
 | 
						||
 | 
						||
	_.fit_filter = fit_filter;
 | 
						||
 | 
						||
	// ---------------------------------------------------------------------//
 | 
						||
 | 
						||
	return (_// JSDT:_module_
 | 
						||
	);
 | 
						||
}
 |