PageSourceSearch

https://sellersprite.ai/assets/js/stream/js/stream-v1.js

js sellersprite.ai collected 2026-09-24 13:04:54 UTC 74,672 bytes, 1,879 lines download raw bytes

1/**
2 * @name Uploader.js
3 * @author Jiang
4 * @create	2012-12-20
5 * @version 0.1
6 * @description	The Annouse funtion for HTML5/FLASH/FORM upload method. The
7 * 	function will autoly to choose the property method to ajust to client
8 *  Browswer. This js function mainly borrow from youku.com's uploader.min.js
9 *  and try to re-create it for fullfiting my requirement. 
10 * @example
11 * 		1. new Stream();
12 * 		2. var cfg = {
13 * 				extFilters : [".txt", ".gz"],
14 * 				fileFieldName : "FileData"
15 * 			};
16 * 		   new Stream(cfg);
17 */ 
18(function(){
19	var Provider, nIdCount = 0, aOtherBrowsers = ["Maxthon", "SE 2.X", "QQBrowser"],
20		nZero = 0, sOneSpace = " ", sLBrace = "{", sRBrace = "}",
21		ga = /(~-(\d+)-~)/g, rLBrace = /\{LBRACE\}/g, rRBrace = /\{RBRACE\}/g,
22		ea = {
23			"&" : "&",
24			"<" : "&lt;",
25			">" : "&gt;",
26			'"' : "&quot;",
27			"'" : "&#x27;",
28			"/" : "&#x2F;",
29			"`" : "&#x60;"
30		}, pa = Array.isArray && /\{\s*\[(?:native code|function)\]\s*\}/i.test(Array.isArray)
31			? Array.isArray
32			: function(a) {return "array" === fToString(a)},
33		sStreamMessagerId = "i_stream_message_container",
34		sCellFileTemplate = '<b class="stream-uploading-ico"></b>' +
35					'<div class="stream-file-name"><strong></strong></div>' +
36					'<div class="stream-process">' +
37					'	<a class="stream-cancel" href="javascript:void(0)">\u5220\u9664</a>' +
38					'	<span class="stream-process-bar"><span style="width: 0%;"></span></span>' +
39					'	<span class="stream-percent">0%</span>' +
40					'</div>' +
41					'<div class="stream-cell-infos">' +
42					'	<span class="stream-cell-info">\u901f\u5ea6\uff1a<em class="stream-speed"></em></span>' +
43					'	<span class="stream-cell-info">\u5df2\u4e0a\u4f20\uff1a<em class="stream-uploaded"></em></span>' +
44					'	<span class="stream-cell-info">\u5269\u4f59\u65f6\u95f4\uff1a<em class="stream-remain-time"></em></span>' +
45					'</div>',
46		sTotalContainer = '<div id="#totalContainerId#" class="stream-total-tips">' +
47			'	\u4e0a\u4f20\u603b\u8fdb\u5ea6\uff1a<span class="stream-process-bar"><span style="width: 0%;"></span></span>' +
48			'	<span class="stream-percent">0%</span>\uff0c\u5df2\u4e0a\u4f20<strong class="_stream-total-uploaded">&nbsp;</strong>' +
49			'	\uff0c\u603b\u6587\u4ef6\u5927\u5c0f<strong class="_stream-total-size">&nbsp;</strong>' +
50			'</div>',
51		sFilesContainer	= '<div class="stream-files-scroll" style="height: #filesQueueHeight#px;"><ul id="#filesContainerId#"></ul></div>';
52	
53	function fGenerateId(prefix) {
54		var b = (new Date).getTime() + "_01v_" + ++nIdCount;
55		return prefix ? prefix + "_" + b : b;
56	}
57	function fGetRandom() {
58		return (new Date).getTime().toString().substring(8);
59	}
60	function fExtend(a, b){
61		var c = 2 < arguments.length ? [arguments[2]] : null;
62		return function(){
63			var d = "string" === typeof a ? b[a] : a,e=c ? [arguments[0]].concat(c) : arguments;
64			return d.apply(b||d, e);
65		};
66	}
67	
68	function fAddEventListener(a, b, c) {
69		a.addEventListener ? a.addEventListener(b, c, !1) : a.attachEvent ? a
70				.attachEvent("on" + b, c) : a["on" + b] = c;
71	}
72	
73	function fRemoveEventListener(a, b, c) {
74		a.removeEventListener ? a.removeEventListener(b, c, !1) : a.detachEvent
75				? a.detachEvent("on" + b, c)
76				: a["on" + b] = null;
77	}
78	
79	function fToString(a) {
80		var b = {
81			"undefined" : "undefined",
82			number : "number",
83			"boolean" : "boolean",
84			string : "string",
85			"[object Function]" : "function",
86			"[object RegExp]" : "regexp",
87			"[object Array]" : "array",
88			"[object Date]" : "date",
89			"[object Error]" : "error"
90		};
91		return b[typeof a] || b[Object.prototype.toString.call(a)] || (a ? "object" : "null");
92	}
93	
94	function fAddVars(json, url, c) {
95		var _array = [], _sep = "&", f = function(json, c) {
96			var e = url ? /\[\]$/.test(url) ? url : url + "[" + c + "]" : c;
97			"undefined" != e && "undefined" != c
98				&& _array.push("object" === typeof json
99							? fAddVars(json, e, !0)
100							: "[object Function]" === Object.prototype.toString.call(json)
101								? encodeURIComponent(e) + "=" + encodeURIComponent(json())
102								: encodeURIComponent(e) + "=" + encodeURIComponent(json))
103		};
104		if (!c && url)
105			_sep = /\?/.test(url) ? /\?$/.test(url) ? "" : "&" : "?",
106			_array.push(url),
107			_array.push(fAddVars(json));
108		else if ("[object Array]" === Object.prototype.toString.call(json)
109				&& "undefined" != typeof json)
110			for (var g = 0, c = json.length; g < c; ++g)
111				f(json[g], g);
112		else if ("undefined" != typeof json && null !== json && "object" === typeof json)
113			for (g in json)
114				f(json[g], g);
115		else
116			_array.push(encodeURIComponent(url) + "=" + encodeURIComponent(json));
117		return _array.join(_sep).replace(/^&/, "").replace(/%20/g, "+")
118	}
119	
120	function fMergeJson(base, extend) {
121		var result = {};
122		for (var attr in base)
123			result[attr] = base[attr];
124		for (var attr in extend)
125			result[attr] = extend[attr];
126		return result;
127	}
128	
129	function fAddClass(element, klass) {
130		fHasClass(element, klass) || (element.className += " " + klass);
131	}
132	
133	function fHasClass(element, klass) {
134		return RegExp("(^| )" + klass + "( |$)").test(element.className);
135	}
136	
137	function fRemoveClass(element, klass) {
138		element && (element.className = element.className.replace(RegExp("(^| )" + klass + "( |$)"), " ").replace(/^\s+|\s+$/g, ""));
139	}
140	
141	function fContains(container, klass) {
142		if (!container)
143			return [];
144		if (container.querySelectorAll)
145			return container.querySelectorAll("." + klass);
146		for (var c = [], eles = container.getElementsByTagName("*"), e = eles.length, f = 0; f < e; f++)
147			fHasClass(eles[f], klass) && c.push(eles[f]);
148		return c;
149	}
150	
151	function fCreateContentEle(content) {
152		var b = document.createElement("div");
153		b.innerHTML = content;
154		content = b.childNodes;
155		return content[0].parentNode.removeChild(content[0]);
156	}
157	
158	function fShowMessage(msg, warning) {
159		var o = document.getElementById(sStreamMessagerId);
160		o && (o.innerHTML += "<br>" + (!!warning ? ("<span style='color:red;'>" + msg + "</span>"): msg)) && (o.scrollTop = o.scrollHeight);
161	}
162	
163	function fMessage(msg, VarVals, c, d) {
164		for (var nLIndex, nRIndex, sepIndex, argName, secondVar, s = [], _argName, length = msg.length;;) {
165			nLIndex = msg.lastIndexOf(sLBrace, length);
166			if (0 > nLIndex)
167				break;
168			nRIndex = msg.indexOf(sRBrace, nLIndex);
169			if (nLIndex + 1 >= nRIndex)
170				break;
171			argName = _argName = msg.substring(nLIndex + 1, nRIndex);
172			secondVar = null;
173			sepIndex = argName.indexOf(sOneSpace);
174			-1 < sepIndex && (secondVar = argName.substring(sepIndex + 1), argName = argName.substring(0, sepIndex));
175			sepIndex = VarVals[argName];
176			c && (sepIndex = c(argName, sepIndex, secondVar));
177			"undefined" === typeof sepIndex && (sepIndex = "~-" + s.length + "-~", s.push(_argName));
178			msg = msg.substring(0, nLIndex) + sepIndex + msg.substring(nRIndex + 1);
179			d || (length = nLIndex - 1);
180		}
181		return msg.replace(ga, function(msg, VarVals, c) {
182					return sLBrace + s[parseInt(c, 10)] + sRBrace
183				}).replace(rLBrace, sLBrace).replace(rRBrace, sRBrace);
184	}
185	
186	function fIsObjOrFun(a, b) {
187		var c = typeof a;
188		return a && ("object" === c || !b && ("function" === c || "function" === fToString(a))) || !1;
189	}
190	function fIsNumber(val) {
191		return "number" === typeof val && isFinite(val);
192	}
193	function fIsArray(val) {
194		return "array" === fToString(val);
195	}
196	function fGetStyle(el,name) { 
197		if (window.getComputedStyle)
198			return window.getComputedStyle(el, null)[name];
199		else
200			return el.currentStyle[name]; 
201	}
202	function fGetWidth(el) { 
203		var val = el.offsetWidth, which = ['Left', 'Right']; 
204		// display is none 
205		if(val === 0) return 0; 
206
207		for(var i = 0, a; a = which[i++];) { 
208			val -= parseFloat(fGetStyle(el, "border" + a + "Width") ) || 0; 
209			val -= parseFloat(fGetStyle(el, "padding" + a) ) || 0; 
210		} 
211		return val + 'px'; 
212	}
213	function fGetHeight(el) { 
214		var val = el.offsetHeight, which = ['Top', 'Bottom']; 
215		// display is none 
216		if(val === 0) return 0;
217
218		for(var i = 0, a; a = which[i++];) { 
219			val -= parseFloat(fGetStyle(el, "border" + a + "Width") ) || 0; 
220			val -= parseFloat(fGetStyle(el, "padding" + a) ) || 0; 
221		} 
222		return val + 'px'; 
223	}
224		
225	/**
226	 * This function is for registering the function(s) on its prototype.
227	 * @hostPrototype	which is its host prototype.
228	 * @funs	functions, such as{aa:function(){}, bb:function(){}}
229	 * @forseReg	boolean: when the @hostPrototype don't have the function, then register it.
230	 * 		true: do it, ignore the @hostPrototype whether has it.
231	 * 		false: when not have it so that register it.
232	 */
233	function fRegFuns(hostPrototype, funs, forseReg, d) {
234		var e, f, g;
235		if (!hostPrototype || !funs)
236			return hostPrototype || {};
237		if (d)
238			for (e = 0, g = d.length; e < g; ++e)
239				f = d[e], Object.prototype.hasOwnProperty.call(funs, f)	&& (forseReg || !(f in hostPrototype)) && (hostPrototype[f] = funs[f]);
240		else {
241			for (f in funs)
242				Object.prototype.hasOwnProperty.call(funs, f) && (forseReg || !(f in hostPrototype)) && (hostPrototype[f] = funs[f]);
243			({valueOf : 0}).propertyIsEnumerable("valueOf")	|| fRegFuns(hostPrototype, funs, forseReg, "hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toString,toLocaleString,valueOf".split(","));
244		}
245		return hostPrototype;
246	}
247	
248	function fRegEvents() {
249		fRegFuns(this.constructor.prototype, {
250					publish : function(a) {
251						this._evts[a] || (this._evts[a] = null);
252					},
253					on : function(a, b, c) {
254						var d = this._evts;
255						d[a] = {};
256						d[a].type = a;
257						this.name && (d[a].type = this.name + ":" + a);
258						d[a].fn = function() {
259							b.apply(c, arguments);
260						};
261					},
262					after : function(a, b, c) {
263						this.on(a, b, c);
264					},
265					fire : function(a) {
266						var b = this._evts[a];
267						if (b) {
268							var c = {target : this,	type : b.type},
269								d = Array.prototype.slice.call(arguments, 1);
270							if (fIsObjOrFun(d[0]))
271								for (var e in c)
272									d[0][e]	? d[0]["_" + e] = c[e] : d[0][e] = c[e];
273							else
274								d[0] = c;
275							"function" === fToString(b.fn) && b.fn.apply(this, d);
276						}
277					},
278					detach : function(a) {
279						delete this._evts[a];
280					}
281				}, !1);
282		this._evts = {};
283	}
284	
285	
286	function Parent(args) {
287		fRegEvents.call(this);
288		this._isApplySuperClass || fRegFuns(this.constructor.prototype, Parent.prototype, !1);
289		if (args) {
290			for (var field in args)
291				this.set(field, args[field]);
292		}
293		"function" === typeof this.initializer && this.initializer.apply(this, arguments);
294	}
295	Parent.prototype = {
296		_isApplySuperClass : !0,
297		initializer : function() {
298		},
299		get : function(key) {
300			return this.config[key];
301		},
302		set : function(key, val) {
303			var c;
304			key && "undefined" !== typeof val && key in this.config	&& (this.config[key] = val, c = key + "Change", this._evt && c in this._evt.events && this.fire(c));
305		}
306	};
307	
308	function SWFReference(a, b, c) {
309		fRegEvents.call(this);
310		var d = this._id = fGenerateId("uploader-swf"), c = c || {}, e = ((c.version || sFlashVersion) + "").split("."),
311			e = SWFReference.isFlashVersionAtLeast(parseInt(e[0], 10), parseInt(e[1], 10), parseInt(e[2], 10)),
312			f = SWFReference.isFlashVersionAtLeast(8, 0, 0) && !e && c.useExpressInstall,
313			g = f ? sFlashDownload : b, 
314			b = "<object ", h = "&SWFId=" + d + "&callback=" + sFlashEventHandler + "&allowedDomain=" + document.location.hostname;
315		SWFReference._instances[d] = this;
316		if (a && (e || f) && g) {
317			b += 'id="' + d + '" ';
318			b = Browser.ie ? b + ('classid="' + sIEFlashClassId + '" ') : b
319					+ ('type="' + sShockwaveFlash + '" data="' + g + '" ');
320			b += 'width="100%" height="100%">';
321			Browser.ie && (b += '<param name="movie" value="' + g + '"/>');
322			for (var j in c.fixedAttributes)
323				oa.hasOwnProperty(j)
324						&& (b += '<param name="' + j + '" value="' + c.fixedAttributes[j] + '"/>');
325			for (var s in c.flashVars)
326				j = c.flashVars[s], "string" === typeof j
327						&& (h += "&" + s + "=" + encodeURIComponent(j));
328			h && (b += '<param name="flashVars" value="' + h + '"/>');
329			a.innerHTML = b + "</object>";
330			this.swf = document.getElementById(d);
331		} else
332			this.publish("wrongflashversion", {fireOnce : !0}), this.fire("wrongflashversion", {type : "wrongflashversion"});
333	}
334	
335	SWFReference.getFlashVersion = function() {
336		return "" + Browser.flashMajor + "." + ("" + Browser.flashMinor) + "." + ("" + Browser.flashRev);
337	};
338	SWFReference.isFlashVersionAtLeast = function(a, b, c) {return true;
339		/*var d = parseInt(Browser.flashMajor, 10), e = parseInt(Browser.flashMinor, 10), f = parseInt(
340				Browser.flashRev, 10), a = parseInt(a || 0, 10), b = parseInt(b || 0,
341				10), c = parseInt(c || 0, 10);
342		return a === d ? b === e ? c <= f : b < e : a < d;*/
343	};
344	SWFReference._instances = SWFReference._instances || {};
345	SWFReference.eventHandler = function(a, b) {SWFReference._instances[a]._eventHandler(b);};
346	SWFReference.prototype = {
347		initializer : function() {},
348		_eventHandler : function(a) {
349			"swfReady" === a.type ? (this.publish("swfReady", {fireOnce : !0}), this.fire("swfReady", a))
350								: "log" !== a.type && this.fire(a.type, a);
351		},
352		callSWF : function(a, b) {
353			b || (b = []);
354			return this.swf[a] ? this.swf[a].apply(this.swf, b) : null;
355		},
356		toString : function() {return "SWF " + this._id;}
357	};
358	SWFReference.prototype.constructor = SWFReference;
359	
360	function SWFProvider(a) {
361		this.swfContainerId = fGenerateId("uploader");
362		this.queue = this.swfReference = null;
363		this.buttonState = "up";
364		this.config = {
365			enabled : !0,
366			multipleFiles : !0,
367			buttonClassNames : {
368				hover : "uploader-button-hover",
369				active : "uploader-button-active",
370				disabled : "uploader-button-disabled",
371				focus : "uploader-button-selected"
372			},
373			containerClassNames : {hover : "uphotBg"},
374			fileFilters : a.fileFilters,
375			fileFieldName : "FileData",
376			simLimit : 1,
377			retryCount : 3,
378			postVarsPerFile : {},
379			swfURL : "/swf/FlashUploader.swf",
380			uploadURL : "/fd"
381		};
382		Parent.apply(this, arguments);
383	}
384	SWFProvider.prototype = {
385		constructor : SWFProvider,
386		name : "uploader",
387		buttonState : "up",
388		swfContainerId : null,
389		swfReference : null,
390		queue : null,
391		initializer : function() {
392			this.publish("fileselect");
393			this.publish("uploadstart");
394			this.publish("fileuploadstart");
395			this.publish("uploadprogress");
396			this.publish("totaluploadprogress");
397			this.publish("uploadcomplete");
398			this.publish("alluploadscomplete");
399			this.publish("uploaderror");
400			this.publish("mouseenter");
401			this.publish("mouseleave");
402			this.publish("mousedown");
403			this.publish("mouseup");
404			this.publish("click");
405		},
406		render : function(a) {
407			a && (this.renderUI(a), this.bindUI());
408		},
409		renderUI : function(a) {
410			this.contentBox = a;
411			this.contentBox.style.position = "relative";
412			var b = fCreateContentEle("<div id='" + this.swfContainerId + "' style='position:absolute;top:0px; left: 0px; margin: 0; padding: 0; border: 0; width:100%; height:100%'></div>");
413			b.style.width = (a.offsetWidth ? a.offsetWidth : a.scrollWidth) + "px";
414			b.style.height = (a.offsetHeight ? a.offsetHeight : a.scrollHeight) + "px";
415			this.contentBox.appendChild(b);
416			this.swfReference = new SWFReference(b, this.get("swfURL"), {
417						version : "10.0.45",
418						fixedAttributes : {
419							wmode : "transparent",
420							allowScriptAccess : "always",
421							allowNetworking : "all",
422							scale : "noscale"
423						}
424					});
425		},
426		bindUI : function() {
427			this.setMultipleFiles();
428			this.setFileFilters();
429			this.triggerEnabled();
430			this.swfReference.on("swfReady", function() {
431				this.setMultipleFiles();
432				this.setFileFilters();
433				this.triggerEnabled();
434				this.after("multipleFilesChange", this.setMultipleFiles, this);
435				this.after("fileFiltersChange", this.setFileFilters, this);
436				this.after("enabledChange", this.triggerEnabled, this);
437			}, this);
438			this.swfReference.on("fileselect", this.updateFileList, this);
439			this.swfReference.on("mouseenter", function() {this.setContainerClass("hover", !0);}, this);
440			this.swfReference.on("mouseleave", function() {this.setContainerClass("hover", !1);}, this);
441		},
442		destroy : function() {
443			this.swfReference.detach("fileselect", this.updateFileList, this);
444			this.swfReference.detach("mouseenter", function() {this.setContainerClass("hover", !0);}, this);
445			this.swfReference.detach("mouseleave", function() {this.setContainerClass("hover", !1);}, this);
446			if (this.contentBox) {
447				while (this.contentBox.firstChild) {
448					var oldNode = this.contentBox.removeChild(this.contentBox.firstChild);
449					oldNode = null;
450				}
451			}
452			this.swfReference = null;
453		},
454		setContainerClass : function(a, b) {
455			b ? fAddClass(this.contentBox, this.get("containerClassNames")[a]) : fRemoveClass(
456					this.contentBox, this.get("containerClassNames")[a]);
457		},
458		setFileFilters : function() {
459			this.swfReference && 0 < this.get("fileFilters").length
460					&& this.swfReference.callSWF("setFileFilters", [[{description: "\u81ea\u5b9a\u4e49\u6587\u4ef6", extensions: "*" + this.get("fileFilters").join(";*"), macType: "*" + this.get("fileFilters").join(";*")}]]);
461		},
462		setMultipleFiles : function() {
463			this.swfReference && this.swfReference.callSWF("setAllowMultipleFiles", [this.get("multipleFiles")]);
464		},
465		triggerEnabled : function() {
466			this.get("enabled")
467					? (this.swfReference.callSWF("enable"), this.swfReference.swf.setAttribute("aria-disabled", "false"))
468					: (this.swfReference.callSWF("disable"), this.swfReference.swf.setAttribute("aria-disabled", "true"))
469		},
470		updateFileList : function(a) {
471			this.swfReference.swf.focus();
472			for (var a = a.fileList, b = [], c = this.swfReference, d = 0; d < a.length; d++) {
473				var e = {};
474				e.id = a[d].fileId;
475				e.name = a[d].fileReference.name;
476				e.size = a[d].fileReference.size;
477				e.type = a[d].fileReference.type;
478				e.dateCreated = a[d].fileReference.creationDate;
479				e.dateModified = a[d].fileReference.modificationDate;
480				e.uploader = c;
481				b.push(new SWFUploader(e));
482			}
483			0 < b.length && this.fire("fileselect", {fileList : b});
484		},
485		uploadEventHandler : function(a) {
486			switch (a.type) {
487				case "executor:uploadstart" :
488					this.fire("fileuploadstart", a);
489					break;
490				case "executor:uploadprogress" :
491					this.fire("uploadprogress", a);
492					break;
493				case "uploaderqueue:totaluploadprogress" :
494					this.fire("totaluploadprogress", a);
495					break;
496				case "executor:uploadcomplete" :
497					this.fire("uploadcomplete", a);
498					break;
499				case "uploaderqueue:alluploadscomplete" :
500					this.queue = null;
501					this.fire("alluploadscomplete", a);
502					break;
503				case "executor:uploaderror" :
504				case "uploaderqueue:uploaderror" :
505					this.fire("uploaderror", a);
506					break;
507				case "executor:uploadcancel" :
508				case "uploaderqueue:uploadcancel" :
509					this.fire("uploadcancel", a);
510			}
511		},
512		upload : function(uploader, url, postVars) {
513			var url = url || this.get("uploadURL"), postVars = fMergeJson(postVars, this.get("postVarsPerFile")), id = uploader.id,
514				postVars = postVars.hasOwnProperty(id) ? postVars[id] : postVars;
515			uploader instanceof SWFUploader
516					&& (uploader.on("uploadstart", this.uploadEventHandler, this),
517						uploader.on("uploadprogress", this.uploadEventHandler, this),
518						uploader.on("uploadcomplete", this.uploadEventHandler, this),
519						uploader.on("uploaderror", this.uploadEventHandler, this),
520						uploader.on("uploadcancel", this.uploadEventHandler, this),
521						uploader.startUpload(url, postVars, this.get("fileFieldName")));
522		}
523	};
524	
525	function SWFUploader(a) {
526		this.bytesSpeed = this.bytesPrevLoaded = 0;
527		this.bytesSpeeds = [];
528		this.preTime = this.remainTime = 0;
529		this.config = {
530			id : "",
531			name : "",
532			size : "",
533			type : "",
534			dateCreated : "",
535			dateModified : "",
536			uploader : ""
537		};
538		Parent.apply(this, arguments);
539	}	
540	SWFUploader.prototype = {
541		constructor : SWFUploader,
542		name : "executor",
543		initializer : function() {
544			this.id = fGenerateId("file");
545		},
546		swfEventHandler : function(a) {
547			if (a.id === this.get("id"))
548				switch (a.type) {
549					case "uploadstart" :
550						this.fire("uploadstart", {uploader : this.get("uploader")});
551						break;
552					case "uploadprogress" :
553						var b = (new Date).getTime(), c = (b - this.preTime) / 1E3, d = 0;
554						if (1 <= c || 0 == this.bytesPrevLoaded) {
555							this.bytesSpeed = Math.round((a.bytesLoaded - this.bytesPrevLoaded) / c);
556							this.bytesPrevLoaded = a.bytesLoaded;
557							this.preTime = b;
558							5 < this.bytesSpeeds.length && this.bytesSpeeds.shift();
559							this.bytesSpeeds.push(this.bytesSpeed);
560							for (b = 0; b < this.bytesSpeeds.length; b++)
561								d += this.bytesSpeeds[b];
562							this.bytesSpeed = Math.round(d / this.bytesSpeeds.length);
563							this.remainTime = Math.ceil((a.bytesTotal - a.bytesLoaded) / this.bytesSpeed);
564						}
565						this.fire("uploadprogress", {
566									originEvent : a,
567									bytesLoaded : a.bytesLoaded,
568									bytesSpeed : this.bytesSpeed,
569									bytesTotal : a.bytesTotal,
570									remainTime : this.remainTime,
571									percentLoaded : Math.min(100, Math.round(1E4 * a.bytesLoaded / a.bytesTotal) / 100)
572								});
573						break;
574					case "uploadcomplete" :
575						this.fire("uploadfinished", {originEvent : a});
576						break;
577					case "uploadcompletedata" :
578						this.fire("uploadcomplete", {
579									originEvent : a,
580									data : a.data
581								});
582						break;
583					case "uploadcancel" :
584						this.fire("uploadcancel", {originEvent : a});
585						break;
586					case "uploaderror" :
587						this.fire("uploaderror", {
588									originEvent : a,
589									status : a.status,
590									statusText : a.message,
591									source : a.source
592								});
593				}
594		},
595		startUpload : function(url, postVars, fileFieldName) {
596			if (this.get("uploader")) {
597				var uploader = this.get("uploader"), fileFieldName = fileFieldName || "FileData", id = this.get("id"), postVars = postVars || null;
598				uploader.on("uploadstart", this.swfEventHandler, this);
599				uploader.on("uploadprogress", this.swfEventHandler, this);
600				uploader.on("uploadcomplete", this.swfEventHandler, this);
601				uploader.on("uploadcompletedata", this.swfEventHandler, this);
602				uploader.on("uploaderror", this.swfEventHandler, this);
603				this.remainTime = this.bytesSpeed = this.bytesPrevLoaded = 0;
604				this.bytesSpeeds = [];
605				if (!this.preTime)
606					this.preTime = (new Date).getTime();
607				uploader.callSWF("upload", [id, url, postVars, fileFieldName]);
608			}
609		},
610		cancelUpload : function() {
611			this.get("uploader") 
612				&& (this.get("uploader").callSWF("cancel", [this.get("id")]), this.fire("uploadcancel"));
613		}
614	};
615	
616	function StreamProvider(a) {
617		this.buttonBinding = this.queue = this.fileInputField = null;
618		this.config = {
619			enabled : !0,
620			multipleFiles : !0,
621			dragAndDropArea : "",
622			dragAndDropTips : "",
623			fileFilters : a.fileFilters,
624			fileFieldName : a.fileFieldName || "FileData",
625			simLimit : 1,
626			retryCount : 3,
627			postVarsPerFile : {},
628			uploadURL : "/upload"
629		};
630		Parent.apply(this, arguments);
631	}
632	StreamProvider.prototype = {
633		constructor : StreamProvider,
634		name : "stream_provider",
635		initializer: function(){
636			this.publish("fileselect");
637			this.publish("uploadstart");
638			this.publish("fileuploadstart");
639			this.publish("uploadprogress");
640			this.publish("totaluploadprogress");
641			this.publish("uploadcomplete");
642			this.publish("alluploadscomplete");
643			this.publish("uploaderror");
644			this.publish("dragenter");
645			this.publish("dragover");
646			this.publish("dragleave");
647			this.publish("drop");
648		},
649		render : function(a) {
650			a && (this.renderUI(a), this.bindUI());
651		},
652		renderUI : function(a) {
653			this.contentBox = a;
654			this.fileInputField = fCreateContentEle("<input type='file' style='visibility:hidden;width:0px;height:0px;opacity:0;position:absolute;
654left:-1000px;'>");
655			this.get("dragAndDropArea") && !this.get("dragAndDropArea").nodeType && this.set("dragAndDropArea", document.getElementById(this.get("dragAndDropArea"))); 
656			bDraggable && this.get("dragAndDropArea") && (fAddClass(this.get("dragAndDropArea"), 'stream-browse-drag-files-area'), this.get("dragAndDropArea").appendChild(fCreateContentEle(this.get("dragAndDropTips"))));
657		},
658		bindUI : function() {
659			this.bindSelectButton();
660			this.setMultipleFiles();
661			this.setFileFilters();
662			this.bindDropArea();
663			this.triggerEnabled();
664			this.after("multipleFilesChange", this.setMultipleFiles, this);
665			this.after("fileFiltersChange", this.setFileFilters, this);
666			this.after("enabledChange", this.triggerEnabled, this);
667			this.after("dragAndDropAreaChange", this.bindDropArea, this);
668			fAddEventListener(this.fileInputField, "change", fExtend(this.updateFileList, this));
669		},
670		bindDropArea : function() {
671			var a = this.get("dragAndDropArea");
672			this.dropBinding = fExtend(this.dragEventHandler, this);
673			null !== a	&& (fAddEventListener(a, "drop", this.dropBinding),
674							fAddEventListener(a, "dragenter", this.dropBinding),
675							fAddEventListener(a, "dragover", this.dropBinding),
676							fAddEventListener(a, "dragleave", this.dropBinding));
677		},
678		destroy : function() {
679			this.buttonBinding = fExtend(this.openFileSelectDialog, this);
680			fRemoveEventListener(this.contentBox, "click", this.buttonBinding);
681			fRemoveEventListener(this.fileInputField, "change", fExtend(this.updateFileList, this));
682			this.detach("multipleFilesChange", this.setMultipleFiles, this);
683			this.detach("fileFiltersChange", this.setFileFilters, this);
684			this.detach("enabledChange", this.triggerEnabled, this);
685			this.detach("dragAndDropAreaChange", this.bindDropArea, this);
686
687			var a = this.get("dragAndDropArea");
688			null !== a && this.dropBinding != null && (fRemoveEventListener(a, "drop", this.dropBinding),
689						fRemoveEventListener(a, "dragenter", this.dropBinding),
690						fRemoveEventListener(a, "dragover", this.dropBinding),
691						fRemoveEventListener(a, "dragleave", this.dropBinding));
692			this.fileInputField = null;
693			this.buttonBinding = null;
694			this.dropBinding = null;
695		},
696		dragEventHandler : function(evt) {
697			evt = evt || window.event;
698			evt.preventDefault ? evt.preventDefault() : evt.returnValue = !1;
699			evt.stopPropagation ? evt.stopPropagation() : evt.cancelBubble = !0;
700			switch (evt.type) {
701				case "dragenter" :
702					this.fire("dragenter");
703					break;
704				case "dragover" :
705					this.fire("dragover");
706					break;
707				case "dragleave" :
708					this.fire("dragleave");
709					break;
710				case "drop" :
711					var self = this, callback = function(files) {
712						for (var list = [], c = 0; c < files.length; c++)
713							list.push(new StreamUploader(files[c]));
714						0 < list.length && self.fire("fileselect", {fileList : list});
715					};
716					if (bFolder) {
717						var items = evt.dataTransfer.items;
718						if (items.length && items[items.length - 1]) {
719							var entry = items[items.length - 1].webkitGetAsEntry() || items[items.length - 1].getAsEntry();
720							var entries = [];
721							for (var i = 0; i < items.length; i++) {
722								entries.push(items[i].webkitGetAsEntry() || items[i].getAsEntry());
723							}
724							entry && this._handleFileTreeEntries(entries, callback);
725						}
726					} else {
727						var files = evt.dataTransfer.files;
728						if (evt.MOZ_SOURCE_MOUSE) {
729							for (var list = [], c = 0; c < files.length; c++)
730								files[c].size > 0 && list.push(files[c]);
731							files = list;
732						}
733						callback(files, this);
734					}
735					this.fire("drop");
736			}
737		},
738		_handleFileTreeEntries: function(entries, callback) {
739			for (var i = 0; i < entries.length; i++) {
740				this._handleFileTreeEntry(entries[i], callback);
741			}
742		},
743		_handleFileTreeEntry: function(entry, callback) {
744			callback.pending || (callback.pending = 0);
745			callback.pending++;
746			callback.files || (callback.files = []);
747			var that = this, reader, path = entry.fullPath.replace(/^\//, "").replace(/(.+?)\/?$/, "$1"), entries = [], succeed = function(entries) {
748				that._handleFileTreeEntries(entries, callback);
749				(--callback.pending === 0) && callback(callback.files, self);
750			}, error = function(e) {
751				alert("Read file Error: " + e);
752				console && console.log(e);
753			}, read = function() {
754				reader.readEntries(function(results) {
755					if (results.length) {
756						entries = entries.concat(results);
757						read();
758					} else {
759						succeed(entries);
760						if (entries && entries.length === 0 && path != null && path != '' && path != '/')
761							fShowMessage("\u5FFD\u7565\u7A7A\u6587\u4EF6\u5939\uFF1A`" + path + "`", true);
762					}
763				}, error); 
764			};
765			if (entry.isFile) {
766				entry.file(function(f) {
767					f.RelativePath = path; /** self define argument */
768					callback.files.push(f);
769					(--callback.pending === 0) && callback(callback.files, self);
770				});
771			} else if (entry.isDirectory) {
772				reader = entry.createReader();
773				read();
774			}
775		},
776		rebindFileField : function() {
777			this.fileInputField = fCreateContentEle("<input type='file' style='visibility:hidden;width:0px;height:0px;opacity:0;position:absolute;left:-1000px;'>");
778			this.get("dragAndDropArea") && !this.get("dragAndDropArea").nodeType && this.set("dragAndDropArea", document.getElementById(this.get("dragAndDropArea"))); 
779			bDraggable && (fAddClass(this.get("dragAndDropArea"), 'stream-browse-drag-files-area'));
780			this.setMultipleFiles();
781			this.setFileFilters();
782			fAddEventListener(this.fileInputField, "change", fExtend(this.updateFileList, this));
783		},
784		bindSelectButton : function() {
785			this.buttonBinding = fExtend(this.openFileSelectDialog, this);
786			fAddEventListener(this.contentBox, "click", this.buttonBinding);
787		},
788		setMultipleFiles : function() {
789			!0 === this.get("multipleFiles")
790					&& this.fileInputField.setAttribute("multiple", "multiple")
791		},
792		setFileFilters : function() {
793			var a = this.get("fileFilters");
794			0 < a.length ? this.fileInputField.setAttribute("accept", a
795							.join(",")) : this.fileInputField.setAttribute(
796					"accept", "")
797		},
798		triggerEnabled : function() {
799			var a = this.get("dragAndDropArea");
800			fRemoveClass(a, 'stream-disabled');
801			if (this.get("enabled") && null === this.buttonBinding)
802				this.bindSelectButton(), this.bindDropArea(), fRemoveClass(a, 'stream-disabled');
803			else if (!this.get("enabled") && this.buttonBinding) {
804				fRemoveEventListener(this.contentBox, "click", this.buttonBinding),
805				this.buttonBinding = null;
806				
807				null !== a && this.dropBinding != null && (fRemoveEventListener(a, "drop", this.dropBinding),
808							fRemoveEventListener(a, "dragenter", this.dropBinding),
809							fRemoveEventListener(a, "dragover", this.dropBinding),
810							fRemoveEventListener(a, "dragleave", this.dropBinding),
811							fAddClass(a, 'stream-disabled'));
812			}				
813		},
814		updateFileList : function(a) {
815			for (var a = a.target.files, b = [], c = 0; c < a.length; c++) {
816				if (a[c].name == ".") continue;
817				b.push(new StreamUploader(a[c]));
818			}
819			0 < b.length && this.fire("fileselect", {fileList : b});
820			this.rebindFileField();
821		},
822		openFileSelectDialog : function(a) {
823			this.fileInputField && this.fileInputField.click && a.target != this.fileInputField && this.fileInputField.click();
824		},
825		uploadEventHandler : function(a) {
826			switch (a.type) {
827				case "executor:uploadstart" :
828					this.fire("fileuploadstart", a);
829					break;
830				case "executor:uploadprogress" :
831					this.fire("uploadprogress", a);
832					break;
833				case "uploaderqueue:totaluploadprogress" :
834					this.fire("totaluploadprogress", a);
835					break;
836				case "executor:uploadcomplete" :
837					this.fire("uploadcomplete", a);
838					break;
839				case "uploaderqueue:alluploadscomplete" :
840					this.queue = null;
841					this.fire("alluploadscomplete", a);
842					break;
843				case "executor:uploaderror" :
844				case "uploaderqueue:uploaderror" :
845					this.fire("uploaderror", a);
846					break;
847				case "executor:uploadcancel" :
848				case "uploaderqueue:uploadcancel" :
849					this.fire("uploadcancel", a);
850			}
851		},
852		upload : function(uploader, url, postVars) {
853			var url = url || this.get("uploadURL"), postVars = fMergeJson(postVars, this.get("postVarsPerFile")),
854				d = uploader.id, postVars = postVars.hasOwnProperty(d) ? postVars[d] : postVars;
855			uploader instanceof StreamUploader
856					&& (uploader.on("uploadstart", this.uploadEventHandler, this),
857						uploader.on("uploadprogress", this.uploadEventHandler, this),
858						uploader.on("uploadcomplete", this.uploadEventHandler, this),
859						uploader.on("uploaderror", this.uploadEventHandler, this),
860						uploader.on("uploadcancel", this.uploadEventHandler, this),
861						uploader.startUpload(url, postVars, this.get("fileFieldName")));
862		}
863	};
864	
865	var StreamUploader = function(){
866		this.remainTime = this.bytesSpeed = this.bytesStart = this.bytesPrevLoaded = 0;
867		this.bytesSpeeds = [];
868		this.retryTimes = this.preTime = 0;
869		this.config = {
870			id : "",
871			name : "",
872			size : "",
873			type : "",
874			dateCreated : "",
875			dateModified : "",
876			uploader : "",
877			uploadURL : "",
878			serverAddress : "",
879			portionSize : 10485760,
880			parameters : {},
881			fileFieldName : "FileData",
882			uploadMethod : "formUpload"
883		};
884		Parent.apply(this, arguments);
885	};
886	StreamUploader.isValidFile = function(a) {return "undefined" != typeof File && a instanceof File;};
887	StreamUploader.canUpload = function() {return "undefined" != typeof FormData;};
888	StreamUploader.prototype = {
889		constructor : StreamUploader,
890		name: "executor",
891		initializer: function(file){
892			this.XHR = null;
893			this.retryTimes = 10;
894			this.retriedTimes = 0;
895			this.file = null;
896			this.fileId = null;
897			this.filePiece = 10485760;/** 10M. */
898			this.fileSizeValue = 0;
899			this.fileStartPosValue = null;
900			
901			this.durationTime = 2000;
902			this.xhrHandler = null;
903			
904			var b = StreamUploader.isValidFile(file) ? file : StreamUploader.isValidFile(file.file)	? file.file	: !1;
905			this.get("id") || this.set("id", fGenerateId("file"));
906			if (b && StreamUploader.canUpload()) {
907				if (!this.file)
908					this.file = b;
909				this.set("name", b.RelativePath || b.webkitRelativePath || b.name || b.fileName);
910				if (this.get("size") != (b.size || b.fileSize))
911					this.set("size", b.size || b.fileSize);
912				this.get("type") || this.set("type", b.type);
913				b.lastModifiedDate && !this.get("dateModified")	&& this.set("dateModified", b.lastModifiedDate);
914			}
915		},
916		resetXhr: function(){
917			if(this.XHR){
918				try{
919					this.XHR.upload.removeEventListener("progress", this.xhrHandler),
920					this.XHR.upload.removeEventListener("error", this.xhrHandler),
921					this.XHR.upload.removeEventListener("abort", this.xhrHandler),
922					this.XHR.removeEventListener("loadend", this.xhrHandler),
923					this.XHR.removeEventListener("error", this.xhrHandler),
924					this.XHR.removeEventListener("abort", this.xhrHandler),
925					this.XHR.removeEventListener("readystatechange", this.xhrHandler);
926				}catch(e){throw e;}
927				this.XHR = null;
928			}
929		},
930		formUpload : function() {
931			this.resetXhr();
932			this.XHR = new XMLHttpRequest;
933			this.uploadEventHandler = fExtend(this.uploadEventHandler, this);
934			var fd = new FormData, fileFileName = this.get("fileFieldName"),
935				url = this.get("uploadURL"), _xhr = this.XHR, _upload = _xhr.upload;
936			this.set("uploadMethod", "formUpload");
937			this.bytesStart = 0;
938			this.preTime = (new Date).getTime();
939			for (var I in this.get('parameters')) I && fd.append(I, this.get('parameters')[I]);
940			// need set file after normal form items.
941			fd.append(fileFileName, this.file);
942			_xhr.addEventListener("loadstart", this.uploadEventHandler, !1);
943			_upload.addEventListener("progress", this.uploadEventHandler, !1);
944			_xhr.addEventListener("load", this.uploadEventHandler, !1);
945			_xhr.addEventListener("error", this.uploadEventHandler, !1);
946			_upload.addEventListener("error", this.uploadEventHandler, !1);
947			_upload.addEventListener("abort", this.uploadEventHandler, !1);
948			_xhr.addEventListener("abort", this.uploadEventHandler, !1);
949			_xhr.addEventListener("loadend", this.uploadEventHandler, !1);
950			_xhr.addEventListener("readystatechange", this.uploadEventHandler, !1);
951			_xhr.open("POST", url, !0);
952			_xhr.send(fd);
953			this.fire("uploadstart", {xhr : _xhr});
954		},
955		streamUpload: function(pos){
956			/** whether continue uploading. */
957			var _url = this.get("uploadURL");
958			this.resetXhr();
959			this.resume = false;
960			this.bytesStart = pos;
961			this.XHR = new XMLHttpRequest;
962			this.xhrHandler = fExtend(this.uploadEventHandler, this);
963			//register callback function
964			var _xhr = this.XHR, upload = _xhr.upload;
965			_xhr.addEventListener("loadstart", this.xhrHandler, !1);
966			upload.addEventListener("progress", this.xhrHandler, !1);
967			_xhr.addEventListener("load", this.xhrHandler, !1);
968			_xhr.addEventListener("error", this.xhrHandler, !1);
969			upload.addEventListener("error", this.xhrHandler, !1);
970			upload.addEventListener("abort", this.xhrHandler, !1);
971			_xhr.addEventListener("abort", this.xhrHandler, !1);
972			_xhr.addEventListener("loadend", this.xhrHandler, !1);
973			_xhr.addEventListener("readystatechange", this.xhrHandler, !1);
974			var blob = this.sliceFile(this.file, pos, pos + this.filePiece);
975			var range = "bytes "+ pos + "-"+ (pos + blob.size) + "/" + this.get("size");
976			this.preTime = (new Date).getTime();
977			_xhr.open("POST", _url, !0);
978			_xhr.setRequestHeader("Content-Range", range);
979			_xhr.send(blob);
980			0 === pos && this.fire("uploadstart", {xhr : _xhr});
981		},
982		resumeUpload: function() {
983			/** when Browse has `File`, but has not `File.slice` */
984			if (!bFileSlice) {
985				this.formUpload();
986				return;
987			}
988			
989			this.resetXhr();
990			this.XHR = new XMLHttpRequest;
991			this.resume = true;
992			
993			var _url = this.get("uploadURL") + "&" + fGetRandom();
994			this.xhrHandler = fExtend(this.uploadEventHandler, this);
995			this.XHR.addEventListener("loadstart", this.xhrHandler, !1);
996			this.XHR.addEventListener("load", this.xhrHandler, !1);
997			this.XHR.addEventListener("abort", this.xhrHandler, !1);
998			this.XHR.addEventListener("error", this.xhrHandler, !1);
999			this.XHR.addEventListener("loadend", this.xhrHandler, !1);
1000			this.XHR.addEventListener("readystatechange", this.xhrHandler, !1);
1001			this.preTime = (new Date).getTime();
1002			this.XHR.open("GET", _url, !0);
1003			this.XHR.send(null);
1004		},
1005		retry: function(){
1006            this.retriedTimes++;
1007            var g = this;
1008            2 > this.retriedTimes ? this.resumeUpload()
1009            					: (this.timeoutHandler && clearTimeout(this.timeoutHandler), this.timeoutHandler = setTimeout(function() {g.resumeUpload()}, 1E4));
1010		},
1011		uploadEventHandler: function(event){
1012			var xhr = this.XHR, method = this.get("uploadMethod");
1013			switch(event.type){
1014				case "load":
1015					var uploaded = 0;
1016					var respJson = null;
1017					var bError = !1;
1018					try {
1019						if (xhr.readyState == 4 && (xhr.status == 200 || xhr.status == 308)) {
1020							uploaded = (respJson = eval("(" + xhr.responseText + ")")) ? respJson.start : -1;
1021						} else if (xhr.status < 500 && xhr.status >= 400) {
1022							bError = !0;
1023						} else if (xhr.status < 200) {return;}
1024						/** the response can't process the request, so throws out the error. */
1025						bError = bError || respJson.success == false;
1026					} catch(e) {
1027						bError = "formUpload" === method || this.retriedTimes > this.retryTimes;
1028						if (!bError) {
1029							this.retry();
1030							return;
1031						}
1032					}
1033					if (bError) {
1034						this.fire("uploaderror", {
1035							originEvent : event,
1036							status : xhr.status,
1037							statusText : xhr.responseText,
1038							source : respJson && respJson.message
1039						});
1040						return;
1041					}
1042					//check whether upload complete yet
1043					if(uploaded < this.get("size") -1) {
1044						this.retriedTimes = 0;
1045						/** StreamUploader request is over and mark the date. */
1046						this.streamUpload(uploaded);
1047					} else {
1048						this.fire("uploadcomplete", {originEvent : event, data : event.target.responseText});
1049					}
1050					break;
1051				case "error":
1052					this.retriedTimes < this.retryTimes ? this.retry()
1053						: this.fire("uploaderror", {
1054									originEvent : event,
1055									status : xhr.status,
1056									statusText : xhr.statusText,
1057									source : "io"
1058								});
1059					break;
1060				case "abort":
1061					this.fire("uploadcancel", {originEvent : event});
1062					break;
1063				case "progress":
1064					var total = this.get("size"), loaded = this.bytesStart + event.loaded,
1065						now = (new Date).getTime(), cost = (now - this.preTime) / 1E3, totalSpeeds = 0;
1066					if (0.68 <= cost || 0 === this.bytesSpeeds.length) {
1067						this.bytesPrevLoaded = Math.max(this.bytesStart, this.bytesPrevLoaded);
1068						this.bytesSpeed = Math.round((loaded - this.bytesPrevLoaded) / cost);
1069						this.bytesPrevLoaded = loaded;
1070						this.preTime = now;
1071						5 < this.bytesSpeeds.length && this.bytesSpeeds.shift();
1072						5 > this.bytesSpeeds.length && (this.bytesSpeed = this.bytesSpeed / 2);
1073						this.bytesSpeeds.push(this.bytesSpeed);
1074						for (var i = 0; i < this.bytesSpeeds.length; i++)
1075							totalSpeeds += this.bytesSpeeds[i];
1076						this.bytesSpeed = Math.round(totalSpeeds / this.bytesSpeeds.length);
1077						this.remainTime = Math.ceil((total - loaded) / this.bytesSpeed);
1078					}
1079					this.fire("uploadprogress", {
1080								originEvent : event,
1081								bytesLoaded : loaded,
1082								bytesTotal : total,
1083								bytesSpeed : this.bytesSpeed,
1084								remainTime : this.remainTime,
1085								percentLoaded : Math.min(100, Math.floor(1E4 * loaded / total) / 100)
1086							});
1087					break;
1088				case "readystatechange":
1089					this.fire("readystatechange", {readyState : event.target.readyState, originEvent : event});
1090			}
1091		},
1092		startUpload: function(url, postVars, fileFieldName){
1093			this.fileStartPosValue = null;
1094			this.retriedTimes = 0;
1095
1096			postVars.name = this.get("name");
1097			postVars.size = this.get("size");
1098			var method = this.get("uploadMethod");
1099			this.set("uploadURL", 'formUpload' === method ? url : fAddVars(postVars, url));
1100			this.set("parameters", postVars);
1101			this.set("fileFieldName", fileFieldName);
1102			this.remainTime = this.bytesSpeed = this.bytesPrevLoaded = 0;
1103			this.bytesSpeeds = [];
1104			this.resetXhr();
1105			switch (method) {
1106				case "formUpload" :
1107					this.formUpload();
1108					break;
1109				case "streamUpload" :
1110					this.streamUpload();
1111					break;
1112				case "resumeUpload" :
1113					this.resumeUpload()
1114			}
1115		},
1116		sliceFile: function(f, startPos, endPos){
1117			startPos = startPos || 0;
1118			endPos = endPos || 0;
1119			return f.slice ? f.slice(startPos, endPos) : f.webkitSlice ? f.webkitSlice(startPos, endPos) : f.mozSlice ? f.mozSlice(startPos, endPos) : f;
1120		},
1121		cancelUpload : function() {
1122			this.XHR && (this.XHR.abort(), this.resetXhr());
1123		}
1124	};
1125	
1126	function Main(cfg){
1127		cfg = cfg || {};
1128		this.bStreaming = bStreaming;
1129		this.bDraggable = bDraggable;
1130		this.uploadInfo = {};
1131		this.config = {
1132			enabled : !0,
1133			customered : !!cfg.customered,
1134			formed : !!cfg.formed,
1135			multipleFiles : !!cfg.multipleFiles,
1136			autoRemoveCompleted : !!cfg.autoRemoveCompleted,
1137			autoUploading : cfg.autoUploading == null ? true : !!cfg.autoUploading,
1138			dragAndDropArea: cfg.dragAndDropArea,
1139			dragAndDropTips: cfg.dragAndDropTips || "<span>把文件(文件夹)拖拽到这里</span>",
1140			fileFieldName : cfg.fileFieldName || "FileData",
1141			browser : cfg.browser,
1142			browseFileId : cfg.browseFileId || "i_select_files",
1143			browseFileBtn : cfg.browseFileBtn || "<div>请选择文件</div>",
1144			filesQueueId : cfg.filesQueueId || "i_stream_files_queue",
1145			filesQueueHeight : cfg.filesQueueHeight || 450,
1146			messagerId : cfg.messagerId || "i_stream_message_container",
1147			onSelect : cfg.onSelect,
1148			onRepeatedFile : cfg.onRepeatedFile,
1149			onAddTask: cfg.onAddTask,
1150			onMaxSizeExceed : cfg.onMaxSizeExceed,
1151			onFileCountExceed : cfg.onFileCountExceed,
1152			onExtNameMismatch : cfg.onExtNameMismatch,
1153			onCancel : cfg.onCancel,
1154			onStop : cfg.onStop,
1155			onCancelAll : cfg.onCancelAll,
1156			onComplete : cfg.onComplete,
1157			onQueueComplete: cfg.onQueueComplete,
1158			onUploadProgress: cfg.onUploadProgress,
1159			onUploadError: cfg.onUploadError,
1160			onDestroy: cfg.onDestroy,
1161			maxSize : cfg.maxSize || 2147483648,
1162			simLimit : cfg.simLimit || 10000,
1163			fileFilters: fIsArray(cfg.extFilters) ? cfg.extFilters : [],
1164			retryCount : cfg.retryCount || 5,
1165			postVarsPerFile : cfg.postVarsPerFile || {},
1166			swfURL : cfg.swfURL || "/swf/FlashUploader.swf",
1167			tokenURL : cfg.tokenURL || "/tk",
1168			frmUploadURL : cfg.frmUploadURL || Browser.firefox ? "/fd;" + document.cookie : "/fd",
1169			uploadURL : cfg.uploadURL || "/upload"
1170		};
1171		Parent.apply(this, arguments);
1172	}
1173	Main.applyTo = function(a, b) {
1174		if (!a || "SWF.eventHandler" != a)
1175			return null;
1176		try {
1177			return SWFReference.eventHandler.apply(SWFReference, b);
1178		} catch (c) {
1179			return null;
1180		}
1181	};
1182	Main.prototype = {
1183		constructor : Main,
1184		name : "uploader",
1185		initializer : function() {
1186			sStreamMessagerId = this.config.messagerId;
1187			this.startPanel = this.config.browser || document.getElementById(this.config.browseFileId);
1188			/** the default UI */
1189			if (!this.config.customered) {
1190				fAddClass(this.startPanel, "stream-browse-files");
1191				this.startPanel.appendChild(fCreateContentEle(this.config.browseFileBtn));
1192				var filesQueuePanel = document.getElementById(this.config.filesQueueId);
1193				fAddClass(filesQueuePanel, "stream-main-upload-box");
1194				var filesContainerId = fGenerateId("files-container"),
1195				    totalContainerId = fGenerateId("total-container");
1196				var filesQueue = fCreateContentEle(sFilesContainer.replace("#filesContainerId#", filesContainerId).replace("#filesQueueHeight#", this.config.filesQueueHeight)),
1197					totalQueue = fCreateContentEle(sTotalContainer.replace("#totalContainerId#", totalContainerId));
1198				filesQueuePanel.appendChild(filesQueue);
1199				filesQueuePanel.appendChild(totalQueue);
1200				
1201				this.containerPanel = document.getElementById(filesContainerId);
1202				this.totalContainerPanel = document.getElementById(totalContainerId);
1203				this.template = sCellFileTemplate;
1204			}
1205			
1206			this.fileProvider = new Provider(this.config);
1207			this.fileProvider.render(this.startPanel);
1208			this.fileProvider.on("uploadprogress", this.uploadProgress, this);
1209			this.fileProvider.on("uploadcomplete", this.uploadComplete, this);
1210			this.fileProvider.on("uploaderror", this.uploadError, this);
1211			this.fileProvider.on("fileselect", this.fileSelect, this);
1212			fAddEventListener(window, "beforeunload", fExtend(this.unloadHandler, this));
1213			this.waiting = [];
1214			this.uploading = !1;
1215			this.totalFileSize = 0;
1216			this.totalUploadedSize = 0;
1217			this.showBrowseBlock();
1218		},
1219		addStreamTask : function(a) {
1220			var file_id = a.get("id"), cell_file = fCreateContentEle("<li id='" + file_id + "' class='stream-cell-file'></li>");
1221			cell_file.innerHTML = this.template;
1222			this.uploadInfo[file_id] = {
1223				uploadToken : "",
1224				uploadComplete : !1,
1225				file : a,
1226				disabled : !1,
1227				actived : !1,
1228				progressNode : this.getNode("stream-process", cell_file),
1229				cellInfosNode : this.getNode("stream-cell-infos", cell_file)
1230			};
1231			this.totalFileSize += this.uploadInfo[file_id].file.get("size");
1232			if (!this.config.customered) {
1233				this.getNode("stream-file-name", cell_file).getElementsByTagName("strong")[0].innerHTML = a.get("name");
1234				this.containerPanel.appendChild(cell_file);
1235				this.renderUI(file_id);
1236				this.bindUI(file_id);
1237			}
1238			/** do not hidden the upload button */
1239			/*bStreaming ? this.startPanel.style.display = "none" : (this.startPanel.style.height = "1px", this.startPanel.style.width = "1px");*/
1240			this.waiting.push(file_id);
1241			this.config.autoUploading && this.upload(file_id);
1242		},
1243		hideBrowseBlock: function() {
1244			this.browseFileBlockHeight = fGetHeight(this.startPanel);
1245			this.browseFileBlockWidth = fGetWidth(this.startPanel);
1246			!this.browseFileBlockDisplay && (this.browseFileBlockDisplay = this.startPanel.style.display == "" ? "block" : this.startPanel.style.display);
1247			bStreaming ? this.startPanel.style.display = "none" : (this.startPanel.style.height = "1px", this.startPanel.style.width = "1px");
1248		},
1249		showBrowseBlock: function() {
1250			!this.browseFileBlockHeight && (this.browseFileBlockHeight = fGetHeight(this.startPanel));
1251			!this.browseFileBlockWidth && (this.browseFileBlockWidth = fGetWidth(this.startPanel));
1252			!this.browseFileBlockDisplay && (this.browseFileBlockDisplay = this.startPanel.style.display == "" ? "block" : this.startPanel.style.display);
1253			if (this.browseFileBlockDisplay == "none") {this.browseFileBlockDisplay = "block", this.browseFileBlockWidth = null, this.browseFileBlockHeight = null; return !1;}
1254			bStreaming ? this.startPanel.style.display = this.browseFileBlockDisplay : (this.startPanel.style.height = this.browseFileBlockHeight, this.startPanel.style.width = this.browseFileBlockWidth);
1255		},
1256		renderUI : function(file_id) {
1257			var progressNode = this.uploadInfo[file_id].progressNode,
1258				cellInfosNode = this.uploadInfo[file_id].cellInfosNode,
1259				size = this.uploadInfo[file_id].file.get("size"),
1260				total = this.formatBytes(size);
1261			this.getNode("stream-process-bar", progressNode).innerHTML = "<span style='width:0%;'></span>";
1262			this.getNode("stream-percent", progressNode).innerHTML = "0%";
1263			this.getNode("stream-speed", cellInfosNode).innerHTML = "-";
1264			this.getNode("stream-remain-time", cellInfosNode).innerHTML = "--:--:--";
1265			this.getNode("stream-uploaded", cellInfosNode).innerHTML = "0/" + total;
1266			var _total = this.formatBytes(this.totalFileSize);
1267			this.getNode("_stream-total-size", this.totalContainerPanel).innerHTML = _total;
1268		},
1269		bindUI : function(file_id) {
1270			var b = this.uploadInfo[file_id].progressNode, cancelBtn = this.getNode("stream-cancel", b);
1271			this.cancelBtnHandler = fExtend(this.cancelUploadHandler, this, {type : "click",	nodeId : file_id});
1272			fAddEventListener(cancelBtn, "click", this.cancelBtnHandler);
1273		},
1274		completeUpload : function(info) {
1275			/** set the current scroll for files container */
1276			var count = 0, scroll = null, ratio = 1;
1277			for(var i in this.uploadInfo) count++;
1278			ratio = (count - this.waiting.length - 1) / (count <= 0 ? 1 : count);
1279			this.containerPanel && this.containerPanel.parentNode && (scroll = this.containerPanel.parentNode, scroll.
1279scrollTop = scroll.scrollHeight * ratio);
1280			this.get("onComplete") ? this.get("onComplete")(info) : this.onComplete(info);
1281			this.waiting.length == 0 && (this.get("onQueueComplete") ? this.get("onQueueComplete")(info.msg) : this.onQueueComplete(info.msg));
1282			this.config.autoRemoveCompleted && (info = document.getElementById(info.id), info.parentNode && info.parentNode.removeChild(info));
1283			this.uploading = !1;
1284			this.upload();
1285		},
1286		onSelect : function(list) {
1287			fShowMessage("selected files: " + list.length);
1288		},
1289		onRepeatedFile : function(file) {
1290			fShowMessage("File:" + file.name + " Size:" + file.size +" has been UPLOADED or ADDED.", true);
1291			return false;
1292		},
1293		onFileCountExceed : function(selected, limit) {
1294			fShowMessage("File counts:" + selected + ", but limited:" + limit, true);
1295		},
1296		onMaxSizeExceed : function(file) {
1297			fShowMessage("File:" + file.name + " size is:" + file.size +" Exceed limited:" + file.limitSize, true);
1298		},
1299		onExtNameMismatch: function(file) {
1300			fShowMessage("Allow ext name: [" + file.filters.toString() + "], not for " + file.name, true);
1301		},
1302		onAddTask: function(file) {
1303			fShowMessage("Add to task << name: [" + file.name);
1304		},
1305		onCancel : function(file) {
1306			fShowMessage("Canceled: " + file.name);
1307		},
1308		onStop : function() {
1309			fShowMessage("Stopped!");
1310		},
1311		onCancelAll : function(numbers) {
1312			fShowMessage(numbers + " files Canceled! ");
1313		},
1314		onComplete : function(file) {
1315			fShowMessage("File:" + file.name + ", Size:" + file.size + " onComplete	[OK]");
1316		},
1317		onQueueComplete : function(msg) {
1318			fShowMessage("onQueueComplete(msg: "+msg+")	---==>		[OK]");
1319		},
1320		onUploadError : function(status, msg) {
1321			fShowMessage("Error Occur.  Status:" + status + ", Message: " + msg, true);
1322		},
1323		disable : function() {
1324			this.fileProvider.set("enabled", !1), this.fileProvider.triggerEnabled(), fAddClass(this.startPanel.children[0], "stream-disable-browser"), fAddClass(this.startPanel, "disabled");
1325		},
1326		enable : function() {
1327			this.fileProvider.set("enabled", !0), this.fileProvider.triggerEnabled(), fRemoveClass(this.startPanel.children[0], "stream-disable-browser"), fRemoveClass(this.startPanel, "disabled");
1328		},
1329		stop : function() {
1330			if (!this.uploading) return false;
1331			this.uploading = !1;
1332			var files = this.uploadInfo, number = 0;
1333			/** cancel the unfinished uploading files */
1334			for(var fileId in files) {
1335				/** add the `file_id` to `waiting` @ index of 0 */
1336				if (!files[fileId].uploadComplete) {
1337					this.cancelOne(fileId, true) && this.uploadInfo[fileId] && this.waiting.unshift(fileId);
1338					break;	
1339				}
1340			}
1341			this.get("onStop") ? this.get("onStop")() : this.onStop();
1342		},
1343		destroy : function() {
1344			this.stop();
1345			this.fileProvider.destroy();
1346			this.waiting = [];
1347			/** the default UI */
1348			if (!this.config.customered) {
1349				fRemoveClass(this.startPanel, "stream-browse-files");
1350				fRemoveClass(this.startPanel, "stream-browse-drag-files-area");
1351				var filesQueuePanel = document.getElementById(this.config.filesQueueId);
1352				fRemoveClass(filesQueuePanel, "stream-main-upload-box");
1353				while (this.startPanel.firstChild) {
1354					var oldNode = this.startPanel.removeChild(this.startPanel.firstChild);
1355					oldNode = null;
1356				}
1357				while (filesQueuePanel.firstChild) {
1358					var oldNode = filesQueuePanel.removeChild(filesQueuePanel.firstChild);
1359					oldNode = null;
1360				}
1361			}
1362			this.get("onDestroy") && this.get("onDestroy")(); 
1363			var selfthis = this, selfthis = null;
1364		},
1365		cancel : function() {
1366			this.uploading = !1;
1367			var files = this.uploadInfo, number = 0;
1368			/** cancel the unfinished uploading files */
1369			for(var fileId in files)
1370				!files[fileId].uploadComplete && (++number) && this.cancelOne(fileId);
1371			this.get("onCancelAll") ? this.get("onCancelAll")(number) : this.onCancelAll(number);
1372		},
1373		cancelOne : function(file_id, stopping) {
1374			var provider = this.uploadInfo[file_id].file, actived = this.uploadInfo[file_id].actived;
1375			provider && provider.cancelUpload && provider.cancelUpload();
1376			if (!!stopping) {
1377				this.uploadInfo[file_id].actived = !1;
1378				return true;
1379			}
1380			
1381			var totalSize = this.totalFileSize - this.uploadInfo[file_id].file.config.size, info = {
1382				id:   file_id,
1383				name: this.uploadInfo[file_id].file.config.name,
1384				size: this.uploadInfo[file_id].file.config.size,
1385				totalSize: totalSize,
1386				formatTotalSize: this.formatBytes(totalSize),
1387				totalLoaded: this.totalUploadedSize,
1388				formatTotalLoaded: this.formatBytes(this.totalUploadedSize),
1389				totalPercent: totalSize == 0 ? 0 : this.totalUploadedSize * 10000 / totalSize / 100
1390			};
1391			100 > info.totalPercent && (info.totalPercent = parseFloat(info.totalPercent).toFixed(2));
1392			
1393			this.get("onCancel") ? this.get("onCancel")(info) : this.onCancel(info);
1394			this.uploadInfo[file_id] && delete this.uploadInfo[file_id];
1395			fRemoveEventListener(document, "click", this.cancelBtnHandler);
1396			!this.config.customered && this.containerPanel.removeChild(document.getElementById(file_id));
1397			if (actived) {
1398				this.uploading = !1;
1399				this.upload();
1400			} else {
1401				for(var i in this.waiting)
1402					if (this.waiting[i] === file_id)
1403						this.waiting.splice(i, 1);
1404			}
1405			var size = provider.config.size;
1406			this.totalFileSize -= size;
1407			var _loaded = this.formatBytes(this.totalUploadedSize);
1408			var percent = this.totalUploadedSize * 10000 / this.totalFileSize / 100;
1409			100 > percent && (percent = parseFloat(percent).toFixed(2));
1410			if (this.totalFileSize === 0)
1411				percent = 100;
1412				
1413			if (!this.config.customered) {
1414				var _total = this.formatBytes(this.totalFileSize);
1415				this.getNode("_stream-total-size", this.totalContainerPanel).innerHTML = _total;
1416				this.getNode("_stream-total-uploaded", this.totalContainerPanel).innerHTML = _loaded;
1417				this.getNode("stream-percent", this.totalContainerPanel).innerHTML = percent + "%";
1418				this.getNode("stream-process-bar", this.totalContainerPanel).innerHTML = '<span style="width: '+percent+'%;"></span>';
1419				
1420				/*** TODO: this code will be removed in the future.
1421				bStreaming ? this.startPanel.style.display = "block"
1422					: (this.startPanel.style.height = "auto", this.startPanel.style.width = "970px");*/
1423			}
1424		},
1425		cancelUploadHandler : function(event, b) {
1426			var c = event || window.event, id = b.nodeId, self = this;
1427			this.preventDefault(c);
1428			this.stopPropagation(c);
1429			if (this.uploadInfo[id].disabled)
1430				return !1;
1431			this.uploadInfo[id] && !this.uploadInfo[id].uploadComplete;
1432			this.cancelOne(id);
1433		},
1434		unloadHandler : function(evt) {
1435			var evt = evt || window.event;
1436			if (this.waiting.length > 0)
1437				return evt.returnValue = "\u60A8\u6B63\u5728\u4E0A\u4F20\u6587\u4EF6\uFF0C\u5173\u95ED\u6B64\u9875\u9762\u5C06\u4F1A\u4E2D\u65AD\u4E0A\u4F20\uFF0C\u5EFA\u8BAE\u60A8\u7B49\u5F85\u4E0A\u4F20\u5B8C\u6210\u540E\u518D\u5173\u95ED\u6B64\u9875\u9762";
1438		},
1439		upload : function(index) {
1440			if(this.uploading) return;
1441			index = this.waiting.shift();
1442			if(index == null) return;
1443			this.uploading = !0;
1444			
1445			this.uploadInfo[index].actived = !0;
1446			var file = this.uploadInfo[index].file, self = this;
1447			var frmUploadURL = this.get("frmUploadURL");
1448			var uploadURL = this.get("uploadURL");
1449			/** request the server to figure out what's the token for the file: */
1450			var xhr = window.XMLHttpRequest ? new XMLHttpRequest : new ActiveXObject("Microsoft.XMLHTTP");
1451			
1452			var vars = {
1453				name:	 file.get('name'),
1454				type: file.get('type'),
1455				size: file.get('size'),
1456				modified: file.get("dateModified") + ""
1457			};
1458			vars = fMergeJson(vars, this.get("postVarsPerFile"));
1459			var tokenUrl = fAddVars(vars, this.get("tokenURL")) + "&" + fGetRandom();
1460			xhr.open("GET", tokenUrl, !0);
1461			/** IE7,8 兼容*/
1462			xhr.onreadystatechange = function() {
1463			    if (xhr.readyState != 4 || xhr.status < 200)
1464			        return false;
1465			    
1466			    var token, server;
1467				try {
1468					try {
1469						token = eval("(" + xhr.responseText + ")").token;
1470						server = eval("(" + xhr.responseText + ")").server;
1471					} catch(e) {}
1472					if (token) {
1473						if(server != null && server != "") {
1474							frmUploadURL = server + frmUploadURL;
1475							uploadURL = server + uploadURL;
1476						}
1477						bStreaming && bFileSlice && !self.config.formed ? (self.uploadInfo[index].serverAddress = server,
1478										self.uploadFile(file, uploadURL, token, "resumeUpload"))
1479								: self.uploadFile(file, frmUploadURL, token, "formUpload");
1480					} else {
1481						/** not found any token */
1482						self.cancelOne(index);
1483						var msg = "\u521B\u5EFA\u4E0A\u4F20\u4EFB\u52A1\u5931\u8D25[tokenURL=" + self.get("tokenURL") + "],\u72B6\u6001\u7801:" + xhr.status;
1484						fShowMessage(msg, true);
1485					}
1486				} catch(e) {
1487					/** streaming, swf, resume methods all failed, no more try  */
1488				}
1489			}
1490			window.XMLHttpRequest && (xhr.onerror = function() {
1491				self.cancelOne(index);
1492				var msg = "\u521B\u5EFA\u4E0A\u4F20\u4EFB\u52A1\u5931\u8D25,\u72B6\u6001\u7801:" 
1492+ xhr.status + ",\u8BF7\u68C0\u6D4B\u7F51\u7EDC...";
1493				fShowMessage(msg, true);
1494			});
1495			xhr.send();
1496		},
1497		uploadFile : function(file, url, token, method) {
1498			var token = {
1499				token : token,
1500				client : method == "formUpload" || this.config.formed ? "formUpload" : "html5"
1501			};
1502			url = url || "";
1503			method && file instanceof StreamUploader && file.set("uploadMethod", method);
1504			this.fileProvider.upload(file, url, token);
1505		},
1506		uploadProgress : function(a) {
1507			var id = a.target.get("id"), percent = Math.min(99.99, a.percentLoaded),
1508				totalPercent = (this.totalUploadedSize + a.bytesLoaded) * 10000 / this.totalFileSize / 100, totalPercent = Math.min(99.99, totalPercent);
1509			100 > totalPercent && (totalPercent = parseFloat(totalPercent).toFixed(2));	
1510			
1511			if (!this.uploadInfo[id]) return false;
1512			if (this.config.customered) {
1513				var info = {
1514					id:                 id,
1515					loaded:             a.bytesLoaded,
1516					formatLoaded:       this.formatBytes(a.bytesLoaded),
1517					speed:              a.bytesSpeed,
1518					formatSpeed:        this.formatSpeed(a.bytesSpeed),
1519					size:               a.bytesTotal,
1520					formatSize:         this.formatBytes(a.bytesTotal),
1521					percent:            percent,
1522					timeLeft:           a.remainTime,
1523					formatTimeLeft:     this.formatTime(a.remainTime),
1524					totalSize:          this.totalFileSize,
1525					formatTotalSize:    this.formatBytes(this.totalFileSize),
1526					totalLoaded:        this.totalUploadedSize + a.bytesLoaded,
1527					formatTotalLoaded:  this.formatBytes(this.totalUploadedSize + a.bytesLoaded),
1528					totalPercent:       totalPercent
1529				};
1530				this.get("onUploadProgress") && this.get("onUploadProgress")(info);
1531				return false;
1532			}
1533			
1534			var progressNode = this.uploadInfo[id].progressNode,
1535				cellInfosNode = this.uploadInfo[id].cellInfosNode, bytesLoaded = a.bytesLoaded,
1536				c = this.formatSpeed(a.bytesSpeed), loaded = this.formatBytes(bytesLoaded),
1537				total = this.formatBytes(a.bytesTotal), _remainTime = this.formatTime(a.remainTime),
1538				a = Math.min(99.99, a.percentLoaded);
1539			100 > a && (a = parseFloat(a).toFixed(2));
1540			this.getNode("stream-process-bar", progressNode).innerHTML = "<span style='width:"+a+"%;'></span>";
1541			this.getNode("stream-percent", progressNode).innerHTML = a + "%";
1542			this.getNode("stream-speed", cellInfosNode).innerHTML = c;
1543			if (_remainTime)
1544				this.getNode("stream-remain-time", cellInfosNode).innerHTML = _remainTime;
1545			this.getNode("stream-uploaded", cellInfosNode).innerHTML = loaded + "/" + total;
1546			
1547			var _loaded = this.formatBytes(this.totalUploadedSize + bytesLoaded);
1548			var percent = (this.totalUploadedSize + bytesLoaded) * 10000 / this.totalFileSize / 100, percent = Math.min(99.99, percent);
1549			100 > percent && (percent = parseFloat(percent).toFixed(2));
1550			this.getNode("_stream-total-uploaded", this.totalContainerPanel).innerHTML = _loaded;
1551			this.getNode("stream-percent", this.totalContainerPanel).innerHTML = percent + "%";
1552			this.getNode("stream-process-bar", this.totalContainerPanel).innerHTML = '<span style="width: '+percent+'%;"></span>';
1553		},
1554		uploadComplete : function(a) {
1555			this.totalUploadedSize += a.target.get("size");
1556			var id = a.target.get("id"), percent = Math.min(100, a.percentLoaded),
1557				totalPercent = this.totalUploadedSize * 10000 / this.totalFileSize / 100;
1558			100 > totalPercent && (totalPercent = parseFloat(totalPercent).toFixed(2));
1559			if (this.totalFileSize === 0)
1560				percent = 100;
1561
1562			if (!this.uploadInfo[id]) return false;
1563			
1564			var info = {
1565				id:                 id,
1566				name:               a.target.get("name"),
1567				loaded:             a.target.get("size"),
1568				formatLoaded:       this.formatBytes(a.target.get("size")),
1569				size:               a.target.get("size"),
1570				formatSize:         this.formatBytes(a.target.get("size")),
1571				percent:            100,
1572				totalSize:          this.totalFileSize,
1573				formatTotalSize:    this.formatBytes(this.totalFileSize),
1574				totalLoaded:        this.totalUploadedSize,
1575				formatTotalLoaded:  this.formatBytes(this.totalUploadedSize),
1576				totalPercent:       totalPercent,
1577				msg:                a.data
1578			};
1579			/** uploaded flag and its callback function. */
1580			this.uploadInfo[id].uploadComplete = !0;
1581			
1582			if (!this.config.customered) {
1583				var progressNode = this.uploadInfo[id].progressNode,
1584					cellInfosNode = this.uploadInfo[id].cellInfosNode,
1585					size = a.target.get("size"), a = eval("(" + a.data + ")"), fmtSize = this.formatBytes(size);
1586				this.getNode("stream-process-bar", progressNode).innerHTML = "<span style='width:100%;'></span>";
1587				this.getNode("stream-percent", progressNode).innerHTML = "100%";
1588				this.getNode("stream-uploaded", cellInfosNode).innerHTML = fmtSize + "/" + fmtSize;
1589				this.getNode("stream-remain-time", cellInfosNode).innerHTML = "00:00:00";
1590				this.getNode("stream-cancel", progressNode).innerHTML = "";
1591				
1592				var _loaded = this.formatBytes(this.totalUploadedSize);
1593				var percent = this.totalUploadedSize * 10000 / this.totalFileSize / 100;
1594				100 > percent && (percent = parseFloat(percent).toFixed(2));
1595				if (this.totalFileSize === 0)
1596					percent = 100;
1597				this.getNode("_stream-total-uploaded", this.totalContainerPanel).innerHTML = _loaded;
1598				this.getNode("stream-percent", this.totalContainerPanel).innerHTML = percent + "%";
1599				this.getNode("stream-process-bar", this.totalContainerPanel).innerHTML = '<span style="width: '+percent+'%;"></span>';
1600			}
1601			
1602			this.completeUpload(info);
1603		},
1604		getNode : function(a, b) {
1605			return fContains(b || this.containerPanel, a)[0] || null;
1606		},
1607		uploadError : function(evt) {
1608			this.get("onUploadError") ? this.get("onUploadError")(evt.status, evt.statusText) : this.onUploadError(evt.status, evt.statusText);
1609		},
1610		fileSelect : function(a) {
1611			var a = a.fileList, b = 0, c, files = [];
1612			for (c = 0; c < a.length; c++)
1613				files.push(a[c].config);
1614			this.get("onSelect") ? this.get("onSelect")(files) : this.onSelect(files);
1615			for (c in this.uploadInfo)
1616				b++;
1617			if (b == this.get("simLimit") || a.length > this.get("simLimit")) {
1618				this.get("onFileCountExceed") ? this.get("onFileCountExceed")(Math.max(a.length, b), this.get("simLimit"))
1619						: this.onFileCountExceed(Math.max(a.length, b), this.get("simLimit"));
1620				return !1;
1621			}
1622			for (c = 0; c < a.length; c++)
1623				this.validateFile(a[c]) && this.addStreamTask(a[c]);
1624		},
1625		validateFile : function(uploader) {
1626			var name = uploader.get("name"), size = uploader.get("size"),
1627				ext = -1 !== name.indexOf(".") ? name.replace(/.*[.]/, "").toLowerCase() : "",
1628				filters = this.get("fileFilters"), valid = !1, msg = "",
1629				info = {
1630					id:               uploader.get("id"),
1631					name:             uploader.get("name"),
1632					size:             uploader.get("size"),
1633					formatSize:       this.formatBytes(uploader.get("size")),
1634					lastModifiedDate: uploader.get("lastModifiedDate"),
1635					limitSize:        this.get("maxSize"),
1636					formatLimitSize:  this.formatBytes(this.get("maxSize")),
1637					filters:          filters
1638				};
1639			
1640			// check the file been uploaded?
1641			if (this.uploadInfo) {
1642				var unique = uploader.get("name") + "_" + uploader.get("size");
1643				for (var i in this.uploadInfo) {
1644					var key = this.uploadInfo[i].file.get("name") + "_" + this.uploadInfo[i].file.get("size");
1645					if (key === unique) {
1646						var ignore = this.get("onRepeatedFile") ? this.get("onRepeatedFile")(info) : this.onRepeatedFile(info);
1647						if (!ignore) return !1;
1648					}
1649				}
1650			}
1651				
1652			if(!bStreaming && size > 2147483648){this.uploadError({status:100, statusText:"Flash最大只能上传2G的文件!"});return !1;}
1653			if (this.get("maxSize") < size)
1654				this.get("onMaxSizeExceed") ? this.get("onMaxSizeExceed")(info) : this.onMaxSizeExceed(info);
1655			else {
1656				filters.length || (valid = !0);
1657				for (var i = 0; i < filters.length; i++)
1658					filters[i].toLowerCase() == "." + ext && (valid = !0);
1659				if (!valid)
1660					this.get("onExtNameMismatch") ? this.get("onExtNameMismatch")(info) : this.onExtNameMismatch(info);
1661			}
1662			valid && this.config.customered && this.get("onAddTask") && this.get("onAddTask")(info, uploader);
1663			return valid;
1664		},
1665		formatSpeed : function(a) {
1666			var b = 0;
1667			1024 <= Math.round(a / 1024) 
1668				? (b = Math.round(100 * (a / 1048576)) / 100, b = Math.max(0, b), b = isNaN(b) ? 0 : parseFloat(b).toFixed(2), a = b + "MB/s")
1669				: (b = Math.round(100 * (a / 1024))	/ 100, b = Math.max(0, b), b = isNaN(b) ? 0 : parseFloat(b).toFixed(2), a = b + "KB/s");
1670			return a;
1671		},
1672		formatBytes : function(size) {
1673			if (size < 100) {
1674				return (size + 'B');
1675			} else if (size < 102400) {
1676				size = Math.round(100 * (size / 1024)) / 100;
1677				size = isNaN(size) ? 0 : parseFloat(size).toFixed(2);
1678				return (size + 'K');
1679			} else if (size < 1047527424) {
1680				size = Math.round(100 * (size / 1048576)) / 100;
1681				size = isNaN(size) ? 0 : parseFloat(size).toFixed(2);
1682				return (size + 'M');
1683			}
1684			
1685			size = Math.round(100 * (size / 1073741824)) / 100;
1686			size = isNaN(size) ? 0 : parseFloat(size).toFixed(2);
1687			return (size + 'G');
1688		},
1689		formatTime : function(time) {
1690			var total = time || 0, hour = Math.floor(total / 3600), minute = Math.floor((total - 3600 * hour) / 60),
1691				second = Math.floor(total - 3600 * hour - 60 * minute), hour = "" + (!isNaN(hour) && 0 < hour ? (hour < 10 ? ("0" + hour + ":") : (hour + ":")): "00:"),
1692				hour = hour + (!isNaN(minute) && 0 < minute ? (minute < 10 ? ("0" + minute + ":") : minute + ":") : "00:");
1693			return hour += !isNaN(second) && 0 < second ? (second < 10 ? ("0" + second + "") : second): "00";
1694		},
1695		preventDefault : function(a) {
1696			a.preventDefault ? a.preventDefault() : a.returnValue = !1
1697		},
1698		stopPropagation : function(a) {
1699			a.stopPropagation ? a.stopPropagation() : a.cancelBubble = !0
1700		}
1701	};
1702	
1703	var sIEFlashClassId = "clsid:d27cdb6e-ae6d-11cf-96b8-444553540000",
1704		sShockwaveFlash = "application/x-shockwave-flash", sFlashVersion = "10.0.22",
1705		sFlashDownload = "http://fpdownload.macromedia.com/pub/flashplayer/update/current/swf/autoUpdater.swf?"	+ Math.random(),
1706		sFlashEventHandler = "SWF.eventHandler",
1707		oa = {
1708			align : "",
1709			allowFullScreen : "",
1710			allowNetworking : "",
1711			allowScriptAccess : "",
1712			base : "",
1713			bgcolor : "",
1714			loop : "",
1715			menu : "",
1716			name : "",
1717			play : "",
1718			quality : "",
1719			salign : "",
1720			scale : "",
1721			tabindex : "",
1722			wmode : ""
1723		};
1724	var Browser = function(a) {
1725		var b = function(a) {
1726			var b = 0;
1727			return parseFloat(a.replace(/\./g, function() {
1728						return 1 == b++ ? "" : ".";
1729					}))
1730		}, c = window, d = c && c.navigator, e = {
1731			ie : 0,
1732			opera : 0,
1733			gecko : 0,
1734			webkit : 0,
1735			safari : 0,
1736			chrome : 0,
1737			firefox : 0,
1738			mobile : null,
1739			air : 0,
1740			phantomjs : 0,
1741			air : 0,
1742			ipad : 0,
1743			iphone : 0,
1744			ipod : 0,
1745			ios : null,
1746			android : 0,
1747			silk : 0,
1748			accel : !1,
1749			webos : 0,
1750			caja : d && d.cajaVersion,
1751			secure : !1,
1752			os : null,
1753			nodejs : 0
1754		}, a = a || d && d.userAgent, d = (c = c && c.location) && c.href, c = 0, f, g, h;
1755		e.userAgent = a;
1756		e.secure = d && 0 === d.toLowerCase().indexOf("https");
1757		if (a) {
1758			if (/windows|win32/i.test(a))
1759				e.os = "windows";
1760			else if (/macintosh|mac_powerpc/i.test(a))
1761				e.os = "macintosh";
1762			else if (/android/i.test(a))
1763				e.os = "android";
1764			else if (/symbos/i.test(a))
1765				e.os = "symbos";
1766			else if (/linux/i.test(a))
1767				e.os = "linux";
1768			else if (/rhino/i.test(a))
1769				e.os = "rhino";
1770			if (/KHTML/.test(a))
1771				e.webkit = 1;
1772			if (/IEMobile|XBLWP7/.test(a))
1773				e.mobile = "windows";
1774			if (/Fennec/.test(a))
1775				e.mobile = "gecko";
1776			if ((d = a.match(/AppleWebKit\/([^\s]*)/)) && d[1]) {
1777				e.webkit = b(d[1]);
1778				if ((d = a.match(/Version\/([^\s]*)/)) && d[1])
1779					e.safari = d[1];
1780				if (/PhantomJS/.test(a) && (d = a.match(/PhantomJS\/([^\s]*)/))
1781						&& d[1])
1782					e.phantomjs = b(d[1]);
1783				if (/Mobile\//.test(a) || /iPad|iPod|iPhone/.test(a)) {
1784					if (e.mobile = "Apple", (d = a.match(/OS ([^\s]*)/))
1785							&& d[1] && (d = b(d[1].replace("_", "."))), e.ios = d, e.os = "ios", e.ipad = e.ipod = e.iphone = 0, (d = a
1786							.match(/iPad|iPod|iPhone/))
1787							&& d[0])
1788						e[d[0].toLowerCase()] = e.ios;
1789				} else {
1790					if (d = a.match(/NokiaN[^\/]*|webOS\/\d\.\d/))
1791						e.mobile = d[0];
1792					if (/webOS/.test(a)
1793							&& (e.mobile = "WebOS", (d = a
1794									.match(/webOS\/([^\s]*);/))
1795									&& d[1]))
1796						e.webos = b(d[1]);
1797					if (/ Android/.test(a)) {
1798						if (/Mobile/.test(a))
1799							e.mobile = "Android";
1800						if ((d = a.match(/Android ([^\s]*);/)) && d[1])
1801							e.android = b(d[1]);
1802					}
1803					if (/Silk/.test(a)) {
1804						if ((d = a.match(/Silk\/([^\s]*)\)/)) && d[1])
1805							e.silk = b(d[1]);
1806						if (!e.android)
1807							e.android = 2.34, e.os = "Android";
1808						if (/Accelerated=true/.test(a))
1809							e.accel = !0;
1810					}
1811				}
1812				if ((d = a.match(/(Chrome|CrMo|CriOS)\/([^\s]*)/)) && d[1]
1813						&& d[2]) {
1814					if (e.chrome = b(d[2]), e.safari = 0, "CrMo" === d[1])
1815						e.mobile = "chrome";
1816				} else if (d = a.match(/AdobeAIR\/([^\s]*)/))
1817					e.air = d[0];
1818			}
1819			if (!e.webkit)
1820				if (/Opera/.test(a)) {
1821					if ((d = a.match(/Opera[\s\/]([^\s]*)/)) && d[1])
1822						e.opera = b(d[1]);
1823					if ((d = a.match(/Version\/([^\s]*)/)) && d[1])
1824						e.opera = b(d[1]);
1825					if (/Opera Mobi/.test(a) && (e.mobile = "opera", (d = a.replace("Opera Mobi", "").match(/Opera ([^\s]*)/)) && d[1]))
1826						e.opera = b(d[1]);
1827					if (d = a.match(/Opera Mini[^;]*/))
1828						e.mobile = d[0];
1829				} else if ((d = a.match(/MSIE\s([^;]*)/)) && d[1])
1830					e.ie = b(d[1]);
1831				else if (d = a.match(/Gecko\/([^\s]*)/)) {
1832					if (e.gecko = 1, (d = a.match(/rv:([^\s\)]*)/)) && d[1])
1833						e.gecko = b(d[1]);
1834					if ((d = a.match(/(Firefox)\/([^\s]*)/)) && d[1] && d[2])
1835						e.firefox = d[2];
1836				}
1837		}
1838		if (e.gecko || e.webkit || e.opera) {
1839			if (b = navigator.mimeTypes["application/x-shockwave-flash"])
1840				if (b = b.enabledPlugin)
1841					f = b.description.replace(/\s[rd]/g, ".").replace(
1842							/[A-Za-z\s]+/g, "").split(".");
1843		} else if (e.ie) {
1844			try {
1845				g = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6"), g.AllowScriptAccess = "always";
1846			} catch (j) {null !== g && (c = 6);}
1847			if (0 === c)
1848				try {
1849					h = new ActiveXObject("ShockwaveFlash.ShockwaveFlash"),
1850					f = h.GetVariable("$version").replace(/[A-Za-z\s]+/g, "").split(",");
1851				} catch (s) {}
1852		}
1853		if (fIsArray(f)) {
1854			if (fIsNumber(parseInt(f[0], 10)))
1855				e.flashMajor = f[0];
1856			if (fIsNumber(parseInt(f[1], 10)))
1857				e.flashMinor = f[1];
1858			if (fIsNumber(parseInt(f[2], 10)))
1859				e.flashRev = f[2];
1860		}
1861		return e;
1862	}();
1863	var bFileSlice = !1;
1864	var bStreaming = function() {
1865		var bFile = !1, bHtml5 = !1, bFormData = window.FormData ? !0 : !1, bStreaming = !1;
1866		"undefined" != typeof File && "undefined" != typeof (new XMLHttpRequest).upload && (bFile = !0);
1867		if (bFile && (bFileSlice = "slice" in File.prototype || "mozSlice" in File.prototype || "webkitSlice" in File.prototype))
1868			bHtml5 = !0;
1869		(function() {
1870			for (var a = 0; a < aOtherBrowsers.length; a++)
1871				-1 !== navigator.userAgent.indexOf(aOtherBrowsers[a]) && (bHtml5 = !1);
1872		})();
1873		/** some browsers has problems. */
1874		(bFormData && Browser.os === "windows" && Browser.safari === "5.1.7") && (bFormData = !1);
1875		return bFile && (bFormData || bHtml5);
1876	}(), bDraggable = bStreaming && ('draggable' in document.createElement('span')), bFolder = bDraggable && (window.webkitRequestFileSystem || window.requestFileSystem);
1877	Provider = bStreaming ? StreamProvider : SWFProvider;
1878	window.Stream = window.Uploader = Main; /** window.Uploader是SWF组件的关键字(保留) */
1879})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.