PageSourceSearch

https://www.todos-math.org/wp-includes/js/plupload/moxie.js?ver=1.3.5.1

js todos-math.org collected 2026-10-01 11:53:40 UTC 254,342 bytes, 9,904 lines download raw bytes

1;var MXI_DEBUG = false;
2/**
3 * mOxie - multi-runtime File API & XMLHttpRequest L2 Polyfill
4 * v1.3.5.1
5 *
6 * Copyright 2013, Moxiecode Systems AB
7 * Released under GPL License.
8 *
9 * License: http://www.plupload.com/license
10 * Contributing: http://www.plupload.com/contributing
11 *
12 * Date: 2016-05-15
13 */
14/**
15 * Compiled inline version. (Library mode)
16 */
17
18/**
19 * Modified for WordPress.
20 * - Silverlight and Flash runtimes support was removed. See https://core.trac.wordpress.org/ticket/41755.
21 * - A stray Unicode character has been removed. See https://core.trac.wordpress.org/ticket/59329.
22 *
23 * This is a de-facto fork of the mOxie library that will be maintained by WordPress due to upstream license changes
24 * that are incompatible with the GPL.
25 */
26
27/*jshint smarttabs:true, undef:true, latedef:true, curly:true, bitwise:true, camelcase:true */
28/*globals $code */
29
30(function(exports, undefined) {
31	"use strict";
32
33	var modules = {};
34
35	function require(ids, callback) {
36		var module, defs = [];
37
38		for (var i = 0; i < ids.length; ++i) {
39			module = modules[ids[i]] || resolve(ids[i]);
40			if (!module) {
41				throw 'module definition dependecy not found: ' + ids[i];
42			}
43
44			defs.push(module);
45		}
46
47		callback.apply(null, defs);
48	}
49
50	function define(id, dependencies, definition) {
51		if (typeof id !== 'string') {
52			throw 'invalid module definition, module id must be defined and be a string';
53		}
54
55		if (dependencies === undefined) {
56			throw 'invalid module definition, dependencies must be specified';
57		}
58
59		if (definition === undefined) {
60			throw 'invalid module definition, definition function must be specified';
61		}
62
63		require(dependencies, function() {
64			modules[id] = definition.apply(null, arguments);
65		});
66	}
67
68	function defined(id) {
69		return !!modules[id];
70	}
71
72	function resolve(id) {
73		var target = exports;
74		var fragments = id.split(/[.\/]/);
75
76		for (var fi = 0; fi < fragments.length; ++fi) {
77			if (!target[fragments[fi]]) {
78				return;
79			}
80
81			target = target[fragments[fi]];
82		}
83
84		return target;
85	}
86
87	function expose(ids) {
88		for (var i = 0; i < ids.length; i++) {
89			var target = exports;
90			var id = ids[i];
91			var fragments = id.split(/[.\/]/);
92
93			for (var fi = 0; fi < fragments.length - 1; ++fi) {
94				if (target[fragments[fi]] === undefined) {
95					target[fragments[fi]] = {};
96				}
97
98				target = target[fragments[fi]];
99			}
100
101			target[fragments[fragments.length - 1]] = modules[id];
102		}
103	}
104
105// Included from: src/javascript/core/utils/Basic.js
106
107/**
108 * Basic.js
109 *
110 * Copyright 2013, Moxiecode Systems AB
111 * Released under GPL License.
112 *
113 * License: http://www.plupload.com/license
114 * Contributing: http://www.plupload.com/contributing
115 */
116
117define('moxie/core/utils/Basic', [], function() {
118	/**
119	Gets the true type of the built-in object (better version of typeof).
120	@author Angus Croll (http://javascriptweblog.wordpress.com/)
121
122	@method typeOf
123	@for Utils
124	@static
125	@param {Object} o Object to check.
126	@return {String} Object [[Class]]
127	*/
128	var typeOf = function(o) {
129		var undef;
130
131		if (o === undef) {
132			return 'undefined';
133		} else if (o === null) {
134			return 'null';
135		} else if (o.nodeType) {
136			return 'node';
137		}
138
139		// the snippet below is awesome, however it fails to detect null, undefined and arguments types in IE lte 8
140		return ({}).toString.call(o).match(/\s([a-z|A-Z]+)/)[1].toLowerCase();
141	};
142		
143	/**
144	Extends the specified object with another object.
145
146	@method extend
147	@static
148	@param {Object} target Object to extend.
149	@param {Object} [obj]* Multiple objects to extend with.
150	@return {Object} Same as target, the extended object.
151	*/
152	var extend = function(target) {
153		var undef;
154
155		each(arguments, function(arg, i) {
156			if (i > 0) {
157				each(arg, function(value, key) {
158					if (value !== undef) {
159						if (typeOf(target[key]) === typeOf(value) && !!~inArray(typeOf(value), ['array', 'object'])) {
160							extend(target[key], value);
161						} else {
162							target[key] = value;
163						}
164					}
165				});
166			}
167		});
168		return target;
169	};
170		
171	/**
172	Executes the callback function for each item in array/object. If you return false in the
173	callback it will break the loop.
174
175	@method each
176	@static
177	@param {Object} obj Object to iterate.
178	@param {function} callback Callback function to execute for each item.
179	*/
180	var each = function(obj, callback) {
181		var length, key, i, undef;
182
183		if (obj) {
184			if (typeOf(obj.length) === 'number') { // it might be Array, FileList or even arguments object
185				// Loop array items
186				for (i = 0, length = obj.length; i < length; i++) {
187					if (callback(obj[i], i) === false) {
188						return;
189					}
190				}
191			} else if (typeOf(obj) === 'object') {
192				// Loop object items
193				for (key in obj) {
194					if (obj.hasOwnProperty(key)) {
195						if (callback(obj[key], key) === false) {
196							return;
197						}
198					}
199				}
200			}
201		}
202	};
203
204	/**
205	Checks if object is empty.
206	
207	@method isEmptyObj
208	@static
209	@param {Object} o Object to check.
210	@return {Boolean}
211	*/
212	var isEmptyObj = function(obj) {
213		var prop;
214
215		if (!obj || typeOf(obj) !== 'object') {
216			return true;
217		}
218
219		for (prop in obj) {
220			return false;
221		}
222
223		return true;
224	};
225
226	/**
227	Recieve an array of functions (usually async) to call in sequence, each  function
228	receives a callback as first argument that it should call, when it completes. Finally,
229	after everything is complete, main callback is called. Passing truthy value to the
230	callback as a first argument will interrupt the sequence and invoke main callback
231	immediately.
232
233	@method inSeries
234	@static
235	@param {Array} queue Array of functions to call in sequence
236	@param {Function} cb Main callback that is called in the end, or in case of error
237	*/
238	var inSeries = function(queue, cb) {
239		var i = 0, length = queue.length;
240
241		if (typeOf(cb) !== 'function') {
242			cb = function() {};
243		}
244
245		if (!queue || !queue.length) {
246			cb();
247		}
248
249		function callNext(i) {
250			if (typeOf(queue[i]) === 'function') {
251				queue[i](function(error) {
252					/*jshint expr:true */
253					++i < length && !error ? callNext(i) : cb(error);
254				});
255			}
256		}
257		callNext(i);
258	};
259
260
261	/**
262	Recieve an array of functions (usually async) to call in parallel, each  function
263	receives a callback as first argument that it should call, when it completes. After 
264	everything is complete, main callback is called. Passing truthy value to the
265	callback as a first argument will interrupt the process and invoke main callback
266	immediately.
267
268	@method inParallel
269	@static
270	@param {Array} queue Array of functions to call in sequence
271	@param {Function} cb Main callback that is called in the end, or in case of error
272	*/
273	var inParallel = function(queue, cb) {
274		var count = 0, num = queue.length, cbArgs = new Array(num);
275
276		each(queue, function(fn, i) {
277			fn(function(error) {
278				if (error) {
279					return cb(error);
280				}
281				
282				var args = [].slice.call(arguments);
283				args.shift(); // strip error - undefined or not
284
285				cbArgs[i] = args;
286				count++;
287
288				if (count === num) {
289					cbArgs.unshift(null);
290					cb.apply(this, cbArgs);
291				} 
292			});
293		});
294	};
295	
296	
297	/**
298	Find an element in array and return it's index if present, otherwise return -1.
299	
300	@method inArray
301	@static
302	@param {Mixed} needle Element to find
303	@param {Array} array
304	@return {Int} Index of the element, or -1 if not found
305	*/
306	var inArray = function(needle, array) {
307		if (array) {
308			if (Array.prototype.indexOf) {
309				return Array.prototype.indexOf.call(array, needle);
310			}
311		
312			for (var i = 0, length = array.length; i < length; i++) {
313				if (array[i] === needle) {
314					return i;
315				}
316			}
317		}
318		return -1;
319	};
320
321
322	/**
323	Returns elements of first array if they are not present in second. And false - otherwise.
324
325	@private
326	@method arrayDiff
327	@param {Array} needles
328	@param {Array} array
329	@return {Array|Boolean}
330	*/
331	var arrayDiff = function(needles, array) {
332		var diff = [];
333
334		if (typeOf(needles) !== 'array') {
335			needles = [needles];
336		}
337
338		if (typeOf(array) !== 'array') {
339			array = [array];
340		}
341
342		for (var i in needles) {
343			if (inArray(needles[i], array) === -1) {
344				diff.push(needles[i]);
345			}	
346		}
347		return diff.length ? diff : false;
348	};
349
350
351	/**
352	Find intersection of two arrays.
353
354	@private
355	@method arrayIntersect
356	@param {Array} array1
357	@param {Array} array2
358	@return {Array} Intersection of two arrays or null if there is none
359	*/
360	var arrayIntersect = function(array1, array2) {
361		var result = [];
362		each(array1, function(item) {
363			if (inArray(item, array2) !== -1) {
364				result.push(item);
365			}
366		});
367		return result.length ? result : null;
368	};
369	
370	
371	/**
372	Forces anything into an array.
373	
374	@method toArray
375	@static
376	@param {Object} obj Object with length field.
377	@return {Array} Array object containing all items.
378	*/
379	var toArray = function(obj) {
380		var i, arr = [];
381
382		for (i = 0; i < obj.length; i++) {
383			arr[i] = obj[i];
384		}
385
386		return arr;
387	};
388	
389			
390	/**
391	Generates an unique ID. The only way a user would be able to get the same ID is if the two persons
392	at the same exact millisecond manage to get the same 5 random numbers between 0-65535; it also uses 
393	a counter so each ID is guaranteed to be unique for the given page. It is more probable for the earth 
394	to be hit with an asteroid.
395	
396	@method guid
397	@static
398	@param {String} prefix to prepend (by default 'o' will be prepended).
399	@method guid
400	@return {String} Virtually unique id.
401	*/
402	var guid = (function() {
403		var counter = 0;
404		
405		return function(prefix) {
406			var guid = new Date().getTime().toString(32), i;
407
408			for (i = 0; i < 5; i++) {
409				guid += Math.floor(Math.random() * 65535).toString(32);
410			}
411			
412			return (prefix || 'o_') + guid + (counter++).toString(32);
413		};
414	}());
415	
416
417	/**
418	Trims white spaces around the string
419	
420	@method trim
421	@static
422	@param {String} str
423	@return {String}
424	*/
425	var trim = function(str) {
426		if (!str) {
427			return str;
428		}
429		return String.prototype.trim ? String.prototype.trim.call(str) : str.toString().replace(/^\s*/, '').replace(/\s*$/, '');
430	};
431
432
433	/**
434	Parses the specified size string into a byte value. For example 10kb becomes 10240.
435	
436	@method parseSizeStr
437	@static
438	@param {String/Number} size String to parse or number to just pass through.
439	@return {Number} Size in bytes.
440	*/
441	var parseSizeStr = function(size) {
442		if (typeof(size) !== 'string') {
443			return size;
444		}
445		
446		var muls = {
447				t: 1099511627776,
448				g: 1073741824,
449				m: 1048576,
450				k: 1024
451			},
452			mul;
453
454
455		size = /^([0-9\.]+)([tmgk]?)$/.exec(size.toLowerCase().replace(/[^0-9\.tmkg]/g, ''));
456		mul = size[2];
457		size = +size[1];
458		
459		if (muls.hasOwnProperty(mul)) {
460			size *= muls[mul];
461		}
462		return Math.floor(size);
463	};
464
465
466	/**
467	 * Pseudo sprintf implementation - simple way to replace tokens with specified values.
468	 *
469	 * @param {String} str String with tokens
470	 * @return {String} String with replaced tokens
471	 */
472	var sprintf = function(str) {
473		var args = [].slice.call(arguments, 1);
474
475		return str.replace(/%[a-z]/g, function() {
476			var value = args.shift();
477			return typeOf(value) !== 'undefined' ? value : '';
478		});
479	};
480	
481
482	return {
483		guid: guid,
484		typeOf: typeOf,
485		extend: extend,
486		each: each,
487		isEmptyObj: isEmptyObj,
488		inSeries: inSeries,
489		inParallel: inParallel,
490		inArray: inArray,
491		arrayDiff: arrayDiff,
492		arrayIntersect: arrayIntersect,
493		toArray: toArray,
494		trim: trim,
495		sprintf: sprintf,
496		parseSizeStr: parseSizeStr
497	};
498});
499
500// Included from: src/javascript/core/utils/Env.js
501
502/**
503 * Env.js
504 *
505 * Copyright 2013, Moxiecode Systems AB
506 * Released under GPL License.
507 *
508 * License: http://www.plupload.com/license
509 * Contributing: http://www.plupload.com/contributing
510 */
511
512define("moxie/core/utils/Env", [
513	"moxie/core/utils/Basic"
514], function(Basic) {
515	
516	/**
517	 * UAParser.js v0.7.7
518	 * Lightweight JavaScript-based User-Agent string parser
519	 * https://github.com/faisalman/ua-parser-js
520	 *
521	 * Copyright © 2012-2015 Faisal Salman <[email protected]>
522	 * Dual licensed under GPLv2 & MIT
523	 */
524	var UAParser = (function (undefined) {
525
526	    //////////////
527	    // Constants
528	    /////////////
529
530
531	    var EMPTY       = '',
532	        UNKNOWN     = '?',
533	        FUNC_TYPE   = 'function',
534	        UNDEF_TYPE  = 'undefined',
535	        OBJ_TYPE    = 'object',
536	        MAJOR       = 'major',
537	        MODEL       = 'model',
538	        NAME        = 'name',
539	        TYPE        = 'type',
540	        VENDOR      = 'vendor',
541	        VERSION     = 'version',
542	        ARCHITECTURE= 'architecture',
543	        CONSOLE     = 'console',
544	        MOBILE      = 'mobile',
545	        TABLET      = 'tablet';
546
547
548	    ///////////
549	    // Helper
550	    //////////
551
552
553	    var util = {
554	        has : function (str1, str2) {
555	            return str2.toLowerCase().indexOf(str1.toLowerCase()) !== -1;
556	        },
557	        lowerize : function (str) {
558	            return str.toLowerCase();
559	        }
560	    };
561
562
563	    ///////////////
564	    // Map helper
565	    //////////////
566
567
568	    var mapper = {
569
570	        rgx : function () {
571
572	            // loop through all regexes maps
573	            for (var result, i = 0, j, k, p, q, matches, match, args = arguments; i < args.length; i += 2) {
574
575	                var regex = args[i],       // even sequence (0,2,4,..)
576	                    props = args[i + 1];   // odd sequence (1,3,5,..)
577
578	                // construct object barebones
579	                if (typeof(result) === UNDEF_TYPE) {
580	                    result = {};
581	                    for (p in props) {
582	                        q = props[p];
583	                        if (typeof(q) === OBJ_TYPE) {
584	                            result[q[0]] = undefined;
585	                        } else {
586	                            result[q] = undefined;
587	                        }
588	                    }
589	                }
590
591	                // try matching uastring with regexes
592	                for (j = k = 0; j < regex.length; j++) {
593	                    matches = regex[j].exec(this.getUA());
594	                    if (!!matches) {
595	                        for (p = 0; p < props.length; p++) {
596	                            match = matches[++k];
597	                            q = props[p];
598	                            // check if given property is actually array
599	                            if (typeof(q) === OBJ_TYPE && q.length > 0) {
600	                                if (q.length == 2) {
601	                                    if (typeof(q[1]) == FUNC_TYPE) {
602	                                        // assign modified match
603	                                        result[q[0]] = q[1].call(this, match);
604	                                    } else {
605	                                        // assign given value, ignore regex match
606	                                        result[q[0]] = q[1];
607	                                    }
608	                                } else if (q.length == 3) {
609	                                    // check whether function or regex
610	                                    if (typeof(q[1]) === FUNC_TYPE && !(q[1].exec && q[1].test)) {
611	                                        // call function (usually string mapper)
612	                                        result[q[0]] = match ? q[1].call(this, match, q[2]) : undefined;
613	                                    } else {
614	                                        // sanitize match using given regex
615	                                        result[q[0]] = match ? match.replace(q[1], q[2]) : undefined;
616	                                    }
617	                                } else if (q.length == 4) {
618	                                        result[q[0]] = match ? q[3].call(this, match.replace(q[1], q[2])) : undefined;
619	                                }
620	                            } else {
621	                                result[q] = match ? match : undefined;
622	                            }
623	                        }
624	                        break;
625	                    }
626	                }
627
628	                if(!!matches) break; // break the loop immediately if match found
629	            }
630	            return result;
631	        },
632
633	        str : function (str, map) {
634
635	            for (var i in map) {
636	                // check if array
637	                if (typeof(map[i]) === OBJ_TYPE && map[i].length > 0) {
638	                    for (var j = 0; j < map[i].length; j++) {
639	                        if (util.has(map[i][j], str)) {
640	                            return (i === UNKNOWN) ? undefined : i;
641	                        }
642	                    }
643	                } else if (util.has(map[i], str)) {
644	                    return (i === UNKNOWN) ? undefined : i;
645	                }
646	            }
647	            return str;
648	        }
649	    };
650
651
vendor: 5,701 bytes, lines 652-792
652	    ///////////////
653	    // String map
654	    //////////////
655
656
657	    var maps = {
658
659	        browser : {
660	            oldsafari : {
661	                major : {
662	                    '1' : ['/8', '/1', '/3'],
663	                    '2' : '/4',
664	                    '?' : '/'
665	                },
666	                version : {
667	                    '1.0'   : '/8',
668	                    '1.2'   : '/1',
669	                    '1.3'   : '/3',
670	                    '2.0'   : '/412',
671	                    '2.0.2' : '/416',
672	                    '2.0.3' : '/417',
673	                    '2.0.4' : '/419',
674	                    '?'     : '/'
675	                }
676	            }
677	        },
678
679	        device : {
680	            sprint : {
681	                model : {
682	                    'Evo Shift 4G' : '7373KT'
683	                },
684	                vendor : {
685	                    'HTC'       : 'APA',
686	                    'Sprint'    : 'Sprint'
687	                }
688	            }
689	        },
690
691	        os : {
692	            windows : {
693	                version : {
694	                    'ME'        : '4.90',
695	                    'NT 3.11'   : 'NT3.51',
696	                    'NT 4.0'    : 'NT4.0',
697	                    '2000'      : 'NT 5.0',
698	                    'XP'        : ['NT 5.1', 'NT 5.2'],
699	                    'Vista'     : 'NT 6.0',
700	                    '7'         : 'NT 6.1',
701	                    '8'         : 'NT 6.2',
702	                    '8.1'       : 'NT 6.3',
703	                    'RT'        : 'ARM'
704	                }
705	            }
706	        }
707	    };
708
709
710	    //////////////
711	    // Regex map
712	    /////////////
713
714
715	    var regexes = {
716
717	        browser : [[
718	        
719	            // Presto based
720	            /(opera\smini)\/([\w\.-]+)/i,                                       // Opera Mini
721	            /(opera\s[mobiletab]+).+version\/([\w\.-]+)/i,                      // Opera Mobi/Tablet
722	            /(opera).+version\/([\w\.]+)/i,                                     // Opera > 9.80
723	            /(opera)[\/\s]+([\w\.]+)/i                                          // Opera < 9.80
724
725	            ], [NAME, VERSION], [
726
727	            /\s(opr)\/([\w\.]+)/i                                               // Opera Webkit
728	            ], [[NAME, 'Opera'], VERSION], [
729
730	            // Mixed
731	            /(kindle)\/([\w\.]+)/i,                                             // Kindle
732	            /(lunascape|maxthon|netfront|jasmine|blazer)[\/\s]?([\w\.]+)*/i,
733	                                                                                // Lunascape/Maxthon/Netfront/Jasmine/Blazer
734
735	            // Trident based
736	            /(avant\s|iemobile|slim|baidu)(?:browser)?[\/\s]?([\w\.]*)/i,
737	                                                                                // Avant/IEMobile/SlimBrowser/Baidu
738	            /(?:ms|\()(ie)\s([\w\.]+)/i,                                        // Internet Explorer
739
740	            // Webkit/KHTML based
741	            /(rekonq)\/([\w\.]+)*/i,                                            // Rekonq
742	            /(chromium|flock|rockmelt|midori|epiphany|silk|skyfire|ovibrowser|bolt|iron|vivaldi)\/([\w\.-]+)/i
743	                                                                                // Chromium/Flock/RockMelt/Midori/Epiphany/Silk/Skyfire/Bolt/Iron
744	            ], [NAME, VERSION], [
745
746	            /(trident).+rv[:\s]([\w\.]+).+like\sgecko/i                         // IE11
747	            ], [[NAME, 'IE'], VERSION], [
748
749	            /(edge)\/((\d+)?[\w\.]+)/i                                          // Microsoft Edge
750	            ], [NAME, VERSION], [
751
752	            /(yabrowser)\/([\w\.]+)/i                                           // Yandex
753	            ], [[NAME, 'Yandex'], VERSION], [
754
755	            /(comodo_dragon)\/([\w\.]+)/i                                       // Comodo Dragon
756	            ], [[NAME, /_/g, ' '], VERSION], [
757
758	            /(chrome|omniweb|arora|[tizenoka]{5}\s?browser)\/v?([\w\.]+)/i,
759	                                                                                // Chrome/OmniWeb/Arora/Tizen/Nokia
760	            /(uc\s?browser|qqbrowser)[\/\s]?([\w\.]+)/i
761	                                                                                // UCBrowser/QQBrowser
762	            ], [NAME, VERSION], [
763
764	            /(dolfin)\/([\w\.]+)/i                                              // Dolphin
765	            ], [[NAME, 'Dolphin'], VERSION], [
766
767	            /((?:android.+)crmo|crios)\/([\w\.]+)/i                             // Chrome for Android/iOS
768	            ], [[NAME, 'Chrome'], VERSION], [
769
770	            /XiaoMi\/MiuiBrowser\/([\w\.]+)/i                                   // MIUI Browser
771	            ], [VERSION, [NAME, 'MIUI Browser']], [
772
773	            /android.+version\/([\w\.]+)\s+(?:mobile\s?safari|safari)/i         // Android Browser
774	            ], [VERSION, [NAME, 'Android Browser']], [
775
776	            /FBAV\/([\w\.]+);/i                                                 // Facebook App for iOS
777	            ], [VERSION, [NAME, 'Facebook']], [
778
779	            /version\/([\w\.]+).+?mobile\/\w+\s(safari)/i                       // Mobile Safari
780	            ], [VERSION, [NAME, 'Mobile Safari']], [
781
782	            /version\/([\w\.]+).+?(mobile\s?safari|safari)/i                    // Safari & Safari Mobile
783	            ], [VERSION, NAME], [
784
785	            /webkit.+?(mobile\s?safari|safari)(\/[\w\.]+)/i                     // Safari < 3.0
786	            ], [NAME, [VERSION, mapper.str, maps.browser.oldsafari.version]], [
787
788	            /(konqueror)\/([\w\.]+)/i,                                          // Konqueror
789	            /(webkit|khtml)\/([\w\.]+)/i
790	            ], [NAME, VERSION], [
791
792	            // Gecko based
793	            /(navigator|netscape)\/([\w\.-]+)/i                                 // Netscape
794	            ], [[NAME, 'Netscape'], VERSION], [
795	            /(swiftfox)/i,                                                      // Swiftfox
796	            /(icedragon|iceweasel|camino|chimera|fennec|maemo\sbrowser|minimo|conkeror)[\/\s]?([\w\.\+]+)/i,
797	                                                                                // IceDragon/Iceweasel/Camino/Chimera/Fennec/Maemo/Minimo/Conkeror
798	            /(firefox|seamonkey|k-meleon|icecat|iceape|firebird|phoenix)\/([\w\.-]+)/i,
799	                                                                                // Firefox/SeaMonkey/K-Meleon/IceCat/IceApe/Firebird/Phoenix
800	            /(mozilla)\/([\w\.]+).+rv\:.+gecko\/\d+/i,                          // Mozilla
801
802	            // Other
803	            /(polaris|lynx|dillo|icab|doris|amaya|w3m|netsurf)[\/\s]?([\w\.]+)/i,
804	                                                                                // Polaris/Lynx/Dillo/iCab/Doris/Amaya/w3m/NetSurf
805	            /(links)\s\(([\w\.]+)/i,                                            // Links
806	            /(gobrowser)\/?([\w\.]+)*/i,                                        // GoBrowser
807	            /(ice\s?browser)\/v?([\w\._]+)/i,                                   // ICE Browser
808	            /(mosaic)[\/\s]([\w\.]+)/i                                          // Mosaic
809	            ], [NAME, VERSION]
810	        ],
811
812	        engine : [[
813
814	            /windows.+\sedge\/([\w\.]+)/i                                       // EdgeHTML
815	            ], [VERSION, [NAME, 'EdgeHTML']], [
816
817	            /(presto)\/([\w\.]+)/i,                                             // Presto
818	            /(webkit|trident|netfront|netsurf|amaya|lynx|w3m)\/([\w\.]+)/i,     // WebKit/Trident/NetFront/NetSurf/Amaya/Lynx/w3m
819	            /(khtml|tasman|links)[\/\s]\(?([\w\.]+)/i,                          // KHTML/Tasman/Links
820	            /(icab)[\/\s]([23]\.[\d\.]+)/i                                      // iCab
821	            ], [NAME, VERSION], [
822
823	            /rv\:([\w\.]+).*(gecko)/i                                           // Gecko
824	            ], [VERSION, NAME]
825	        ],
826
827	        os : [[
828
vendor: 1,816 bytes, lines 829-855
829	            // Windows based
830	            /microsoft\s(windows)\s(vista|xp)/i                                 // Windows (iTunes)
831	            ], [NAME, VERSION], [
832	            /(windows)\snt\s6\.2;\s(arm)/i,                                     // Windows RT
833	            /(windows\sphone(?:\sos)*|windows\smobile|windows)[\s\/]?([ntce\d\.\s]+\w)/i
834	            ], [NAME, [VERSION, mapper.str, maps.os.windows.version]], [
835	            /(win(?=3|9|n)|win\s9x\s)([nt\d\.]+)/i
836	            ], [[NAME, 'Windows'], [VERSION, mapper.str, maps.os.windows.version]], [
837
838	            // Mobile/Embedded OS
839	            /\((bb)(10);/i                                                      // BlackBerry 10
840	            ], [[NAME, 'BlackBerry'], VERSION], [
841	            /(blackberry)\w*\/?([\w\.]+)*/i,                                    // Blackberry
842	            /(tizen)[\/\s]([\w\.]+)/i,                                          // Tizen
843	            /(android|webos|palm\os|qnx|bada|rim\stablet\sos|meego|contiki)[\/\s-]?([\w\.]+)*/i,
844	                                                                                // Android/WebOS/Palm/QNX/Bada/RIM/MeeGo/Contiki
845	            /linux;.+(sailfish);/i                                              // Sailfish OS
846	            ], [NAME, VERSION], [
847	            /(symbian\s?os|symbos|s60(?=;))[\/\s-]?([\w\.]+)*/i                 // Symbian
848	            ], [[NAME, 'Symbian'], VERSION], [
849	            /\((series40);/i                                                    // Series 40
850	            ], [NAME], [
851	            /mozilla.+\(mobile;.+gecko.+firefox/i                               // Firefox OS
852	            ], [[NAME, 'Firefox OS'], VERSION], [
853
854	            // Console
855	            /(nintendo|playstation)\s([wids3portablevu]+)/i,                    // Nintendo
855/Playstation
856
857	            // GNU/Linux based
858	            /(mint)[\/\s\(]?(\w+)*/i,                                           // Mint
859	            /(mageia|vectorlinux)[;\s]/i,                                       // Mageia/VectorLinux
860	            /(joli|[kxln]?ubuntu|debian|[open]*suse|gentoo|arch|slackware|fedora|mandriva|centos|pclinuxos|redhat|zenwalk|linpus)[\/\s-]?([\w\.-]+)*/i,
861	                                                                                // Joli/Ubuntu/Debian/SUSE/Gentoo/Arch/Slackware
862	                                                                                // Fedora/Mandriva/CentOS/PCLinuxOS/RedHat/Zenwalk/Linpus
863	            /(hurd|linux)\s?([\w\.]+)*/i,                                       // Hurd/Linux
864	            /(gnu)\s?([\w\.]+)*/i                                               // GNU
865	            ], [NAME, VERSION], [
866
867	            /(cros)\s[\w]+\s([\w\.]+\w)/i                                       // Chromium OS
868	            ], [[NAME, 'Chromium OS'], VERSION],[
869
870	            // Solaris
871	            /(sunos)\s?([\w\.]+\d)*/i                                           // Solaris
872	            ], [[NAME, 'Solaris'], VERSION], [
873
874	            // BSD based
875	            /\s([frentopc-]{0,4}bsd|dragonfly)\s?([\w\.]+)*/i                   // FreeBSD/NetBSD/OpenBSD/PC-BSD/DragonFly
876	            ], [NAME, VERSION],[
877
878	            /(ip[honead]+)(?:.*os\s*([\w]+)*\slike\smac|;\sopera)/i             // iOS
879	            ], [[NAME, 'iOS'], [VERSION, /_/g, '.']], [
880
881	            /(mac\sos\sx)\s?([\w\s\.]+\w)*/i,
882	            /(macintosh|mac(?=_powerpc)\s)/i                                    // Mac OS
883	            ], [[NAME, 'Mac OS'], [VERSION, /_/g, '.']], [
884
885	            // Other
886	            /((?:open)?solaris)[\/\s-]?([\w\.]+)*/i,                            // Solaris
887	            /(haiku)\s(\w+)/i,                                                  // Haiku
888	            /(aix)\s((\d)(?=\.|\)|\s)[\w\.]*)*/i,                               // AIX
889	            /(plan\s9|minix|beos|os\/2|amigaos|morphos|risc\sos|openvms)/i,
890	                                                                                // Plan9/Minix/BeOS/OS2/AmigaOS/MorphOS/RISCOS/OpenVMS
891	            /(unix)\s?([\w\.]+)*/i                                              // UNIX
892	            ], [NAME, VERSION]
893	        ]
894	    };
895
896
897	    /////////////////
898	    // Constructor
899	    ////////////////
900
901
902	    var UAParser = function (uastring) {
903
904	        var ua = uastring || ((window && window.navigator && window.navigator.userAgent) ? window.navigator.userAgent : EMPTY);
905
906	        this.getBrowser = function () {
907	            return mapper.rgx.apply(this, regexes.browser);
908	        };
909	        this.getEngine = function () {
910	            return mapper.rgx.apply(this, regexes.engine);
911	        };
912	        this.getOS = function () {
913	            return mapper.rgx.apply(this, regexes.os);
914	        };
915	        this.getResult = function() {
916	            return {
917	                ua      : this.getUA(),
918	                browser : this.getBrowser(),
919	                engine  : this.getEngine(),
920	                os      : this.getOS()
921	            };
922	        };
923	        this.getUA = function () {
924	            return ua;
925	        };
926	        this.setUA = function (uastring) {
927	            ua = uastring;
928	            return this;
929	        };
930	        this.setUA(ua);
931	    };
932
933	    return UAParser;
934	})();
935
936
937	function version_compare(v1, v2, operator) {
938	  // From: http://phpjs.org/functions
939	  // +      original by: Philippe Jausions (http://pear.php.net/user/jausions)
940	  // +      original by: Aidan Lister (http://aidanlister.com/)
941	  // + reimplemented by: Kankrelune (http://www.webfaktory.info/)
942	  // +      improved by: Brett Zamir (http://brett-zamir.me)
943	  // +      improved by: Scott Baker
944	  // +      improved by: Theriault
945	  // *        example 1: version_compare('8.2.5rc', '8.2.5a');
946	  // *        returns 1: 1
947	  // *        example 2: version_compare('8.2.50', '8.2.52', '<');
948	  // *        returns 2: true
949	  // *        example 3: version_compare('5.3.0-dev', '5.3.0');
950	  // *        returns 3: -1
951	  // *        example 4: version_compare('4.1.0.52','4.01.0.51');
952	  // *        returns 4: 1
953
954	  // Important: compare must be initialized at 0.
955	  var i = 0,
956	    x = 0,
957	    compare = 0,
958	    // vm maps textual PHP versions to negatives so they're less than 0.
959	    // PHP currently defines these as CASE-SENSITIVE. It is important to
960	    // leave these as negatives so that they can come before numerical versions
961	    // and as if no letters were there to begin with.
962	    // (1alpha is < 1 and < 1.1 but > 1dev1)
963	    // If a non-numerical value can't be mapped to this table, it receives
964	    // -7 as its value.
965	    vm = {
966	      'dev': -6,
967	      'alpha': -5,
968	      'a': -5,
969	      'beta': -4,
970	      'b': -4,
971	      'RC': -3,
972	      'rc': -3,
973	      '#': -2,
974	      'p': 1,
975	      'pl': 1
976	    },
977	    // This function will be called to prepare each version argument.
978	    // It replaces every _, -, and + with a dot.
979	    // It surrounds any nonsequence of numbers/dots with dots.
980	    // It replaces sequences of dots with a single dot.
981	    //    version_compare('4..0', '4.0') == 0
982	    // Important: A string of 0 length needs to be converted into a value
983	    // even less than an unexisting value in vm (-7), hence [-8].
984	    // It's also important to not strip spaces because of this.
985	    //   version_compare('', ' ') == 1
986	    prepVersion = function (v) {
987	      v = ('' + v).replace(/[_\-+]/g, '.');
988	      v = v.replace(/([^.\d]+)/g, '.$1.').replace(/\.{2,}/g, '.');
989	      return (!v.length ? [-8] : v.split('.'));
990	    },
991	    // This converts a version component to a number.
992	    // Empty component becomes 0.
993	    // Non-numerical component becomes a negative number.
994	    // Numerical component becomes itself as an integer.
995	    numVersion = function (v) {
996	      return !v ? 0 : (isNaN(v) ? vm[v] || -7 : parseInt(v, 10));
997	    };
998
999	  v1 = prepVersion(v1);
1000	  v2 = prepVersion(v2);
1001	  x = Math.max(v1.length, v2.length);
1002	  for (i = 0; i < x; i++) {
1003	    if (v1[i] == v2[i]) {
1004	      continue;
1005	    }
1006	    v1[i] = numVersion(v1[i]);
1007	    v2[i] = numVersion(v2[i]);
1008	    if (v1[i] < v2[i]) {
1009	      compare = -1;
1010	      break;
1011	    } else if (v1[i] > v2[i]) {
1012	      compare = 1;
1013	      break;
1014	    }
1015	  }
1016	  if (!operator) {
1017	    return compare;
1018	  }
1019
1020	  // Important: operator is CASE-SENSITIVE.
1021	  // "No operator" seems to be treated as "<."
1022	  // Any other values seem to make the function return null.
1023	  switch (operator) {
1024	  case '>':
1025	  case 'gt':
1026	    return (compare > 0);
1027	  case '>=':
1028	  case 'ge':
1029	    return (compare >= 0);
1030	  case '<=':
1031	  case 'le':
1032	    return (compare <= 0);
1033	  case '==':
1034	  case '=':
1035	  case 'eq':
1036	    return (compare === 0);
1037	  case '<>':
1038	  case '!=':
1039	  case 'ne':
1040	    return (compare !== 0);
1041	  case '':
1042	  case '<':
1043	  case 'lt':
1044	    return (compare < 0);
1045	  default:
1046	    return null;
1047	  }
1048	}
1049
1050
1051	var can = (function() {
1052		var caps = {
1053				define_property: (function() {
1054					/* // currently too much extra code required, not exactly worth it
1055					try { // as of IE8, getters/setters are supported only on DOM elements
1056						var obj = {};
1057						if (Object.defineProperty) {
1058							Object.defineProperty(obj, 'prop', {
1059								enumerable: true,
1060								configurable: true
1061							});
1062							return true;
1063						}
1064					} catch(ex) {}
1065
1066					if (Object.prototype.__defineGetter__ && Object.prototype.__defineSetter__) {
1067						return true;
1068					}*/
1069					return false;
1070				}()),
1071
1072				create_canvas: (function() {
1073					// On the S60 and BB Storm, getContext exists, but always returns undefined
1074					// so we actually have to call getContext() to verify
1075					// github.com/Modernizr/Modernizr/issues/issue/97/
1076					var el = document.createElement('canvas');
1077					return !!(el.getContext && el.getContext('2d'));
1078				}()),
1079
1080				return_response_type: function(responseType) {
1081					try {
1082						if (Basic.inArray(responseType, ['', 'text', 'document']) !== -1) {
1083							return true;
1084						} else if (window.XMLHttpRequest) {
1085							var xhr = new XMLHttpRequest();
1086							xhr.open('get', '/'); // otherwise Gecko throws an exception
1087							if ('responseType' in xhr) {
1088								xhr.responseType = responseType;
1089								// as of 23.0.1271.64, Chrome switched from throwing exception to merely logging it to the console (why? o why?)
1090								if (xhr.responseType !== responseType) {
1091									return false;
1092								}
1093								return true;
1094							}
1095						}
1096					} catch (ex) {}
1097					return false;
1098				},
1099
1100				// ideas for this heavily come from Modernizr (http://modernizr.com/)
1101				use_data_uri: (function() {
1102					var du = new Image();
1103
1104					du.onload = function() {
1105						caps.use_data_uri = (du.width === 1 && du.height === 1);
1106					};
1107					
1108					setTimeout(function() {
1109						du.src = "data:image/gif;base64,R0lGODlhAQABAIAAAP8AAAAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==";
1110					}, 1);
1111					return false;
1112				}()),
1113
1114				use_data_uri_over32kb: function() { // IE8
1115					return caps.use_data_uri && (Env.browser !== 'IE' || Env.version >= 9);
1116				},
1117
1118				use_data_uri_of: function(bytes) {
1119					return (caps.use_data_uri && bytes < 33000 || caps.use_data_uri_over32kb());
1120				},
1121
1122				use_fileinput: function() {
1123					if (navigator.userAgent.match(/(Android (1.0|1.1|1.5|1.6|2.0|2.1))|(Windows Phone (OS 7|8.0))|(XBLWP)|(ZuneWP)|(w(eb)?OSBrowser)|(webOS)|(Kindle\/(1.0|2.0|2.5|3.0))/)) {
1124						return false;
1125					}
1126
1127					var el = document.createElement('input');
1128					el.setAttribute('type', 'file');
1129					return !el.disabled;
1130				}
1131			};
1132
1133		return function(cap) {
1134			var args = [].slice.call(arguments);
1135			args.shift(); // shift of cap
1136			return Basic.typeOf(caps[cap]) === 'function' ? caps[cap].apply(this, args) : !!caps[cap];
1137		};
1138	}());
1139
1140
1141	var uaResult = new UAParser().getResult();
1142
1143
1144	var Env = {
1145		can: can,
1146
1147		uaParser: UAParser,
1148		
1149		browser: uaResult.browser.name,
1150		version: uaResult.browser.version,
1151		os: uaResult.os.name, // everybody intuitively types it in a lowercase for some reason
1152		osVersion: uaResult.os.version,
1153
1154		verComp: version_compare,
1155
1156		global_event_dispatcher: "moxie.core.EventTarget.instance.dispatchEvent"
1157	};
1158
1159	// for backward compatibility
1160	// @deprecated Use `Env.os` instead
1161	Env.OS = Env.os;
1162
1163	if (MXI_DEBUG) {
1164		Env.debug = {
1165			runtime: true,
1166			events: false
1167		};
1168
1169		Env.log = function() {
1170			
1171			function logObj(data) {
1172				// TODO: this should recursively print out the object in a pretty way
1173				console.appendChild(document.createTextNode(data + "\n"));
1174			}
1175
1176			var data = arguments[0];
1177
1178			if (Basic.typeOf(data) === 'string') {
1179				data = Basic.sprintf.apply(this, arguments);
1180			}
1181
1182			if (window && window.console && window.console.log) {
1183				window.console.log(data);
1184			} else if (document) {
1185				var console = document.getElementById('moxie-console');
1186				if (!console) {
1187					console = document.createElement('pre');
1188					console.id = 'moxie-console';
1189					//console.style.display = 'none';
1190					document.body.appendChild(console);
1191				}
1192
1193				if (Basic.inArray(Basic.typeOf(data), ['object', 'array']) !== -1) {
1194					logObj(data);
1195				} else {
1196					console.appendChild(document.createTextNode(data + "\n"));
1197				}
1198			}
1199		};
1200	}
1201
1202	return Env;
1203});
1204
1205// Included from: src/javascript/core/I18n.js
1206
1207/**
1208 * I18n.js
1209 *
1210 * Copyright 2013, Moxiecode Systems AB
1211 * Released under GPL License.
1212 *
1213 * License: http://www.plupload.com/license
1214 * Contributing: http://www.plupload.com/contributing
1215 */
1216
1217define("moxie/core/I18n", [
1218	"moxie/core/utils/Basic"
1219], function(Basic) {
1220	var i18n = {};
1221
1222	return {
1223		/**
1224		 * Extends the language pack object with new items.
1225		 *
1226		 * @param {Object} pack Language pack items to add.
1227		 * @return {Object} Extended language pack object.
1228		 */
1229		addI18n: function(pack) {
1230			return Basic.extend(i18n, pack);
1231		},
1232
1233		/**
1234		 * Translates the specified string by checking for the english string in the language pack lookup.
1235		 *
1236		 * @param {String} str String to look for.
1237		 * @return {String} Translated string or the input string if it wasn't found.
1238		 */
1239		translate: function(str) {
1240			return i18n[str] || str;
1241		},
1242
1243		/**
1244		 * Shortcut for translate function
1245		 *
1246		 * @param {String} str String to look for.
1247		 * @return {String} Translated string or the input string if it wasn't found.
1248		 */
1249		_: function(str) {
1250			return this.translate(str);
1251		},
1252
1253		/**
1254		 * Pseudo sprintf implementation - simple way to replace tokens with specified values.
1255		 *
1256		 * @param {String} str String with tokens
1257		 * @return {String} String with replaced tokens
1258		 */
1259		sprintf: function(str) {
1260			var args = [].slice.call(arguments, 1);
1261
1262			return str.replace(/%[a-z]/g, function() {
1263				var value = args.shift();
1264				return Basic.typeOf(value) !== 'undefined' ? value : '';
1265			});
1266		}
1267	};
1268});
1269
1270// Included from: src/javascript/core/utils/Mime.js
1271
1272/**
1273 * Mime.js
1274 *
1275 * Copyright 2013, Moxiecode Systems AB
1276 * Released under GPL License.
1277 *
1278 * License: http://www.plupload.com/license
1279 * Contributing: http://www.plupload.com/contributing
1280 */
1281
1282define("moxie/core/utils/Mime", [
1283	"moxie/core/utils/Basic",
1284	"moxie/core/I18n"
1285], function(Basic, I18n) {
1286	
1287	var mimeData = "" +
1288		"application/msword,doc dot," +
1289		"application/pdf,pdf," +
1290		"application/pgp-signature,pgp," +
1291		"application/postscript,ps ai eps," +
1292		"application/rtf,rtf," +
1293		"application/vnd.ms-excel,xls xlb," +
1294		"application/vnd.ms-powerpoint,ppt pps pot," +
1295		"application/zip,zip," +
1296		"application/x-shockwave-flash,swf swfl," +
1297		"application/vnd.openxmlformats-officedocument.wordprocessingml.document,docx," +
1298		"application/vnd.openxmlformats-officedocument.wordprocessingml.template,dotx," +
1299		"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,xlsx," +
1300		"application/vnd.openxmlformats-officedocument.presentationml.presentation,pptx," +
1301		"application/vnd.openxmlformats-officedocument.presentationml.template,potx," +
1302		"application/vnd.openxmlformats-officedocument.presentationml.slideshow,ppsx," +
1303		"application/x-javascript,js," +
1304		"application/json,json," +
1305		"audio/mpeg,mp3 mpga mpega mp2," +
1306		"audio/x-wav,wav," +
1307		"audio/x-m4a,m4a," +
1308		"audio/ogg,oga ogg," +
1309		"audio/aiff,aiff aif," +
1310		"audio/flac,flac," +
1311		"audio/aac,aac," +
1312		"audio/ac3,ac3," +
1313		"audio/x-ms-wma,wma," +
1314		"image/bmp,bmp," +
1315		"image/gif,gif," +
1316		"image/jpeg,jpg jpeg jpe," +
1317		"image/photoshop,psd," +
1318		"image/png,png," +
1319		"image/svg+xml,svg svgz," +
1320		"image/tiff,tiff tif," +
1321		"text/plain,asc txt text diff log," +
1322		"text/html,htm html xhtml," +
1323		"text/css,css," +
1324		"text/csv,csv," +
1325		"text/rtf,rtf," +
1326		"video/mpeg,mpeg mpg mpe m2v," +
1327		"video/quicktime,qt mov," +
1328		"video/mp4,mp4," +
1329		"video/x-m4v,m4v," +
1330		"video/x-flv,flv," +
1331		"video/x-ms-wmv,wmv," +
1332		"video/avi,avi," +
1333		"video/webm,webm," +
1334		"video/3gpp,3gpp 3gp," +
1335		"video/3gpp2,3g2," +
1336		"video/vnd.rn-realvideo,rv," +
1337		"video/ogg,ogv," + 
1338		"video/x-matroska,mkv," +
1339		"application/vnd.oasis.opendocument.formula-template,otf," +
1340		"application/octet-stream,exe";
1341	
1342	
1343	var Mime = {
1344
1345		mimes: {},
1346
1347		extensions: {},
1348
1349		// Parses the default mime types string into a mimes and extensions lookup maps
1350		addMimeType: function (mimeData) {
1351			var items = mimeData.split(/,/), i, ii, ext;
1352			
1353			for (i = 0; i < items.length; i += 2) {
1354				ext = items[i + 1].split(/ /);
1355
1356				// extension to mime lookup
1357				for (ii = 0; ii < ext.length; ii++) {
1358					this.mimes[ext[ii]] = items[i];
1359				}
1360				// mime to extension lookup
1361				this.extensions[items[i]] = ext;
1362			}
1363		},
1364
1365
1366		extList2mimes: function (filters, addMissingExtensions) {
1367			var self = this, ext, i, ii, type, mimes = [];
1368			
1369			// convert extensions to mime types list
1370			for (i = 0; i < filters.length; i++) {
1371				ext = filters[i].extensions.split(/\s*,\s*/);
1372
1373				for (ii = 0; ii < ext.length; ii++) {
1374					
1375					// if there's an asterisk in the list, then accept attribute is not required
1376					if (ext[ii] === '*') {
1377						return [];
1378					}
1379
1380					type = self.mimes[ext[ii]];
1381					if (type && Basic.inArray(type, mimes) === -1) {
1382						mimes.push(type);
1383					}
1384
1385					// future browsers should filter by extension, finally
1386					if (addMissingExtensions && /^\w+$/.test(ext[ii])) {
1387						mimes.push('.' + ext[ii]);
1388					} else if (!type) {
1389						// if we have no type in our map, then accept all
1390						return [];
1391					}
1392				}
1393			}
1394			return mimes;
1395		},
1396
1397
1398		mimes2exts: function(mimes) {
1399			var self = this, exts = [];
1400			
1401			Basic.each(mimes, function(mime) {
1402				if (mime === '*') {
1403					exts = [];
1404					return false;
1405				}
1406
1407				// check if this thing looks like mime type
1408				var m = mime.match(/^(\w+)\/(\*|\w+)$/);
1409				if (m) {
1410					if (m[2] === '*') { 
1411						// wildcard mime type detected
1412						Basic.each(self.extensions, function(arr, mime) {
1413							if ((new RegExp('^' + m[1] + '/')).test(mime)) {
1414								[].push.apply(exts, self.extensions[mime]);
1415							}
1416						});
1417					} else if (self.extensions[mime]) {
1418						[].push.apply(exts, self.extensions[mime]);
1419					}
1420				}
1421			});
1422			return exts;
1423		},
1424
1425
1426		mimes2extList: function(mimes) {
1427			var accept = [], exts = [];
1428
1429			if (Basic.typeOf(mimes) === 'string') {
1430				mimes = Basic.trim(mimes).split(/\s*,\s*/);
1431			}
1432
1433			exts = this.mimes2exts(mimes);
1434			
1435			accept.push({
1436				title: I18n.translate('Files'),
1437				extensions: exts.length ? exts.join(',') : '*'
1438			});
1439			
1440			// save original mimes string
1441			accept.mimes = mimes;
1442
1443			return accept;
1444		},
1445
1446
1447		getFileExtension: function(fileName) {
1448			var matches = fileName && fileName.match(/\.([^.]+)$/);
1449			if (matches) {
1450				return matches[1].toLowerCase();
1451			}
1452			return '';
1453		},
1454
1455		getFileMime: function(fileName) {
1456			return this.mimes[this.getFileExtension(fileName)] || '';
1457		}
1458	};
1459
1460	Mime.addMimeType(mimeData);
1461
1462	return Mime;
1463});
1464
1465// Included from: src/javascript/core/utils/Dom.js
1466
1467/**
1468 * Dom.js
1469 *
1470 * Copyright 2013, Moxiecode Systems AB
1471 * Released under GPL License.
1472 *
1473 * License: http://www.plupload.com/license
1474 * Contributing: http://www.plupload.com/contributing
1475 */
1476
1477define('moxie/core/utils/Dom', ['moxie/core/utils/Env'], function(Env) {
1478
1479	/**
1480	Get DOM Element by it's id.
1481
1482	@method get
1483	@for Utils
1484	@param {String} id Identifier of the DOM Element
1485	@return {DOMElement}
1486	*/
1487	var get = function(id) {
1488		if (typeof id !== 'string') {
1489			return id;
1490		}
1491		return document.getElementById(id);
1492	};
1493
1494	/**
1495	Checks if specified DOM element has specified class.
1496
1497	@method hasClass
1498	@static
1499	@param {Object} obj DOM element like object to add handler to.
1500	@param {String} name Class name
1501	*/
1502	var hasClass = function(obj, name) {
1503		if (!obj.className) {
1504			return false;
1505		}
1506
1507		var regExp = new RegExp("(^|\\s+)"+name+"(\\s+|$)");
1508		return regExp.test(obj.className);
1509	};
1510
1511	/**
1512	Adds specified className to specified DOM element.
1513
1514	@method addClass
1515	@static
1516	@param {Object} obj DOM element like object to add handler to.
1517	@param {String} name Class name
1518	*/
1519	var addClass = function(obj, name) {
1520		if (!hasClass(obj, name)) {
1521			obj.className = !obj.className ? name : obj.className.replace(/\s+$/, '') + ' ' + name;
1522		}
1523	};
1524
1525	/**
1526	Removes specified className from specified DOM element.
1527
1528	@method removeClass
1529	@static
1530	@param {Object} obj DOM element like object to add handler to.
1531	@param {String} name Class name
1532	*/
1533	var removeClass = function(obj, name) {
1534		if (obj.className) {
1535			var regExp = new RegExp("(^|\\s+)"+name+"(\\s+|$)");
1536			obj.className = obj.className.replace(regExp, function($0, $1, $2) {
1537				return $1 === ' ' && $2 === ' ' ? ' ' : '';
1538			});
1539		}
1540	};
1541
1542	/**
1543	Returns a given computed style of a DOM element.
1544
1545	@method getStyle
1546	@static
1547	@param {Object} obj DOM element like object.
1548	@param {String} name Style you want to get from the DOM element
1549	*/
1550	var getStyle = function(obj, name) {
1551		if (obj.currentStyle) {
1552			return obj.currentStyle[name];
1553		} else if (window.getComputedStyle) {
1554			return window.getComputedStyle(obj, null)[name];
1555		}
1556	};
1557
1558
1559	/**
1560	Returns the absolute x, y position of an Element. The position will be returned in a object with x, y fields.
1561
1562	@method getPos
1563	@static
1564	@param {Element} node HTML element or element id to get x, y position from.
1565	@param {Element} root Optional root element to stop calculations at.
1566	@return {object} Absolute position of the specified element object with x, y fields.
1567	*/
1568	var getPos = function(node, root) {
1569		var x = 0, y = 0, parent, doc = document, nodeRect, rootRect;
1570
1571		node = node;
1572		root = root || doc.body;
1573
1574		// Returns the x, y cordinate for an element on IE 6 and IE 7
1575		function getIEPos(node) {
1576			var bodyElm, rect, x = 0, y = 0;
1577
1578			if (node) {
1579				rect = node.getBoundingClientRect();
1580				bodyElm = doc.compatMode === "CSS1Compat" ? doc.documentElement : doc.body;
1581				x = rect.left + bodyElm.scrollLeft;
1582				y = rect.top + bodyElm.scrollTop;
1583			}
1584
1585			return {
1586				x : x,
1587				y : y
1588			};
1589		}
1590
1591		// Use getBoundingClientRect on IE 6 and IE 7 but not on IE 8 in standards mode
1592		if (node && node.getBoundingClientRect && Env.browser === 'IE' && (!doc.documentMode || doc.documentMode < 8)) {
1593			nodeRect = getIEPos(node);
1594			rootRect = getIEPos(root);
1595
1596			return {
1597				x : nodeRect.x - rootRect.x,
1598				y : nodeRect.y - rootRect.y
1599			};
1600		}
1601
1602		parent = node;
1603		while (parent && parent != root && parent.nodeType) {
1604			x += parent.offsetLeft || 0;
1605			y += parent.offsetTop || 0;
1606			parent = parent.offsetParent;
1607		}
1608
1609		parent = node.parentNode;
1610		while (parent && parent != root && parent.nodeType) {
1611			x -= parent.scrollLeft || 0;
1612			y -= parent.scrollTop || 0;
1613			parent = parent.parentNode;
1614		}
1615
1616		return {
1617			x : x,
1618			y : y
1619		};
1620	};
1621
1622	/**
1623	Returns the size of the specified node in pixels.
1624
1625	@method getSize
1626	@static
1627	@param {Node} node Node to get the size of.
1628	@return {Object} Object with a w and h property.
1629	*/
1630	var getSize = function(node) {
1631		return {
1632			w : node.offsetWidth || node.clientWidth,
1633			h : node.offsetHeight || node.clientHeight
1634		};
1635	};
1636
1637	return {
1638		get: get,
1639		hasClass: hasClass,
1640		addClass: addClass,
1641		removeClass: removeClass,
1642		getStyle: getStyle,
1643		getPos: getPos,
1644		getSize: getSize
1645	};
1646});
1647
1648// Included from: src/javascript/core/Exceptions.js
1649
1650/**
1651 * Exceptions.js
1652 *
1653 * Copyright 2013, Moxiecode Systems AB
1654 * Released under GPL License.
1655 *
1656 * License: http://www.plupload.com/license
1657 * Contributing: http://www.plupload.com/contributing
1658 */
1659
1660define('moxie/core/Exceptions', [
1661	'moxie/core/utils/Basic'
1662], function(Basic) {
1663	function _findKey(obj, value) {
1664		var key;
1665		for (key in obj) {
1666			if (obj[key] === value) {
1667				return key;
1668			}
1669		}
1670		return null;
1671	}
1672
1673	return {
1674		RuntimeError: (function() {
1675			var namecodes = {
1676				NOT_INIT_ERR: 1,
1677				NOT_SUPPORTED_ERR: 9,
1678				JS_ERR: 4
1679			};
1680
1681			function RuntimeError(code) {
1682				this.code = code;
1683				this.name = _findKey(namecodes, code);
1684				this.message = this.name + ": RuntimeError " + this.code;
1685			}
1686			
1687			Basic.extend(RuntimeError, namecodes);
1688			RuntimeError.prototype = Error.prototype;
1689			return RuntimeError;
1690		}()),
1691		
1692		OperationNotAllowedException: (function() {
1693			
1694			function OperationNotAllowedException(code) {
1695				this.code = code;
1696				this.name = 'OperationNotAllowedException';
1697			}
1698			
1699			Basic.extend(OperationNotAllowedException, {
1700				NOT_ALLOWED_ERR: 1
1701			});
1702			
1703			OperationNotAllowedException.prototype = Error.prototype;
1704			
1705			return OperationNotAllowedException;
1706		}()),
1707
1708		ImageError: (function() {
1709			var namecodes = {
1710				WRONG_FORMAT: 1,
1711				MAX_RESOLUTION_ERR: 2,
1712				INVALID_META_ERR: 3
1713			};
1714
1715			function ImageError(code) {
1716				this.code = code;
1717				this.name = _findKey(namecodes, code);
1718				this.message = this.name + ": ImageError " + this.code;
1719			}
1720			
1721			Basic.extend(ImageError, namecodes);
1722			ImageError.prototype = Error.prototype;
1723
1724			return ImageError;
1725		}()),
1726
1727		FileException: (function() {
1728			var namecodes = {
1729				NOT_FOUND_ERR: 1,
1730				SECURITY_ERR: 2,
1731				ABORT_ERR: 3,
1732				NOT_READABLE_ERR: 4,
1733				ENCODING_ERR: 5,
1734				NO_MODIFICATION_ALLOWED_ERR: 6,
1735				INVALID_STATE_ERR: 7,
1736				SYNTAX_ERR: 8
1737			};
1738
1739			function FileException(code) {
1740				this.code = code;
1741				this.name = _findKey(namecodes, code);
1742				this.message = this.name + ": FileException " + this.code;
1743			}
1744			
1745			Basic.extend(FileException, namecodes);
1746			FileException.prototype = Error.prototype;
1747			return FileException;
1748		}()),
1749		
1750		DOMException: (function() {
1751			var namecodes = {
1752				INDEX_SIZE_ERR: 1,
1753				DOMSTRING_SIZE_ERR: 2,
1754				HIERARCHY_REQUEST_ERR: 3,
1755				WRONG_DOCUMENT_ERR: 4,
1756				INVALID_CHARACTER_ERR: 5,
1757				NO_DATA_ALLOWED_ERR: 6,
1758				NO_MODIFICATION_ALLOWED_ERR: 7,
1759				NOT_FOUND_ERR: 8,
1760				NOT_SUPPORTED_ERR: 9,
1761				INUSE_ATTRIBUTE_ERR: 10,
1762				INVALID_STATE_ERR: 11,
1763				SYNTAX_ERR: 12,
1764				INVALID_MODIFICATION_ERR: 13,
1765				NAMESPACE_ERR: 14,
1766				INVALID_ACCESS_ERR: 15,
1767				VALIDATION_ERR: 16,
1768				TYPE_MISMATCH_ERR: 17,
1769				SECURITY_ERR: 18,
1770				NETWORK_ERR: 19,
1771				ABORT_ERR: 20,
1772				URL_MISMATCH_ERR: 21,
1773				QUOTA_EXCEEDED_ERR: 22,
1774				TIMEOUT_ERR: 23,
1775				INVALID_NODE_TYPE_ERR: 24,
1776				DATA_CLONE_ERR: 25
1777			};
1778
1779			function DOMException(code) {
1780				this.code = code;
1781				this.name = _findKey(namecodes, code);
1782				this.message = this.name + ": DOMException " + this.code;
1783			}
1784			
1785			Basic.extend(DOMException, namecodes);
1786			DOMException.prototype = Error.prototype;
1787			return DOMException;
1788		}()),
1789		
1790		EventException: (function() {
1791			function EventException(code) {
1792				this.code = code;
1793				this.name = 'EventException';
1794			}
1795			
1796			Basic.extend(EventException, {
1797				UNSPECIFIED_EVENT_TYPE_ERR: 0
1798			});
1799			
1800			EventException.prototype = Error.prototype;
1801			
1802			return EventException;
1803		}())
1804	};
1805});
1806
1807// Included from: src/javascript/core/EventTarget.js
1808
1809/**
1810 * EventTarget.js
1811 *
1812 * Copyright 2013, Moxiecode Systems AB
1813 * Released under GPL License.
1814 *
1815 * License: http://www.plupload.com/license
1816 * Contributing: http://www.plupload.com/contributing
1817 */
1818
1819define('moxie/core/EventTarget', [
1820	'moxie/core/utils/Env',
1821	'moxie/core/Exceptions',
1822	'moxie/core/utils/Basic'
1823], function(Env, x, Basic) {
1824	/**
1825	Parent object for all event dispatching components and objects
1826
1827	@class EventTarget
1828	@constructor EventTarget
1829	*/
1830	function EventTarget() {
1831		// hash of event listeners by object uid
1832		var eventpool = {};
1833				
1834		Basic.extend(this, {
1835			
1836			/**
1837			Unique id of the event dispatcher, usually overriden by children
1838
1839			@property uid
1840			@type String
1841			*/
1842			uid: null,
1843			
1844			/**
1845			Can be called from within a child  in order to acquire uniqie id in automated manner
1846
1847			@method init
1848			*/
1849			init: function() {
1850				if (!this.uid) {
1851					this.uid = Basic.guid('uid_');
1852				}
1853			},
1854
1855			/**
1856			Register a handler to a specific event dispatched by the object
1857
1858			@method addEventListener
1859			@param {String} type Type or basically a name of the event to subscribe to
1860			@param {Function} fn Callback function that will be called when event happens
1861			@param {Number} [priority=0] Priority of the event handler - handlers with higher priorities will be called first
1862			@param {Object} [scope=this] A scope to invoke event handler in
1863			*/
1864			addEventListener: function(type, fn, priority, scope) {
1865				var self = this, list;
1866
1867				// without uid no event handlers can be added, so make sure we got one
1868				if (!this.hasOwnProperty('uid')) {
1869					this.uid = Basic.guid('uid_');
1870				}
1871				
1872				type = Basic.trim(type);
1873				
1874				if (/\s/.test(type)) {
1875					// multiple event types were passed for one handler
1876					Basic.each(type.split(/\s+/), function(type) {
1877						self.addEventListener(type, fn, priority, scope);
1878					});
1879					return;
1880				}
1881				
1882				type = type.toLowerCase();
1883				priority = parseInt(priority, 10) || 0;
1884				
1885				list = eventpool[this.uid] && eventpool[this.uid][type] || [];
1886				list.push({fn : fn, priority : priority, scope : scope || this});
1887				
1888				if (!eventpool[this.uid]) {
1889					eventpool[this.uid] = {};
1890				}
1891				eventpool[this.uid][type] = list;
1892			},
1893			
1894			/**
1895			Check if any handlers were registered to the specified event
1896
1897			@method hasEventListener
1898			@param {String} type Type or basically a name of the event to check
1899			@return {Mixed} Returns a handler if it was found and false, if - not
1900			*/
1901			hasEventListener: function(type) {
1902				var list = type ? eventpool[this.uid] && eventpool[this.uid][type] : eventpool[this.uid];
1903				return list ? list : false;
1904			},
1905			
1906			/**
1907			Unregister the handler from the event, or if former was not specified - unregister all handlers
1908
1909			@method removeEventListener
1910			@param {String} type Type or basically a name of the event
1911			@param {Function} [fn] Handler to unregister
1912			*/
1913			removeEventListener: function(type, fn) {
1914				type = type.toLowerCase();
1915	
1916				var list = eventpool[this.uid] && eventpool[this.uid][type], i;
1917	
1918				if (list) {
1919					if (fn) {
1920						for (i = list.length - 1; i >= 0; i--) {
1921							if (list[i].fn === fn) {
1922								list.splice(i, 1);
1923								break;
1924							}
1925						}
1926					} else {
1927						list = [];
1928					}
1929	
1930					// delete event list if it has become empty
1931					if (!list.length) {
1932						delete eventpool[this.uid][type];
1933						
1934						// and object specific entry in a hash if it has no more listeners attached
1935						if (Basic.isEmptyObj(eventpool[this.uid])) {
1936							delete eventpool[this.uid];
1937						}
1938					}
1939				}
1940			},
1941			
1942			/**
1943			Remove all event handlers from the object
1944
1945			@method removeAllEventListeners
1946			*/
1947			removeAllEventListeners: function() {
1948				if (eventpool[this.uid]) {
1949					delete eventpool[this.uid];
1950				}
1951			},
1952			
1953			/**
1954			Dispatch the event
1955
1956			@method dispatchEvent
1957			@param {String/Object} Type of event or event object to dispatch
1958			@param {Mixed} [...] Variable number of arguments to be passed to a handlers
1959			@return {Boolean} true by default and false if any handler returned false
1960			*/
1961			dispatchEvent: function(type) {
1962				var uid, list, args, tmpEvt, evt = {}, result = true, undef;
1963				
1964				if (Basic.typeOf(type) !== 'string') {
1965					// we can't use original object directly (because of Silverlight)
1966					tmpEvt = type;
1967
1968					if (Basic.typeOf(tmpEvt.type) === 'string') {
1969						type = tmpEvt.type;
1970
1971						if (tmpEvt.total !== undef && tmpEvt.loaded !== undef) { // progress event
1972							evt.total = tmpEvt.total;
1973							evt.loaded = tmpEvt.loaded;
1974						}
1975						evt.async = tmpEvt.async || false;
1976					} else {
1977						throw new x.EventException(x.EventException.UNSPECIFIED_EVENT_TYPE_ERR);
1978					}
1979				}
1980				
1981				// check if event is meant to be dispatched on an object having specific uid
1982				if (type.indexOf('::') !== -1) {
1983					(function(arr) {
1984						uid = arr[0];
1985						type = arr[1];
1986					}(type.split('::')));
1987				} else {
1988					uid = this.uid;
1989				}
1990				
1991				type = type.toLowerCase();
1992								
1993				list = eventpool[uid] && eventpool[uid][type];
1994
1995				if (list) {
1996					// sort event list by prority
1997					list.sort(function(a, b) { return b.priority - a.priority; });
1998					
1999					args = [].slice.call(arguments);
2000					
2001					// first argument will be pseudo-event object
2002					args.shift();
2003					evt.type = type;
2004					args.unshift(evt);
2005
2006					if (MXI_DEBUG && Env.debug.events) {
2007						Env.log("Event '%s' fired on %u", evt.type, uid);	
2008					}
2009
2010					// Dispatch event to all listeners
2011					var queue = [];
2012					Basic.each(list, function(handler) {
2013						// explicitly set the target, otherwise events fired from shims do not get it
2014						args[0].target = handler.scope;
2015						// if event is marked as async, detach the handler
2016						if (evt.async) {
2017							queue.push(function(cb) {
2018								setTimeout(function() {
2019									cb(handler.fn.apply(handler.scope, args) === false);
2020								}, 1);
2021							});
2022						} else {
2023							queue.push(function(cb) {
2024								cb(handler.fn.apply(handler.scope, args) === false); // if handler returns false stop propagation
2025							});
2026						}
2027					});
2028					if (queue.length) {
2029						Basic.inSeries(queue, function(err) {
2030							result = !err;
2031						});
2032					}
2033				}
2034				return result;
2035			},
2036			
2037			/**
2038			Alias for addEventListener
2039
2040			@method bind
2041			@protected
2042			*/
2043			bind: function() {
2044				this.addEventListener.apply(this, arguments);
2045			},
2046			
2047			/**
2048			Alias for removeEventListener
2049
2050			@method unbind
2051			@protected
2052			*/
2053			unbind: function() {
2054				this.removeEventListener.apply(this, arguments);
2055			},
2056			
2057			/**
2058			Alias for removeAllEventListeners
2059
2060			@method unbindAll
2061			@protected
2062			*/
2063			unbindAll: function() {
2064				this.removeAllEventListeners.apply(this, arguments);
2065			},
2066			
2067			/**
2068			Alias for dispatchEvent
2069
2070			@method trigger
2071			@protected
2072			*/
2073			trigger: function() {
2074				return this.dispatchEvent.apply(this, arguments);
2075			},
2076			
2077
2078			/**
2079			Handle properties of on[event] type.
2080
2081			@method handleEventProps
2082			@private
2083			*/
2084			handleEventProps: function(dispatches) {
2085				var self = this;
2086
2087				this.bind(dispatches.join(' '), function(e) {
2088					var prop = 'on' + e.type.toLowerCase();
2089					if (Basic.typeOf(this[prop]) === 'function') {
2090						this[prop].apply(this, arguments);
2091					}
2092				});
2093
2094				// object must have defined event properties, even if it doesn't make use of them
2095				Basic.each(dispatches, function(prop) {
2096					prop = 'on' + prop.toLowerCase(prop);
2097					if (Basic.typeOf(self[prop]) === 'undefined') {
2098						self[prop] = null; 
2099					}
2100				});
2101			}
2102			
2103		});
2104	}
2105
2106	EventTarget.instance = new EventTarget(); 
2107
2108	return EventTarget;
2109});
2110
2111// Included from: src/javascript/runtime/Runtime.js
2112
2113/**
2114 * Runtime.js
2115 *
2116 * Copyright 2013, Moxiecode Systems AB
2117 * Released under GPL License.
2118 *
2119 * License: http://www.plupload.com/license
2120 * Contributing: http://www.plupload.com/contributing
2121 */
2122
2123define('moxie/runtime/Runtime', [
2124	"moxie/core/utils/Env",
2125	"moxie/core/utils/Basic",
2126	"moxie/core/utils/Dom",
2127	"moxie/core/EventTarget"
2128], function(Env, Basic, Dom, EventTarget) {
2129	var runtimeConstructors = {}, runtimes = {};
2130
2131	/**
2132	Common set of methods and properties for every runtime instance
2133
2134	@class Runtime
2135
2136	@param {Object} options
2137	@param {String} type Sanitized name of the runtime
2138	@param {Object} [caps] Set of capabilities that differentiate specified runtime
2139	@param {Object} [modeCaps] Set of capabilities that do require specific operational mode
2140	@param {String} [preferredMode='browser'] Preferred operational mode to choose if no required capabilities were requested
2141	*/
2142	function Runtime(options, type, caps, modeCaps, preferredMode) {
2143		/**
2144		Dispatched when runtime is initialized and ready.
2145		Results in RuntimeInit on a connected component.
2146
2147		@event Init
2148		*/
2149
2150		/**
2151		Dispatched when runtime fails to initialize.
2152		Results in RuntimeError on a connected component.
2153
2154		@event Error
2155		*/
2156
2157		var self = this
2158		, _shim
2159		, _uid = Basic.guid(type + '_')
2160		, defaultMode = preferredMode || 'browser'
2161		;
2162
2163		options = options || {};
2164
2165		// register runtime in private hash
2166		runtimes[_uid] = this;
2167
2168		/**
2169		Default set of capabilities, which can be redifined later by specific runtime
2170
2171		@private
2172		@property caps
2173		@type Object
2174		*/
2175		caps = Basic.extend({
2176			// Runtime can: 
2177			// provide access to raw binary data of the file
2178			access_binary: false,
2179			// provide access to raw binary data of the image (image extension is optional) 
2180			access_image_binary: false,
2181			// display binary data as thumbs for example
2182			display_media: false,
2183			// make cross-domain requests
2184			do_cors: false,
2185			// accept files dragged and dropped from the desktop
2186			drag_and_drop: false,
2187			// filter files in selection dialog by their extensions
2188			filter_by_extension: true,
2189			// resize image (and manipulate it raw data of any file in general)
2190			resize_image: false,
2191			// periodically report how many bytes of total in the file were uploaded (loaded)
2192			report_upload_progress: false,
2193			// provide access to the headers of http response 
2194			return_response_headers: false,
2195			// support response of specific type, which should be passed as an argument
2196			// e.g. runtime.can('return_response_type', 'blob')
2197			return_response_type: false,
2198			// return http status code of the response
2199			return_status_code: true,
2200			// send custom http header with the request
2201			send_custom_headers: false,
2202			// pick up the files from a dialog
2203			select_file: false,
2204			// select whole folder in file browse dialog
2205			select_folder: false,
2206			// select multiple files at once in file browse dialog
2207			select_multiple: true,
2208			// send raw binary data, that is generated after image resizing or manipulation of other kind
2209			send_binary_string: false,
2210			// send cookies with http request and therefore retain session
2211			send_browser_cookies: true,
2212			// send data formatted as multipart/form-data
2213			send_multipart: true,
2214			// slice the file or blob to smaller parts
2215			slice_blob: false,
2216			// upload file without preloading it to memory, stream it out directly from disk
2217			stream_upload: false,
2218			// programmatically trigger file browse dialog
2219			summon_file_dialog: false,
2220			// upload file of specific size, size should be passed as argument
2221			// e.g. runtime.can('upload_filesize', '500mb')
2222			upload_filesize: true,
2223			// initiate http request with specific http method, method should be passed as argument
2224			// e.g. runtime.can('use_http_method', 'put')
2225			use_http_method: true
2226		}, caps);
2227			
2228	
2229		// default to the mode that is compatible with preferred caps
2230		if (options.preferred_caps) {
2231			defaultMode = Runtime.getMode(modeCaps, options.preferred_caps, defaultMode);
2232		}
2233
2234		if (MXI_DEBUG && Env.debug.runtime) {
2235			Env.log("\tdefault mode: %s", defaultMode);	
2236		}
2237		
2238		// small extension factory here (is meant to be extended with actual extensions constructors)
2239		_shim = (function() {
2240			var objpool = {};
2241			return {
2242				exec: function(uid, comp, fn, args) {
2243					if (_shim[comp]) {
2244						if (!objpool[uid]) {
2245							objpool[uid] = {
2246								context: this,
2247								instance: new _shim[comp]()
2248							};
2249						}
2250						if (objpool[uid].instance[fn]) {
2251							return objpool[uid].instance[fn].apply(this, args);
2252						}
2253					}
2254				},
2255
2256				removeInstance: function(uid) {
2257					delete objpool[uid];
2258				},
2259
2260				removeAllInstances: function() {
2261					var self = this;
2262					Basic.each(objpool, function(obj, uid) {
2263						if (Basic.typeOf(obj.instance.destroy) === 'function') {
2264							obj.instance.destroy.call(obj.context);
2265						}
2266						self.removeInstance(uid);
2267					});
2268				}
2269			};
2270		}());
2271
2272
2273		// public methods
2274		Basic.extend(this, {
2275			/**
2276			Specifies whether runtime instance was initialized or not
2277
2278			@property initialized
2279			@type {Boolean}
2280			@default false
2281			*/
2282			initialized: false, // shims require this flag to stop initialization retries
2283
2284			/**
2285			Unique ID of the runtime
2286
2287			@property uid
2288			@type {String}
2289			*/
2290			uid: _uid,
2291
2292			/**
2293			Runtime type (e.g. flash, html5, etc)
2294
2295			@property type
2296			@type {String}
2297			*/
2298			type: type,
2299
2300			/**
2301			Runtime (not native one) may operate in browser or client mode.
2302
2303			@property mode
2304			@private
2305			@type {String|Boolean} current mode or false, if none possible
2306			*/
2307			mode: Runtime.getMode(modeCaps, (options.required_caps), defaultMode),
2308
2309			/**
2310			id of the DOM container for the runtime (if available)
2311
2312			@property shimid
2313			@type {String}
2314			*/
2315			shimid: _uid + '_container',
2316
2317			/**
2318			Number of connected clients. If equal to zero, runtime can be destroyed
2319
2320			@property clients
2321			@type {Number}
2322			*/
2323			clients: 0,
2324
2325			/**
2326			Runtime initialization options
2327
2328			@property options
2329			@type {Object}
2330			*/
2331			options: options,
2332
2333			/**
2334			Checks if the runtime has specific capability
2335
2336			@method can
2337			@param {String} cap Name of capability to check
2338			@param {Mixed} [value] If passed, capability should somehow correlate to the value
2339			@param {Object} [refCaps] Set of capabilities to check the specified cap against (defaults to internal set)
2340			@return {Boolean} true if runtime has such capability and false, if - not
2341			*/
2342			can: function(cap, value) {
2343				var refCaps = arguments[2] || caps;
2344
2345				// if cap var is a comma-separated list of caps, convert it to object (key/value)
2346				if (Basic.typeOf(cap) === 'string' && Basic.typeOf(value) === 'undefined') {
2347					cap = Runtime.parseCaps(cap);
2348				}
2349
2350				if (Basic.typeOf(cap) === 'object') {
2351					for (var key in cap) {
2352						if (!this.can(key, cap[key], refCaps)) {
2353							return false;
2354						}
2355					}
2356					return true;
2357				}
2358
2359				// check the individual cap
2360				if (Basic.typeOf(refCaps[cap]) === 'function') {
2361					return refCaps[cap].call(this, value);
2362				} else {
2363					return (value === refCaps[cap]);
2364				}
2365			},
2366
2367			/**
2368			Returns container for the runtime as DOM element
2369
2370			@method getShimContainer
2371			@return {DOMElement}
2372			*/
2373			getShimContainer: function() {
2374				var container, shimContainer = Dom.get(this.shimid);
2375
2376				// if no container for shim, create one
2377				if (!shimContainer) {
2378					container = this.options.container ? Dom.get(this.options.container) : document.body;
2379
2380					// create shim container and insert it at an absolute position into the outer container
2381					shimContainer = document.createElement('div');
2382					shimContainer.id = this.shimid;
2383					shimContainer.className = 'moxie-shim moxie-shim-' + this.type;
2384
2385					Basic.extend(shimContainer.style, {
2386						position: 'absolute',
2387						top: '0px',
2388						left: '0px',
2389						width: '1px',
2390						height: '1px',
2391						overflow: 'hidden'
2392					});
2393
2394					container.appendChild(shimContainer);
2395					container = null;
2396				}
2397
2398				return shimContainer;
2399			},
2400
2401			/**
2402			Returns runtime as DOM element (if appropriate)
2403
2404			@method getShim
2405			@return {DOMElement}
2406			*/
2407			getShim: function() {
2408				return _shim;
2409			},
2410
2411			/**
2412			Invokes a method within the runtime itself (might differ across the runtimes)
2413
2414			@method shimExec
2415			@param {Mixed} []
2416			@protected
2417			@return {Mixed} Depends on the action and component
2418			*/
2419			shimExec: function(component, action) {
2420				var args = [].slice.call(arguments, 2);
2421				return self.getShim().exec.call(this, this.uid, component, action, args);
2422			},
2423
2424			/**
2425			Operaional interface that is used by components to invoke specific actions on the runtime
2426			(is invoked in the scope of component)
2427
2428			@method exec
2429			@param {Mixed} []*
2430			@protected
2431			@return {Mixed} Depends on the action and component
2432			*/
2433			exec: function(component, action) { // this is called in the context of component, not runtime
2434				var args = [].slice.call(arguments, 2);
2435
2436				if (self[component] && self[component][action]) {
2437					return self[component][action].apply(this, args);
2438				}
2439				return self.shimExec.apply(this, arguments);
2440			},
2441
2442			/**
2443			Destroys the runtime (removes all events and deletes DOM structures)
2444
2445			@method destroy
2446			*/
2447			destroy: function() {
2448				if (!self) {
2449					return; // obviously already destroyed
2450				}
2451
2452				var shimContainer = Dom.get(this.shimid);
2453				if (shimContainer) {
2454					shimContainer.parentNode.removeChild(shimContainer);
2455				}
2456
2457				if (_shim) {
2458					_shim.removeAllInstances();
2459				}
2460
2461				this.unbindAll();
2462				delete runtimes[this.uid];
2463				this.uid = null; // mark this runtime as destroyed
2464				_uid = self = _shim = shimContainer = null;
2465			}
2466		});
2467
2468		// once we got the mode, test against all caps
2469		if (this.mode && options.required_caps && !this.can(options.required_caps)) {
2470			this.mode = false;
2471		}	
2472	}
2473
2474
2475	/**
2476	Default order to try different runtime types
2477
2478	@property order
2479	@type String
2480	@static
2481	*/
2482	Runtime.order = 'html5,html4';
2483
2484
2485	/**
2486	Retrieves runtime from private hash by it's uid
2487
2488	@method getRuntime
2489	@private
2490	@static
2491	@param {String} uid Unique identifier of the runtime
2492	@return {Runtime|Boolean} Returns runtime, if it exists and false, if - not
2493	*/
2494	Runtime.getRuntime = function(uid) {
2495		return runtimes[uid] ? runtimes[uid] : false;
2496	};
2497
2498
2499	/**
2500	Register constructor for the Runtime of new (or perhaps modified) type
2501
2502	@method addConstructor
2503	@static
2504	@param {String} type Runtime type (e.g. flash, html5, etc)
2505	@param {Function} construct Constructor for the Runtime type
2506	*/
2507	Runtime.addConstructor = function(type, constructor) {
2508		constructor.prototype = EventTarget.instance;
2509		runtimeConstructors[type] = constructor;
2510	};
2511
2512
2513	/**
2514	Get the constructor for the specified type.
2515
2516	method getConstructor
2517	@static
2518	@param {String} type Runtime type (e.g. flash, html5, etc)
2519	@return {Function} Constructor for the Runtime type
2520	*/
2521	Runtime.getConstructor = function(type) {
2522		return runtimeConstructors[type] || null;
2523	};
2524
2525
2526	/**
2527	Get info about the runtime (uid, type, capabilities)
2528
2529	@method getInfo
2530	@static
2531	@param {String} uid Unique identifier of the runtime
2532	@return {Mixed} Info object or null if runtime doesn't exist
2533	*/
2534	Runtime.getInfo = function(uid) {
2535		var runtime = Runtime.getRuntime(uid);
2536
2537		if (runtime) {
2538			return {
2539				uid: runtime.uid,
2540				type: runtime.type,
2541				mode: runtime.mode,
2542				can: function() {
2543					return runtime.can.apply(runtime, arguments);
2544				}
2545			};
2546		}
2547		return null;
2548	};
2549
2550
2551	/**
2552	Convert caps represented by a comma-separated string to the object representation.
2553
2554	@method parseCaps
2555	@static
2556	@param {String} capStr Comma-separated list of capabilities
2557	@return {Object}
2558	*/
2559	Runtime.parseCaps = function(capStr) {
2560		var capObj = {};
2561
2562		if (Basic.typeOf(capStr) !== 'string') {
2563			return capStr || {};
2564		}
2565
2566		Basic.each(capStr.split(','), function(key) {
2567			capObj[key] = true; // we assume it to be - true
2568		});
2569
2570		return capObj;
2571	};
2572
2573	/**
2574	Test the specified runtime for specific capabilities.
2575
2576	@method can
2577	@static
2578	@param {String} type Runtime type (e.g. flash, html5, etc)
2579	@param {String|Object} caps Set of capabilities to check
2580	@return {Boolean} Result of the test
2581	*/
2582	Runtime.can = function(type, caps) {
2583		var runtime
2584		, constructor = Runtime.getConstructor(type)
2585		, mode
2586		;
2587		if (constructor) {
2588			runtime = new constructor({
2589				required_caps: caps
2590			});
2591			mode = runtime.mode;
2592			runtime.destroy();
2593			return !!mode;
2594		}
2595		return false;
2596	};
2597
2598
2599	/**
2600	Figure out a runtime that supports specified capabilities.
2601
2602	@method thatCan
2603	@static
2604	@param {String|Object} caps Set of capabilities to check
2605	@param {String} [runtimeOrder] Comma-separated list of runtimes to check against
2606	@return {String} Usable runtime identifier or null
2607	*/
2608	Runtime.thatCan = function(caps, runtimeOrder) {
2609		var types = (runtimeOrder || Runtime.order).split(/\s*,\s*/);
2610		for (var i in types) {
2611			if (Runtime.can(types[i], caps)) {
2612				return types[i];
2613			}
2614		}
2615		return null;
2616	};
2617
2618
2619	/**
2620	Figure out an operational mode for the specified set of capabilities.
2621
2622	@method getMode
2623	@static
2624	@param {Object} modeCaps Set of capabilities that depend on particular runtime mode
2625	@param {Object} [requiredCaps] Supplied set of capabilities to find operational mode for
2626	@param {String|Boolean} [defaultMode='browser'] Default mode to use 
2627	@return {String|Boolean} Compatible operational mode
2628	*/
2629	Runtime.getMode = function(modeCaps, requiredCaps, defaultMode) {
2630		var mode = null;
2631
2632		if (Basic.typeOf(defaultMode) === 'undefined') { // only if not specified
2633			defaultMode = 'browser';
2634		}
2635
2636		if (requiredCaps && !Basic.isEmptyObj(modeCaps)) {
2637			// loop over required caps and check if they do require the same mode
2638			Basic.each(requiredCaps, function(value, cap) {
2639				if (modeCaps.hasOwnProperty(cap)) {
2640					var capMode = modeCaps[cap](value);
2641
2642					// make sure we always have an array
2643					if (typeof(capMode) === 'string') {
2644						capMode = [capMode];
2645					}
2646					
2647					if (!mode) {
2648						mode = capMode;						
2649					} else if (!(mode = Basic.arrayIntersect(mode, capMode))) {
2650						// if cap requires conflicting mode - runtime cannot fulfill required caps
2651
2652						if (MXI_DEBUG && Env.debug.runtime) {
2653							Env.log("\t\t%c: %v (conflicting mode requested: %s)", cap, value, capMode);	
2654						}
2655
2656						return (mode = false);
2657					}					
2658				}
2659
2660				if (MXI_DEBUG && Env.debug.runtime) {
2661					Env.log("\t\t%c: %v (compatible modes: %s)", cap, value, mode);	
2662				}
2663			});
2664
2665			if (mode) {
2666				return Basic.inArray(defaultMode, mode) !== -1 ? defaultMode : mode[0];
2667			} else if (mode === false) {
2668				return false;
2669			}
2670		}
2671		return defaultMode; 
2672	};
2673
2674
2675	/**
2676	Capability check that always returns true
2677
2678	@private
2679	@static
2680	@return {True}
2681	*/
2682	Runtime.capTrue = function() {
2683		return true;
2684	};
2685
2686	/**
2687	Capability check that always returns false
2688
2689	@private
2690	@static
2691	@return {False}
2692	*/
2693	Runtime.capFalse = function() {
2694		return false;
2695	};
2696
2697	/**
2698	Evaluate the expression to boolean value and create a function that always returns it.
2699
2700	@private
2701	@static
2702	@param {Mixed} expr Expression to evaluate
2703	@return {Function} Function returning the result of evaluation
2704	*/
2705	Runtime.capTest = function(expr) {
2706		return function() {
2707			return !!expr;
2708		};
2709	};
2710
2711	return Runtime;
2712});
2713
2714// Included from: src/javascript/runtime/RuntimeClient.js
2715
2716/**
2717 * RuntimeClient.js
2718 *
2719 * Copyright 2013, Moxiecode Systems AB
2720 * Released under GPL License.
2721 *
2722 * License: http://www.plupload.com/license
2723 * Contributing: http://www.plupload.com/contributing
2724 */
2725
2726define('moxie/runtime/RuntimeClient', [
2727	'moxie/core/utils/Env',
2728	'moxie/core/Exceptions',
2729	'moxie/core/utils/Basic',
2730	'moxie/runtime/Runtime'
2731], function(Env, x, Basic, Runtime) {
2732	/**
2733	Set of methods and properties, required by a component to acquire ability to connect to a runtime
2734
2735	@class RuntimeClient
2736	*/
2737	return function RuntimeClient() {
2738		var runtime;
2739
2740		Basic.extend(this, {
2741			/**
2742			Connects to the runtime specified by the options. Will either connect to existing runtime or create a new one.
2743			Increments number of clients connected to the specified runtime.
2744
2745			@private
2746			@method connectRuntime
2747			@param {Mixed} options Can be a runtme uid or a set of key-value pairs defining requirements and pre-requisites
2748			*/
2749			connectRuntime: function(options) {
2750				var comp = this, ruid;
2751
2752				function initialize(items) {
2753					var type, constructor;
2754
2755					// if we ran out of runtimes
2756					if (!items.length) {
2757						comp.trigger('RuntimeError', new x.RuntimeError(x.RuntimeError.NOT_INIT_ERR));
2758						runtime = null;
2759						return;
2760					}
2761
2762					type = items.shift().toLowerCase();
2763					constructor = Runtime.getConstructor(type);
2764					if (!constructor) {
2765						initialize(items);
2766						return;
2767					}
2768
2769					if (MXI_DEBUG && Env.debug.runtime) {
2770						Env.log("Trying runtime: %s", type);
2771						Env.log(options);
2772					}
2773
2774					// try initializing the runtime
2775					runtime = new constructor(options);
2776
2777					runtime.bind('Init', function() {
2778						// mark runtime as initialized
2779						runtime.initialized = true;
2780
2781						if (MXI_DEBUG && Env.debug.runtime) {
2782							Env.log("Runtime '%s' initialized", runtime.type);
2783						}
2784
2785						// jailbreak ...
2786						setTimeout(function() {
2787							runtime.clients++;
2788							// this will be triggered on component
2789							comp.trigger('RuntimeInit', runtime);
2790						}, 1);
2791					});
2792
2793					runtime.bind('Error', function() {
2794						if (MXI_DEBUG && Env.debug.runtime) {
2795							Env.log("Runtime '%s' failed to initialize", runtime.type);
2796						}
2797
2798						runtime.destroy(); // runtime cannot destroy itself from inside at a right moment, thus we do it here
2799						initialize(items);
2800					});
2801
2802					/*runtime.bind('Exception', function() { });*/
2803
2804					if (MXI_DEBUG && Env.debug.runtime) {
2805						Env.log("\tselected mode: %s", runtime.mode);	
2806					}
2807
2808					// check if runtime managed to pick-up operational mode
2809					if (!runtime.mode) {
2810						runtime.trigger('Error');
2811						return;
2812					}
2813
2814					runtime.init();
2815				}
2816
2817				// check if a particular runtime was requested
2818				if (Basic.typeOf(options) === 'string') {
2819					ruid = options;
2820				} else if (Basic.typeOf(options.ruid) === 'string') {
2821					ruid = options.ruid;
2822				}
2823
2824				if (ruid) {
2825					runtime = Runtime.getRuntime(ruid);
2826					if (runtime) {
2827						runtime.clients++;
2828						return runtime;
2829					} else {
2830						// there should be a runtime and there's none - weird case
2831						throw new x.RuntimeError(x.RuntimeError.NOT_INIT_ERR);
2832					}
2833				}
2834
2835				// initialize a fresh one, that fits runtime list and required features best
2836				initialize((options.runtime_order || Runtime.order).split(/\s*,\s*/));
2837			},
2838
2839
2840			/**
2841			Disconnects from the runtime. Decrements number of clients connected to the specified runtime.
2842
2843			@private
2844			@method disconnectRuntime
2845			*/
2846			disconnectRuntime: function() {
2847				if (runtime && --runtime.clients <= 0) {
2848					runtime.destroy();
2849				}
2850
2851				// once the component is disconnected, it shouldn't have access to the runtime
2852				runtime = null;
2853			},
2854
2855
2856			/**
2857			Returns the runtime to which the client is currently connected.
2858
2859			@method getRuntime
2860			@return {Runtime} Runtime or null if client is not connected
2861			*/
2862			getRuntime: function() {
2863				if (runtime && runtime.uid) {
2864					return runtime;
2865				}
2866				return runtime = null; // make sure we do not leave zombies rambling around
2867			},
2868
2869
2870			/**
2871			Handy shortcut to safely invoke runtime extension methods.
2872			
2873			@private
2874			@method exec
2875			@return {Mixed} Whatever runtime extension method returns
2876			*/
2877			exec: function() {
2878				if (runtime) {
2879					return runtime.exec.apply(this, arguments);
2880				}
2881				return null;
2882			}
2883
2884		});
2885	};
2886
2887
2888});
2889
2890// Included from: src/javascript/file/FileInput.js
2891
2892/**
2893 * FileInput.js
2894 *
2895 * Copyright 2013, Moxiecode Systems AB
2896 * Released under GPL License.
2897 *
2898 * License: http://www.plupload.com/license
2899 * Contributing: http://www.plupload.com/contributing
2900 */
2901
2902define('moxie/file/FileInput', [
2903	'moxie/core/utils/Basic',
2904	'moxie/core/utils/Env',
2905	'moxie/core/utils/Mime',
2906	'moxie/core/utils/Dom',
2907	'moxie/core/Exceptions',
2908	'moxie/core/EventTarget',
2909	'moxie/core/I18n',
2910	'moxie/runtime/Runtime',
2911	'moxie/runtime/RuntimeClient'
2912], function(Basic, Env, Mime, Dom, x, EventTarget, I18n, Runtime, RuntimeClient) {
2913	/**
2914	Provides a convenient way to create cross-browser file-picker. Generates file selection dialog on click,
2915	converts selected files to _File_ objects, to be used in conjunction with _Image_, preloaded in memory
2916	with _FileReader_ or uploaded to a server through _XMLHttpRequest_.
2917
2918	@class FileInput
2919	@constructor
2920	@extends EventTarget
2921	@uses RuntimeClient
2922	@param {Object|String|DOMElement} options If options is string or node, argument is considered as _browse\_button_.
2923		@param {String|DOMElement} options.browse_button DOM Element to turn into file picker.
2924		@param {Array} [options.accept] Array of mime types to accept. By default accepts all.
2925		@param {String} [options.file='file'] Name of the file field (not the filename).
2926		@param {Boolean} [options.multiple=false] Enable selection of multiple files.
2927		@param {Boolean} [options.directory=false] Turn file input into the folder input (cannot be both at the same time).
2928		@param {String|DOMElement} [options.container] DOM Element to use as a container for file-picker. Defaults to parentNode 
2929		for _browse\_button_.
2930		@param {Object|String} [options.required_caps] Set of required capabilities, that chosen runtime must support.
2931
2932	@example
2933		<div id="container">
2934			<a id="file-picker" href="javascript:;">Browse...</a>
2935		</div>
2936
2937		<script>
2938			var fileInput = new mOxie.FileInput({
2939				browse_button: 'file-picker', // or document.getElementById('file-picker')
2940				container: 'container',
2941				accept: [
2942					{title: "Image files", extensions: "jpg,gif,png"} // accept only images
2943				],
2944				multiple: true // allow multiple file selection
2945			});
2946
2947			fileInput.onchange = function(e) {
2948				// do something to files array
2949				console.info(e.target.files); // or this.files or fileInput.files
2950			};
2951
2952			fileInput.init(); // initialize
2953		</script>
2954	*/
2955	var dispatches = [
2956		/**
2957		Dispatched when runtime is connected and file-picker is ready to be used.
2958
2959		@event ready
2960		@param {Object} event
2961		*/
2962		'ready',
2963
2964		/**
2965		Dispatched right after [ready](#event_ready) event, and whenever [refresh()](#method_refresh) is invoked. 
2966		Check [corresponding documentation entry](#method_refresh) for more info.
2967
2968		@event refresh
2969		@param {Object} event
2970		*/
2971
2972		/**
2973		Dispatched when selection of files in the dialog is complete.
2974
2975		@event change
2976		@param {Object} event
2977		*/
2978		'change',
2979
2980		'cancel', // TODO: might be useful
2981
2982		/**
2983		Dispatched when mouse cursor enters file-picker area. Can be used to style element
2984		accordingly.
2985
2986		@event mouseenter
2987		@param {Object} event
2988		*/
2989		'mouseenter',
2990
2991		/**
2992		Dispatched when mouse cursor leaves file-picker area. Can be used to style element
2993		accordingly.
2994
2995		@event mouseleave
2996		@param {Object} event
2997		*/
2998		'mouseleave',
2999
3000		/**
3001		Dispatched when functional mouse button is pressed on top of file-picker area.
3002
3003		@event mousedown
3004		@param {Object} event
3005		*/
3006		'mousedown',
3007
3008		/**
3009		Dispatched when functional mouse button is released on top of file-picker area.
3010
3011		@event mouseup
3012		@param {Object} event
3013		*/
3014		'mouseup'
3015	];
3016
3017	function FileInput(options) {
3018		if (MXI_DEBUG) {
3019			Env.log("Instantiating FileInput...");	
3020		}
3021
3022		var self = this,
3023			container, browseButton, defaults;
3024
3025		// if flat argument passed it should be browse_button id
3026		if (Basic.inArray(Basic.typeOf(options), ['string', 'node']) !== -1) {
3027			options = { browse_button : options };
3028		}
3029
3030		// this will help us to find proper default container
3031		browseButton = Dom.get(options.browse_button);
3032		if (!browseButton) {
3033			// browse button is required
3034			throw new x.DOMException(x.DOMException.NOT_FOUND_ERR);
3035		}
3036
3037		// figure out the options
3038		defaults = {
3039			accept: [{
3040				title: I18n.translate('All Files'),
3041				extensions: '*'
3042			}],
3043			name: 'file',
3044			multiple: false,
3045			required_caps: false,
3046			container: browseButton.parentNode || document.body
3047		};
3048		
3049		options = Basic.extend({}, defaults, options);
3050
3051		// convert to object representation
3052		if (typeof(options.required_caps) === 'string') {
3053			options.required_caps = Runtime.parseCaps(options.required_caps);
3054		}
3055					
3056		// normalize accept option (could be list of mime types or array of title/extensions pairs)
3057		if (typeof(options.accept) === 'string') {
3058			options.accept = Mime.mimes2extList(options.accept);
3059		}
3060
3061		container = Dom.get(options.container);
3062		// make sure we have container
3063		if (!container) {
3064			container = document.body;
3065		}
3066
3067		// make container relative, if it's not
3068		if (Dom.getStyle(container, 'position') === 'static') {
3069			container.style.position = 'relative';
3070		}
3071
3072		container = browseButton = null; // IE
3073						
3074		RuntimeClient.call(self);
3075		
3076		Basic.extend(self, {
3077			/**
3078			Unique id of the component
3079
3080			@property uid
3081			@protected
3082			@readOnly
3083			@type {String}
3084			@default UID
3085			*/
3086			uid: Basic.guid('uid_'),
3087			
3088			/**
3089			Unique id of the connected runtime, if any.
3090
3091			@property ruid
3092			@protected
3093			@type {String}
3094			*/
3095			ruid: null,
3096
3097			/**
3098			Unique id of the runtime container. Useful to get hold of it for various manipulations.
3099
3100			@property shimid
3101			@protected
3102			@type {String}
3103			*/
3104			shimid: null,
3105			
3106			/**
3107			Array of selected mOxie.File objects
3108
3109			@property files
3110			@type {Array}
3111			@default null
3112			*/
3113			files: null,
3114
3115			/**
3116			Initializes the file-picker, connects it to runtime and dispatches event ready when done.
3117
3118			@method init
3119			*/
3120			init: function() {
3121				self.bind('RuntimeInit', function(e, runtime) {
3122					self.ruid = runtime.uid;
3123					self.shimid = runtime.shimid;
3124
3125					self.bind("Ready", function() {
3126						self.trigger("Refresh");
3127					}, 999);
3128
3129					// re-position and resize shim container
3130					self.bind('Refresh', function() {
3131						var pos, size, browseButton, shimContainer;
3132						
3133						browseButton = Dom.get(options.browse_button);
3134						shimContainer = Dom.get(runtime.shimid); // do not use runtime.getShimContainer(), since it will create container if it doesn't exist
3135
3136						if (browseButton) {
3137							pos = Dom.getPos(browseButton, Dom.get(options.container));
3138							size = Dom.getSize(browseButton);
3139
3140							if (shimContainer) {
3141								Basic.extend(shimContainer.style, {
3142									top     : pos.y + 'px',
3143									left    : pos.x + 'px',
3144									width   : size.w + 'px',
3145									height  : size.h + 'px'
3146								});
3147							}
3148						}
3149						shimContainer = browseButton = null;
3150					});
3151					
3152					runtime.exec.call(self, 'FileInput', 'init', options);
3153				});
3154
3155				// runtime needs: options.required_features, options.runtime_order and options.container
3156				self.connectRuntime(Basic.extend({}, options, {
3157					required_caps: {
3158						select_file: true
3159					}
3160				}));
3161			},
3162
3163			/**
3164			Disables file-picker element, so that it doesn't react to mouse clicks.
3165
3166			@method disable
3167			@param {Boolean} [state=true] Disable component if - true, enable if - false
3168			*/
3169			disable: function(state) {
3170				var runtime = this.getRuntime();
3171				if (runtime) {
3172					runtime.exec.call(this, 'FileInput', 'disable', Basic.typeOf(state) === 'undefined' ? true : state);
3173				}
3174			},
3175
3176
3177			/**
3178			Reposition and resize dialog trigger to match the position and size of browse_button element.
3179
3180			@method refresh
3181			*/
3182			refresh: function() {
3183				self.trigger("Refresh");
3184			},
3185
3186
3187			/**
3188			Destroy component.
3189
3190			@method destroy
3191			*/
3192			destroy: function() {
3193				var runtime = this.getRuntime();
3194				if (runtime) {
3195					runtime.exec.call(this, 'FileInput', 'destroy');
3196					this.disconnectRuntime();
3197				}
3198
3199				if (Basic.typeOf(this.files) === 'array') {
3200					// no sense in leaving associated files behind
3201					Basic.each(this.files, function(file) {
3202						file.destroy();
3203					});
3204				} 
3205				this.files = null;
3206
3207				this.unbindAll();
3208			}
3209		});
3210
3211		this.handleEventProps(dispatches);
3212	}
3213
3214	FileInput.prototype = EventTarget.instance;
3215
3216	return FileInput;
3217});
3218
3219// Included from: src/javascript/core/utils/Encode.js
3220
3221/**
3222 * Encode.js
3223 *
3224 * Copyright 2013, Moxiecode Systems AB
3225 * Released under GPL License.
3226 *
3227 * License: http://www.plupload.com/license
3228 * Contributing: http://www.plupload.com/contributing
3229 */
3230
3231define('moxie/core/utils/Encode', [], function() {
3232
3233	/**
3234	Encode string with UTF-8
3235
3236	@method utf8_encode
3237	@for Utils
3238	@static
3239	@param {String} str String to encode
3240	@return {String} UTF-8 encoded string
3241	*/
3242	var utf8_encode = function(str) {
3243		return unescape(encodeURIComponent(str));
3244	};
3245	
3246	/**
3247	Decode UTF-8 encoded string
3248
3249	@method utf8_decode
3250	@static
3251	@param {String} str String to decode
3252	@return {String} Decoded string
3253	*/
3254	var utf8_decode = function(str_data) {
3255		return decodeURIComponent(escape(str_data));
3256	};
3257	
3258	/**
3259	Decode Base64 encoded string (uses browser's default method if available),
3260	from: https://raw.github.com/kvz/phpjs/master/functions/url/base64_decode.js
3261
3262	@method atob
3263	@static
3264	@param {String} data String to decode
3265	@return {String} Decoded string
3266	*/
3267	var atob = function(data, utf8) {
3268		if (typeof(window.atob) === 'function') {
3269			return utf8 ? utf8_decode(window.atob(data)) : window.atob(data);
3270		}
3271
3272		// http://kevin.vanzonneveld.net
3273		// +   original by: Tyler Akins (http://rumkin.com)
3274		// +   improved by: Thunder.m
3275		// +      input by: Aman Gupta
3276		// +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
3277		// +   bugfixed by: Onno Marsman
3278		// +   bugfixed by: Pellentesque Malesuada
3279		// +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
3280		// +      input by: Brett Zamir (http://brett-zamir.me)
3281		// +   bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
3282		// *     example 1: base64_decode('S2V2aW4gdmFuIFpvbm5ldmVsZA==');
3283		// *     returns 1: 'Kevin van Zonneveld'
3284		// mozilla has this native
3285		// - but breaks in 2.0.0.12!
3286		//if (typeof this.window.atob == 'function') {
3287		//    return atob(data);
3288		//}
3289		var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
3290		var o1, o2, o3, h1, h2, h3, h4, bits, i = 0,
3291			ac = 0,
3292			dec = "",
3293			tmp_arr = [];
3294
3295		if (!data) {
3296			return data;
3297		}
3298
3299		data += '';
3300
3301		do { // unpack four hexets into three octets using index points in b64
3302			h1 = b64.indexOf(data.charAt(i++));
3303			h2 = b64.indexOf(data.charAt(i++));
3304			h3 = b64.indexOf(data.charAt(i++));
3305			h4 = b64.indexOf(data.charAt(i++));
3306
3307			bits = h1 << 18 | h2 << 12 | h3 << 6 | h4;
3308
3309			o1 = bits >> 16 & 0xff;
3310			o2 = bits >> 8 & 0xff;
3311			o3 = bits & 0xff;
3312
3313			if (h3 == 64) {
3314				tmp_arr[ac++] = String.fromCharCode(o1);
3315			} else if (h4 == 64) {
3316				tmp_arr[ac++] = String.fromCharCode(o1, o2);
3317			} else {
3318				tmp_arr[ac++] = String.fromCharCode(o1, o2, o3);
3319			}
3320		} while (i < data.length);
3321
3322		dec = tmp_arr.join('');
3323
3324		return utf8 ? utf8_decode(dec) : dec;
3325	};
3326	
3327	/**
3328	Base64 encode string (uses browser's default method if available),
3329	from: https://raw.github.com/kvz/phpjs/master/functions/url/base64_encode.js
3330
3331	@method btoa
3332	@static
3333	@param {String} data String to encode
3334	@return {String} Base64 encoded string
3335	*/
3336	var btoa = function(data, utf8) {
3337		if (utf8) {
3338			data = utf8_encode(data);
3339		}
3340
3341		if (typeof(window.btoa) === 'function') {
3342			return window.btoa(data);
3343		}
3344
3345		// http://kevin.vanzonneveld.net
3346		// +   original by: Tyler Akins (http://rumkin.com)
3347		// +   improved by: Bayron Guevara
3348		// +   improved by: Thunder.m
3349		// +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
3350		// +   bugfixed by: Pellentesque Malesuada
3351		// +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
3352		// +   improved by: Rafał Kukawski (http://kukawski.pl)
3353		// *     example 1: base64_encode('Kevin van Zonneveld');
3354		// *     returns 1: 'S2V2aW4gdmFuIFpvbm5ldmVsZA=='
3355		// mozilla has this native
3356		// - but breaks in 2.0.0.12!
3357		var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
3358		var o1, o2, o3, h1, h2, h3, h4, bits, i = 0,
3359			ac = 0,
3360			enc = "",
3361			tmp_arr = [];
3362
3363		if (!data) {
3364			return data;
3365		}
3366
3367		do { // pack three octets into four hexets
3368			o1 = data.charCodeAt(i++);
3369			o2 = data.charCodeAt(i++);
3370			o3 = data.charCodeAt(i++);
3371
3372			bits = o1 << 16 | o2 << 8 | o3;
3373
3374			h1 = bits >> 18 & 0x3f;
3375			h2 = bits >> 12 & 0x3f;
3376			h3 = bits >> 6 & 0x3f;
3377			h4 = bits & 0x3f;
3378
3379			// use hexets to index into b64, and append result to encoded string
3380			tmp_arr[ac++] = b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4);
3381		} while (i < data.length);
3382
3383		enc = tmp_arr.join('');
3384
3385		var r = data.length % 3;
3386
3387		return (r ? enc.slice(0, r - 3) : enc) + '==='.slice(r || 3);
3388	};
3389
3390
3391	return {
3392		utf8_encode: utf8_encode,
3393		utf8_decode: utf8_decode,
3394		atob: atob,
3395		btoa: btoa
3396	};
3397});
3398
3399// Included from: src/javascript/file/Blob.js
3400
3401/**
3402 * Blob.js
3403 *
3404 * Copyright 2013, Moxiecode Systems AB
3405 * Released under GPL License.
3406 *
3407 * License: http://www.plupload.com/license
3408 * Contributing: http://www.plupload.com/contributing
3409 */
3410
3411define('moxie/file/Blob', [
3412	'moxie/core/utils/Basic',
3413	'moxie/core/utils/Encode',
3414	'moxie/runtime/RuntimeClient'
3415], function(Basic, Encode, RuntimeClient) {
3416	
3417	var blobpool = {};
3418
3419	/**
3420	@class Blob
3421	@constructor
3422	@param {String} ruid Unique id of the runtime, to which this blob belongs to
3423	@param {Object} blob Object "Native" blob object, as it is represented in the runtime
3424	*/
3425	function Blob(ruid, blob) {
3426
3427		function _sliceDetached(start, end, type) {
3428			var blob, data = blobpool[this.uid];
3429
3430			if (Basic.typeOf(data) !== 'string' || !data.length) {
3431				return null; // or throw exception
3432			}
3433
3434			blob = new Blob(null, {
3435				type: type,
3436				size: end - start
3437			});
3438			blob.detach(data.substr(start, blob.size));
3439
3440			return blob;
3441		}
3442
3443		RuntimeClient.call(this);
3444
3445		if (ruid) {	
3446			this.connectRuntime(ruid);
3447		}
3448
3449		if (!blob) {
3450			blob = {};
3451		} else if (Basic.typeOf(blob) === 'string') { // dataUrl or binary string
3452			blob = { data: blob };
3453		}
3454
3455		Basic.extend(this, {
3456			
3457			/**
3458			Unique id of the component
3459
3460			@property uid
3461			@type {String}
3462			*/
3463			uid: blob.uid || Basic.guid('uid_'),
3464			
3465			/**
3466			Unique id of the connected runtime, if falsy, then runtime will have to be initialized 
3467			before this Blob can be used, modified or sent
3468
3469			@property ruid
3470			@type {String}
3471			*/
3472			ruid: ruid,
3473	
3474			/**
3475			Size of blob
3476
3477			@property size
3478			@type {Number}
3479			@default 0
3480			*/
3481			size: blob.size || 0,
3482			
3483			/**
3484			Mime type of blob
3485
3486			@property type
3487			@type {String}
3488			@default ''
3489			*/
3490			type: blob.type || '',
3491			
3492			/**
3493			@method slice
3494			@param {Number} [start=0]
3495			*/
3496			slice: function(start, end, type) {		
3497				if (this.isDetached()) {
3498					return _sliceDetached.apply(this, arguments);
3499				}
3500				return this.getRuntime().exec.call(this, 'Blob', 'slice', this.getSource(), start, end, type);
3501			},
3502
3503			/**
3504			Returns "native" blob object (as it is represented in connected runtime) or null if not found
3505
3506			@method getSource
3507			@return {Blob} Returns "native" blob object or null if not found
3508			*/
3509			getSource: function() {
3510				if (!blobpool[this.uid]) {
3511					return null;	
3512				}
3513				return blobpool[this.uid];
3514			},
3515
3516			/** 
3517			Detaches blob from any runtime that it depends on and initialize with standalone value
3518
3519			@method detach
3520			@protected
3521			@param {DOMString} [data=''] Standalone value
3522			*/
3523			detach: function(data) {
3524				if (this.ruid) {
3525					this.getRuntime().exec.call(this, 'Blob', 'destroy');
3526					this.disconnectRuntime();
3527					this.ruid = null;
3528				}
3529
3530				data = data || '';
3531
3532				// if dataUrl, convert to binary string
3533				if (data.substr(0, 5) == 'data:') {
3534					var base64Offset = data.indexOf(';base64,');
3535					this.type = data.substring(5, base64Offset);
3536					data = Encode.atob(data.substring(base64Offset + 8));
3537				}
3538
3539				this.size = data.length;
3540
3541				blobpool[this.uid] = data;
3542			},
3543
3544			/**
3545			Checks if blob is standalone (detached of any runtime)
3546			
3547			@method isDetached
3548			@protected
3549			@return {Boolean}
3550			*/
3551			isDetached: function() {
3552				return !this.ruid && Basic.typeOf(blobpool[this.uid]) === 'string';
3553			},
3554			
3555			/** 
3556			Destroy Blob and free any resources it was using
3557
3558			@method destroy
3559			*/
3560			destroy: function() {
3561				this.detach();
3562				delete blobpool[this.uid];
3563			}
3564		});
3565
3566		
3567		if (blob.data) {
3568			this.detach(blob.data); // auto-detach if payload has been passed
3569		} else {
3570			blobpool[this.uid] = blob;	
3571		}
3572	}
3573	
3574	return Blob;
3575});
3576
3577// Included from: src/javascript/file/File.js
3578
3579/**
3580 * File.js
3581 *
3582 * Copyright 2013, Moxiecode Systems AB
3583 * Released under GPL License.
3584 *
3585 * License: http://www.plupload.com/license
3586 * Contributing: http://www.plupload.com/contributing
3587 */
3588
3589define('moxie/file/File', [
3590	'moxie/core/utils/Basic',
3591	'moxie/core/utils/Mime',
3592	'moxie/file/Blob'
3593], function(Basic, Mime, Blob) {
3594	/**
3595	@class File
3596	@extends Blob
3597	@constructor
3598	@param {String} ruid Unique id of the runtime, to which this blob belongs to
3599	@param {Object} file Object "Native" file object, as it is represented in the runtime
3600	*/
3601	function File(ruid, file) {
3602		if (!file) { // avoid extra errors in case we overlooked something
3603			file = {};
3604		}
3605
3606		Blob.apply(this, arguments);
3607
3608		if (!this.type) {
3609			this.type = Mime.getFileMime(file.name);
3610		}
3611
3612		// sanitize file name or generate new one
3613		var name;
3614		if (file.name) {
3615			name = file.name.replace(/\\/g, '/');
3616			name = name.substr(name.lastIndexOf('/') + 1);
3617		}
3617 else if (this.type) {
3618			var prefix = this.type.split('/')[0];
3619			name = Basic.guid((prefix !== '' ? prefix : 'file') + '_');
3620			
3621			if (Mime.extensions[this.type]) {
3622				name += '.' + Mime.extensions[this.type][0]; // append proper extension if possible
3623			}
3624		}
3625		
3626		
3627		Basic.extend(this, {
3628			/**
3629			File name
3630
3631			@property name
3632			@type {String}
3633			@default UID
3634			*/
3635			name: name || Basic.guid('file_'),
3636
3637			/**
3638			Relative path to the file inside a directory
3639
3640			@property relativePath
3641			@type {String}
3642			@default ''
3643			*/
3644			relativePath: '',
3645			
3646			/**
3647			Date of last modification
3648
3649			@property lastModifiedDate
3650			@type {String}
3651			@default now
3652			*/
3653			lastModifiedDate: file.lastModifiedDate || (new Date()).toLocaleString() // Thu Aug 23 2012 19:40:00 GMT+0400 (GET)
3654		});
3655	}
3656
3657	File.prototype = Blob.prototype;
3658
3659	return File;
3660});
3661
3662// Included from: src/javascript/file/FileDrop.js
3663
3664/**
3665 * FileDrop.js
3666 *
3667 * Copyright 2013, Moxiecode Systems AB
3668 * Released under GPL License.
3669 *
3670 * License: http://www.plupload.com/license
3671 * Contributing: http://www.plupload.com/contributing
3672 */
3673
3674define('moxie/file/FileDrop', [
3675	'moxie/core/I18n',
3676	'moxie/core/utils/Dom',
3677	'moxie/core/Exceptions',
3678	'moxie/core/utils/Basic',
3679	'moxie/core/utils/Env',
3680	'moxie/file/File',
3681	'moxie/runtime/RuntimeClient',
3682	'moxie/core/EventTarget',
3683	'moxie/core/utils/Mime'
3684], function(I18n, Dom, x, Basic, Env, File, RuntimeClient, EventTarget, Mime) {
3685	/**
3686	Turn arbitrary DOM element to a drop zone accepting files. Converts selected files to _File_ objects, to be used 
3687	in conjunction with _Image_, preloaded in memory with _FileReader_ or uploaded to a server through 
3688	_XMLHttpRequest_.
3689
3690	@example
3691		<div id="drop_zone">
3692			Drop files here
3693		</div>
3694		<br />
3695		<div id="filelist"></div>
3696
3697		<script type="text/javascript">
3698			var fileDrop = new mOxie.FileDrop('drop_zone'), fileList = mOxie.get('filelist');
3699
3700			fileDrop.ondrop = function() {
3701				mOxie.each(this.files, function(file) {
3702					fileList.innerHTML += '<div>' + file.name + '</div>';
3703				});
3704			};
3705
3706			fileDrop.init();
3707		</script>
3708
3709	@class FileDrop
3710	@constructor
3711	@extends EventTarget
3712	@uses RuntimeClient
3713	@param {Object|String} options If options has typeof string, argument is considered as options.drop_zone
3714		@param {String|DOMElement} options.drop_zone DOM Element to turn into a drop zone
3715		@param {Array} [options.accept] Array of mime types to accept. By default accepts all
3716		@param {Object|String} [options.required_caps] Set of required capabilities, that chosen runtime must support
3717	*/
3718	var dispatches = [
3719		/**
3720		Dispatched when runtime is connected and drop zone is ready to accept files.
3721
3722		@event ready
3723		@param {Object} event
3724		*/
3725		'ready', 
3726
3727		/**
3728		Dispatched when dragging cursor enters the drop zone.
3729
3730		@event dragenter
3731		@param {Object} event
3732		*/
3733		'dragenter',
3734
3735		/**
3736		Dispatched when dragging cursor leaves the drop zone.
3737
3738		@event dragleave
3739		@param {Object} event
3740		*/
3741		'dragleave', 
3742
3743		/**
3744		Dispatched when file is dropped onto the drop zone.
3745
3746		@event drop
3747		@param {Object} event
3748		*/
3749		'drop', 
3750
3751		/**
3752		Dispatched if error occurs.
3753
3754		@event error
3755		@param {Object} event
3756		*/
3757		'error'
3758	];
3759
3760	function FileDrop(options) {
3761		if (MXI_DEBUG) {
3762			Env.log("Instantiating FileDrop...");	
3763		}
3764
3765		var self = this, defaults;
3766
3767		// if flat argument passed it should be drop_zone id
3768		if (typeof(options) === 'string') {
3769			options = { drop_zone : options };
3770		}
3771
3772		// figure out the options
3773		defaults = {
3774			accept: [{
3775				title: I18n.translate('All Files'),
3776				extensions: '*'
3777			}],
3778			required_caps: {
3779				drag_and_drop: true
3780			}
3781		};
3782		
3783		options = typeof(options) === 'object' ? Basic.extend({}, defaults, options) : defaults;
3784
3785		// this will help us to find proper default container
3786		options.container = Dom.get(options.drop_zone) || document.body;
3787
3788		// make container relative, if it is not
3789		if (Dom.getStyle(options.container, 'position') === 'static') {
3790			options.container.style.position = 'relative';
3791		}
3792					
3793		// normalize accept option (could be list of mime types or array of title/extensions pairs)
3794		if (typeof(options.accept) === 'string') {
3795			options.accept = Mime.mimes2extList(options.accept);
3796		}
3797
3798		RuntimeClient.call(self);
3799
3800		Basic.extend(self, {
3801			uid: Basic.guid('uid_'),
3802
3803			ruid: null,
3804
3805			files: null,
3806
3807			init: function() {		
3808				self.bind('RuntimeInit', function(e, runtime) {
3809					self.ruid = runtime.uid;
3810					runtime.exec.call(self, 'FileDrop', 'init', options);
3811					self.dispatchEvent('ready');
3812				});
3813							
3814				// runtime needs: options.required_features, options.runtime_order and options.container
3815				self.connectRuntime(options); // throws RuntimeError
3816			},
3817
3818			destroy: function() {
3819				var runtime = this.getRuntime();
3820				if (runtime) {
3821					runtime.exec.call(this, 'FileDrop', 'destroy');
3822					this.disconnectRuntime();
3823				}
3824				this.files = null;
3825				
3826				this.unbindAll();
3827			}
3828		});
3829
3830		this.handleEventProps(dispatches);
3831	}
3832
3833	FileDrop.prototype = EventTarget.instance;
3834
3835	return FileDrop;
3836});
3837
3838// Included from: src/javascript/file/FileReader.js
3839
3840/**
3841 * FileReader.js
3842 *
3843 * Copyright 2013, Moxiecode Systems AB
3844 * Released under GPL License.
3845 *
3846 * License: http://www.plupload.com/license
3847 * Contributing: http://www.plupload.com/contributing
3848 */
3849
3850define('moxie/file/FileReader', [
3851	'moxie/core/utils/Basic',
3852	'moxie/core/utils/Encode',
3853	'moxie/core/Exceptions',
3854	'moxie/core/EventTarget',
3855	'moxie/file/Blob',
3856	'moxie/runtime/RuntimeClient'
3857], function(Basic, Encode, x, EventTarget, Blob, RuntimeClient) {
3858	/**
3859	Utility for preloading o.Blob/o.File objects in memory. By design closely follows [W3C FileReader](http://www.w3.org/TR/FileAPI/#dfn-filereader)
3860	interface. Where possible uses native FileReader, where - not falls back to shims.
3861
3862	@class FileReader
3863	@constructor FileReader
3864	@extends EventTarget
3865	@uses RuntimeClient
3866	*/
3867	var dispatches = [
3868
3869		/** 
3870		Dispatched when the read starts.
3871
3872		@event loadstart
3873		@param {Object} event
3874		*/
3875		'loadstart', 
3876
3877		/** 
3878		Dispatched while reading (and decoding) blob, and reporting partial Blob data (progess.loaded/progress.total).
3879
3880		@event progress
3881		@param {Object} event
3882		*/
3883		'progress', 
3884
3885		/** 
3886		Dispatched when the read has successfully completed.
3887
3888		@event load
3889		@param {Object} event
3890		*/
3891		'load', 
3892
3893		/** 
3894		Dispatched when the read has been aborted. For instance, by invoking the abort() method.
3895
3896		@event abort
3897		@param {Object} event
3898		*/
3899		'abort', 
3900
3901		/** 
3902		Dispatched when the read has failed.
3903
3904		@event error
3905		@param {Object} event
3906		*/
3907		'error', 
3908
3909		/** 
3910		Dispatched when the request has completed (either in success or failure).
3911
3912		@event loadend
3913		@param {Object} event
3914		*/
3915		'loadend'
3916	];
3917	
3918	function FileReader() {
3919
3920		RuntimeClient.call(this);
3921
3922		Basic.extend(this, {
3923			/**
3924			UID of the component instance.
3925
3926			@property uid
3927			@type {String}
3928			*/
3929			uid: Basic.guid('uid_'),
3930
3931			/**
3932			Contains current state of FileReader object. Can take values of FileReader.EMPTY, FileReader.LOADING
3933			and FileReader.DONE.
3934
3935			@property readyState
3936			@type {Number}
3937			@default FileReader.EMPTY
3938			*/
3939			readyState: FileReader.EMPTY,
3940			
3941			/**
3942			Result of the successful read operation.
3943
3944			@property result
3945			@type {String}
3946			*/
3947			result: null,
3948			
3949			/**
3950			Stores the error of failed asynchronous read operation.
3951
3952			@property error
3953			@type {DOMError}
3954			*/
3955			error: null,
3956			
3957			/**
3958			Initiates reading of File/Blob object contents to binary string.
3959
3960			@method readAsBinaryString
3961			@param {Blob|File} blob Object to preload
3962			*/
3963			readAsBinaryString: function(blob) {
3964				_read.call(this, 'readAsBinaryString', blob);
3965			},
3966			
3967			/**
3968			Initiates reading of File/Blob object contents to dataURL string.
3969
3970			@method readAsDataURL
3971			@param {Blob|File} blob Object to preload
3972			*/
3973			readAsDataURL: function(blob) {
3974				_read.call(this, 'readAsDataURL', blob);
3975			},
3976			
3977			/**
3978			Initiates reading of File/Blob object contents to string.
3979
3980			@method readAsText
3981			@param {Blob|File} blob Object to preload
3982			*/
3983			readAsText: function(blob) {
3984				_read.call(this, 'readAsText', blob);
3985			},
3986			
3987			/**
3988			Aborts preloading process.
3989
3990			@method abort
3991			*/
3992			abort: function() {
3993				this.result = null;
3994				
3995				if (Basic.inArray(this.readyState, [FileReader.EMPTY, FileReader.DONE]) !== -1) {
3996					return;
3997				} else if (this.readyState === FileReader.LOADING) {
3998					this.readyState = FileReader.DONE;
3999				}
4000
4001				this.exec('FileReader', 'abort');
4002				
4003				this.trigger('abort');
4004				this.trigger('loadend');
4005			},
4006
4007			/**
4008			Destroy component and release resources.
4009
4010			@method destroy
4011			*/
4012			destroy: function() {
4013				this.abort();
4014				this.exec('FileReader', 'destroy');
4015				this.disconnectRuntime();
4016				this.unbindAll();
4017			}
4018		});
4019
4020		// uid must already be assigned
4021		this.handleEventProps(dispatches);
4022
4023		this.bind('Error', function(e, err) {
4024			this.readyState = FileReader.DONE;
4025			this.error = err;
4026		}, 999);
4027		
4028		this.bind('Load', function(e) {
4029			this.readyState = FileReader.DONE;
4030		}, 999);
4031
4032		
4033		function _read(op, blob) {
4034			var self = this;			
4035
4036			this.trigger('loadstart');
4037
4038			if (this.readyState === FileReader.LOADING) {
4039				this.trigger('error', new x.DOMException(x.DOMException.INVALID_STATE_ERR));
4040				this.trigger('loadend');
4041				return;
4042			}
4043
4044			// if source is not o.Blob/o.File
4045			if (!(blob instanceof Blob)) {
4046				this.trigger('error', new x.DOMException(x.DOMException.NOT_FOUND_ERR));
4047				this.trigger('loadend');
4048				return;
4049			}
4050
4051			this.result = null;
4052			this.readyState = FileReader.LOADING;
4053			
4054			if (blob.isDetached()) {
4055				var src = blob.getSource();
4056				switch (op) {
4057					case 'readAsText':
4058					case 'readAsBinaryString':
4059						this.result = src;
4060						break;
4061					case 'readAsDataURL':
4062						this.result = 'data:' + blob.type + ';base64,' + Encode.btoa(src);
4063						break;
4064				}
4065				this.readyState = FileReader.DONE;
4066				this.trigger('load');
4067				this.trigger('loadend');
4068			} else {
4069				this.connectRuntime(blob.ruid);
4070				this.exec('FileReader', 'read', op, blob);
4071			}
4072		}
4073	}
4074	
4075	/**
4076	Initial FileReader state
4077
4078	@property EMPTY
4079	@type {Number}
4080	@final
4081	@static
4082	@default 0
4083	*/
4084	FileReader.EMPTY = 0;
4085
4086	/**
4087	FileReader switches to this state when it is preloading the source
4088
4089	@property LOADING
4090	@type {Number}
4091	@final
4092	@static
4093	@default 1
4094	*/
4095	FileReader.LOADING = 1;
4096
4097	/**
4098	Preloading is complete, this is a final state
4099
4100	@property DONE
4101	@type {Number}
4102	@final
4103	@static
4104	@default 2
4105	*/
4106	FileReader.DONE = 2;
4107
4108	FileReader.prototype = EventTarget.instance;
4109
4110	return FileReader;
4111});
4112
4113// Included from: src/javascript/core/utils/Url.js
4114
4115/**
4116 * Url.js
4117 *
4118 * Copyright 2013, Moxiecode Systems AB
4119 * Released under GPL License.
4120 *
4121 * License: http://www.plupload.com/license
4122 * Contributing: http://www.plupload.com/contributing
4123 */
4124
4125define('moxie/core/utils/Url', [], function() {
4126	/**
4127	Parse url into separate components and fill in absent parts with parts from current url,
4128	based on https://raw.github.com/kvz/phpjs/master/functions/url/parse_url.js
4129
4130	@method parseUrl
4131	@for Utils
4132	@static
4133	@param {String} url Url to parse (defaults to empty string if undefined)
4134	@return {Object} Hash containing extracted uri components
4135	*/
4136	var parseUrl = function(url, currentUrl) {
4137		var key = ['source', 'scheme', 'authority', 'userInfo', 'user', 'pass', 'host', 'port', 'relative', 'path', 'directory', 'file', 'query', 'fragment']
4138		, i = key.length
4139		, ports = {
4140			http: 80,
4141			https: 443
4142		}
4143		, uri = {}
4144		, regex = /^(?:([^:\/?#]+):)?(?:\/\/()(?:(?:()(?:([^:@\/]*):?([^:@\/]*))?@)?([^:\/?#]*)(?::(\d*))?))?()(?:(()(?:(?:[^?#\/]*\/)*)()(?:[^?#]*))(?:\\?([^#]*))?(?:#(.*))?)/
4145		, m = regex.exec(url || '')
4146		;
4147					
4148		while (i--) {
4149			if (m[i]) {
4150				uri[key[i]] = m[i];
4151			}
4152		}
4153
4154		// when url is relative, we set the origin and the path ourselves
4155		if (!uri.scheme) {
4156			// come up with defaults
4157			if (!currentUrl || typeof(currentUrl) === 'string') {
4158				currentUrl = parseUrl(currentUrl || document.location.href);
4159			}
4160
4161			uri.scheme = currentUrl.scheme;
4162			uri.host = currentUrl.host;
4163			uri.port = currentUrl.port;
4164
4165			var path = '';
4166			// for urls without trailing slash we need to figure out the path
4167			if (/^[^\/]/.test(uri.path)) {
4168				path = currentUrl.path;
4169				// if path ends with a filename, strip it
4170				if (/\/[^\/]*\.[^\/]*$/.test(path)) {
4171					path = path.replace(/\/[^\/]+$/, '/');
4172				} else {
4173					// avoid double slash at the end (see #127)
4174					path = path.replace(/\/?$/, '/');
4175				}
4176			}
4177			uri.path = path + (uri.path || ''); // site may reside at domain.com or domain.com/subdir
4178		}
4179
4180		if (!uri.port) {
4181			uri.port = ports[uri.scheme] || 80;
4182		} 
4183		
4184		uri.port = parseInt(uri.port, 10);
4185
4186		if (!uri.path) {
4187			uri.path = "/";
4188		}
4189
4190		delete uri.source;
4191
4192		return uri;
4193	};
4194
4195	/**
4196	Resolve url - among other things will turn relative url to absolute
4197
4198	@method resolveUrl
4199	@static
4200	@param {String|Object} url Either absolute or relative, or a result of parseUrl call
4201	@return {String} Resolved, absolute url
4202	*/
4203	var resolveUrl = function(url) {
4204		var ports = { // we ignore default ports
4205			http: 80,
4206			https: 443
4207		}
4208		, urlp = typeof(url) === 'object' ? url : parseUrl(url);
4209		;
4210
4211		return urlp.scheme + '://' + urlp.host + (urlp.port !== ports[urlp.scheme] ? ':' + urlp.port : '') + urlp.path + (urlp.query ? urlp.query : '');
4212	};
4213
4214	/**
4215	Check if specified url has the same origin as the current document
4216
4217	@method hasSameOrigin
4218	@param {String|Object} url
4219	@return {Boolean}
4220	*/
4221	var hasSameOrigin = function(url) {
4222		function origin(url) {
4223			return [url.scheme, url.host, url.port].join('/');
4224		}
4225			
4226		if (typeof url === 'string') {
4227			url = parseUrl(url);
4228		}	
4229		
4230		return origin(parseUrl()) === origin(url);
4231	};
4232
4233	return {
4234		parseUrl: parseUrl,
4235		resolveUrl: resolveUrl,
4236		hasSameOrigin: hasSameOrigin
4237	};
4238});
4239
4240// Included from: src/javascript/runtime/RuntimeTarget.js
4241
4242/**
4243 * RuntimeTarget.js
4244 *
4245 * Copyright 2013, Moxiecode Systems AB
4246 * Released under GPL License.
4247 *
4248 * License: http://www.plupload.com/license
4249 * Contributing: http://www.plupload.com/contributing
4250 */
4251
4252define('moxie/runtime/RuntimeTarget', [
4253	'moxie/core/utils/Basic',
4254	'moxie/runtime/RuntimeClient',
4255	"moxie/core/EventTarget"
4256], function(Basic, RuntimeClient, EventTarget) {
4257	/**
4258	Instance of this class can be used as a target for the events dispatched by shims,
4259	when allowing them onto components is for either reason inappropriate
4260
4261	@class RuntimeTarget
4262	@constructor
4263	@protected
4264	@extends EventTarget
4265	*/
4266	function RuntimeTarget() {
4267		this.uid = Basic.guid('uid_');
4268		
4269		RuntimeClient.call(this);
4270
4271		this.destroy = function() {
4272			this.disconnectRuntime();
4273			this.unbindAll();
4274		};
4275	}
4276
4277	RuntimeTarget.prototype = EventTarget.instance;
4278
4279	return RuntimeTarget;
4280});
4281
4282// Included from: src/javascript/file/FileReaderSync.js
4283
4284/**
4285 * FileReaderSync.js
4286 *
4287 * Copyright 2013, Moxiecode Systems AB
4288 * Released under GPL License.
4289 *
4290 * License: http://www.plupload.com/license
4291 * Contributing: http://www.plupload.com/contributing
4292 */
4293
4294define('moxie/file/FileReaderSync', [
4295	'moxie/core/utils/Basic',
4296	'moxie/runtime/RuntimeClient',
4297	'moxie/core/utils/Encode'
4298], function(Basic, RuntimeClient, Encode) {
4299	/**
4300	Synchronous FileReader implementation. Something like this is available in WebWorkers environment, here
4301	it can be used to read only preloaded blobs/files and only below certain size (not yet sure what that'd be,
4302	but probably < 1mb). Not meant to be used directly by user.
4303
4304	@class FileReaderSync
4305	@private
4306	@constructor
4307	*/
4308	return function() {
4309		RuntimeClient.call(this);
4310
4311		Basic.extend(this, {
4312			uid: Basic.guid('uid_'),
4313
4314			readAsBinaryString: function(blob) {
4315				return _read.call(this, 'readAsBinaryString', blob);
4316			},
4317			
4318			readAsDataURL: function(blob) {
4319				return _read.call(this, 'readAsDataURL', blob);
4320			},
4321			
4322			/*readAsArrayBuffer: function(blob) {
4323				return _read.call(this, 'readAsArrayBuffer', blob);
4324			},*/
4325			
4326			readAsText: function(blob) {
4327				return _read.call(this, 'readAsText', blob);
4328			}
4329		});
4330
4331		function _read(op, blob) {
4332			if (blob.isDetached()) {
4333				var src = blob.getSource();
4334				switch (op) {
4335					case 'readAsBinaryString':
4336						return src;
4337					case 'readAsDataURL':
4338						return 'data:' + blob.type + ';base64,' + Encode.btoa(src);
4339					case 'readAsText':
4340						var txt = '';
4341						for (var i = 0, length = src.length; i < length; i++) {
4342							txt += String.fromCharCode(src[i]);
4343						}
4344						return txt;
4345				}
4346			} else {
4347				var result = this.connectRuntime(blob.ruid).exec.call(this, 'FileReaderSync', 'read', op, blob);
4348				this.disconnectRuntime();
4349				return result;
4350			}
4351		}
4352	};
4353});
4354
4355// Included from: src/javascript/xhr/FormData.js
4356
4357/**
4358 * FormData.js
4359 *
4360 * Copyright 2013, Moxiecode Systems AB
4361 * Released under GPL License.
4362 *
4363 * License: http://www.plupload.com/license
4364 * Contributing: http://www.plupload.com/contributing
4365 */
4366
4367define("moxie/xhr/FormData", [
4368	"moxie/core/Exceptions",
4369	"moxie/core/utils/Basic",
4370	"moxie/file/Blob"
4371], function(x, Basic, Blob) {
4372	/**
4373	FormData
4374
4375	@class FormData
4376	@constructor
4377	*/
4378	function FormData() {
4379		var _blob, _fields = [];
4380
4381		Basic.extend(this, {
4382			/**
4383			Append another key-value pair to the FormData object
4384
4385			@method append
4386			@param {String} name Name for the new field
4387			@param {String|Blob|Array|Object} value Value for the field
4388			*/
4389			append: function(name, value) {
4390				var self = this, valueType = Basic.typeOf(value);
4391
4392				// according to specs value might be either Blob or String
4393				if (value instanceof Blob) {
4394					_blob = {
4395						name: name,
4396						value: value // unfortunately we can only send single Blob in one FormData
4397					};
4398				} else if ('array' === valueType) {
4399					name += '[]';
4400
4401					Basic.each(value, function(value) {
4402						self.append(name, value);
4403					});
4404				} else if ('object' === valueType) {
4405					Basic.each(value, function(value, key) {
4406						self.append(name + '[' + key + ']', value);
4407					});
4408				} else if ('null' === valueType || 'undefined' === valueType || 'number' === valueType && isNaN(value)) {
4409					self.append(name, "false");
4410				} else {
4411					_fields.push({
4412						name: name,
4413						value: value.toString()
4414					});
4415				}
4416			},
4417
4418			/**
4419			Checks if FormData contains Blob.
4420
4421			@method hasBlob
4422			@return {Boolean}
4423			*/
4424			hasBlob: function() {
4425				return !!this.getBlob();
4426			},
4427
4428			/**
4429			Retrieves blob.
4430
4431			@method getBlob
4432			@return {Object} Either Blob if found or null
4433			*/
4434			getBlob: function() {
4435				return _blob && _blob.value || null;
4436			},
4437
4438			/**
4439			Retrieves blob field name.
4440
4441			@method getBlobName
4442			@return {String} Either Blob field name or null
4443			*/
4444			getBlobName: function() {
4445				return _blob && _blob.name || null;
4446			},
4447
4448			/**
4449			Loop over the fields in FormData and invoke the callback for each of them.
4450
4451			@method each
4452			@param {Function} cb Callback to call for each field
4453			*/
4454			each: function(cb) {
4455				Basic.each(_fields, function(field) {
4456					cb(field.value, field.name);
4457				});
4458
4459				if (_blob) {
4460					cb(_blob.value, _blob.name);
4461				}
4462			},
4463
4464			destroy: function() {
4465				_blob = null;
4466				_fields = [];
4467			}
4468		});
4469	}
4470
4471	return FormData;
4472});
4473
4474// Included from: src/javascript/xhr/XMLHttpRequest.js
4475
4476/**
4477 * XMLHttpRequest.js
4478 *
4479 * Copyright 2013, Moxiecode Systems AB
4480 * Released under GPL License.
4481 *
4482 * License: http://www.plupload.com/license
4483 * Contributing: http://www.plupload.com/contributing
4484 */
4485
4486define("moxie/xhr/XMLHttpRequest", [
4487	"moxie/core/utils/Basic",
4488	"moxie/core/Exceptions",
4489	"moxie/core/EventTarget",
4490	"moxie/core/utils/Encode",
4491	"moxie/core/utils/Url",
4492	"moxie/runtime/Runtime",
4493	"moxie/runtime/RuntimeTarget",
4494	"moxie/file/Blob",
4495	"moxie/file/FileReaderSync",
4496	"moxie/xhr/FormData",
4497	"moxie/core/utils/Env",
4498	"moxie/core/utils/Mime"
4499], function(Basic, x, EventTarget, Encode, Url, Runtime, RuntimeTarget, Blob, FileReaderSync, FormData, Env, Mime) {
4500
4501	var httpCode = {
4502		100: 'Continue',
4503		101: 'Switching Protocols',
4504		102: 'Processing',
4505
4506		200: 'OK',
4507		201: 'Created',
4508		202: 'Accepted',
4509		203: 'Non-Authoritative Information',
4510		204: 'No Content',
4511		205: 'Reset Content',
4512		206: 'Partial Content',
4513		207: 'Multi-Status',
4514		226: 'IM Used',
4515
4516		300: 'Multiple Choices',
4517		301: 'Moved Permanently',
4518		302: 'Found',
4519		303: 'See Other',
4520		304: 'Not Modified',
4521		305: 'Use Proxy',
4522		306: 'Reserved',
4523		307: 'Temporary Redirect',
4524
4525		400: 'Bad Request',
4526		401: 'Unauthorized',
4527		402: 'Payment Required',
4528		403: 'Forbidden',
4529		404: 'Not Found',
4530		405: 'Method Not Allowed',
4531		406: 'Not Acceptable',
4532		407: 'Proxy Authentication Required',
4533		408: 'Request Timeout',
4534		409: 'Conflict',
4535		410: 'Gone',
4536		411: 'Length Required',
4537		412: 'Precondition Failed',
4538		413: 'Request Entity Too Large',
4539		414: 'Request-URI Too Long',
4540		415: 'Unsupported Media Type',
4541		416: 'Requested Range Not Satisfiable',
4542		417: 'Expectation Failed',
4543		422: 'Unprocessable Entity',
4544		423: 'Locked',
4545		424: 'Failed Dependency',
4546		426: 'Upgrade Required',
4547
4548		500: 'Internal Server Error',
4549		501: 'Not Implemented',
4550		502: 'Bad Gateway',
4551		503: 'Service Unavailable',
4552		504: 'Gateway Timeout',
4553		505: 'HTTP Version Not Supported',
4554		506: 'Variant Also Negotiates',
4555		507: 'Insufficient Storage',
4556		510: 'Not Extended'
4557	};
4558
4559	function XMLHttpRequestUpload() {
4560		this.uid = Basic.guid('uid_');
4561	}
4562	
4563	XMLHttpRequestUpload.prototype = EventTarget.instance;
4564
4565	/**
4566	Implementation of XMLHttpRequest
4567
4568	@class XMLHttpRequest
4569	@constructor
4570	@uses RuntimeClient
4571	@extends EventTarget
4572	*/
4573	var dispatches = [
4574		'loadstart',
4575
4576		'progress',
4577
4578		'abort',
4579
4580		'error',
4581
4582		'load',
4583
4584		'timeout',
4585
4586		'loadend'
4587
4588		// readystatechange (for historical reasons)
4589	]; 
4590	
4591	var NATIVE = 1, RUNTIME = 2;
4592					
4593	function XMLHttpRequest() {
4594		var self = this,
4595			// this (together with _p() @see below) is here to gracefully upgrade to setter/getter syntax where possible
4596			props = {
4597				/**
4598				The amount of milliseconds a request can take before being terminated. Initially zero. Zero means there is no timeout.
4599
4600				@property timeout
4601				@type Number
4602				@default 0
4603				*/
4604				timeout: 0,
4605
4606				/**
4607				Current state, can take following values:
4608				UNSENT (numeric value 0)
4609				The object has been constructed.
4610
4611				OPENED (numeric value 1)
4612				The open() method has been successfully invoked. During this state request headers can be set using setRequestHeader() and the request can be made using the send() method.
4613
4614				HEADERS_RECEIVED (numeric value 2)
4615				All redirects (if any) have been followed and all HTTP headers of the final response have been received. Several response members of the object are now available.
4616
4617				LOADING (numeric value 3)
4618				The response entity body is being received.
4619
4620				DONE (numeric value 4)
4621
4622				@property readyState
4623				@type Number
4624				@default 0 (UNSENT)
4625				*/
4626				readyState: XMLHttpRequest.UNSENT,
4627
4628				/**
4629				True when user credentials are to be included in a cross-origin request. False when they are to be excluded
4630				in a cross-origin request and when cookies are to be ignored in its response. Initially false.
4631
4632				@property withCredentials
4633				@type Boolean
4634				@default false
4635				*/
4636				withCredentials: false,
4637
4638				/**
4639				Returns the HTTP status code.
4640
4641				@property status
4642				@type Number
4643				@default 0
4644				*/
4645				status: 0,
4646
4647				/**
4648				Returns the HTTP status text.
4649
4650				@property statusText
4651				@type String
4652				*/
4653				statusText: "",
4654
4655				/**
4656				Returns the response type. Can be set to change the response type. Values are:
4657				the empty string (default), "arraybuffer", "blob", "document", "json", and "text".
4658				
4659				@property responseType
4660				@type String
4661				*/
4662				responseType: "",
4663
4664				/**
4665				Returns the document response entity body.
4666				
4667				Throws an "InvalidStateError" exception if responseType is not the empty string or "document".
4668
4669				@property responseXML
4670				@type Document
4671				*/
4672				responseXML: null,
4673
4674				/**
4675				Returns the text response entity body.
4676				
4677				Throws an "InvalidStateError" exception if responseType is not the empty string or "text".
4678
4679				@property responseText
4680				@type String
4681				*/
4682				responseText: null,
4683
4684				/**
4685				Returns the response entity body (http://www.w3.org/TR/XMLHttpRequest/#response-entity-body).
4686				Can become: ArrayBuffer, Blob, Document, JSON, Text
4687				
4688				@property response
4689				@type Mixed
4690				*/
4691				response: null
4692			},
4693
4694			_async = true,
4695			_url,
4696			_method,
4697			_headers = {},
4698			_user,
4699			_password,
4700			_encoding = null,
4701			_mimeType = null,
4702
4703			// flags
4704			_sync_flag = false,
4705			_send_flag = false,
4706			_upload_events_flag = false,
4707			_upload_complete_flag = false,
4708			_error_flag = false,
4709			_same_origin_flag = false,
4710
4711			// times
4712			_start_time,
4713			_timeoutset_time,
4714
4715			_finalMime = null,
4716			_finalCharset = null,
4717
4718			_options = {},
4719			_xhr,
4720			_responseHeaders = '',
4721			_responseHeadersBag
4722			;
4723
4724		
4725		Basic.extend(this, props, {
4726			/**
4727			Unique id of the component
4728
4729			@property uid
4730			@type String
4731			*/
4732			uid: Basic.guid('uid_'),
4733			
4734			/**
4735			Target for Upload events
4736
4737			@property upload
4738			@type XMLHttpRequestUpload
4739			*/
4740			upload: new XMLHttpRequestUpload(),
4741			
4742
4743			/**
4744			Sets the request method, request URL, synchronous flag, request username, and request password.
4745
4746			Throws a "SyntaxError" exception if one of the following is true:
4747
4748			method is not a valid HTTP method.
4749			url cannot be resolved.
4750			url contains the "user:password" format in the userinfo production.
4751			Throws a "SecurityError" exception if method is a case-insensitive match for CONNECT, TRACE or TRACK.
4752
4753			Throws an "InvalidAccessError" exception if one of the following is true:
4754
4755			Either user or password is passed as argument and the origin of url does not match the XMLHttpRequest origin.
4756			There is an associated XMLHttpRequest document and either the timeout attribute is not zero,
4757			the withCredentials attribute is true, or the responseType attribute is not the empty string.
4758
4759
4760			@method open
4761			@param {String} method HTTP method to use on request
4762			@param {String} url URL to request
4763			@param {Boolean} [async=true] If false request will be done in synchronous manner. Asynchronous by default.
4764			@param {String} [user] Username to use in HTTP authentication process on server-side
4765			@param {String} [password] Password to use in HTTP authentication process on server-side
4766			*/
4767			open: function(method, url, async, user, password) {
4768				var urlp;
4769				
4770				// first two arguments are required
4771				if (!method || !url) {
4772					throw new x.DOMException(x.DOMException.SYNTAX_ERR);
4773				}
4774				
4775				// 2 - check if any code point in method is higher than U+00FF or after deflating method it does not match the method
4776				if (/[\u0100-\uffff]/.test(method) || Encode.utf8_encode(method) !== method) {
4777					throw new x.DOMException(x.DOMException.SYNTAX_ERR);
4778				}
4779
4780				// 3
4781				if (!!~Basic.inArray(method.toUpperCase(), ['CONNECT', 'DELET
4781E', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT', 'TRACE', 'TRACK'])) {
4782					_method = method.toUpperCase();
4783				}
4784				
4785				
4786				// 4 - allowing these methods poses a security risk
4787				if (!!~Basic.inArray(_method, ['CONNECT', 'TRACE', 'TRACK'])) {
4788					throw new x.DOMException(x.DOMException.SECURITY_ERR);
4789				}
4790
4791				// 5
4792				url = Encode.utf8_encode(url);
4793				
4794				// 6 - Resolve url relative to the XMLHttpRequest base URL. If the algorithm returns an error, throw a "SyntaxError".
4795				urlp = Url.parseUrl(url);
4796
4797				_same_origin_flag = Url.hasSameOrigin(urlp);
4798																
4799				// 7 - manually build up absolute url
4800				_url = Url.resolveUrl(url);
4801		
4802				// 9-10, 12-13
4803				if ((user || password) && !_same_origin_flag) {
4804					throw new x.DOMException(x.DOMException.INVALID_ACCESS_ERR);
4805				}
4806
4807				_user = user || urlp.user;
4808				_password = password || urlp.pass;
4809				
4810				// 11
4811				_async = async || true;
4812				
4813				if (_async === false && (_p('timeout') || _p('withCredentials') || _p('responseType') !== "")) {
4814					throw new x.DOMException(x.DOMException.INVALID_ACCESS_ERR);
4815				}
4816				
4817				// 14 - terminate abort()
4818				
4819				// 15 - terminate send()
4820
4821				// 18
4822				_sync_flag = !_async;
4823				_send_flag = false;
4824				_headers = {};
4825				_reset.call(this);
4826
4827				// 19
4828				_p('readyState', XMLHttpRequest.OPENED);
4829				
4830				// 20
4831				this.dispatchEvent('readystatechange');
4832			},
4833			
4834			/**
4835			Appends an header to the list of author request headers, or if header is already
4836			in the list of author request headers, combines its value with value.
4837
4838			Throws an "InvalidStateError" exception if the state is not OPENED or if the send() flag is set.
4839			Throws a "SyntaxError" exception if header is not a valid HTTP header field name or if value
4840			is not a valid HTTP header field value.
4841			
4842			@method setRequestHeader
4843			@param {String} header
4844			@param {String|Number} value
4845			*/
4846			setRequestHeader: function(header, value) {
4847				var uaHeaders = [ // these headers are controlled by the user agent
4848						"accept-charset",
4849						"accept-encoding",
4850						"access-control-request-headers",
4851						"access-control-request-method",
4852						"connection",
4853						"content-length",
4854						"cookie",
4855						"cookie2",
4856						"content-transfer-encoding",
4857						"date",
4858						"expect",
4859						"host",
4860						"keep-alive",
4861						"origin",
4862						"referer",
4863						"te",
4864						"trailer",
4865						"transfer-encoding",
4866						"upgrade",
4867						"user-agent",
4868						"via"
4869					];
4870				
4871				// 1-2
4872				if (_p('readyState') !== XMLHttpRequest.OPENED || _send_flag) {
4873					throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
4874				}
4875
4876				// 3
4877				if (/[\u0100-\uffff]/.test(header) || Encode.utf8_encode(header) !== header) {
4878					throw new x.DOMException(x.DOMException.SYNTAX_ERR);
4879				}
4880
4881				// 4
4882				/* this step is seemingly bypassed in browsers, probably to allow various unicode characters in header values
4883				if (/[\u0100-\uffff]/.test(value) || Encode.utf8_encode(value) !== value) {
4884					throw new x.DOMException(x.DOMException.SYNTAX_ERR);
4885				}*/
4886
4887				header = Basic.trim(header).toLowerCase();
4888				
4889				// setting of proxy-* and sec-* headers is prohibited by spec
4890				if (!!~Basic.inArray(header, uaHeaders) || /^(proxy\-|sec\-)/.test(header)) {
4891					return false;
4892				}
4893
4894				// camelize
4895				// browsers lowercase header names (at least for custom ones)
4896				// header = header.replace(/\b\w/g, function($1) { return $1.toUpperCase(); });
4897				
4898				if (!_headers[header]) {
4899					_headers[header] = value;
4900				} else {
4901					// http://tools.ietf.org/html/rfc2616#section-4.2 (last paragraph)
4902					_headers[header] += ', ' + value;
4903				}
4904				return true;
4905			},
4906
4907			/**
4908			Returns all headers from the response, with the exception of those whose field name is Set-Cookie or Set-Cookie2.
4909
4910			@method getAllResponseHeaders
4911			@return {String} reponse headers or empty string
4912			*/
4913			getAllResponseHeaders: function() {
4914				return _responseHeaders || '';
4915			},
4916
4917			/**
4918			Returns the header field value from the response of which the field name matches header, 
4919			unless the field name is Set-Cookie or Set-Cookie2.
4920
4921			@method getResponseHeader
4922			@param {String} header
4923			@return {String} value(s) for the specified header or null
4924			*/
4925			getResponseHeader: function(header) {
4926				header = header.toLowerCase();
4927
4928				if (_error_flag || !!~Basic.inArray(header, ['set-cookie', 'set-cookie2'])) {
4929					return null;
4930				}
4931
4932				if (_responseHeaders && _responseHeaders !== '') {
4933					// if we didn't parse response headers until now, do it and keep for later
4934					if (!_responseHeadersBag) {
4935						_responseHeadersBag = {};
4936						Basic.each(_responseHeaders.split(/\r\n/), function(line) {
4937							var pair = line.split(/:\s+/);
4938							if (pair.length === 2) { // last line might be empty, omit
4939								pair[0] = Basic.trim(pair[0]); // just in case
4940								_responseHeadersBag[pair[0].toLowerCase()] = { // simply to retain header name in original form
4941									header: pair[0],
4942									value: Basic.trim(pair[1])
4943								};
4944							}
4945						});
4946					}
4947					if (_responseHeadersBag.hasOwnProperty(header)) {
4948						return _responseHeadersBag[header].header + ': ' + _responseHeadersBag[header].value;
4949					}
4950				}
4951				return null;
4952			},
4953			
4954			/**
4955			Sets the Content-Type header for the response to mime.
4956			Throws an "InvalidStateError" exception if the state is LOADING or DONE.
4957			Throws a "SyntaxError" exception if mime is not a valid media type.
4958
4959			@method overrideMimeType
4960			@param String mime Mime type to set
4961			*/
4962			overrideMimeType: function(mime) {
4963				var matches, charset;
4964			
4965				// 1
4966				if (!!~Basic.inArray(_p('readyState'), [XMLHttpRequest.LOADING, XMLHttpRequest.DONE])) {
4967					throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
4968				}
4969
4970				// 2
4971				mime = Basic.trim(mime.toLowerCase());
4972
4973				if (/;/.test(mime) && (matches = mime.match(/^([^;]+)(?:;\scharset\=)?(.*)$/))) {
4974					mime = matches[1];
4975					if (matches[2]) {
4976						charset = matches[2];
4977					}
4978				}
4979
4980				if (!Mime.mimes[mime]) {
4981					throw new x.DOMException(x.DOMException.SYNTAX_ERR);
4982				}
4983
4984				// 3-4
4985				_finalMime = mime;
4986				_finalCharset = charset;
4987			},
4988			
4989			/**
4990			Initiates the request. The optional argument provides the request entity body.
4991			The argument is ignored if request method is GET or HEAD.
4992
4993			Throws an "InvalidStateError" exception if the state is not OPENED or if the send() flag is set.
4994
4995			@method send
4996			@param {Blob|Document|String|FormData} [data] Request entity body
4997			@param {Object} [options] Set of requirements and pre-requisities for runtime initialization
4998			*/
4999			send: function(data, options) {					
5000				if (Basic.typeOf(options) === 'string') {
5001					_options = { ruid: options };
5002				} else if (!options) {
5003					_options = {};
5004				} else {
5005					_options = options;
5006				}
5007															
5008				// 1-2
5009				if (this.readyState !== XMLHttpRequest.OPENED || _send_flag) {
5010					throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
5011				}
5012				
5013				// 3					
5014				// sending Blob
5015				if (data instanceof Blob) {
5016					_options.ruid = data.ruid;
5017					_mimeType = data.type || 'application/octet-stream';
5018				}
5019				
5020				// FormData
5021				else if (data instanceof FormData) {
5022					if (data.hasBlob()) {
5023						var blob = data.getBlob();
5024						_options.ruid = blob.ruid;
5025						_mimeType = blob.type || 'application/octet-stream';
5026					}
5027				}
5028				
5029				// DOMString
5030				else if (typeof data === 'string') {
5031					_encoding = 'UTF-8';
5032					_mimeType = 'text/plain;charset=UTF-8';
5033					
5034					// data should be converted to Unicode and encoded as UTF-8
5035					data = Encode.utf8_encode(data);
5036				}
5037
5038				// if withCredentials not set, but requested, set it automatically
5039				if (!this.withCredentials) {
5040					this.withCredentials = (_options.required_caps && _options.required_caps.send_browser_cookies) && !_same_origin_flag;
5041				}
5042
5043				// 4 - storage mutex
5044				// 5
5045				_upload_events_flag = (!_sync_flag && this.upload.hasEventListener()); // DSAP
5046				// 6
5047				_error_flag = false;
5048				// 7
5049				_upload_complete_flag = !data;
5050				// 8 - Asynchronous steps
5051				if (!_sync_flag) {
5052					// 8.1
5053					_send_flag = true;
5054					// 8.2
5055					// this.dispatchEvent('loadstart'); // will be dispatched either by native or runtime xhr
5056					// 8.3
5057					//if (!_upload_complete_flag) {
5058						// this.upload.dispatchEvent('loadstart');	// will be dispatched either by native or runtime xhr
5059					//}
5060				}
5061				// 8.5 - Return the send() method call, but continue running the steps in this algorithm.
5062				_doXHR.call(this, data);
5063			},
5064			
5065			/**
5066			Cancels any network activity.
5067			
5068			@method abort
5069			*/
5070			abort: function() {
5071				_error_flag = true;
5072				_sync_flag = false;
5073
5074				if (!~Basic.inArray(_p('readyState'), [XMLHttpRequest.UNSENT, XMLHttpRequest.OPENED, XMLHttpRequest.DONE])) {
5075					_p('readyState', XMLHttpRequest.DONE);
5076					_send_flag = false;
5077
5078					if (_xhr) {
5079						_xhr.getRuntime().exec.call(_xhr, 'XMLHttpRequest', 'abort', _upload_complete_flag);
5080					} else {
5081						throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
5082					}
5083
5084					_upload_complete_flag = true;
5085				} else {
5086					_p('readyState', XMLHttpRequest.UNSENT);
5087				}
5088			},
5089
5090			destroy: function() {
5091				if (_xhr) {
5092					if (Basic.typeOf(_xhr.destroy) === 'function') {
5093						_xhr.destroy();
5094					}
5095					_xhr = null;
5096				}
5097
5098				this.unbindAll();
5099
5100				if (this.upload) {
5101					this.upload.unbindAll();
5102					this.upload = null;
5103				}
5104			}
5105		});
5106
5107		this.handleEventProps(dispatches.concat(['readystatechange'])); // for historical reasons
5108		this.upload.handleEventProps(dispatches);
5109
5110		/* this is nice, but maybe too lengthy
5111
5112		// if supported by JS version, set getters/setters for specific properties
5113		o.defineProperty(this, 'readyState', {
5114			configurable: false,
5115
5116			get: function() {
5117				return _p('readyState');
5118			}
5119		});
5120
5121		o.defineProperty(this, 'timeout', {
5122			configurable: false,
5123
5124			get: function() {
5125				return _p('timeout');
5126			},
5127
5128			set: function(value) {
5129
5130				if (_sync_flag) {
5131					throw new x.DOMException(x.DOMException.INVALID_ACCESS_ERR);
5132				}
5133
5134				// timeout still should be measured relative to the start time of request
5135				_timeoutset_time = (new Date).getTime();
5136
5137				_p('timeout', value);
5138			}
5139		});
5140
5141		// the withCredentials attribute has no effect when fetching same-origin resources
5142		o.defineProperty(this, 'withCredentials', {
5143			configurable: false,
5144
5145			get: function() {
5146				return _p('withCredentials');
5147			},
5148
5149			set: function(value) {
5150				// 1-2
5151				if (!~o.inArray(_p('readyState'), [XMLHttpRequest.UNSENT, XMLHttpRequest.OPENED]) || _send_flag) {
5152					throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
5153				}
5154
5155				// 3-4
5156				if (_anonymous_flag || _sync_flag) {
5157					throw new x.DOMException(x.DOMException.INVALID_ACCESS_ERR);
5158				}
5159
5160				// 5
5161				_p('withCredentials', value);
5162			}
5163		});
5164
5165		o.defineProperty(this, 'status', {
5166			configurable: false,
5167
5168			get: function() {
5169				return _p('status');
5170			}
5171		});
5172
5173		o.defineProperty(this, 'statusText', {
5174			configurable: false,
5175
5176			get: function() {
5177				return _p('statusText');
5178			}
5179		});
5180
5181		o.defineProperty(this, 'responseType', {
5182			configurable: false,
5183
5184			get: function() {
5185				return _p('responseType');
5186			},
5187
5188			set: function(value) {
5189				// 1
5190				if (!!~o.inArray(_p('readyState'), [XMLHttpRequest.LOADING, XMLHttpRequest.DONE])) {
5191					throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
5192				}
5193
5194				// 2
5195				if (_sync_flag) {
5196					throw new x.DOMException(x.DOMException.INVALID_ACCESS_ERR);
5197				}
5198
5199				// 3
5200				_p('responseType', value.toLowerCase());
5201			}
5202		});
5203
5204		o.defineProperty(this, 'responseText', {
5205			configurable: false,
5206
5207			get: function() {
5208				// 1
5209				if (!~o.inArray(_p('responseType'), ['', 'text'])) {
5210					throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
5211				}
5212
5213				// 2-3
5214				if (_p('readyState') !== XMLHttpRequest.DONE && _p('readyState') !== XMLHttpRequest.LOADING || _error_flag) {
5215					throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
5216				}
5217
5218				return _p('responseText');
5219			}
5220		});
5221
5222		o.defineProperty(this, 'responseXML', {
5223			configurable: false,
5224
5225			get: function() {
5226				// 1
5227				if (!~o.inArray(_p('responseType'), ['', 'document'])) {
5228					throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
5229				}
5230
5231				// 2-3
5232				if (_p('readyState') !== XMLHttpRequest.DONE || _error_flag) {
5233					throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
5234				}
5235
5236				return _p('responseXML');
5237			}
5238		});
5239
5240		o.defineProperty(this, 'response', {
5241			configurable: false,
5242
5243			get: function() {
5244				if (!!~o.inArray(_p('responseType'), ['', 'text'])) {
5245					if (_p('readyState') !== XMLHttpRequest.DONE && _p('readyState') !== XMLHttpRequest.LOADING || _error_flag) {
5246						return '';
5247					}
5248				}
5249
5250				if (_p('readyState') !== XMLHttpRequest.DONE || _error_flag) {
5251					return null;
5252				}
5253
5254				return _p('response');
5255			}
5256		});
5257
5258		*/
5259
5260		function _p(prop, value) {
5261			if (!props.hasOwnProperty(prop)) {
5262				return;
5263			}
5264			if (arguments.length === 1) { // get
5265				return Env.can('define_property') ? props[prop] : self[prop];
5266			} else { // set
5267				if (Env.can('define_property')) {
5268					props[prop] = value;
5269				} else {
5270					self[prop] = value;
5271				}
5272			}
5273		}
5274		
5275		/*
5276		function _toASCII(str, AllowUnassigned, UseSTD3ASCIIRules) {
5277			// TODO: http://tools.ietf.org/html/rfc3490#section-4.1
5278			return str.toLowerCase();
5279		}
5280		*/
5281		
5282		
5283		function _doXHR(data) {
5284			var self = this;
5285			
5286			_start_time = new Date().getTime();
5287
5288			_xhr = new RuntimeTarget();
5289
5290			function loadEnd() {
5291				if (_xhr) { // it could have been destroyed by now
5292					_xhr.destroy();
5293					_xhr = null;
5294				}
5295				self.dispatchEvent('loadend');
5296				self = null;
5297			}
5298
5299			function exec(runtime) {
5300				_xhr.bind('LoadStart', function(e) {
5301					_p('readyState', XMLHttpRequest.LOADING);
5302					self.dispatchEvent('readystatechange');
5303
5304					self.dispatchEvent(e);
5305					
5306					if (_upload_events_flag) {
5307						self.upload.dispatchEvent(e);
5308					}
5309				});
5310				
5311				_xhr.bind('Progress', function(e) {
5312					if (_p('readyState') !== XMLHttpRequest.LOADING) {
5313						_p('readyState', XMLHttpRequest.LOADING); // LoadStart unreliable (in Flash for example)
5314						self.dispatchEvent('readystatechange');
5315					}
5316					self.dispatchEvent(e);
5317				});
5318				
5319				_xhr.bind('UploadProgress', function(e) {
5320					if (_upload_events_flag) {
5321						self.upload.dispatchEvent({
5322							type: 'progress',
5323							lengthComputable: false,
5324							total: e.total,
5325							loaded: e.loaded
5326						});
5327					}
5328				});
5329				
5330				_xhr.bind('Load', function(e) {
5331					_p('readyState', XMLHttpRequest.DONE);
5332					_p('status', Number(runtime.exec.call(_xhr, 'XMLHttpRequest', 'getStatus') || 0));
5333					_p('statusText', httpCode[_p('status')] || "");
5334					
5335					_p('response', runtime.exec.call(_xhr, 'XMLHttpRequest', 'getResponse', _p('responseType')));
5336
5337					if (!!~Basic.inArray(_p('responseType'), ['text', ''])) {
5338						_p('responseText', _p('response'));
5339					} else if (_p('responseType') === 'document') {
5340						_p('responseXML', _p('response'));
5341					}
5342
5343					_responseHeaders = runtime.exec.call(_xhr, 'XMLHttpRequest', 'getAllResponseHeaders');
5344
5345					self.dispatchEvent('readystatechange');
5346					
5347					if (_p('status') > 0) { // status 0 usually means that server is unreachable
5348						if (_upload_events_flag) {
5349							self.upload.dispatchEvent(e);
5350						}
5351						self.dispatchEvent(e);
5352					} else {
5353						_error_flag = true;
5354						self.dispatchEvent('error');
5355					}
5356					loadEnd();
5357				});
5358
5359				_xhr.bind('Abort', function(e) {
5360					self.dispatchEvent(e);
5361					loadEnd();
5362				});
5363				
5364				_xhr.bind('Error', function(e) {
5365					_error_flag = true;
5366					_p('readyState', XMLHttpRequest.DONE);
5367					self.dispatchEvent('readystatechange');
5368					_upload_complete_flag = true;
5369					self.dispatchEvent(e);
5370					loadEnd();
5371				});
5372
5373				runtime.exec.call(_xhr, 'XMLHttpRequest', 'send', {
5374					url: _url,
5375					method: _method,
5376					async: _async,
5377					user: _user,
5378					password: _password,
5379					headers: _headers,
5380					mimeType: _mimeType,
5381					encoding: _encoding,
5382					responseType: self.responseType,
5383					withCredentials: self.withCredentials,
5384					options: _options
5385				}, data);
5386			}
5387
5388			// clarify our requirements
5389			if (typeof(_options.required_caps) === 'string') {
5390				_options.required_caps = Runtime.parseCaps(_options.required_caps);
5391			}
5392
5393			_options.required_caps = Basic.extend({}, _options.required_caps, {
5394				return_response_type: self.responseType
5395			});
5396
5397			if (data instanceof FormData) {
5398				_options.required_caps.send_multipart = true;
5399			}
5400
5401			if (!Basic.isEmptyObj(_headers)) {
5402				_options.required_caps.send_custom_headers = true;
5403			}
5404
5405			if (!_same_origin_flag) {
5406				_options.required_caps.do_cors = true;
5407			}
5408			
5409
5410			if (_options.ruid) { // we do not need to wait if we can connect directly
5411				exec(_xhr.connectRuntime(_options));
5412			} else {
5413				_xhr.bind('RuntimeInit', function(e, runtime) {
5414					exec(runtime);
5415				});
5416				_xhr.bind('RuntimeError', function(e, err) {
5417					self.dispatchEvent('RuntimeError', err);
5418				});
5419				_xhr.connectRuntime(_options);
5420			}
5421		}
5422	
5423		
5424		function _reset() {
5425			_p('responseText', "");
5426			_p('responseXML', null);
5427			_p('response', null);
5428			_p('status', 0);
5429			_p('statusText', "");
5430			_start_time = _timeoutset_time = null;
5431		}
5432	}
5433
5434	XMLHttpRequest.UNSENT = 0;
5435	XMLHttpRequest.OPENED = 1;
5436	XMLHttpRequest.HEADERS_RECEIVED = 2;
5437	XMLHttpRequest.LOADING = 3;
5438	XMLHttpRequest.DONE = 4;
5439	
5440	XMLHttpRequest.prototype = EventTarget.instance;
5441
5442	return XMLHttpRequest;
5443});
5444
5445// Included from: src/javascript/runtime/Transporter.js
5446
5447/**
5448 * Transporter.js
5449 *
5450 * Copyright 2013, Moxiecode Systems AB
5451 * Released under GPL License.
5452 *
5453 * License: http://www.plupload.com/license
5454 * Contributing: http://www.plupload.com/contributing
5455 */
5456
5457define("moxie/runtime/Transporter", [
5458	"moxie/core/utils/Basic",
5459	"moxie/core/utils/Encode",
5460	"moxie/runtime/RuntimeClient",
5461	"moxie/core/EventTarget"
5462], function(Basic, Encode, RuntimeClient, EventTarget) {
5463	function Transporter() {
5464		var mod, _runtime, _data, _size, _pos, _chunk_size;
5465
5466		RuntimeClient.call(this);
5467
5468		Basic.extend(this, {
5469			uid: Basic.guid('uid_'),
5470
5471			state: Transporter.IDLE,
5472
5473			result: null,
5474
5475			transport: function(data, type, options) {
5476				var self = this;
5477
5478				options = Basic.extend({
5479					chunk_size: 204798
5480				}, options);
5481
5482				// should divide by three, base64 requires this
5483				if ((mod = options.chunk_size % 3)) {
5484					options.chunk_size += 3 - mod;
5485				}
5486
5487				_chunk_size = options.chunk_size;
5488
5489				_reset.call(this);
5490				_data = data;
5491				_size = data.length;
5492
5493				if (Basic.typeOf(options) === 'string' || options.ruid) {
5494					_run.call(self, type, this.connectRuntime(options));
5495				} else {
5496					// we require this to run only once
5497					var cb = function(e, runtime) {
5498						self.unbind("RuntimeInit", cb);
5499						_run.call(self, type, runtime);
5500					};
5501					this.bind("RuntimeInit", cb);
5502					this.connectRuntime(options);
5503				}
5504			},
5505
5506			abort: function() {
5507				var self = this;
5508
5509				self.state = Transporter.IDLE;
5510				if (_runtime) {
5511					_runtime.exec.call(self, 'Transporter', 'clear');
5512					self.trigger("TransportingAborted");
5513				}
5514
5515				_reset.call(self);
5516			},
5517
5518
5519			destroy: function() {
5520				this.unbindAll();
5521				_runtime = null;
5522				this.disconnectRuntime();
5523				_reset.call(this);
5524			}
5525		});
5526
5527		function _reset() {
5528			_size = _pos = 0;
5529			_data = this.result = null;
5530		}
5531
5532		function _run(type, runtime) {
5533			var self = this;
5534
5535			_runtime = runtime;
5536
5537			//self.unbind("RuntimeInit");
5538
5539			self.bind("TransportingProgress", function(e) {
5540				_pos = e.loaded;
5541
5542				if (_pos < _size && Basic.inArray(self.state, [Transporter.IDLE, Transporter.DONE]) === -1) {
5543					_transport.call(self);
5544				}
5545			}, 999);
5546
5547			self.bind("TransportingComplete", function() {
5548				_pos = _size;
5549				self.state = Transporter.DONE;
5550				_data = null; // clean a bit
5551				self.result = _runtime.exec.call(self, 'Transporter', 'getAsBlob', type || '');
5552			}, 999);
5553
5554			self.state = Transporter.BUSY;
5555			self.trigger("TransportingStarted");
5556			_transport.call(self);
5557		}
5558
5559		function _transport() {
5560			var self = this,
5561				chunk,
5562				bytesLeft = _size - _pos;
5563
5564			if (_chunk_size > bytesLeft) {
5565				_chunk_size = bytesLeft;
5566			}
5567
5568			chunk = Encode.btoa(_data.substr(_pos, _chunk_size));
5569			_runtime.exec.call(self, 'Transporter', 'receive', chunk, _size);
5570		}
5571	}
5572
5573	Transporter.IDLE = 0;
5574	Transporter.BUSY = 1;
5575	Transporter.DONE = 2;
5576
5577	Transporter.prototype = EventTarget.instance;
5578
5579	return Transporter;
5580});
5581
5582// Included from: src/javascript/image/Image.js
5583
5584/**
5585 * Image.js
5586 *
5587 * Copyright 2013, Moxiecode Systems AB
5588 * Released under GPL License.
5589 *
5590 * License: http://www.plupload.com/license
5591 * Contributing: http://www.plupload.com/contributing
5592 */
5593
5594define("moxie/image/Image", [
5595	"moxie/core/utils/Basic",
5596	"moxie/core/utils/Dom",
5597	"moxie/core/Exceptions",
5598	"moxie/file/FileReaderSync",
5599	"moxie/xhr/XMLHttpRequest",
5600	"moxie/runtime/Runtime",
5601	"moxie/runtime/RuntimeClient",
5602	"moxie/runtime/Transporter",
5603	"moxie/core/utils/Env",
5604	"moxie/core/EventTarget",
5605	"moxie/file/Blob",
5606	"moxie/file/File",
5607	"moxie/core/utils/Encode"
5608], function(Basic, Dom, x, FileReaderSync, XMLHttpRequest, Runtime, RuntimeClient, Transporter, Env, EventTarget, Blob, File, Encode) {
5609	/**
5610	Image preloading and manipulation utility. Additionally it provides access to image meta info (Exif, GPS) and raw binary data.
5611
5612	@class Image
5613	@constructor
5614	@extends EventTarget
5615	*/
5616	var dispatches = [
5617		'progress',
5618
5619		/**
5620		Dispatched when loading is complete.
5621
5622		@event load
5623		@param {Object} event
5624		*/
5625		'load',
5626
5627		'error',
5628
5629		/**
5630		Dispatched when resize operation is complete.
5631		
5632		@event resize
5633		@param {Object} event
5634		*/
5635		'resize',
5636
5637		/**
5638		Dispatched when visual representation of the image is successfully embedded
5639		into the corresponsing container.
5640
5641		@event embedded
5642		@param {Object} event
5643		*/
5644		'embedded'
5645	];
5646
5647	function Image() {
5648
5649		RuntimeClient.call(this);
5650
5651		Basic.extend(this, {
5652			/**
5653			Unique id of the component
5654
5655			@property uid
5656			@type {String}
5657			*/
5658			uid: Basic.guid('uid_'),
5659
5660			/**
5661			Unique id of the connected runtime, if any.
5662
5663			@property ruid
5664			@type {String}
5665			*/
5666			ruid: null,
5667
5668			/**
5669			Name of the file, that was used to create an image, if available. If not equals to empty string.
5670
5671			@property name
5672			@type {String}
5673			@default ""
5674			*/
5675			name: "",
5676
5677			/**
5678			Size of the image in bytes. Actual value is set only after image is preloaded.
5679
5680			@property size
5681			@type {Number}
5682			@default 0
5683			*/
5684			size: 0,
5685
5686			/**
5687			Width of the image. Actual value is set only after image is preloaded.
5688
5689			@property width
5690			@type {Number}
5691			@default 0
5692			*/
5693			width: 0,
5694
5695			/**
5696			Height of the image. Actual value is set only after image is preloaded.
5697
5698			@property height
5699			@type {Number}
5700			@default 0
5701			*/
5702			height: 0,
5703
5704			/**
5705			Mime type of the image. Currently only image/jpeg and image/png are supported. Actual value is set only after image is preloaded.
5706
5707			@property type
5708			@type {String}
5709			@default ""
5710			*/
5711			type: "",
5712
5713			/**
5714			Holds meta info (Exif, GPS). Is populated only for image/jpeg. Actual value is set only after image is preloaded.
5715
5716			@property meta
5717			@type {Object}
5718			@default {}
5719			*/
5720			meta: {},
5721
5722			/**
5723			Alias for load method, that takes another mOxie.Image object as a source (see load).
5724
5725			@method clone
5726			@param {Image} src Source for the image
5727			@param {Boolean} [exact=false] Whether to activate in-depth clone mode
5728			*/
5729			clone: function() {
5730				this.load.apply(this, arguments);
5731			},
5732
5733			/**
5734			Loads image from various sources. Currently the source for new image can be: mOxie.Image, mOxie.Blob/mOxie.File, 
5735			native Blob/File, dataUrl or URL. Depending on the type of the source, arguments - differ. When source is URL, 
5736			Image will be downloaded from remote destination and loaded in memory.
5737
5738			@example
5739				var img = new mOxie.Image();
5740				img.onload = function() {
5741					var blob = img.getAsBlob();
5742					
5743					var formData = new mOxie.FormData();
5744					formData.append('file', blob);
5745
5746					var xhr = new mOxie.XMLHttpRequest();
5747					xhr.onload = function() {
5748						// upload complete
5749					};
5750					xhr.open('post', 'upload.php');
5751					xhr.send(formData);
5752				};
5753				img.load("http://www.moxiecode.com/images/mox-logo.jpg"); // notice file extension (.jpg)
5754			
5755
5756			@method load
5757			@param {Image|Blob|File|String} src Source for the image
5758			@param {Boolean|Object} [mixed]
5759			*/
5760			load: function() {
5761				_load.apply(this, arguments);
5762			},
5763
5764			/**
5765			Downsizes the image to fit the specified width/height. If crop is supplied, image will be cropped to exact dimensions.
5766
5767			@method downsize
5768			@param {Object} opts
5769				@param {Number} opts.width Resulting width
5770				@param {Number} [opts.height=width] Resulting height (optional, if not supplied will default to width)
5771				@param {Boolean} [opts.crop=false] Whether to crop the image to exact dimensions
5772				@param {Boolean} [opts.preserveHeaders=true] Whether to preserve meta headers (on JPEGs after resize)
5773				@param {String} [opts.resample=false] Resampling algorithm to use for resizing
5774			*/
5775			downsize: function(opts) {
5776				var defaults = {
5777					width: this.width,
5778					height: this.height,
5779					type: this.type || 'image/jpeg',
5780					quality: 90,
5781					crop: false,
5782					preserveHeaders: true,
5783					resample: false
5784				};
5785
5786				if (typeof(opts) === 'object') {
5787					opts = Basic.extend(defaults, opts);
5788				} else {
5789					// for backward compatibility
5790					opts = Basic.extend(defaults, {
5791						width: arguments[0],
5792						height: arguments[1],
5793						crop: arguments[2],
5794						preserveHeaders: arguments[3]
5795					});
5796				}
5797
5798				try {
5799					if (!this.size) { // only preloaded image objects can be used as source
5800						throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
5801					}
5802
5803					// no way to reliably intercept the crash due to high resolution, so we simply avoid it
5804					if (this.width > Image.MAX_RESIZE_WIDTH || this.height > Image.MAX_RESIZE_HEIGHT) {
5805						throw new x.ImageError(x.ImageError.MAX_RESOLUTION_ERR);
5806					}
5807
5808					this.exec('Image', 'downsize', opts.width, opts.height, opts.crop, opts.preserveHeaders);
5809				} catch(ex) {
5810					// for now simply trigger error event
5811					this.trigger('error', ex.code);
5812				}
5813			},
5814
5815			/**
5816			Alias for downsize(width, height, true). (see downsize)
5817			
5818			@method crop
5819			@param {Number} width Resulting width
5820			@param {Number} [height=width] Resulting height (optional, if not supplied will default to width)
5821			@param {Boolean} [preserveHeaders=true] Whether to preserve meta headers (on JPEGs after resize)
5822			*/
5823			crop: function(width, height, preserveHeaders) {
5824				this.downsize(width, height, true, preserveHeaders);
5825			},
5826
5827			getAsCanvas: function() {
5828				if (!Env.can('create_canvas')) {
5829					throw new x.RuntimeError(x.RuntimeError.NOT_SUPPORTED_ERR);
5830				}
5831
5832				var runtime = this.connectRuntime(this.ruid);
5833				return runtime.exec.call(this, 'Image', 'getAsCanvas');
5834			},
5835
5836			/**
5837			Retrieves image in it's current state as mOxie.Blob object. Cannot be run on empty or image in progress (throws
5838			DOMException.INVALID_STATE_ERR).
5839
5840			@method getAsBlob
5841			@param {String} [type="image/jpeg"] Mime type of resulting blob. Can either be image/jpeg or image/png
5842			@param {Number} [quality=90] Applicable only together with mime type image/jpeg
5843			@return {Blob} Image as Blob
5844			*/
5845			getAsBlob: function(type, quality) {
5846				if (!this.size) {
5847					throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
5848				}
5849				return this.exec('Image', 'getAsBlob', type || 'image/jpeg', quality || 90);
5850			},
5851
5852			/**
5853			Retrieves image in it's current state as dataURL string. Cannot be run on empty or image in progress (throws
5854			DOMException.INVALID_STATE_ERR).
5855
5856			@method getAsDataURL
5857			@param {String} [type="image/jpeg"] Mime type of resulting blob. Can either be image/jpeg or image/png
5858			@param {Number} [quality=90] Applicable only together with mime type image/jpeg
5859			@return {String} Image as dataURL string
5860			*/
5861			getAsDataURL: function(type, quality) {
5862				if (!this.size) {
5863					throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
5864				}
5865				return this.exec('Image', 'getAsDataURL', type || 'image/jpeg', quality || 90);
5866			},
5867
5868			/**
5869			Retrieves image in it's current state as binary string. Cannot be run on empty or image in progress (throws
5870			DOMException.INVALID_STATE_ERR).
5871
5872			@method getAsBinaryString
5873			@param {String} [type="image/jpeg"] Mime type of resulting blob. Can either be image/jpeg or image/png
5874			@param {Number} [quality=90] Applicable only together with mime type image/jpeg
5875			@return {String} Image as binary string
5876			*/
5877			getAsBinaryString: function(type, quality) {
5878				var dataUrl = this.getAsDataURL(type, quality);
5879				return Encode.atob(dataUrl.substring(dataUrl.indexOf('base64,') + 7));
5880			},
5881
5882			/**
5883			Embeds a visual representation of the image into the specified node. Depending on the runtime, 
5884			it might be a canvas, an img node or a thrid party shim object (Flash or SilverLight - very rare, 
5885			can be used in legacy browsers that do not have canvas or proper dataURI support).
5886
5887			@method embed
5888			@param {DOMElement} el DOM element to insert the image object into
5889			@param {Object} [opts]
5890				@param {Number} [opts.width] The width of an embed (defaults to the image width)
5891				@param {Number} [opts.height] The height of an embed (defaults to the image height)
5892				@param {String} [type="image/jpeg"] Mime type
5893				@param {Number} [quality=90] Quality of an embed, if mime type is image/jpeg
5894				@param {Boolean} [crop=false] Whether to crop an embed to the specified dimensions
5895			*/
5896			embed: function(el, opts) {
5897				var self = this
5898				, runtime // this has to be outside of all the closures to contain proper runtime
5899				;
5900
5901				opts = Basic.extend({
5902					width: this.width,
5903					height: this.height,
5904					type: this.type || 'image/jpeg',
5905					quality: 90
5906				}, opts || {});
5907				
5908
5909				function render(type, quality) {
5910					var img = this;
5911
5912					// if possible, embed a canvas element directly
5913					if (Env.can('create_canvas')) {
5914						var canvas = img.getAsCanvas();
5915						if (canvas) {
5916							el.appendChild(canvas);
5917							canvas = null;
5918							img.destroy();
5919							self.trigger('embedded');
5920							return;
5921						}
5922					}
5923
5924					var dataUrl = img.getAsDataURL(type, quality);
5925					if (!dataUrl) {
5926						throw new x.ImageError(x.ImageError.WRONG_FORMAT);
5927					}
5928
5929					if (Env.can('use_data_uri_of', dataUrl.length)) {
5930						el.innerHTML = '<img src="' + dataUrl + '" width="' + img.width + '" height="' + img.height + '" />';
5931						img.destroy();
5932						self.trigger('embedded');
5933					} else {
5934						var tr = new Transporter();
5935
5936						tr.bind("TransportingComplete", function() {
5937							runtime = self.connectRuntime(this.result.ruid);
5938
5939							self.bind("Embedded", function() {
5940								// position and size properly
5941								Basic.extend(runtime.getShimContainer().style, {
5942									//position: 'relative',
5943									top: '0px',
5944									left: '0px',
5945									width: img.width + 'px',
5946									height: img.height + 'px'
5947								});
5948
5949								// some shims (Flash/SilverLight) reinitialize, if parent element is hidden, reordered or it's
5950								// position type changes (in Gecko), but since we basically need this only in IEs 6/7 and
5951								// sometimes 8 and they do not have this problem, we can comment this for now
5952								/*tr.bind("RuntimeInit", function(e, runtime) {
5953									tr.destroy();
5954									runtime.destroy();
5955									onResize.call(self); // re-feed our image data
5956								});*/
5957
5958								runtime = null; // release
5959							}, 999);
5960
5961							runtime.exec.call(self, "ImageView", "display", this.result.uid, width, height);
5962							img.destroy();
5963						});
5964
5965						tr.transport(Encode.atob(dataUrl.substring(dataUrl.indexOf('base64,') + 7)), type, {
5966							required_caps: {
5967								display_media: true
5968							},
5969							runtime_order: 'flash,silverlight',
5970							container: el
5971						});
5972					}
5973				}
5974
5975				try {
5976					if (!(el = Dom.get(el))) {
5977						throw new x.DOMException(x.DOMException.INVALID_NODE_TYPE_ERR);
5978					}
5979
5980					if (!this.size) { // only preloaded image objects can be used as source
5981						throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
5982					}
5983					
5984					// high-resolution images cannot be consistently handled across the runtimes
5985					if (this.width > Image.MAX_RESIZE_WIDTH || this.height > Image.MAX_RESIZE_HEIGHT) {
5986						//throw new x.ImageError(x.ImageError.MAX_RESOLUTION_ERR);
5987					}
5988
5989					var imgCopy = new Image();
5990
5991					imgCopy.bind("Resize", function() {
5992						render.call(this, opts.type, opts.quality);
5993					});
5994
5995					imgCopy.bind("Load", function() {
5996						imgCopy.downsize(opts);
5997					});
5998
5999					// if embedded thumb data is available and dimensions are big enough, use it
6000					if (this.meta.thumb && this.meta.thumb.width >= opts.width && this.meta.thumb.height >= opts.height) {
6001						imgCopy.load(this.meta.thumb.data);
6002					} else {
6003						imgCopy.clone(this, false);
6004					}
6005
6006					return imgCopy;
6007				} catch(ex) {
6008					// for now simply trigger error event
6009					this.trigger('error', ex.code);
6010				}
6011			},
6012
6013			/**
6014			Properly destroys the image and frees resources in use. If any. Recommended way to dispose mOxie.Image object.
6015
6016			@method destroy
6017			*/
6018			destroy: function() {
6019				if (this.ruid) {
6020					this.getRuntime().exec.call(this, 'Image', 'destroy');
6021					this.disconnectRuntime();
6022				}
6023				this.unbindAll();
6024			}
6025		});
6026
6027
6028		// this is here, because in order to bind properly, we need uid, which is created above
6029		this.handleEventProps(dispatches);
6030
6031		this.bind('Load Resize', function() {
6032			_updateInfo.call(this);
6033		}, 999);
6034
6035
6036		function _updateInfo(info) {
6037			if (!info) {
6038				info = this.exec('Image', 'getInfo');
6039			}
6040
6041			this.size = info.size;
6042			this.width = info.width;
6043			this.height = info.height;
6044			this.type = info.type;
6045			this.meta = info.meta;
6046
6047			// update file name, only if empty
6048			if (this.name === '') {
6049				this.name = info.name;
6050			}
6051		}
6052		
6053
6054		function _load(src) {
6055			var srcType = Basic.typeOf(src);
6056
6057			try {
6058				// if source is Image
6059				if (src instanceof Image) {
6060					if (!src.size) { // only preloaded image objects can be used as source
6061						throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
6062					}
6063					_loadFromImage.apply(this, arguments);
6064				}
6065				// if source is o.Blob/o.File
6066				else if (src instanceof Blob) {
6067					if (!~Basic.inArray(src.type, ['image/jpeg', 'image/png'])) {
6068						throw new x.ImageError(x.ImageError.WRONG_FORMAT);
6069					}
6070					_loadFromBlob.apply(this, arguments);
6071				}
6072				// if native blob/file
6073				else if (Basic.inArray(srcType, ['blob', 'file']) !== -1) {
6074					_load.call(this, new File(null, src), arguments[1]);
6075				}
6076				// if String
6077				else if (srcType === 'string') {
6078					// if dataUrl String
6079					if (src.substr(0, 5) === 'data:') {
6080						_load.call(this, new Blob(null, { data: src }), arguments[1]);
6081					}
6082					// else assume Url, either relative or absolute
6083					else {
6084						_loadFromUrl.apply(this, arguments);
6085					}
6086				}
6087				// if source seems to be an img node
6088				else if (srcType === 'node' && src.nodeName.toLowerCase() === 'img') {
6089					_load.call(this, src.src, arguments[1]);
6090				}
6091				else {
6092					throw new x.DOMException(x.DOMException.TYPE_MISMATCH_ERR);
6093				}
6094			} catch(ex) {
6095				// for now simply trigger error event
6096				this.trigger('error', ex.code);
6097			}
6098		}
6099
6100
6101		function _loadFromImage(img, exact) {
6102			var runtime = this.connectRuntime(img.ruid);
6103			this.ruid = runtime.uid;
6104			runtime.exec.call(this, 'Image', 'loadFromImage', img, (Basic.typeOf(exact) === 'undefined' ? true : exact));
6105		}
6106
6107
6108		function _loadFromBlob(blob, options) {
6109			var self = this;
6110
6111			self.name = blob.name || '';
6112
6113			function exec(runtime) {
6114				self.ruid = runtime.uid;
6115				runtime.exec.call(self, 'Image', 'loadFromBlob', blob);
6116			}
6117
6118			if (blob.isDetached()) {
6119				this.bind('RuntimeInit', function(e, runtime) {
6120					exec(runtime);
6121				});
6122
6123				// convert to object representation
6124				if (options && typeof(options.required_caps) === 'string') {
6125					options.required_caps = Runtime.parseCaps(options.required_caps);
6126				}
6127
6128				this.connectRuntime(Basic.extend({
6129					required_caps: {
6130						access_image_binary: true,
6131						resize_image: true
6132					}
6133				}, options));
6134			} else {
6135				exec(this.connectRuntime(blob.ruid));
6136			}
6137		}
6138
6139
6140		function _loadFromUrl(url, options) {
6141			var self = this, xhr;
6142
6143			xhr = new XMLHttpRequest();
6144
6145			xhr.open('get', url);
6146			xhr.responseType = 'blob';
6147
6148			xhr.onprogress = function(e) {
6149				self.trigger(e);
6150			};
6151
6152			xhr.onload = function() {
6153				_loadFromBlob.call(self, xhr.response, true);
6154			};
6155
6156			xhr.onerror = function(e) {
6157				self.trigger(e);
6158			};
6159
6160			xhr.onloadend = function() {
6161				xhr.destroy();
6162			};
6163
6164			xhr.bind('RuntimeError', function(e, err) {
6165				self.trigger('RuntimeError', err);
6166			});
6167
6168			xhr.send(null, options);
6169		}
6170	}
6171
6172	// virtual world will crash on you if image has a resolution higher than this:
6173	Image.MAX_RESIZE_WIDTH = 8192;
6174	Image.MAX_RESIZE_HEIGHT = 8192; 
6175
6176	Image.prototype = EventTarget.instance;
6177
6178	return Image;
6179});
6180
6181// Included from: src/javascript/runtime/html5/Runtime.js
6182
6183/**
6184 * Runtime.js
6185 *
6186 * Copyright 2013, Moxiecode Systems AB
6187 * Released under GPL License.
6188 *
6189 * License: http://www.plupload.com/license
6190 * Contributing: http://www.plupload.com/contributing
6191 */
6192
6193/*global File:true */
6194
6195/**
6196Defines constructor for HTML5 runtime.
6197
6198@class moxie/runtime/html5/Runtime
6199@private
6200*/
6201define("moxie/runtime/html5/Runtime", [
6202	"moxie/core/utils/Basic",
6203	"moxie/core/Exceptions",
6204	"moxie/runtime/Runtime",
6205	"moxie/core/utils/Env"
6206], function(Basic, x, Runtime, Env) {
6207	
6208	var type = "html5", extensions = {};
6209	
6210	function Html5Runtime(options) {
6211		var I = this
6212		, Test = Runtime.capTest
6213		, True = Runtime.capTrue
6214		;
6215
6216		var caps = Basic.extend({
6217				access_binary: Test(window.FileReader || window.File && window.File.getAsDataURL),
6218				access_image_binary: function() {
6219					return I.can('access_binary') && !!extensions.Image;
6220				},
6221				display_media: Test(Env.can('create_canvas') || Env.can('use_data_uri_over32kb')),
6222				do_cors: Test(window.XMLHttpRequest && 'withCredentials' in new XMLHttpRequest()),
6223				drag_and_drop: Test(function() {
6224					// this comes directly from Modernizr: http://www.modernizr.com/
6225					var div = document.createElement('div');
6226					// IE has support for drag and drop since version 5, but doesn't support dropping files from desktop
6227					return (('draggable' in div) || ('ondragstart' in div && 'ondrop' in div)) && 
6228						(Env.browser !== 'IE' || Env.verComp(Env.version, 9, '>'));
6229				}()),
6230				filter_by_extension: Test(function() { // if you know how to feature-detect this, please suggest
6231					return (Env.browser === 'Chrome' && Env.verComp(Env.version, 28, '>=')) || 
6232						(Env.browser === 'IE' && Env.verComp(Env.version, 10, '>=')) || 
6233						(Env.browser === 'Safari' && Env.verComp(Env.version, 7, '>='));
6234				}()),
6235				return_response_headers: True,
6236				return_response_type: function(responseType) {
6237					if (responseType === 'json' && !!window.JSON) { // we can fake this one even if it's not supported
6238						return true;
6239					} 
6240					return Env.can('return_response_type', responseType);
6241				},
6242				return_status_code: True,
6243				report_upload_progress: Test(window.XMLHttpRequest && new XMLHttpRequest().upload),
6244				resize_image: function() {
6245					return I.can('access_binary') && Env.can('create_canvas');
6246				},
6247				select_file: function() {
6248					return Env.can('use_fileinput') && window.File;
6249				},
6250				select_folder: function() {
6251					return I.can('select_file') && Env.browser === 'Chrome' && Env.verComp(Env.version, 21, '>=');
6252				},
6253				select_multiple: function() {
6254					// it is buggy on Safari Windows and iOS
6255					return I.can('select_file') &&
6256						!(Env.browser === 'Safari' && Env.os === 'Windows') &&
6257						!(Env.os === 'iOS' && Env.verComp(Env.osVersion, "7.0.0", '>') && Env.verComp(Env.osVersion, "8.0.0", '<'));
6258				},
6259				send_binary_string: Test(window.XMLHttpRequest && (new XMLHttpRequest().sendAsBinary || (window.Uint8Array && window.ArrayBuffer))),
6260				send_custom_headers: Test(window.XMLHttpRequest),
6261				send_multipart: function() {
6262					return !!(window.XMLHttpRequest && new XMLHttpRequest().upload && window.FormData) || I.can('send_binary_string');
6263				},
6264				slice_blob: Test(window.File && (File.prototype.mozSlice || File.prototype.webkitSlice || File.prototype.slice)),
6265				stream_upload: function(){
6266					return I.can('slice_blob') && I.can('send_multipart');
6267				},
6268				summon_file_dialog: function() { // yeah... some dirty sniffing here...
6269					return I.can('select_file') && (
6270						(Env.browser === 'Firefox' && Env.verComp(Env.version, 4, '>=')) ||
6271						(Env.browser === 'Opera' && Env.verComp(Env.version, 12, '>=')) ||
6272						(Env.browser === 'IE' && Env.verComp(Env.version, 10, '>=')) ||
6273						!!~Basic.inArray(Env.browser, ['Chrome', 'Safari'])
6274					);
6275				},
6276				upload_filesize: True
6277			}, 
6278			arguments[2]
6279		);
6280
6281		Runtime.call(this, options, (arguments[1] || type), caps);
6282
6283
6284		Basic.extend(this, {
6285
6286			init : function() {
6287				this.trigger("Init");
6288			},
6289
6290			destroy: (function(destroy) { // extend default destroy method
6291				return function() {
6292					destroy.call(I);
6293					destroy = I = null;
6294				};
6295			}(this.destroy))
6296		});
6297
6298		Basic.extend(this.getShim(), extensions);
6299	}
6300
6301	Runtime.addConstructor(type, Html5Runtime);
6302
6303	return extensions;
6304});
6305
6306// Included from: src/javascript/core/utils/Events.js
6307
6308/**
6309 * Events.js
6310 *
6311 * Copyright 2013, Moxiecode Systems AB
6312 * Released under GPL License.
6313 *
6314 * License: http://www.plupload.com/license
6315 * Contributing: http://www.plupload.com/contributing
6316 */
6317
6318define('moxie/core/utils/Events', [
6319	'moxie/core/utils/Basic'
6320], function(Basic) {
6321	var eventhash = {}, uid = 'moxie_' + Basic.guid();
6322	
6323	// IE W3C like event funcs
6324	function preventDefault() {
6325		this.returnValue = false;
6326	}
6327
6328	function stopPropagation() {
6329		this.cancelBubble = true;
6330	}
6331
6332	/**
6333	Adds an event handler to the specified object and store reference to the handler
6334	in objects internal Plupload registry (@see removeEvent).
6335	
6336	@method addEvent
6337	@for Utils
6338	@static
6339	@param {Object} obj DOM element like object to add handler to.
6340	@param {String} name Name to add event listener to.
6341	@param {Function} callback Function to call when event occurs.
6342	@param {String} [key] that might be used to add specifity to the event record.
6343	*/
6344	var addEvent = function(obj, name, callback, key) {
6345		var func, events;
6346					
6347		name = name.toLowerCase();
6348
6349		// Add event listener
6350		if (obj.addEventListener) {
6351			func = callback;
6352			
6353			obj.addEventListener(name, func, false);
6354		} else if (obj.attachEvent) {
6355			func = function() {
6356				var evt = window.event;
6357
6358				if (!evt.target) {
6359					evt.target = evt.srcElement;
6360				}
6361
6362				evt.preventDefault = preventDefault;
6363				evt.stopPropagation = stopPropagation;
6364
6365				callback(evt);
6366			};
6367
6368			obj.attachEvent('on' + name, func);
6369		}
6370		
6371		// Log event handler to objects internal mOxie registry
6372		if (!obj[uid]) {
6373			obj[uid] = Basic.guid();
6374		}
6375		
6376		if (!eventhash.hasOwnProperty(obj[uid])) {
6377			eventhash[obj[uid]] = {};
6378		}
6379		
6380		events = eventhash[obj[uid]];
6381		
6382		if (!events.hasOwnProperty(name)) {
6383			events[name] = [];
6384		}
6385				
6386		events[name].push({
6387			func: func,
6388			orig: callback, // store original callback for IE
6389			key: key
6390		});
6391	};
6392	
6393	
6394	/**
6395	Remove event handler from the specified object. If third argument (callback)
6396	is not specified remove all events with the specified name.
6397	
6398	@method removeEvent
6399	@static
6400	@param {Object} obj DOM element to remove event listener(s) from.
6401	@param {String} name Name of event listener to remove.
6402	@param {Function|String} [callback] might be a callback or unique key to match.
6403	*/
6404	var removeEvent = function(obj, name, callback) {
6405		var type, undef;
6406		
6407		name = name.toLowerCase();
6408		
6409		if (obj[uid] && eventhash[obj[uid]] && eventhash[obj[uid]][name]) {
6410			type = eventhash[obj[uid]][name];
6411		} else {
6412			return;
6413		}
6414			
6415		for (var i = type.length - 1; i >= 0; i--) {
6416			// undefined or not, key should match
6417			if (type[i].orig === callback || type[i].key === callback) {
6418				if (obj.removeEventListener) {
6419					obj.removeEventListener(name, type[i].func, false);
6420				} else if (obj.detachEvent) {
6421					obj.detachEvent('on'+name, type[i].func);
6422				}
6423				
6424				type[i].orig = null;
6425				type[i].func = null;
6426				type.splice(i, 1);
6427				
6428				// If callback was passed we are done here, otherwise proceed
6429				if (callback !== undef) {
6430					break;
6431				}
6432			}
6433		}
6434		
6435		// If event array got empty, remove it
6436		if (!type.length) {
6437			delete eventhash[obj[uid]][name];
6438		}
6439		
6440		// If mOxie registry has become empty, remove it
6441		if (Basic.isEmptyObj(eventhash[obj[uid]])) {
6442			delete eventhash[obj[uid]];
6443			
6444			// IE doesn't let you remove DOM object property with - delete
6445			try {
6446				delete obj[uid];
6447			} catch(e) {
6448				obj[uid] = undef;
6449			}
6450		}
6451	};
6452	
6453	
6454	/**
6455	Remove all kind of events from the specified object
6456	
6457	@method removeAllEvents
6458	@static
6459	@param {Object} obj DOM element to remove event listeners from.
6460	@param {String} [key] unique key to match, when removing events.
6461	*/
6462	var removeAllEvents = function(obj, key) {		
6463		if (!obj || !obj[uid]) {
6464			return;
6465		}
6466		
6467		Basic.each(eventhash[obj[uid]], function(events, name) {
6468			removeEvent(obj, name, key);
6469		});
6470	};
6471
6472	return {
6473		addEvent: addEvent,
6474		removeEvent: removeEvent,
6475		removeAllEvents: removeAllEvents
6476	};
6477});
6478
6479// Included from: src/javascript/runtime/html5/file/FileInput.js
6480
6481/**
6482 * FileInput.js
6483 *
6484 * Copyright 2013, Moxiecode Systems AB
6485 * Released under GPL License.
6486 *
6487 * License: http://www.plupload.com/license
6488 * Contributing: http://www.plupload.com/contributing
6489 */
6490
6491/**
6492@class moxie/runtime/html5/file/FileInput
6493@private
6494*/
6495define("moxie/runtime/html5/file/FileInput", [
6496	"moxie/runtime/html5/Runtime",
6497	"moxie/file/File",
6498	"moxie/core/utils/Basic",
6499	"moxie/core/utils/Dom",
6500	"moxie/core/utils/Events",
6501	"moxie/core/utils/Mime",
6502	"moxie/core/utils/Env"
6503], function(extensions, File, Basic, Dom, Events, Mime, Env) {
6504	
6505	function FileInput() {
6506		var _options;
6507
6508		Basic.extend(this, {
6509			init: function(options) {
6510				var comp = this, I = comp.getRuntime(), input, shimContainer, mimes, browseButton, zIndex, top;
6511
6512				_options = options;
6513
6514				// figure out accept string
6515				mimes = _options.accept.mimes || Mime.extList2mimes(_options.accept, I.can('filter_by_extension'));
6516
6517				shimContainer = I.getShimContainer();
6518
6519				shimContainer.innerHTML = '<input id="' + I.uid +'" type="file" style="font-size:999px;opacity:0;"' +
6520					(_options.multiple && I.can('select_multiple') ? 'multiple' : '') + 
6521					(_options.directory && I.can('select_folder') ? 'webkitdirectory directory' : '') + // Chrome 11+
6522					(mimes ? ' accept="' + mimes.join(',') + '"' : '') + ' />';
6523
6524				input = Dom.get(I.uid);
6525
6526				// prepare file input to be placed underneath the browse_button element
6527				Basic.extend(input.style, {
6528					position: 'absolute',
6529					top: 0,
6530					left: 0,
6531					width: '100%',
6532					height: '100%'
6533				});
6534
6535
6536				browseButton = Dom.get(_options.browse_button);
6537
6538				// Route click event to the input[type=file] element for browsers that support such behavior
6539				if (I.can('summon_file_dialog')) {
6540					if (Dom.getStyle(browseButton, 'position') === 'static') {
6541						browseButton.style.position = 'relative';
6542					}
6543
6544					zIndex = parseInt(Dom.getStyle(browseButton, 'z-index'), 10) || 1;
6545
6546					browseButton.style.zIndex = zIndex;
6547					shimContainer.style.zIndex = zIndex - 1;
6548
6549					Events.addEvent(browseButton, 'click', function(e) {
6550						var input = Dom.get(I.uid);
6551						if (input && !input.disabled) { // for some reason FF (up to 8.0.1 so far) lets to click disabled input[type=file]
6552							input.click();
6553						}
6554						e.preventDefault();
6555					}, comp.uid);
6556				}
6557
6558				/* Since we have to place input[type=file] on top of the browse_button for some browsers,
6559				browse_button loses interactivity, so we restore it here */
6560				top = I.can('summon_file_dialog') ? browseButton : shimContainer;
6561
6562				Events.addEvent(top, 'mouseover', function() {
6563					comp.trigger('mouseenter');
6564				}, comp.uid);
6565
6566				Events.addEvent(top, 'mouseout', function() {
6567					comp.trigger('mouseleave');
6568				}, comp.uid);
6569
6570				Events.addEvent(top, 'mousedown', function() {
6571					comp.trigger('mousedown');
6572				}, comp.uid);
6573
6574				Events.addEvent(Dom.get(_options.container), 'mouseup', function() {
6575					comp.trigger('mouseup');
6576				}, comp.uid);
6577
6578
6579				input.onchange = function onChange(e) { // there should be only one handler for this
6580					comp.files = [];
6581
6582					Basic.each(this.files, function(file) {
6583						var relativePath = '';
6584
6585						if (_options.directory) {
6586							// folders are represented by dots, filter them out (Chrome 11+)
6587							if (file.name == ".") {
6588								// if it looks like a folder...
6589								return true;
6590							}
6591						}
6592
6593						if (file.webkitRelativePath) {
6594							relativePath = '/' + file.webkitRelativePath.replace(/^\//, '');
6595						}
6596						
6597						file = new File(I.uid, file);
6598						file.relativePath = relativePath;
6599
6600						comp.files.push(file);
6601					});
6602
6603					// clearing the value enables the user to select the same file again if they want to
6604					if (Env.browser !== 'IE' && Env.browser !== 'IEMobile') {
6605						this.value = '';
6606					} else {
6607						// in IE input[type="file"] is read-only so the only way to reset it is to re-insert it
6608						var clone = this.cloneNode(true);
6609						this.parentNode.replaceChild(clone, this);
6610						clone.onchange = onChange;
6611					}
6612
6613					if (comp.files.length) {
6614						comp.trigger('change');
6615					}
6616				};
6617
6618				// ready event is perfectly asynchronous
6619				comp.trigger({
6620					type: 'ready',
6621					async: true
6622				});
6623
6624				shimContainer = null;
6625			},
6626
6627
6628			disable: function(state) {
6629				var I = this.getRuntime(), input;
6630
6631				if ((input = Dom.get(I.uid))) {
6632					input.disabled = !!state;
6633				}
6634			},
6635
6636			destroy: function() {
6637				var I = this.getRuntime()
6638				, shim = I.getShim()
6639				, shimContainer = I.getShimContainer()
6640				;
6641				
6642				Events.removeAllEvents(shimContainer, this.uid);
6643				Events.removeAllEvents(_options && Dom.get(_options.container), this.uid);
6644				Events.removeAllEvents(_options && Dom.get(_options.browse_button), this.uid);
6645				
6646				if (shimContainer) {
6647					shimContainer.innerHTML = '';
6648				}
6649
6650				shim.removeInstance(this.uid);
6651
6652				_options = shimContainer = shim = null;
6653			}
6654		});
6655	}
6656
6657	return (extensions.FileInput = FileInput);
6658});
6659
6660// Included from: src/javascript/runtime/html5/file/Blob.js
6661
6662/**
6663 * Blob.js
6664 *
6665 * Copyright 2013, Moxiecode Systems AB
6666 * Released under GPL License.
6667 *
6668 * License: http://www.plupload.com/license
6669 * Contributing: http://www.plupload.com/contributing
6670 */
6671
6672/**
6673@class moxie/runtime/html5/file/Blob
6674@private
6675*/
6676define("moxie/runtime/html5/file/Blob", [
6677	"moxie/runtime/html5/Runtime",
6678	"moxie/file/Blob"
6679], function(extensions, Blob) {
6680
6681	function HTML5Blob() {
6682		function w3cBlobSlice(blob, start, end) {
6683			var blobSlice;
6684
6685			if (window.File.prototype.slice) {
6686				try {
6687					blob.slice();	// depricated version will throw WRONG_ARGUMENTS_ERR exception
6688					return blob.slice(start, end);
6689				} catch (e) {
6690					// depricated slice method
6691					return blob.slice(start, end - start);
6692				}
6693			// slice method got prefixed: https://bugzilla.mozilla.org/show_bug.cgi?id=649672
6694			} else if ((blobSlice = window.File.prototype.webkitSlice || window.File.prototype.mozSlice)) {
6695				return blobSlice.call(blob, start, end);
6696			} else {
6697				return null; // or throw some exception
6698			}
6699		}
6700
6701		this.slice = function() {
6702			return new Blob(this.getRuntime().uid, w3cBlobSlice.apply(this, arguments));
6703		};
6704	}
6705
6706	return (extensions.Blob = HTML5Blob);
6707});
6708
6709// Included from: src/javascript/runtime/html5/file/FileDrop.js
6710
6711/**
6712 * FileDrop.js
6713 *
6714 * Copyright 2013, Moxiecode Systems AB
6715 * Released under GPL License.
6716 *
6717 * License: http://www.plupload.com/license
6718 * Contributing: http://www.plupload.com/contributing
6719 */
6720
6721/**
6722@class moxie/runtime/html5/file/FileDrop
6723@private
6724*/
6725define("moxie/runtime/html5/file/FileDrop", [
6726	"moxie/runtime/html5/Runtime",
6727	'moxie/file/File',
6728	"moxie/core/utils/Basic",
6729	"moxie/core/utils/Dom",
6730	"moxie/core/utils/Events",
6731	"moxie/core/utils/Mime"
6732], function(extensions, File, Basic, Dom, Events, Mime) {
6733	
6734	function FileDrop() {
6735		var _files = [], _allowedExts = [], _options, _ruid;
6736
6737		Basic.extend(this, {
6738			init: function(options) {
6739				var comp = this, dropZone;
6740
6741				_options = options;
6742				_ruid = comp.ruid; // every dropped-in file should have a reference to the runtime
6743				_allowedExts = _extractExts(_options.accept);
6744				dropZone = _options.container;
6745
6746				Events.addEvent(dropZone, 'dragover', function(e) {
6747					if (!_hasFiles(e)) {
6748						return;
6749					}
6750					e.preventDefault();
6751					e.dataTransfer.dropEffect = 'copy';
6752				}, comp.uid);
6753
6754				Events.addEvent(dropZone, 'drop', function(e) {
6755					if (!_hasFiles(e)) {
6756						return;
6757					}
6758					e.preventDefault();
6759
6760					_files = [];
6761
6762					// Chrome 21+ accepts folders via Drag'n'Drop
6763					if (e.dataTransfer.items && e.dataTransfer.items[0].webkitGetAsEntry) {
6764						_readItems(e.dataTransfer.items, function() {
6765							comp.files = _files;
6766							comp.trigger("drop");
6767						});
6768					} else {
6769						Basic.each(e.dataTransfer.files, function(file) {
6770							_addFile(file);
6771						});
6772						comp.files = _files;
6773						comp.trigger("drop");
6774					}
6775				}, comp.uid);
6776
6777				Events.addEvent(dropZone, 'dragenter', function(e) {
6778					comp.trigger("dragenter");
6779				}, comp.uid);
6780
6781				Events.addEvent(dropZone, 'dragleave', function(e) {
6782					comp.trigger("dragleave");
6783				}, comp.uid);
6784			},
6785
6786			destroy: function() {
6787				Events.removeAllEvents(_options && Dom.get(_options.container), this.uid);
6788				_ruid = _files = _allowedExts = _options = null;
6789			}
6790		});
6791
6792
6793		function _hasFiles(e) {
6794			if (!e.dataTransfer || !e.dataTransfer.types) { // e.dataTransfer.files is not available in Gecko during dragover
6795				return false;
6796			}
6797
6798			var types = Basic.toArray(e.dataTransfer.types || []);
6799
6800			return Basic.inArray("Files", types) !== -1 ||
6801				Basic.inArray("public.file-url", types) !== -1 || // Safari < 5
6802				Basic.inArray("application/x-moz-file", types) !== -1 // Gecko < 1.9.2 (< Firefox 3.6)
6803				;
6804		}
6805
6806
6807		function _addFile(file, relativePath) {
6808			if (_isAcceptable(file)) {
6809				var fileObj = new File(_ruid, file);
6810				fileObj.relativePath = relativePath || '';
6811				_files.push(fileObj);
6812			}
6813		}
6814
6815		
6816		function _extractExts(accept) {
6817			var exts = [];
6818			for (var i = 0; i < accept.length; i++) {
6819				[].push.apply(exts, accept[i].extensions.split(/\s*,\s*/));
6820			}
6821			return Basic.inArray('*', exts) === -1 ? exts : [];
6822		}
6823
6824
6825		function _isAcceptable(file) {
6826			if (!_allowedExts.length) {
6827				return true;
6828			}
6829			var ext = Mime.getFileExtension(file.name);
6830			return !ext || Basic.inArray(ext, _allowedExts) !== -1;
6831		}
6832
6833
6834		function _readItems(items, cb) {
6835			var entries = [];
6836			Basic.each(items, function(item) {
6837				var entry = item.webkitGetAsEntry();
6838				// Address #998 (https://code.google.com/p/chromium/issues/detail?id=332579)
6839				if (entry) {
6840					// file() fails on OSX when the filename contains a special character (e.g. umlaut): see #61
6841					if (entry.isFile) {
6842						_addFile(item.getAsFile(), entry.fullPath);
6843					} else {
6844						entries.push(entry);
6845					}
6846				}
6847			});
6848
6849			if (entries.length) {
6850				_readEntries(entries, cb);
6851			} else {
6852				cb();
6853			}
6854		}
6855
6856
6857		function _readEntries(entries, cb) {
6858			var queue = [];
6859			Basic.each(entries, function(entry) {
6860				queue.push(function(cbcb) {
6861					_readEntry(entry, cbcb);
6862				});
6863			});
6864			Basic.inSeries(queue, function() {
6865				cb();
6866			});
6867		}
6868
6869
6870		function _readEntry(entry, cb) {
6871			if (entry.isFile) {
6872				entry.file(function(file) {
6873					_addFile(file, entry.fullPath);
6874					cb();
6875				}, function() {
6876					// fire an error event maybe
6877					cb();
6878				});
6879			} else if (entry.isDirectory) {
6880				_readDirEntry(entry, cb);
6881			} else {
6882				cb(); // not file, not directory? what then?..
6883			}
6884		}
6885
6886
6887		function _readDirEntry(dirEntry, cb) {
6888			var entries = [], dirReader = dirEntry.createReader();
6889
6890			// keep quering recursively till no more entries
6891			function getEntries(cbcb) {
6892				dirReader.readEntries(function(moreEntries) {
6893					if (moreEntries.length) {
6894						[].push.apply(entries, moreEntries);
6895						getEntries(cbcb);
6896					} else {
6897						cbcb();
6898					}
6899				}, cbcb);
6900			}
6901
6902			// ...and you thought FileReader was crazy...
6903			getEntries(function() {
6904				_readEntries(entries, cb);
6905			}); 
6906		}
6907	}
6908
6909	return (extensions.FileDrop = FileDrop);
6910});
6911
6912// Included from: src/javascript/runtime/html5/file/FileReader.js
6913
6914/**
6915 * FileReader.js
6916 *
6917 * Copyright 2013, Moxiecode Systems AB
6918 * Released under GPL License.
6919 *
6920 * License: http://www.plupload.com/license
6921 * Contributing: http://www.plupload.com/contributing
6922 */
6923
6924/**
6925@class moxie/runtime/html5/file/FileReader
6926@private
6927*/
6928define("moxie/runtime/html5/file/FileReader", [
6929	"moxie/runtime/html5/Runtime",
6930	"moxie/core/utils/Encode",
6931	"moxie/core/utils/Basic"
6932], function(extensions, Encode, Basic) {
6933	
6934	function FileReader() {
6935		var _fr, _convertToBinary = false;
6936
6937		Basic.extend(this, {
6938
6939			read: function(op, blob) {
6940				var comp = this;
6941
6942				comp.result = '';
6943
6944				_fr = new window.FileReader();
6945
6946				_fr.addEventListener('progress', function(e) {
6947					comp.trigger(e);
6948				});
6949
6950				_fr.addEventListener('load', function(e) {
6951					comp.result = _convertToBinary ? _toBinary(_fr.result) : _fr.result;
6952					comp.trigger(e);
6953				});
6954
6955				_fr.addEventListener('error', function(e) {
6956					comp.trigger(e, _fr.error);
6957				});
6958
6959				_fr.addEventListener('loadend', function(e) {
6960					_fr = null;
6961					comp.trigger(e);
6962				});
6963
6964				if (Basic.typeOf(_fr[op]) === 'function') {
6965					_convertToBinary = false;
6966					_fr[op](blob.getSource());
6967				} else if (op === 'readAsBinaryString') { // readAsBinaryString is depricated in general and never existed in IE10+
6968					_convertToBinary = true;
6969					_fr.readAsDataURL(blob.getSource());
6970				}
6971			},
6972
6973			abort: function() {
6974				if (_fr) {
6975					_fr.abort();
6976				}
6977			},
6978
6979			destroy: function() {
6980				_fr = null;
6981			}
6982		});
6983
6984		function _toBinary(str) {
6985			return Encode.atob(str.substring(str.indexOf('base64,') + 7));
6986		}
6987	}
6988
6989	return (extensions.FileReader = FileReader);
6990});
6991
6992// Included from: src/javascript/runtime/html5/xhr/XMLHttpRequest.js
6993
6994/**
6995 * XMLHttpRequest.js
6996 *
6997 * Copyright 2013, Moxiecode Systems AB
6998 * Released under GPL License.
6999 *
7000 * License: http://www.plupload.com/license
7001 * Contributing: http://www.plupload.com/contributing
7002 */
7003
7004/*global ActiveXObject:true */
7005
7006/**
7007@class moxie/runtime/html5/xhr/XMLHttpRequest
7008@private
7009*/
7010define("moxie/runtime/html5/xhr/XMLHttpRequest", [
7011	"moxie/runtime/html5/Runtime",
7012	"moxie/core/utils/Basic",
7013	"moxie/core/utils/Mime",
7014	"moxie/core/utils/Url",
7015	"moxie/file/File",
7016	"moxie/file/Blob",
7017	"moxie/xhr/FormData",
7018	"moxie/core/Exceptions",
7019	"moxie/core/utils/Env"
7020], function(extensions, Basic, Mime, Url, File, Blob, FormData, x, Env) {
7021	
7022	function XMLHttpRequest() {
7023		var self = this
7024		, _xhr
7025		, _filename
7026		;
7027
7028		Basic.extend(this, {
7029			send: function(meta, data) {
7030				var target = this
7031				, isGecko2_5_6 = (Env.browser === 'Mozilla' && Env.verComp(Env.version, 4, '>=') && Env.verComp(Env.version, 7, '<'))
7032				, isAndroidBrowser = Env.browser === 'Android Browser'
7033				, mustSendAsBinary = false
7034				;
7035
7036				// extract file name
7037				_filename = meta.url.replace(/^.+?\/([\w\-\.]+)$/, '$1').toLowerCase();
7038
7039				_xhr = _getNativeXHR();
7040				_xhr.open(meta.method, meta.url, meta.async, meta.user, meta.password);
7041
7042
7043				// prepare data to be sent
7044				if (data instanceof Blob) {
7045					if (data.isDetached()) {
7046						mustSendAsBinary = true;
7047					}
7048					data = data.getSource();
7049				} else if (data instanceof FormData) {
7050
7051					if (data.hasBlob()) {
7052						if (data.getBlob().isDetached()) {
7053							data = _prepareMultipart.call(target, data); // _xhr must be instantiated and be in OPENED state
7054							mustSendAsBinary = true;
7055						} else if ((isGecko2_5_6 || isAndroidBrowser) && Basic.typeOf(data.getBlob().getSource()) === 'blob' && window.FileReader) {
7056							// Gecko 2/5/6 can't send blob in FormData: https://bugzilla.mozilla.org/show_bug.cgi?id=649150
7057							// Android browsers (default one and Dolphin) seem to have the same issue, see: #613
7058							_preloadAndSend.call(target, meta, data);
7059							return; // _preloadAndSend will reinvoke send() with transmutated FormData =%D
7060						}	
7061					}
7062
7063					// transfer fields to real FormData
7064					if (data instanceof FormData) { // if still a FormData, e.g. not mangled by _prepareMultipart()
7065						var fd = new window.FormData();
7066						data.each(function(value, name) {
7067							if (value instanceof Blob) {
7068								fd.append(name, value.getSource());
7069							} else {
7070								fd.append(name, value);
7071							}
7072						});
7073						data = fd;
7074					}
7075				}
7076
7077
7078				// if XHR L2
7079				if (_xhr.upload) {
7080					if (meta.withCredentials) {
7081						_xhr.withCredentials = true;
7082					}
7083
7084					_xhr.addEventListener('load', function(e) {
7085						target.trigger(e);
7086					});
7087
7088					_xhr.addEventListener('error', function(e) {
7089						target.trigger(e);
7090					});
7091
7092					// additionally listen to progress events
7093					_xhr.addEventListener('progress', function(e) {
7094						target.trigger(e);
7095					});
7096
7097					_xhr.upload.addEventListener('progress', function(e) {
7098						target.trigger({
7099							type: 'UploadProgress',
7100							loaded: e.loaded,
7101							total: e.total
7102						});
7103					});
7104				// ... otherwise simulate XHR L2
7105				} else {
7106					_xhr.onreadystatechange = function onReadyStateChange() {
7107						
7108						// fake Level 2 events
7109						switch (_xhr.readyState) {
7110							
7111							case 1: // XMLHttpRequest.OPENED
7112								// readystatechanged is fired twice for OPENED state (in IE and Mozilla) - neu
7113								break;
7114							
7115							// looks like HEADERS_RECEIVED (state 2) is not reported in Opera (or it's old versions) - neu
7116							case 2: // XMLHttpRequest.HEADERS_RECEIVED
7117								break;
7118								
7119							case 3: // XMLHttpRequest.LOADING 
7120								// try to fire progress event for not XHR L2
7121								var total, loaded;
7122								
7123								try {
7124									if (Url.hasSameOrigin(meta.url)) { // Content-Length not accessible for cross-domain on some browsers
7125										total = _xhr.getResponseHeader('Content-Length') || 0; // old Safari throws an exception here
7126									}
7127
7128									if (_xhr.responseText) { // responseText was introduced in IE7
7129										loaded = _xhr.responseText.length;
7130									}
7131								} catch(ex) {
7132									total = loaded = 0;
7133								}
7134
7135								target.trigger({
7136									type: 'progress',
7137									lengthComputable: !!total,
7138									total: parseInt(total, 10),
7139									loaded: loaded
7140								});
7141								break;
7142								
7143							case 4: // XMLHttpRequest.DONE
7144								// release readystatechange handler (mostly for IE)
7145								_xhr.onreadystatechange = function() {};
7146
7147								// usually status 0 is returned when server is unreachable, but FF also fails to status 0 for 408 timeout
7148								if (_xhr.status === 0) {
7149									target.trigger('error');
7150								} else {
7151									target.trigger('load');
7152								}							
7153								break;
7154						}
7155					};
7156				}
7157				
7158
7159				// set request headers
7160				if (!Basic.isEmptyObj(meta.headers)) {
7161					Basic.each(meta.headers, function(value, header) {
7162						_xhr.setRequestHeader(header, value);
7163					});
7164				}
7165
7166				// request response type
7167				if ("" !== meta.responseType && 'responseType' in _xhr) {
7168					if ('json' === meta.responseType && !Env.can('return_response_type', 'json')) { // we can fake this one
7169						_xhr.responseType = 'text';
7170					} else {
7171						_xhr.responseType = meta.responseType;
7172					}
7173				}
7174
7175				// send ...
7176				if (!mustSendAsBinary) {
7177					_xhr.send(data);
7178				} else {
7179					if (_xhr.sendAsBinary) { // Gecko
7180						_xhr.sendAsBinary(data);
7181					} else { // other browsers having support for typed arrays
7182						(function() {
7183							// mimic Gecko's sendAsBinary
7184							var ui8a = new Uint8Array(data.length);
7185							for (var i = 0; i < data.length; i++) {
7186								ui8a[i] = (data.charCodeAt(i) & 0xff);
7187							}
7188							_xhr.send(ui8a.buffer);
7189						}());
7190					}
7191				}
7192
7193				target.trigger('loadstart');
7194			},
7195
7196			getStatus: function() {
7197				// according to W3C spec it should return 0 for readyState < 3, but instead it throws an exception
7198				try {
7199					if (_xhr) {
7200						return _xhr.status;
7201					}
7202				} catch(ex) {}
7203				return 0;
7204			},
7205
7206			getResponse: function(responseType) {
7207				var I = this.getRuntime();
7208
7209				try {
7210					switch (responseType) {
7211						case 'blob':
7212							var file = new File(I.uid, _xhr.response);
7213							
7214							// try to extract file name from content-disposition if possible (might be - not, if CORS for example)	
7215							var disposition = _xhr.getResponseHeader('Content-Disposition');
7216							if (disposition) {
7217								// extract filename from response header if available
7218								var match = disposition.match(/filename=([\'\"'])([^\1]+)\1/);
7219								if (match) {
7220									_filename = match[2];
7221								}
7222							}
7223							file.name = _filename;
7224
7225							// pre-webkit Opera doesn't set type property on the blob response
7226							if (!file.type) {
7227								file.type = Mime.getFileMime(_filename);
7228							}
7229							return file;
7230
7231						case 'json':
7232							if (!Env.can('return_response_type', 'json')) {
7233								return _xhr.status === 200 && !!window.JSON ? JSON.parse(_xhr.responseText) : null;
7234							}
7235							return _xhr.response;
7236
7237						case 'document':
7238							return _getDocument(_xhr);
7239
7240						default:
7241							return _xhr.responseText !== '' ? _xhr.responseText : null; // against the specs, but for consistency across the runtimes
7242					}
7243				} catch(ex) {
7244					return null;
7245				}				
7246			},
7247
7248			getAllResponseHeaders: function() {
7249				try {
7250					return _xhr.getAllResponseHeaders();
7251				} catch(ex) {}
7252				return '';
7253			},
7254
7255			abort: function() {
7256				if (_xhr) {
7257					_xhr.abort();
7258				}
7259			},
7260
7261			destroy: function() {
7262				self = _filename = null;
7263			}
7264		});
7265
7266
7267		// here we go... ugly fix for ugly bug
7268		function _preloadAndSend(meta, data) {
7269			var target = this, blob, fr;
7270				
7271			// get original blob
7272			blob = data.getBlob().getSource();
7273			
7274			// preload blob in memory to be sent as binary string
7275			fr = new window.FileReader();
7276			fr.onload = function() {
7277				// overwrite original blob
7278				data.append(data.getBlobName(), new Blob(null, {
7279					type: blob.type,
7280					data: fr.result
7281				}));
7282				// invoke send operation again
7283				self.send.call(target, meta, data);
7284			};
7285			fr.readAsBinaryString(blob);
7286		}
7287
7288		
7289		function _getNativeXHR() {
7290			if (window.XMLHttpRequest && !(Env.browser === 'IE' && Env.verComp(Env.version, 8, '<'))) { // IE7 has native XHR but it's buggy
7291				return new window.XMLHttpRequest();
7292			} else {
7293				return (function() {
7294					var progIDs = ['Msxml2.XMLHTTP.6.0', 'Microsoft.XMLHTTP']; // if 6.0 available, use it, otherwise failback to default 3.0
7295					for (var i = 0; i < progIDs.length; i++) {
7296						try {
7297							return new ActiveXObject(progIDs[i]);
7298						} catch (ex) {}
7299					}
7300				})();
7301			}
7302		}
7303		
7304		// @credits Sergey Ilinsky	(http://www.ilinsky.com/)
7305		function _getDocument(xhr) {
7306			var rXML = xhr.responseXML;
7307			var rText = xhr.responseText;
7308			
7309			// Try parsing responseText (@see: http://www.ilinsky.com/articles/XMLHttpRequest/#bugs-ie-responseXML-content-type)
7310			if (Env.browser === 'IE' && rText && rXML && !rXML.documentElement && /[^\/]+\/[^\+]+\+xml/.test(xhr.getResponseHeader("Content-Type"))) {
7311				rXML = new window.ActiveXObject("Microsoft.XMLDOM");
7312				rXML.async = false;
7313				rXML.validateOnParse = false;
7314				rXML.loadXML(rText);
7315			}
7316	
7317			// Check if there is no error in document
7318			if (rXML) {
7319				if ((Env.browser === 'IE' && rXML.parseError !== 0) || !rXML.documentElement || rXML.documentElement.tagName === "parsererror") {
7320					return null;
7321				}
7322			}
7323			return rXML;
7324		}
7325
7326
7327		function _prepareMultipart(fd) {
7328			var boundary = '----moxieboundary' + new Date().getTime()
7329			, dashdash = '--'
7330			, crlf = '\r\n'
7331			, multipart = ''
7332			, I = this.getRuntime()
7333			;
7334
7335			if (!I.can('send_binary_string')) {
7336				throw new x.RuntimeError(x.RuntimeError.NOT_SUPPORTED_ERR);
7337			}
7338
7339			_xhr.setRequestHeader('Content-Type', 'multipart/form-data; boundary=' + boundary);
7340
7341			// append multipart parameters
7342			fd.each(function(value, name) {
7343				// Firefox 3.6 failed to convert multibyte characters to UTF-8 in sendAsBinary(), 
7344				// so we try it here ourselves with: unescape(encodeURIComponent(value))
7345				if (value instanceof Blob) {
7346					// Build RFC2388 blob
7347					multipart += dashdash + boundary + crlf +
7348						'Content-Disposition: form-data; name="' + name + '"; filename="' + unescape(encodeURIComponent(value.name || 'blob')) + '"' + crlf +
7349						'Content-Type: ' + (value.type || 'application/octet-stream') + crlf + crlf +
7350						value.getSource() + crlf;
7351				} else {
7352					multipart += dashdash + boundary + crlf +
7353						'Content-Disposition: form-data; name="' + name + '"' + crlf + crlf +
7354						unescape(encodeURIComponent(value)) + crlf;
7355				}
7356			});
7357
7358			multipart += dashdash + boundary + dashdash + crlf;
7359
7360			return multipart;
7361		}
7362	}
7363
7364	return (extensions.XMLHttpRequest = XMLHttpRequest);
7365});
7366
7367// Included from: src/javascript/runtime/html5/utils/BinaryReader.js
7368
7369/**
7370 * BinaryReader.js
7371 *
7372 * Copyright 2013, Moxiecode Systems AB
7373 * Released under GPL License.
7374 *
7375 * License: http://www.plupload.com/license
7376 * Contributing: http://www.plupload.com/contributing
7377 */
7378
7379/**
7380@class moxie/runtime/html5/utils/BinaryReader
7381@private
7382*/
7383define("moxie/runtime/html5/utils/BinaryReader", [
7384	"moxie/core/utils/Basic"
7385], function(Basic) {
7386
7387	
7388	function BinaryReader(data) {
7389		if (data instanceof ArrayBuffer) {
7390			ArrayBufferReader.apply(this, arguments);
7391		} else {
7392			UTF16StringReader.apply(this, arguments);
7393		}
7394	}
7395
7396	Basic.extend(BinaryReader.prototype, {
7397		
7398		littleEndian: false,
7399
7400
7401		read: function(idx, size) {
7402			var sum, mv, i;
7403
7404			if (idx + size > this.length()) {
7405				throw new Error("You are trying to read outside the source boundaries.");
7406			}
7407			
7408			mv = this.littleEndian 
7409				? 0 
7410				: -8 * (size - 1)
7411			;
7412
7413			for (i = 0, sum = 0; i < size; i++) {
7414				sum |= (this.readByteAt(idx + i) << Math.abs(mv + i*8));
7415			}
7416			return sum;
7417		},
7418
7419
7420		write: function(idx, num, size) {
7421			var mv, i, str = '';
7422
7423			if (idx > this.length()) {
7424				throw new Error("You are trying to write outside the source boundaries.");
7425			}
7426
7427			mv = this.littleEndian 
7428				? 0 
7429				: -8 * (size - 1)
7430			;
7431
7432			for (i = 0; i < size; i++) {
7433				this.writeByteAt(idx + i, (num >> Math.abs(mv + i*8)) & 255);
7434			}
7435		},
7436
7437
7438		BYTE: function(idx) {
7439			return this.read(idx, 1);
7440		},
7441
7442
7443		SHORT: function(idx) {
7444			return this.read(idx, 2);
7445		},
7446
7447
7448		LONG: function(idx) {
7449			return this.read(idx, 4);
7450		},
7451
7452
7453		SLONG: function(idx) { // 2's complement notation
7454			var num = this.read(idx, 4);
7455			return (num > 2147483647 ? num - 4294967296 : num);
7456		},
7457
7458
7459		CHAR: function(idx) {
7460			return String.fromCharCode(this.read(idx, 1));
7461		},
7462
7463
7464		STRING: function(idx, count) {
7465			return this.asArray('CHAR', idx, count).join('');
7466		},
7467
7468
7469		asArray: function(type, idx, count) {
7470			var values = [];
7471
7472			for (var i = 0; i < count; i++) {
7473				values[i] = this[type](idx + i);
7474			}
7475			return values;
7476		}
7477	});
7478
7479
7480	function ArrayBufferReader(data) {
7481		var _dv = new DataView(data);
7482
7483		Basic.extend(this, {
7484			
7485			readByteAt: function(idx) {
7486				return _dv.getUint8(idx);
7487			},
7488
7489
7490			writeByteAt: function(idx, value) {
7491				_dv.setUint8(idx, value);
7492			},
7493			
7494
7495			SEGMENT: function(idx, size, value) {
7496				switch (arguments.length) {
7497					case 2:
7498						return data.slice(idx, idx + size);
7499
7500					case 1:
7501						return data.slice(idx);
7502
7503					case 3:
7504						if (value === null) {
7505							value = new ArrayBuffer();
7506						}
7507
7508						if (value instanceof ArrayBuffer) {					
7509							var arr = new Uint8Array(this.length() - size + value.byteLength);
7510							if (idx > 0) {
7511								arr.set(new Uint8Array(data.slice(0, idx)), 0);
7512							}
7513							arr.set(new Uint8Array(value), idx);
7514							arr.set(new Uint8Array(data.slice(idx + size)), idx + value.byteLength);
7515
7516							this.clear();
7517							data = arr.buffer;
7518							_dv = new DataView(data);
7519							break;
7520						}
7521
7522					default: return data;
7523				}
7524			},
7525
7526
7527			length: function() {
7528				return data ? data.byteLength : 0;
7529			},
7530
7531
7532			clear: function() {
7533				_dv = data = null;
7534			}
7535		});
7536	}
7537
7538
7539	function UTF16StringReader(data) {
7540		Basic.extend(this, {
7541			
7542			readByteAt: function(idx) {
7543				return data.charCodeAt(idx);
7544			},
7545
7546
7547			writeByteAt: function(idx, value) {
7548				putstr(String.fromCharCode(value), idx, 1);
7549			},
7550
7551
7552			SEGMENT: function(idx, length, segment) {
7553				switch (arguments.length) {
7554					case 1:
7555						return data.substr(idx);
7556					case 2:
7557						return data.substr(idx, length);
7558					case 3:
7559						putstr(segment !== null ? segment : '', idx, length);
7560						break;
7561					default: return data;
7562				}
7563			},
7564
7565
7566			length: function() {
7567				return data ? data.length : 0;
7568			}, 
7569
7570			clear: function() {
7571				data = null;
7572			}
7573		});
7574
7575
7576		function putstr(segment, idx, length) {
7577			length = arguments.length === 3 ? length : data.length - idx - 1;
7578			data = data.substr(0, idx) + segment + data.substr(length + idx);
7579		}
7580	}
7581
7582
7583	return BinaryReader;
7584});
7585
7586// Included from: src/javascript/runtime/html5/image/JPEGHeaders.js
7587
7588/**
7589 * JPEGHeaders.js
7590 *
7591 * Copyright 2013, Moxiecode Systems AB
7592 * Released under GPL License.
7593 *
7594 * License: http://www.plupload.com/license
7595 * Contributing: http://www.plupload.com/contributing
7596 */
7597 
7598/**
7599@class moxie/runtime/html5/image/JPEGHeaders
7600@private
7601*/
7602define("moxie/runtime/html5/image/JPEGHeaders", [
7603	"moxie/runtime/html5/utils/BinaryReader",
7604	"moxie/core/Exceptions"
7605], function(BinaryReader, x) {
7606	
7607	return function JPEGHeaders(data) {
7608		var headers = [], _br, idx, marker, length = 0;
7609
7610		_br = new BinaryReader(data);
7611
7612		// Check if data is jpeg
7613		if (_br.SHORT(0) !== 0xFFD8) {
7614			_br.clear();
7615			throw new x.ImageError(x.ImageError.WRONG_FORMAT);
7616		}
7617
7618		idx = 2;
7619
7620		while (idx <= _br.length()) {
7621			marker = _br.SHORT(idx);
7622
7623			// omit RST (restart) markers
7624			if (marker >= 0xFFD0 && marker <= 0xFFD7) {
7625				idx += 2;
7626				continue;
7627			}
7628
7629			// no headers allowed after SOS marker
7630			if (marker === 0xFFDA || marker === 0xFFD9) {
7631				break;
7632			}
7633
7634			length = _br.SHORT(idx + 2) + 2;
7635
7636			// APPn marker detected
7637			if (marker >= 0xFFE1 && marker <= 0xFFEF) {
7638				headers.push({
7639					hex: marker,
7640					name: 'APP' + (marker & 0x000F),
7641					start: idx,
7642					length: length,
7643					segment: _br.SEGMENT(idx, length)
7644				});
7645			}
7646
7647			idx += length;
7648		}
7649
7650		_br.clear();
7651
7652		return {
7653			headers: headers,
7654
7655			restore: function(data) {
7656				var max, i, br;
7657
7658				br = new BinaryReader(data);
7659
7660				idx = br.SHORT(2) == 0xFFE0 ? 4 + br.SHORT(4) : 2;
7661
7662				for (i = 0, max = headers.length; i < max; i++) {
7663					br.SEGMENT(idx, 0, headers[i].segment);
7664					idx += headers[i].length;
7665				}
7666
7667				data = br.SEGMENT();
7668				br.clear();
7669				return data;
7670			},
7671
7672			strip: function(data) {
7673				var br, headers, jpegHeaders, i;
7674
7675				jpegHeaders = new JPEGHeaders(data);
7676				headers = jpegHeaders.headers;
7677				jpegHeaders.purge();
7678
7679				br = new BinaryReader(data);
7680
7681				i = headers.length;
7682				while (i--) {
7683					br.SEGMENT(headers[i].start, headers[i].length, '');
7684				}
7685				
7686				data = br.SEGMENT();
7687				br.clear();
7688				return data;
7689			},
7690
7691			get: function(name) {
7692				var array = [];
7693
7694				for (var i = 0, max = headers.length; i < max; i++) {
7695					if (headers[i].name === name.toUpperCase()) {
7696						array.push(headers[i].segment);
7697					}
7698				}
7699				return array;
7700			},
7701
7702			set: function(name, segment) {
7703				var array = [], i, ii, max;
7704
7705				if (typeof(segment) === 'string') {
7706					array.push(segment);
7707				} else {
7708					array = segment;
7709				}
7710
7711				for (i = ii = 0, max = headers.length; i < max; i++) {
7712					if (headers[i].name === name.toUpperCase()) {
7713						headers[i].segment = array[ii];
7714						headers[i].length = array[ii].length;
7715						ii++;
7716					}
7717					if (ii >= array.length) {
7718						break;
7719					}
7720				}
7721			},
7722
7723			purge: function() {
7724				this.headers = headers = [];
7725			}
7726		};
7727	};
7728});
7729
7730// Included from: src/javascript/runtime/html5/image/ExifParser.js
7731
7732/**
7733 * ExifParser.js
7734 *
7735 * Copyright 2013, Moxiecode Systems AB
7736 * Released under GPL License.
7737 *
7738 * License: http://www.plupload.com/license
7739 * Contributing: http://www.plupload.com/contributing
7740 */
7741
7742/**
7743@class moxie/runtime/html5/image/ExifParser
7744@private
7745*/
7746define("moxie/runtime/html5/image/ExifParser", [
7747	"moxie/core/utils/Basic",
7748	"moxie/runtime/html5/utils/BinaryReader",
7749	"moxie/core/Exceptions"
7750], function(Basic, BinaryReader, x) {
7751	
7752	function ExifParser(data) {
7753		var __super__, tags, tagDescs, offsets, idx, Tiff;
7754		
7755		BinaryReader.call(this, data);
7756
7757		tags = {
7758			tiff: {
7759				/*
7760				The image orientation viewed in terms of rows and columns.
7761
7762				1 = The 0th row is at the visual top of the image, and the 0th column is the visual left-hand side.
7763				2 = The 0th row is at the visual top of the image, and the 0th column is the visual right-hand side.
7764				3 = The 0th row is at the visual bottom of the image, and the 0th column is the visual right-hand side.
7765				4 = The 0th row is at the visual bottom of the image, and the 0th column is the visual left-hand side.
7766				5 = The 0th row is the visual left-hand side of the image, and the 0th column is the visual top.
7767				6 = The 0th row is the visual right-hand side of the image, and the 0th column is the visual top.
7768				7 = The 0th row is the visual right-hand side of the image, and the 0th column is the visual bottom.
7769				8 = The 0th row is the visual left-hand side of the image, and the 0th column is the visual bottom.
7770				*/
7771				0x0112: 'Orientation',
7772				0x010E: 'ImageDescription',
7773				0x010F: 'Make',
7774				0x0110: 'Model',
7775				0x0131: 'Software',
7776				0x8769: 'ExifIFDPointer',
7777				0x8825:	'GPSInfoIFDPointer'
7778			},
7779			exif: {
7780				0x9000: 'ExifVersion',
7781				0xA001: 'ColorSpace',
7782				0xA002: 'PixelXDimension',
7783				0xA003: 'PixelYDimension',
7784				0x9003: 'DateTimeOriginal',
7785				0x829A: 'ExposureTime',
7786				0x829D: 'FNumber',
7787				0x8827: 'ISOSpeedRatings',
7788				0x9201: 'ShutterSpeedValue',
7789				0x9202: 'ApertureValue'	,
7790				0x9207: 'MeteringMode',
7791				0x9208: 'LightSource',
7792				0x9209: 'Flash',
7793				0x920A: 'FocalLength',
7794				0xA402: 'ExposureMode',
7795				0xA403: 'WhiteBalance',
7796				0xA406: 'SceneCaptureType',
7797				0xA404: 'DigitalZoomRatio',
7798				0xA408: 'Contrast',
7799				0xA409: 'Saturation',
7800				0xA40A: 'Sharpness'
7801			},
7802			gps: {
7803				0x0000: 'GPSVersionID',
7804				0x0001: 'GPSLatitudeRef',
7805				0x0002: 'GPSLatitude',
7806				0x0003: 'GPSLongitudeRef',
7807				0x0004: 'GPSLongitude'
7808			},
7809
7810			thumb: {
7811				0x0201: 'JPEGInterchangeFormat',
7812				0x0202: 'JPEGInterchangeFormatLength'
7813			}
7814		};
7815
7816		tagDescs = {
7817			'ColorSpace': {
7818				1: 'sRGB',
7819				0: 'Uncalibrated'
7820			},
7821
7822			'MeteringMode': {
7823				0: 'Unknown',
7824				1: 'Average',
7825				2: 'CenterWeightedAverage',
7826				3: 'Spot',
7827				4: 'MultiSpot',
7828				5: 'Pattern',
7829				6: 'Partial',
7830				255: 'Other'
7831			},
7832
7833			'LightSource': {
7834				1: 'Daylight',
7835				2: 'Fliorescent',
7836				3: 'Tungsten',
7837				4: 'Flash',
7838				9: 'Fine weather',
7839				10: 'Cloudy weather',
7840				11: 'Shade',
7841				12: 'Daylight fluorescent (D 5700 - 7100K)',
7842				13: 'Day white fluorescent (N 4600 -5400K)',
7843				14: 'Cool white fluorescent (W 3900 - 4500K)',
7844				15: 'White fluorescent (WW 3200 - 3700K)',
7845				17: 'Standard light A',
7846				18: 'Standard light B',
7847				19: 'Standard light C',
7848				20: 'D55',
7849				21: 'D65',
7850				22: 'D75',
7851				23: 'D50',
7852				24: 'ISO studio tungsten',
7853				255: 'Other'
7854			},
7855
7856			'Flash': {
7857				0x0000: 'Flash did not fire',
7858				0x0001: 'Flash fired',
7859				0x0005: 'Strobe return light not detected',
7860				0x0007: 'Strobe return light detected',
7861				0x0009: 'Flash fired, compulsory flash mode',
7862				0x000D: 'Flash fired, compulsory flash mode, return light not detected',
7863				0x000F: 'Flash fired, compulsory flash mode, return light detected',
7864				0x0010: 'Flash did not fire, compulsory flash mode',
7865				0x0018: 'Flash did not fire, auto mode',
7866				0x0019: 'Flash fired, auto mode',
7867				0x001D: 'Flash fired, auto mode, return light not detected',
7868				0x001F: 'Flash fired, auto mode, return light detected',
7869				0x0020: 'No flash function',
7870				0x0041: 'Flash fired, red-eye reduction mode',
7871				0x0045: 'Flash fired, red-eye reduction mode, return light not detected',
7872				0x0047: 'Flash fired, red-eye reduction mode, return light detected',
7873				0x0049: 'Flash fired, compulsory flash mode, red-eye reduction mode',
7874				0x004D: 'Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected',
7875				0x004F: 'Flash fired, compulsory flash mode, red-eye reduction mode, return light detected',
7876				0x0059: 'Flash fired, auto mode, red-eye reduction mode',
7877				0x005D: 'Flash fired, auto mode, return light not detected, red-eye reduction mode',
7878				0x005F: 'Flash fired, auto mode, return light detected, red-eye reduction mode'
7879			},
7880
7881			'ExposureMode': {
7882				0: 'Auto exposure',
7883				1: 'Manual exposure',
7884				2: 'Auto bracket'
7885			},
7886
7887			'WhiteBalance': {
7888				0: 'Auto white balance',
7889				1: 'Manual white balance'
7890			},
7891
7892			'SceneCaptureType': {
7893				0: 'Standard',
7894				1: 'Landscape',
7895				2: 'Portrait',
7896				3: 'Night scene'
7897			},
7898
7899			'Contrast': {
7900				0: 'Normal',
7901				1: 'Soft',
7902				2: 'Hard'
7903			},
7904
7905			'Saturation': {
7906				0: 'Normal',
7907				1: 'Low saturation',
7908				2: 'High saturation'
7909			},
7910
7911			'Sharpness': {
7912				0: 'Normal',
7913				1: 'Soft',
7914				2: 'Hard'
7915			},
7916
7917			// GPS related
7918			'GPSLatitudeRef': {
7919				N: 'North latitude',
7920				S: 'South latitude'
7921			},
7922
7923			'GPSLongitudeRef': {
7924				E: 'East longitude',
7925				W: 'West longitude'
7926			}
7927		};
7928
7929		offsets = {
7930			tiffHeader: 10
7931		};
7932		
7933		idx = offsets.tiffHeader;
7934
7935		__super__ = {
7936			clear: this.clear
7937		};
7938
7939		// Public functions
7940		Basic.extend(this, {
7941			
7942			read: function() {
7943				try {
7944					return ExifParser.prototype.read.apply(this, arguments);
7945				} catch (ex) {
7946					throw new x.ImageError(x.ImageError.INVALID_META_ERR);
7947				}
7948			},
7949
7950
7951			write: function() {
7952				try {
7953					return ExifParser.prototype.write.apply(this, arguments);
7954				} catch (ex) {
7955					throw new x.ImageError(x.ImageError.INVALID_META_ERR);
7956				}
7957			},
7958
7959
7960			UNDEFINED: function() {
7961				return this.BYTE.apply(this, arguments);
7962			},
7963
7964
7965			RATIONAL: function(idx) {
7966				return this.LONG(idx) / this.LONG(idx + 4)
7967			},
7968
7969
7970			SRATIONAL: function(idx) {
7971				return this.SLONG(idx) / this.SLONG(idx + 4)
7972			},
7973
7974			ASCII: function(idx) {
7975				return this.CHAR(idx);
7976			},
7977
7978			TIFF: function() {
7979				return Tiff || null;
7980			},
7981
7982
7983			EXIF: function() {
7984				var Exif = null;
7985
7986				if (offsets.exifIFD) {
7987					try {
7988						Exif = extractTags.call(this, offsets.exifIFD, tags.exif);
7989					} catch(ex) {
7990						return null;
7991					}
7992
7993					// Fix formatting of some tags
7994					if (Exif.ExifVersion && Basic.typeOf(Exif.ExifVersion) === 'array') {
7995						for (var i = 0, exifVersion = ''; i < Exif.ExifVersion.length; i++) {
7996							exifVersion += String.fromCharCode(Exif.ExifVersion[i]);
7997						}
7998						Exif.ExifVersion = exifVersion;
7999					}
8000				}
8001
8002				return Exif;
8003			},
8004
8005
8006			GPS: function() {
8007				var GPS = null;
8008
8009				if (offsets.gpsIFD) {
8010					try {
8011						GPS = extractTags.call(this, offsets.gpsIFD, tags.gps);
8012					} catch (ex) {
8013						return null;
8014					}
8015
8016					// iOS devices (and probably some others) do not put in GPSVersionID tag (why?..)
8017					if (GPS.GPSVersionID && Basic.typeOf(GPS.GPSVersionID) === 'array') {
8018						GPS.GPSVersionID = GPS.GPSVersionID.join('.');
8019					}
8020				}
8021
8022				return GPS;
8023			},
8024
8025
8026			thumb: function() {
8027				if (offsets.IFD1) {
8028					try {
8029						var IFD1Tags = extractTags.call(this, offsets.IFD1, tags.thumb);
8030						
8031						if ('JPEGInterchangeFormat' in IFD1Tags) {
8032							return this.SEGMENT(offsets.tiffHeader + IFD1Tags.JPEGInterchangeFormat, IFD1Tags.JPEGInterchangeFormatLength);
8033						}
8034					} catch (ex) {}
8035				}
8036				return null;
8037			},
8038
8039
8040			setExif: function(tag, value) {
8041				// Right now only setting of width/height is possible
8042				if (tag !== 'PixelXDimension' && tag !== 'PixelYDimension') { return false; }
8043
8044				return setTag.call(this, 'exif', tag, value);
8045			},
8046
8047
8048			clear: function() {
8049				__super__.clear();
8050				data = tags = tagDescs = Tiff = offsets = __super__ = null;
8051			}
8052		});
8053
8054
8055		// Check if that's APP1 and that it has EXIF
8056		if (this.SHORT(0) !== 0xFFE1 || this.STRING(4, 5).toUpperCase() !== "EXIF\0") {
8057			throw new x.ImageError(x.ImageError.INVALID_META_ERR);
8058		}
8059
8060		// Set read order of multi-byte data
8061		this.littleEndian = (this.SHORT(idx) == 0x4949);
8062
8063		// Check if always present bytes are indeed present
8064		if (this.SHORT(idx+=2) !== 0x002A) {
8065			throw new x.ImageError(x.ImageError.INVALID_META_ERR);
8066		}
8067
8068		offsets.IFD0 = offsets.tiffHeader + this.LONG(idx += 2);
8069		Tiff = extractTags.call(this, offsets.IFD0, tags.tiff);
8070
8071		if ('ExifIFDPointer' in Tiff) {
8072			offsets.exifIFD = offsets.tiffHeader + Tiff.ExifIFDPointer;
8073			delete Tiff.ExifIFDPointer;
8074		}
8075
8076		if ('GPSInfoIFDPointer' in Tiff) {
8077			offsets.gpsIFD = offsets.tiffHeader + Tiff.GPSInfoIFDPointer;
8078			delete Tiff.GPSInfoIFDPointer;
8079		}
8080
8081		if (Basic.isEmptyObj(Tiff)) {
8082			Tiff = null;
8083		}
8084
8085		// check if we have a thumb as well
8086		var IFD1Offset = this.LONG(offsets.IFD0 + this.SHORT(offsets.IFD0) * 12 + 2);
8087		if (IFD1Offset) {
8088			offsets.IFD1 = offsets.tiffHeader + IFD1Offset;
8089		}
8090
8091
8092		function extractTags(IFD_offset, tags2extract) {
8093			var data = this;
8094			var length, i, tag, type, count, size, offset, value, values = [], hash = {};
8095			
8096			var types = {
8097				1 : 'BYTE',
8098				7 : 'UNDEFINED',
8099				2 : 'ASCII',
8100				3 : 'SHORT',
8101				4 : 'LONG',
8102				5 : 'RATIONAL',
8103				9 : 'SLONG',
8104				10: 'SRATIONAL'
8105			};
8106
8107			var sizes = {
8108				'BYTE' 		: 1,
8109				'UNDEFINED'	: 1,
8110				'ASCII'		: 1,
8111				'SHORT'		: 2,
8112				'LONG' 		: 4,
8113				'RATIONAL' 	: 8,
8114				'SLONG'		: 4,
8115				'SRATIONAL'	: 8
8116			};
8117
8118			length = data.SHORT(IFD_offset);
8119
8120			// The size of APP1 including all these elements shall not exceed the 64 Kbytes specified in the JPEG standard.
8121
8122			for (i = 0; i < length; i++) {
8123				values = [];
8124
8125				// Set binary reader pointer to beginning of the next tag
8126				offset = IFD_offset + 2 + i*12;
8127
8128				tag = tags2extract[data.SHORT(offset)];
8129
8130				if (tag === undefined) {
8131					continue; // Not the tag we requested
8132				}
8133
8134				type = types[data.SHORT(offset+=2)];
8135				count = data.LONG(offset+=2);
8136				size = sizes[type];
8137
8138				if (!size) {
8139					throw new x.ImageError(x.ImageError.INVALID_META_ERR);
8140				}
8141
8142				offset += 4;
8143
8144				// tag can only fit 4 bytes of data, if data is larger we should look outside
8145				if (size * count > 4) {
8146					// instead of data tag contains an offset of the data
8147					offset = data.LONG(offset) + offsets.tiffHeader;
8148				}
8149
8150				// in case we left the boundaries of data throw an early exception
8151				if (offset + size * count >= this.length()) {
8152					throw new x.ImageError(x.ImageError.INVALID_META_ERR);
8153				} 
8154
8155				// special care for the string
8156				if (type === 'ASCII') {
8157					hash[tag] = Basic.trim(data.STRING(offset, count).replace(/\0$/, '')); // strip trailing NULL
8158					continue;
8159				} else {
8160					values = data.asArray(type, offset, count);
8161					value = (count == 1 ? values[0] : values);
8162
8163					if (tagDescs.hasOwnProperty(tag) && typeof value != 'object') {
8164						hash[tag] = tagDescs[tag][value];
8165					} else {
8166						hash[tag] = value;
8167					}
8168				}
8169			}
8170
8171			return hash;
8172		}
8173
8174		// At the moment only setting of simple (LONG) values, that do not require offset recalculation, is supported
8175		function setTag(ifd, tag, value) {
8176			var offset, length, tagOffset, valueOffset = 0;
8177
8178			// If tag name passed translate into hex key
8179			if (typeof(tag) === 'string') {
8180				var tmpTags = tags[ifd.toLowerCase()];
8181				for (var hex in tmpTags) {
8182					if (tmpTags[hex] === tag) {
8183						tag = hex;
8184						break;
8185					}
8186				}
8187			}
8188			offset = offsets[ifd.toLowerCase() + 'IFD'];
8189			length = this.SHORT(offset);
8190
8191			for (var i = 0; i < length; i++) {
8192				tagOffset = offset + 12 * i + 2;
8193
8194				if (this.SHORT(tagOffset) == tag) {
8195					valueOffset = tagOffset + 8;
8196					break;
8197				}
8198			}
8199
8200			if (!valueOffset) {
8201				return false;
8202			}
8203
8204			try {
8205				this.write(valueOffset, value, 4);
8206			} catch(ex) {
8207				return false;
8208			}
8209
8210			return true;
8211		}
8212	}
8213
8214	ExifParser.prototype = BinaryReader.prototype;
8215
8216	return ExifParser;
8217});
8218
8219// Included from: src/javascript/runtime/html5/image/JPEG.js
8220
8221/**
8222 * JPEG.js
8223 *
8224 * Copyright 2013, Moxiecode Systems AB
8225 * Released under GPL License.
8226 *
8227 * License: http://www.plupload.com/license
8228 * Contributing: http://www.plupload.com/contributing
8229 */
8230
8231/**
8232@class moxie/runtime/html5/image/JPEG
8233@private
8234*/
8235define("moxie/runtime/html5/image/JPEG", [
8236	"moxie/core/utils/Basic",
8237	"moxie/core/Exceptions",
8238	"moxie/runtime/html5/image/JPEGHeaders",
8239	"moxie/runtime/html5/utils/BinaryReader",
8240	"moxie/runtime/html5/image/ExifParser"
8241], function(Basic, x, JPEGHeaders, BinaryReader, ExifParser) {
8242	
8243	function JPEG(data) {
8244		var _br, _hm, _ep, _info;
8245
8246		_br = new BinaryReader(data);
8247
8248		// check if it is jpeg
8249		if (_br.SHORT(0) !== 0xFFD8) {
8250			throw new x.ImageError(x.ImageError.WRONG_FORMAT);
8251		}
8252
8253		// backup headers
8254		_hm = new JPEGHeaders(data);
8255
8256		// extract exif info
8257		try {
8258			_ep = new ExifParser(_hm.get('app1')[0]);
8259		} catch(ex) {}
8260
8261		// get dimensions
8262		_info = _getDimensions.call(this);
8263
8264		Basic.extend(this, {
8265			type: 'image/jpeg',
8266
8267			size: _br.length(),
8268
8269			width: _info && _info.width || 0,
8270
8271			height: _info && _info.height || 0,
8272
8273			setExif: function(tag, value) {
8274				if (!_ep) {
8275					return false; // or throw an exception
8276				}
8277
8278				if (Basic.typeOf(tag) === 'object') {
8279					Basic.each(tag, function(value, tag) {
8280						_ep.setExif(tag, value);
8281					});
8282				} else {
8283					_ep.setExif(tag, value);
8284				}
8285
8286				// update internal headers
8287				_hm.set('app1', _ep.SEGMENT());
8288			},
8289
8290			writeHeaders: function() {
8291				if (!arguments.length) {
8292					// if no arguments passed, update headers internally
8293					return _hm.restore(data);
8294				}
8295				return _hm.restore(arguments[0]);
8296			},
8297
8298			stripHeaders: function(data) {
8299				return _hm.strip(data);
8300			},
8301
8302			purge: function() {
8303				_purge.call(this);
8304			}
8305		});
8306
8307		if (_ep) {
8308			this.meta = {
8309				tiff: _ep.TIFF(),
8310				exif: _ep.EXIF(),
8311				gps: _ep.GPS(),
8312				thumb: _getThumb()
8313			};
8314		}
8315
8316
8317		function _getDimensions(br) {
8318			var idx = 0
8319			, marker
8320			, length
8321			;
8322
8323			if (!br) {
8324				br = _br;
8325			}
8326
8327			// examine all through the end, since some images might have very large APP segments
8328			while (idx <= br.length()) {
8329				marker = br.SHORT(idx += 2);
8330
8331				if (marker >= 0xFFC0 && marker <= 0xFFC3) { // SOFn
8332					idx += 5; // marker (2 bytes) + length (2 bytes) + Sample precision (1 byte)
8333					return {
8334						height: br.SHORT(idx),
8335						width: br.SHORT(idx += 2)
8336					};
8337				}
8338				length = br.SHORT(idx += 2);
8339				idx += length - 2;
8340			}
8341			return null;
8342		}
8343
8344
8345		function _getThumb() {
8346			var data =  _ep.thumb()
8347			, br
8348			, info
8349			;
8350
8351			if (data) {
8352				br = new BinaryReader(data);
8353				info = _getDimensions(br);
8354				br.clear();
8355
8356				if (info) {
8357					info.data = data;
8358					return info;
8359				}
8360			}
8361			return null;
8362		}
8363
8364
8365		function _purge() {
8366			if (!_ep || !_hm || !_br) { 
8367				return; // ignore any repeating purge requests
8368			}
8369			_ep.clear();
8370			_hm.purge();
8371			_br.clear();
8372			_info = _hm = _ep = _br = null;
8373		}
8374	}
8375
8376	return JPEG;
8377});
8378
8379// Included from: src/javascript/runtime/html5/image/PNG.js
8380
8381/**
8382 * PNG.js
8383 *
8384 * Copyright 2013, Moxiecode Systems AB
8385 * Released under GPL License.
8386 *
8387 * License: http://www.plupload.com/license
8388 * Contributing: http://www.plupload.com/contributing
8389 */
8390
8391/**
8392@class moxie/runtime/html5/image/PNG
8393@private
8394*/
8395define("moxie/runtime/html5/image/PNG", [
8396	"moxie/core/Exceptions",
8397	"moxie/core/utils/Basic",
8398	"moxie/runtime/html5/utils/BinaryReader"
8399], function(x, Basic, BinaryReader) {
8400	
8401	function PNG(data) {
8402		var _br, _hm, _ep, _info;
8403
8404		_br = new BinaryReader(data);
8405
8406		// check if it's png
8407		(function() {
8408			var idx = 0, i = 0
8409			, signature = [0x8950, 0x4E47, 0x0D0A, 0x1A0A]
8410			;
8411
8412			for (i = 0; i < signature.length; i++, idx += 2) {
8413				if (signature[i] != _br.SHORT(idx)) {
8414					throw new x.ImageError(x.ImageError.WRONG_FORMAT);
8415				}
8416			}
8417		}());
8418
8419		function _getDimensions() {
8420			var chunk, idx;
8421
8422			chunk = _getChunkAt.call(this, 8);
8423
8424			if (chunk.type == 'IHDR') {
8425				idx = chunk.start;
8426				return {
8427					width: _br.LONG(idx),
8428					height: _br.LONG(idx += 4)
8429				};
8430			}
8431			return null;
8432		}
8433
8434		function _purge() {
8435			if (!_br) {
8436				return; // ignore any repeating purge requests
8437			}
8438			_br.clear();
8439			data = _info = _hm = _ep = _br = null;
8440		}
8441
8442		_info = _getDimensions.call(this);
8443
8444		Basic.extend(this, {
8445			type: 'image/png',
8446
8447			size: _br.length(),
8448
8449			width: _info.width,
8450
8451			height: _info.height,
8452
8453			purge: function() {
8454				_purge.call(this);
8455			}
8456		});
8457
8458		// for PNG we can safely trigger purge automatically, as we do not keep any data for later
8459		_purge.call(this);
8460
8461		function _getChunkAt(idx) {
8462			var length, type, start, CRC;
8463
8464			length = _br.LONG(idx);
8465			type = _br.STRING(idx += 4, 4);
8466			start = idx += 4;
8467			CRC = _br.LONG(idx + length);
8468
8469			return {
8470				length: length,
8471				type: type,
8472				start: start,
8473				CRC: CRC
8474			};
8475		}
8476	}
8477
8478	return PNG;
8479});
8480
8481// Included from: src/javascript/runtime/html5/image/ImageInfo.js
8482
8483/**
8484 * ImageInfo.js
8485 *
8486 * Copyright 2013, Moxiecode Systems AB
8487 * Released under GPL License.
8488 *
8489 * License: http://www.plupload.com/license
8490 * Contributing: http://www.plupload.com/contributing
8491 */
8492
8493/**
8494@class moxie/runtime/html5/image/ImageInfo
8495@private
8496*/
8497define("moxie/runtime/html5/image/ImageInfo", [
8498	"moxie/core/utils/Basic",
8499	"moxie/core/Exceptions",
8500	"moxie/runtime/html5/image/JPEG",
8501	"moxie/runtime/html5/image/PNG"
8502], function(Basic, x, JPEG, PNG) {
8503	/**
8504	Optional image investigation tool for HTML5 runtime. Provides the following features:
8505	- ability to distinguish image type (JPEG or PNG) by signature
8506	- ability to extract image width/height directly from it's internals, without preloading in memory (fast)
8507	- ability to extract APP headers from JPEGs (Exif, GPS, etc)
8508	- ability to replace width/height tags in extracted JPEG headers
8509	- ability to restore APP headers, that were for example stripped during image manipulation
8510
8511	@class ImageInfo
8512	@constructor
8513	@param {String} data Image source as binary string
8514	*/
8515	return function(data) {
8516		var _cs = [JPEG, PNG], _img;
8517
8518		// figure out the format, throw: ImageError.WRONG_FORMAT if not supported
8519		_img = (function() {
8520			for (var i = 0; i < _cs.length; i++) {
8521				try {
8522					return new _cs[i](data);
8523				} catch (ex) {
8524					// console.info(ex);
8525				}
8526			}
8527			throw new x.ImageError(x.ImageError.WRONG_FORMAT);
8528		}());
8529
8530		Basic.extend(this, {
8531			/**
8532			Image Mime Type extracted from it's depths
8533
8534			@property type
8535			@type {String}
8536			@default ''
8537			*/
8538			type: '',
8539
8540			/**
8541			Image size in bytes
8542
8543			@property size
8544			@type {Number}
8545			@default 0
8546			*/
8547			size: 0,
8548
8549			/**
8550			Image width extracted from image source
8551
8552			@property width
8553			@type {Number}
8554			@default 0
8555			*/
8556			width: 0,
8557
8558			/**
8559			Image height extracted from image source
8560
8561			@property height
8562			@type {Number}
8563			@default 0
8564			*/
8565			height: 0,
8566
8567			/**
8568			Sets Exif tag. Currently applicable only for width and height tags. Obviously works only with JPEGs.
8569
8570			@method setExif
8571			@param {String} tag Tag to set
8572			@param {Mixed} value Value to assign to the tag
8573			*/
8574			setExif: function() {},
8575
8576			/**
8577			Restores headers to the source.
8578
8579			@method writeHeaders
8580			@param {String} data Image source as binary string
8581			@return {String} Updated binary string
8582			*/
8583			writeHeaders: function(data) {
8584				return data;
8585			},
8586
8587			/**
8588			Strip all headers from the source.
8589
8590			@method stripHeaders
8591			@param {String} data Image source as binary string
8592			@return {String} Updated binary string
8593			*/
8594			stripHeaders: function(data) {
8595				return data;
8596			},
8597
8598			/**
8599			Dispose resources.
8600
8601			@method purge
8602			*/
8603			purge: function() {
8604				data = null;
8605			}
8606		});
8607
8608		Basic.extend(this, _img);
8609
8610		this.purge = function() {
8611			_img.purge();
8612			_img = null;
8613		};
8614	};
8615});
8616
8617// Included from: src/javascript/runtime/html5/image/MegaPixel.js
8618
8619/**
8620(The MIT License)
8621
8622Copyright (c) 2012 Shinichi Tomita <[email protected]>;
8623
8624Permission is hereby granted, free of charge, to any person obtaining
8625a copy of this software and associated documentation files (the
8626'Software'), to deal in the Software without restriction, including
8627without limitation the rights to use, copy, modify, merge, publish,
8628distribute, sublicense, and/or sell copies of the Software, and to
8629permit persons to whom the Software is furnished to do so, subject to
8630the following conditions:
8631
8632The above copyright notice and this permission notice shall be
8633included in all copies or substantial portions of the Software.
8634
8635THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
8636EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
8637MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
8638IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
8639CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
8640TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
8641SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8642*/
8643
8644/**
8645 * Mega pixel image rendering library for iOS6 Safari
8646 *
8647 * Fixes iOS6 Safari's image file rendering issue for large size image (over mega-pixel),
8648 * which causes unexpected subsampling when drawing it in canvas.
8649 * By using this library, you can safely render the image with proper stretching.
8650 *
8651 * Copyright (c) 2012 Shinichi Tomita <[email protected]>
8652 * Released under the MIT license
8653 */
8654
8655/**
8656@class moxie/runtime/html5/image/MegaPixel
8657@private
8658*/
8659define("moxie/runtime/html5/image/MegaPixel", [], function() {
8660
8661	/**
8662	 * Rendering image element (with resizing) into the canvas element
8663	 */
8664	function renderImageToCanvas(img, canvas, options) {
8665		var iw = img.naturalWidth, ih = img.naturalHeight;
8666		var width = options.width, height = options.height;
8667		var x = options.x || 0, y = options.y || 0;
8668		var ctx = canvas.getContext('2d');
8669		if (detectSubsampling(img)) {
8670			iw /= 2;
8671			ih /= 2;
8672		}
8673		var d = 1024; // size of tiling canvas
8674		var tmpCanvas = document.createElement('canvas');
8675		tmpCanvas.width = tmpCanvas.height = d;
8676		var tmpCtx = tmpCanvas.getContext('2d');
8677		var vertSquashRatio = detectVerticalSquash(img, iw, ih);
8678		var sy = 0;
8679		while (sy < ih) {
8680			var sh = sy + d > ih ? ih - sy : d;
8681			var sx = 0;
8682			while (sx < iw) {
8683				var sw = sx + d > iw ? iw - sx : d;
8684				tmpCtx.clearRect(0, 0, d, d);
8685				tmpCtx.drawImage(img, -sx, -sy);
8686				var dx = (sx * width / iw + x) << 0;
8687				var dw = Math.ceil(sw * width / iw);
8688				var dy = (sy * height / ih / vertSquashRatio + y) << 0;
8689				var dh = Math.ceil(sh * height / ih / vertSquashRatio);
8690				ctx.drawImage(tmpCanvas, 0, 0, sw, sh, dx, dy, dw, dh);
8691				sx += d;
8692			}
8693			sy += d;
8694		}
8695		tmpCanvas = tmpCtx = null;
8696	}
8697
8698	/**
8699	 * Detect subsampling in loaded image.
8700	 * In iOS, larger images than 2M pixels may be subsampled in rendering.
8701	 */
8702	function detectSubsampling(img) {
8703		var iw = img.naturalWidth, ih = img.naturalHeight;
8704		if (iw * ih > 1024 * 1024) { // subsampling may happen over megapixel image
8705			var canvas = document.createElement('canvas');
8706			canvas.width = canvas.height = 1;
8707			var ctx = canvas.getContext('2d');
8708			ctx.drawImage(img, -iw + 1, 0);
8709			// subsampled image becomes half smaller in rendering size.
8710			// check alpha channel value to confirm image is covering edge pixel or not.
8711			// if alpha value is 0 image is not covering, hence subsampled.
8712			return ctx.getImageData(0, 0, 1, 1).data[3] === 0;
8713		} else {
8714			return false;
8715		}
8716	}
8717
8718
8719	/**
8720	 * Detecting vertical squash in loaded image.
8721	 * Fixes a bug which squash image vertically while drawing into canvas for some images.
8722	 */
8723	function detectVerticalSquash(img, iw, ih) {
8724		var canvas = document.createElement('canvas');
8725		canvas.width = 1;
8726		canvas.height = ih;
8727		var ctx = canvas.getContext('2d');
8728		ctx.drawImage(img, 0, 0);
8729		var data = ctx.getImageData(0, 0, 1, ih).data;
8730		// search image edge pixel position in case it is squashed vertically.
8731		var sy = 0;
8732		var ey = ih;
8733		var py = ih;
8734		while (py > sy) {
8735			var alpha = data[(py - 1) * 4 + 3];
8736			if (alpha === 0) {
8737				ey = py;
8738			} else {
8739			sy = py;
8740			}
8741			py = (ey + sy) >> 1;
8742		}
8743		canvas = null;
8744		var ratio = (py / ih);
8745		return (ratio === 0) ? 1 : ratio;
8746	}
8747
8748	return {
8749		isSubsampled: detectSubsampling,
8750		renderTo: renderImageToCanvas
8751	};
8752});
8753
8754// Included from: src/javascript/runtime/html5/image/Image.js
8755
8756/**
8757 * Image.js
8758 *
8759 * Copyright 2013, Moxiecode Systems AB
8760 * Released under GPL License.
8761 *
8762 * License: http://www.plupload.com/license
8763 * Contributing: http://www.plupload.com/contributing
8764 */
8765
8766/**
8767@class moxie/runtime/html5/image/Image
8768@private
8769*/
8770define("moxie/runtime/html5/image/Image", [
8771	"moxie/runtime/html5/Runtime",
8772	"moxie/core/utils/Basic",
8773	"moxie/core/Exceptions",
8774	"moxie/core/utils/Encode",
8775	"moxie/file/Blob",
8776	"moxie/file/File",
8777	"moxie/runtime/html5/image/ImageInfo",
8778	"moxie/runtime/html5/image/MegaPixel",
8779	"moxie/core/utils/Mime",
8780	"moxie/core/utils/Env"
8781], function(extensions, Basic, x, Encode, Blob, File, ImageInfo, MegaPixel, Mime, Env) {
8782	
8783	function HTML5Image() {
8784		var me = this
8785		, _img, _imgInfo, _canvas, _binStr, _blob
8786		, _modified = false // is set true whenever image is modified
8787		, _preserveHeaders = true
8788		;
8789
8790		Basic.extend(this, {
8791			loadFromBlob: function(blob) {
8792				var comp = this, I = comp.getRuntime()
8793				, asBinary = arguments.length > 1 ? arguments[1] : true
8794				;
8795
8796				if (!I.can('access_binary')) {
8797					throw new x.RuntimeError(x.RuntimeError.NOT_SUPPORTED_ERR);
8798				}
8799
8800				_blob = blob;
8801
8802				if (blob.isDetached()) {
8803					_binStr = blob.getSource();
8804					_preload.call(this, _binStr);
8805					return;
8806				} else {
8807					_readAsDataUrl.call(this, blob.getSource(), function(dataUrl) {
8808						if (asBinary) {
8809							_binStr = _toBinary(dataUrl);
8810						}
8811						_preload.call(comp, dataUrl);
8812					});
8813				}
8814			},
8815
8816			loadFromImage: function(img, exact) {
8817				this.meta = img.meta;
8818
8819				_blob = new File(null, {
8820					name: img.name,
8821					size: img.size,
8822					type: img.type
8823				});
8824
8825				_preload.call(this, exact ? (_binStr = img.getAsBinaryString()) : img.getAsDataURL());
8826			},
8827
8828			getInfo: function() {
8829				var I = this.getRuntime(), info;
8830
8831				if (!_imgInfo && _binStr && I.can('access_image_binary')) {
8832					_imgInfo = new ImageInfo(_binStr);
8833				}
8834
8835				info = {
8836					width: _getImg().width || 0,
8837					height: _getImg().height || 0,
8838					type: _blob.type || Mime.getFileMime(_blob.name),
8839					size: _binStr && _binStr.length || _blob.size || 0,
8840					name: _blob.name || '',
8841					meta: _imgInfo && _imgInfo.meta || this.meta || {}
8842				};
8843
8844				// store thumbnail data as blob
8845				if (info.meta && info.meta.thumb && !(info.meta.thumb.data instanceof Blob)) {
8846					info.meta.thumb.data = new Blob(null, {
8847						type: 'image/jpeg',
8848						data: info.meta.thumb.data
8849					});
8850				}
8851
8852				return info;
8853			},
8854
8855			downsize: function() {
8856				_downsize.apply(this, arguments);
8857			},
8858
8859			getAsCanvas: function() {
8860				if (_canvas) {
8861					_canvas.id = this.uid + '_canvas';
8862				}
8863				return _canvas;
8864			},
8865
8866			getAsBlob: function(type, quality) {
8867				if (type !== this.type) {
8868					// if different mime type requested prepare image for conversion
8869					_downsize.call(this, this.width, this.height, false);
8870				}
8871				return new File(null, {
8872					name: _blob.name || '',
8873					type: type,
8874					data: me.getAsBinaryString.call(this, type, quality)
8875				});
8876			},
8877
8878			getAsDataURL: function(type) {
8879				var quality = arguments[1] || 90;
8880
8881				// if image has not been modified, return the source right away
8882				if (!_modified) {
8883					return _img.src;
8884				}
8885
8886				if ('image/jpeg' !== type) {
8887					return _canvas.toDataURL('image/png');
8888				} else {
8889					try {
8890						// older Geckos used to result in an exception on quality argument
8891						return _canvas.toDataURL('image/jpeg', quality/100);
8892					} catch (ex) {
8893						return _canvas.toDataURL('image/jpeg');
8894					}
8895				}
8896			},
8897
8898			getAsBinaryString: function(type, quality) {
8899				// if image has not been modified, return the source right away
8900				if (!_modified) {
8901					// if image was not loaded from binary string
8902					if (!_binStr) {
8903						_binStr = _toBinary(me.getAsDataURL(type, quality));
8904					}
8905					return _binStr;
8906				}
8907
8908				if ('image/jpeg' !== type) {
8909					_binStr = _toBinary(me.getAsDataURL(type, quality));
8910				} else {
8911					var dataUrl;
8912
8913					// if jpeg
8914					if (!quality) {
8915						quality = 90;
8916					}
8917
8918					try {
8919						// older Geckos used to result in an exception on quality argument
8920						dataUrl = _canvas.toDataURL('image/jpeg', quality/100);
8921					} catch (ex) {
8922						dataUrl = _canvas.toDataURL('image/jpeg');
8923					}
8924
8925					_binStr = _toBinary(dataUrl);
8926
8927					if (_imgInfo) {
8928						_binStr = _imgInfo.stripHeaders(_binStr);
8929
8930						if (_preserveHeaders) {
8931							// update dimensions info in exif
8932							if (_imgInfo.meta && _imgInfo.meta.exif) {
8933								_imgInfo.setExif({
8934									PixelXDimension: this.width,
8935									PixelYDimension: this.height
8936								});
8937							}
8938
8939							// re-inject the headers
8940							_binStr = _imgInfo.writeHeaders(_binStr);
8941						}
8942
8943						// will be re-created from fresh on next getInfo call
8944						_imgInfo.purge();
8945						_imgInfo = null;
8946					}
8947				}
8948
8949				_modified = false;
8950
8951				return _binStr;
8952			},
8953
8954			destroy: function() {
8955				me = null;
8956				_purge.call(this);
8957				this.getRuntime().getShim().removeInstance(this.uid);
8958			}
8959		});
8960
8961
8962		function _getImg() {
8963			if (!_canvas && !_img) {
8964				throw new x.ImageError(x.DOMException.INVALID_STATE_ERR);
8965			}
8966			return _canvas || _img;
8967		}
8968
8969
8970		function _toBinary(str) {
8971			return Encode.atob(str.substring(str.indexOf('base64,') + 7));
8972		}
8973
8974
8975		function _toDataUrl(str, type) {
8976			return 'data:' + (type || '') + ';base64,' + Encode.btoa(str);
8977		}
8978
8979
8980		function _preload(str) {
8981			var comp = this;
8982
8983			_img = new Image();
8984			_img.onerror = function() {
8985				_purge.call(this);
8986				comp.trigger('error', x.ImageError.WRONG_FORMAT);
8987			};
8988			_img.onload = function() {
8989				comp.trigger('load');
8990			};
8991
8992			_img.src = str.substr(0, 5) == 'data:' ? str : _toDataUrl(str, _blob.type);
8993		}
8994
8995
8996		function _readAsDataUrl(file, callback) {
8997			var comp = this, fr;
8998
8999			// use FileReader if it's available
9000			if (window.FileReader) {
9001				fr = new FileReader();
9002				fr.onload = function() {
9003					callback(this.result);
9004				};
9005				fr.onerror = function() {
9006					comp.trigger('error', x.ImageError.WRONG_FORMAT);
9007				};
9008				fr.readAsDataURL(file);
9009			} else {
9010				return callback(file.getAsDataURL());
9011			}
9012		}
9013
9014		function _downsize(width, height, crop, preserveHeaders) {
9015			var self = this
9016			, scale
9017			, mathFn
9018			, x = 0
9019			, y = 0
9020			, img
9021			, destWidth
9022			, destHeight
9023			, orientation
9024			;
9025
9026			_preserveHeaders = preserveHeaders; // we will need to check this on export (see getAsBinaryString())
9027
9028			// take into account orientation tag
9029			orientation = (this.meta && this.meta.tiff && this.meta.tiff.Orientation) || 1;
9030
9031			if (Basic.inArray(orientation, [5,6,7,8]) !== -1) { // values that require 90 degree rotation
9032				// swap dimensions
9033				var tmp = width;
9034				width = height;
9035				height = tmp;
9036			}
9037
9038			img = _getImg();
9039
9040			// unify dimensions
9041			if (!crop) {
9042				scale = Math.min(width/img.width, height/img.height);
9043			} else {
9044				// one of the dimensions may exceed the actual image dimensions - we need to take the smallest value
9045				width = Math.min(width, img.width);
9046				height = Math.min(height, img.height);
9047
9048				scale = Math.max(width/img.width, height/img.height);
9049			}
9050		
9051			// we only downsize here
9052			if (scale > 1 && !crop && preserveHeaders) {
9053				this.trigger('Resize');
9054				return;
9055			}
9056
9057			// prepare canvas if necessary
9058			if (!_canvas) {
9059				_canvas = document.createElement("canvas");
9060			}
9061
9062			// calculate dimensions of proportionally resized image
9063			destWidth = Math.round(img.width * scale);	
9064			destHeight = Math.round(img.height * scale);
9065
9066			// scale image and canvas
9067			if (crop) {
9068				_canvas.width = width;
9069				_canvas.height = height;
9070
9071				// if dimensions of the resulting image still larger than canvas, center it
9072				if (destWidth > width) {
9073					x = Math.round((destWidth - width) / 2);
9074				}
9075
9076				if (destHeight > height) {
9077					y = Math.round((destHeight - height) / 2);
9078				}
9079			} else {
9080				_canvas.width = destWidth;
9081				_canvas.height = destHeight;
9082			}
9083
9084			// rotate if required, according to orientation tag
9085			if (!_preserveHeaders) {
9086				_rotateToOrientaion(_canvas.width, _canvas.height, orientation);
9087			}
9088
9089			_drawToCanvas.call(this, img, _canvas, -x, -y, destWidth, destHeight);
9090
9091			this.width = _canvas.width;
9092			this.height = _canvas.height;
9093
9094			_modified = true;
9095			self.trigger('Resize');
9096		}
9097
9098
9099		function _drawToCanvas(img, canvas, x, y, w, h) {
9100			if (Env.OS === 'iOS') { 
9101				// avoid squish bug in iOS6
9102				MegaPixel.renderTo(img, canvas, { width: w, height: h, x: x, y: y });
9103			} else {
9104				var ctx = canvas.getContext('2d');
9105				ctx.drawImage(img, x, y, w, h);
9106			}
9107		}
9108
9109
9110		/**
9111		* Transform canvas coordination according to specified frame size and orientation
9112		* Orientation value is from EXIF tag
9113		* @author Shinichi Tomita <[email protected]>
9114		*/
9115		function _rotateToOrientaion(width, height, orientation) {
9116			switch (orientation) {
9117				case 5:
9118				case 6:
9119				case 7:
9120				case 8:
9121					_canvas.width = height;
9122					_canvas.height = width;
9123					break;
9124				default:
9125					_canvas.width = width;
9126					_canvas.height = height;
9127			}
9128
9129			/**
9130			1 = The 0th row is at the visual top of the image, and the 0th column is the visual left-hand side.
9131			2 = The 0th row is at the visual top of the image, and the 0th column is the visual right-hand side.
9132			3 = The 0th row is at the visual bottom of the image, and the 0th column is the visual right-hand side.
9133			4 = The 0th row is at the visual bottom of the image, and the 0th column is the visual left-hand side.
9134			5 = The 0th row is the visual left-hand side of the image, and the 0th column is the visual top.
9135			6 = The 0th row is the visual right-hand side of the image, and the 0th column is the visual top.
9136			7 = The 0th row is the visual right-hand side of the image, and the 0th column is the visual bottom.
9137			8 = The 0th row is the visual left-hand side of the image, and the 0th column is the visual bottom.
9138			*/
9139
9140			var ctx = _canvas.getContext('2d');
9141			switch (orientation) {
9142				case 2:
9143					// horizontal flip
9144					ctx.translate(width, 0);
9145					ctx.scale(-1, 1);
9146					break;
9147				case 3:
9148					// 180 rotate left
9149					ctx.translate(width, height);
9150					ctx.rotate(Math.PI);
9151					break;
9152				case 4:
9153					// vertical flip
9154					ctx.translate(0, height);
9155					ctx.scale(1, -1);
9156					break;
9157				case 5:
9158					// vertical flip + 90 rotate right
9159					ctx.rotate(0.5 * Math.PI);
9160					ctx.scale(1, -1);
9161					break;
9162				case 6:
9163					// 90 rotate right
9164					ctx.rotate(0.5 * Math.PI);
9165					ctx.translate(0, -height);
9166					break;
9167				case 7:
9168					// horizontal flip + 90 rotate right
9169					ctx.rotate(0.5 * Math.PI);
9170					ctx.translate(width, -height);
9171					ctx.scale(-1, 1);
9172					break;
9173				case 8:
9174					// 90 rotate left
9175					ctx.rotate(-0.5 * Math.PI);
9176					ctx.translate(-width, 0);
9177					break;
9178			}
9179		}
9180
9181
9182		function _purge() {
9183			if (_imgInfo) {
9184				_imgInfo.purge();
9185				_imgInfo = null;
9186			}
9187			_binStr = _img = _canvas = _blob = null;
9188			_modified = false;
9189		}
9190	}
9191
9192	return (extensions.Image = HTML5Image);
9193});
9194
9195/**
9196 * Stub for moxie/runtime/flash/Runtime
9197 * @private
9198 */
9199define("moxie/runtime/flash/Runtime", [
9200], function() {
9201	return {};
9202});
9203
9204/**
9205 * Stub for moxie/runtime/silverlight/Runtime
9206 * @private
9207 */
9208define("moxie/runtime/silverlight/Runtime", [
9209], function() {
9210	return {};
9211});
9212
9213// Included from: src/javascript/runtime/html4/Runtime.js
9214
9215/**
9216 * Runtime.js
9217 *
9218 * Copyright 2013, Moxiecode Systems AB
9219 * Released under GPL License.
9220 *
9221 * License: http://www.plupload.com/license
9222 * Contributing: http://www.plupload.com/contributing
9223 */
9224
9225/*global File:true */
9226
9227/**
9228Defines constructor for HTML4 runtime.
9229
9230@class moxie/runtime/html4/Runtime
9231@private
9232*/
9233define("moxie/runtime/html4/Runtime", [
9234	"moxie/core/utils/Basic",
9235	"moxie/core/Exceptions",
9236	"moxie/runtime/Runtime",
9237	"moxie/core/utils/Env"
9238], function(Basic, x, Runtime, Env) {
9239	
9240	var type = 'html4', extensions = {};
9241
9242	function Html4Runtime(options) {
9243		var I = this
9244		, Test = Runtime.capTest
9245		, True = Runtime.capTrue
9246		;
9247
9248		Runtime.call(this, options, type, {
9249			access_binary: Test(window.FileReader || window.File && File.getAsDataURL),
9250			access_image_binary: false,
9251			display_media: Test(extensions.Image && (Env.can('create_canvas') || Env.can('use_data_uri_over32kb'))),
9252			do_cors: false,
9253			drag_and_drop: false,
9254			filter_by_extension: Test(function() { // if you know how to feature-detect this, please suggest
9255				return (Env.browser === 'Chrome' && Env.verComp(Env.version, 28, '>=')) || 
9256					(Env.browser === 'IE' && Env.verComp(Env.version, 10, '>=')) || 
9257					(Env.browser === 'Safari' && Env.verComp(Env.version, 7, '>='));
9258			}()),
9259			resize_image: function() {
9260				return extensions.Image && I.can('access_binary') && Env.can('create_canvas');
9261			},
9262			report_upload_progress: false,
9263			return_response_headers: false,
9264			return_response_type: function(responseType) {
9265				if (responseType === 'json' && !!window.JSON) {
9266					return true;
9267				} 
9268				return !!~Basic.inArray(responseType, ['text', 'document', '']);
9269			},
9270			return_status_code: function(code) {
9271				return !Basic.arrayDiff(code, [200, 404]);
9272			},
9273			select_file: function() {
9274				return Env.can('use_fileinput');
9275			},
9276			select_multiple: false,
9277			send_binary_string: false,
9278			send_custom_headers: false,
9279			send_multipart: true,
9280			slice_blob: false,
9281			stream_upload: function() {
9282				return I.can('select_file');
9283			},
9284			summon_file_dialog: function() { // yeah... some dirty sniffing here...
9285				return I.can('select_file') && (
9286					(Env.browser === 'Firefox' && Env.verComp(Env.version, 4, '>=')) ||
9287					(Env.browser === 'Opera' && Env.verComp(Env.version, 12, '>=')) ||
9288					(Env.browser === 'IE' && Env.verComp(Env.version, 10, '>=')) ||
9289					!!~Basic.inArray(Env.browser, ['Chrome', 'Safari'])
9290				);
9291			},
9292			upload_filesize: True,
9293			use_http_method: function(methods) {
9294				return !Basic.arrayDiff(methods, ['GET', 'POST']);
9295			}
9296		});
9297
9298
9299		Basic.extend(this, {
9300			init : function() {
9301				this.trigger("Init");
9302			},
9303
9304			destroy: (function(destroy) { // extend default destroy method
9305				return function() {
9306					destroy.call(I);
9307					destroy = I = null;
9308				};
9309			}(this.destroy))
9310		});
9311
9312		Basic.extend(this.getShim(), extensions);
9313	}
9314
9315	Runtime.addConstructor(type, Html4Runtime);
9316
9317	return extensions;
9318});
9319
9320// Included from: src/javascript/runtime/html4/file/FileInput.js
9321
9322/**
9323 * FileInput.js
9324 *
9325 * Copyright 2013, Moxiecode Systems AB
9326 * Released under GPL License.
9327 *
9328 * License: http://www.plupload.com/license
9329 * Contributing: http://www.plupload.com/contributing
9330 */
9331
9332/**
9333@class moxie/runtime/html4/file/FileInput
9334@private
9335*/
9336define("moxie/runtime/html4/file/FileInput", [
9337	"moxie/runtime/html4/Runtime",
9338	"moxie/file/File",
9339	"moxie/core/utils/Basic",
9340	"moxie/core/utils/Dom",
9341	"moxie/core/utils/Events",
9342	"moxie/core/utils/Mime",
9343	"moxie/core/utils/Env"
9344], function(extensions, File, Basic, Dom, Events, Mime, Env) {
9345	
9346	function FileInput() {
9347		var _uid, _mimes = [], _options;
9348
9349		function addInput() {
9350			var comp = this, I = comp.getRuntime(), shimContainer, browseButton, currForm, form, input, uid;
9351
9352			uid = Basic.guid('uid_');
9353
9354			shimContainer = I.getShimContainer(); // we get new ref everytime to avoid memory leaks in IE
9355
9356			if (_uid) { // move previous form out of the view
9357				currForm = Dom.get(_uid + '_form');
9358				if (currForm) {
9359					Basic.extend(currForm.style, { top: '100%' });
9360				}
9361			}
9362
9363			// build form in DOM, since innerHTML version not able to submit file for some reason
9364			form = document.createElement('form');
9365			form.setAttribute('id', uid + '_form');
9366			form.setAttribute('method', 'post');
9367			form.setAttribute('enctype', 'multipart/form-data');
9368			form.setAttribute('encoding', 'multipart/form-data');
9369
9370			Basic.extend(form.style, {
9371				overflow: 'hidden',
9372				position: 'absolute',
9373				top: 0,
9374				left: 0,
9375				width: '100%',
9376				height: '100%'
9377			});
9378
9379			input = document.createElement('input');
9380			input.setAttribute('id', uid);
9381			input.setAttribute('type', 'file');
9382			input.setAttribute('name', _options.name || 'Filedata');
9383			input.setAttribute('accept', _mimes.join(','));
9384
9385			Basic.extend(input.style, {
9386				fontSize: '999px',
9387				opacity: 0
9388			});
9389
9390			form.appendChild(input);
9391			shimContainer.appendChild(form);
9392
9393			// prepare file input to be placed underneath the browse_button element
9394			Basic.extend(input.style, {
9395				position: 'absolute',
9396				top: 0,
9397				left: 0,
9398				width: '100%',
9399				height: '100%'
9400			});
9401
9402			if (Env.browser === 'IE' && Env.verComp(Env.version, 10, '<')) {
9403				Basic.extend(input.style, {
9404					filter : "progid:DXImageTransform.Microsoft.Alpha(opacity=0)"
9405				});
9406			}
9407
9408			input.onchange = function() { // there should be only one handler for this
9409				var file;
9410
9411				if (!this.value) {
9412					return;
9413				}
9414
9415				if (this.files) { // check if browser is fresh enough
9416					file = this.files[0];
9417
9418					// ignore empty files (IE10 for example hangs if you try to send them via XHR)
9419					if (file.size === 0) {
9420						form.parentNode.removeChild(form);
9421						return;
9422					}
9423				} else {
9424					file = {
9425						name: this.value
9426					};
9427				}
9428
9429				file = new File(I.uid, file);
9430
9431				// clear event handler
9432				this.onchange = function() {}; 
9433				addInput.call(comp); 
9434
9435				comp.files = [file];
9436
9437				// substitute all ids with file uids (consider file.uid read-only - we cannot do it the other way around)
9438				input.setAttribute('id', file.uid);
9439				form.setAttribute('id', file.uid + '_form');
9440				
9441				comp.trigger('change');
9442
9443				input = form = null;
9444			};
9445
9446
9447			// route click event to the input
9448			if (I.can('summon_file_dialog')) {
9449				browseButton = Dom.get(_options.browse_button);
9450				Events.removeEvent(browseButton, 'click', comp.uid);
9451				Events.addEvent(browseButton, 'click', function(e) {
9452					if (input && !input.disabled) { // for some reason FF (up to 8.0.1 so far) lets to click disabled input[type=file]
9453						input.click();
9454					}
9455					e.preventDefault();
9456				}, comp.uid);
9457			}
9458
9459			_uid = uid;
9460
9461			shimContainer = currForm = browseButton = null;
9462		}
9463
9464		Basic.extend(this, {
9465			init: function(options) {
9466				var comp = this, I = comp.getRuntime(), shimContainer;
9467
9468				// figure out accept string
9469				_options = options;
9470				_mimes = options.accept.mimes || Mime.extList2mimes(options.accept, I.can('filter_by_extension'));
9471
9472				shimContainer = I.getShimContainer();
9473
9474				(function() {
9475					var browseButton, zIndex, top;
9476
9477					browseButton = Dom.get(options.browse_button);
9478
9479					// Route click event to the input[type=file] element for browsers that support such behavior
9480					if (I.can('summon_file_dialog')) {
9481						if (Dom.getStyle(browseButton, 'position') === 'static') {
9482							browseButton.style.position = 'relative';
9483						}
9484
9485						zIndex = parseInt(Dom.getStyle(browseButton, 'z-index'), 10) || 1;
9486
9487						browseButton.style.zIndex = zIndex;
9488						shimContainer.style.zIndex = zIndex - 1;
9489					}
9490
9491					/* Since we have to place input[type=file] on top of the browse_button for some browsers,
9492					browse_button loses interactivity, so we restore it here */
9493					top = I.can('summon_file_dialog') ? browseButton : shimContainer;
9494
9495					Events.addEvent(top, 'mouseover', function() {
9496						comp.trigger('mouseenter');
9497					}, comp.uid);
9498
9499					Events.addEvent(top, 'mouseout', function() {
9500						comp.trigger('mouseleave');
9501					}, comp.uid);
9502
9503					Events.addEvent(top, 'mousedown', function() {
9504						comp.trigger('mousedown');
9505					}, comp.uid);
9506
9507					Events.addEvent(Dom.get(options.container), 'mouseup', function() {
9508						comp.trigger('mouseup');
9509					}, comp.uid);
9510
9511					browseButton = null;
9512				}());
9513
9514				addInput.call(this);
9515
9516				shimContainer = null;
9517
9518				// trigger ready event asynchronously
9519				comp.trigger({
9520					type: 'ready',
9521					async: true
9522				});
9523			},
9524
9525
9526			disable: function(state) {
9527				var input;
9528
9529				if ((input = Dom.get(_uid))) {
9530					input.disabled = !!state;
9531				}
9532			},
9533
9534			destroy: function() {
9535				var I = this.getRuntime()
9536				, shim = I.getShim()
9537				, shimContainer = I.getShimContainer()
9538				;
9539				
9540				Events.removeAllEvents(shimContainer, this.uid);
9541				Events.removeAllEvents(_options && Dom.get(_options.container), this.uid);
9542				Events.removeAllEvents(_options && Dom.get(_options.browse_button), this.uid);
9543				
9544				if (shimContainer) {
9545					shimContainer.innerHTML = '';
9546				}
9547
9548				shim.removeInstance(this.uid);
9549
9550				_uid = _mimes = _options = shimContainer = shim = null;
9551			}
9552		});
9553	}
9554
9555	return (extensions.FileInput = FileInput);
9556});
9557
9558// Included from: src/javascript/runtime/html4/file/FileReader.js
9559
9560/**
9561 * FileReader.js
9562 *
9563 * Copyright 2013, Moxiecode Systems AB
9564 * Released under GPL License.
9565 *
9566 * License: http://www.plupload.com/license
9567 * Contributing: http://www.plupload.com/contributing
9568 */
9569
9570/**
9571@class moxie/runtime/html4/file/FileReader
9572@private
9573*/
9574define("moxie/runtime/html4/file/FileReader", [
9575	"moxie/runtime/html4/Runtime",
9576	"moxie/runtime/html5/file/FileReader"
9577], function(extensions, FileReader) {
9578	return (extensions.FileReader = FileReader);
9579});
9580
9581// Included from: src/javascript/runtime/html4/xhr/XMLHttpRequest.js
9582
9583/**
9584 * XMLHttpRequest.js
9585 *
9586 * Copyright 2013, Moxiecode Systems AB
9587 * Released under GPL License.
9588 *
9589 * License: http://www.plupload.com/license
9590 * Contributing: http://www.plupload.com/contributing
9591 */
9592
9593/**
9594@class moxie/runtime/html4/xhr/XMLHttpRequest
9595@private
9596*/
9597define("moxie/runtime/html4/xhr/XMLHttpRequest", [
9598	"moxie/runtime/html4/Runtime",
9599	"moxie/core/utils/Basic",
9600	"moxie/core/utils/Dom",
9601	"moxie/core/utils/Url",
9602	"moxie/core/Exceptions",
9603	"moxie/core/utils/Events",
9604	"moxie/file/Blob",
9605	"moxie/xhr/FormData"
9606], function(extensions, Basic, Dom, Url, x, Events, Blob, FormData) {
9607	
9608	function XMLHttpRequest() {
9609		var _status, _response, _iframe;
9610
9611		function cleanup(cb) {
9612			var target = this, uid, form, inputs, i, hasFile = false;
9613
9614			if (!_iframe) {
9615				return;
9616			}
9617
9618			uid = _iframe.id.replace(/_iframe$/, '');
9619
9620			form = Dom.get(uid + '_form');
9621			if (form) {
9622				inputs = form.getElementsByTagName('input');
9623				i = inputs.length;
9624
9625				while (i--) {
9626					switch (inputs[i].getAttribute('type')) {
9627						case 'hidden':
9628							inputs[i].parentNode.removeChild(inputs[i]);
9629							break;
9630						case 'file':
9631							hasFile = true; // flag the case for later
9632							break;
9633					}
9634				}
9635				inputs = [];
9636
9637				if (!hasFile) { // we need to keep the form for sake of possible retries
9638					form.parentNode.removeChild(form);
9639				}
9640				form = null;
9641			}
9642
9643			// without timeout, request is marked as canceled (in console)
9644			setTimeout(function() {
9645				Events.removeEvent(_iframe, 'load', target.uid);
9646				if (_iframe.parentNode) { // #382
9647					_iframe.parentNode.removeChild(_iframe);
9648				}
9649
9650				// check if shim container has any other children, if - not, remove it as well
9651				var shimContainer = target.getRuntime().getShimContainer();
9652				if (!shimContainer.children.length) {
9653					shimContainer.parentNode.removeChild(shimContainer);
9654				}
9655
9656				shimContainer = _iframe = null;
9657				cb();
9658			}, 1);
9659		}
9660
9661		Basic.extend(this, {
9662			send: function(meta, data) {
9663				var target = this, I = target.getRuntime(), uid, form, input, blob;
9664
9665				_status = _response = null;
9666
9667				function createIframe() {
9668					var container = I.getShimContainer() || document.body
9669					, temp = document.createElement('div')
9670					;
9671
9672					// IE 6 won't be able to set the name using setAttribute or iframe.name
9673					temp.innerHTML = '<iframe id="' + uid + '_iframe" name="' + uid + '_iframe" src="javascript:&quot;&quot;" style="display:none"></iframe>';
9674					_iframe = temp.firstChild;
9675					container.appendChild(_iframe);
9676
9677					/* _iframe.onreadystatechange = function() {
9678						console.info(_iframe.readyState);
9679					};*/
9680
9681					Events.addEvent(_iframe, 'load', function() { // _iframe.onload doesn't work in IE lte 8
9682						var el;
9683
9684						try {
9685							el = _iframe.contentWindow.document || _iframe.contentDocument || window.frames[_iframe.id].document;
9686
9687							// try to detect some standard error pages
9688							if (/^4(0[0-9]|1[0-7]|2[2346])\s/.test(el.title)) { // test if title starts with 4xx HTTP error
9689								_status = el.title.replace(/^(\d+).*$/, '$1');
9690							} else {
9691								_status = 200;
9692								// get result
9693								_response = Basic.trim(el.body.innerHTML);
9694
9695								// we need to fire these at least once
9696								target.trigger({
9697									type: 'progress',
9698									loaded: _response.length,
9699									total: _response.length
9700								});
9701
9702								if (blob) { // if we were uploading a file
9703									target.trigger({
9704										type: 'uploadprogress',
9705										loaded: blob.size || 1025,
9706										total: blob.size || 1025
9707									});
9708								}
9709							}
9710						} catch (ex) {
9711							if (Url.hasSameOrigin(meta.url)) {
9712								// if response is sent with error code, iframe in IE gets redirected to res://ieframe.dll/http_x.htm
9713								// which obviously results to cross domain error (wtf?)
9714								_status = 404;
9715							} else {
9716								cleanup.call(target, function() {
9717									target.trigger('error');
9718								});
9719								return;
9720							}
9721						}	
9722					
9723						cleanup.call(target, function() {
9724							target.trigger('load');
9725						});
9726					}, target.uid);
9727				} // end createIframe
9728
9729				// prepare data to be sent and convert if required
9730				if (data instanceof FormData && data.hasBlob()) {
9731					blob = data.getBlob();
9732					uid = blob.uid;
9733					input = Dom.get(uid);
9734					form = Dom.get(uid + '_form');
9735					if (!form) {
9736						throw new x.DOMException(x.DOMException.NOT_FOUND_ERR);
9737					}
9738				} else {
9739					uid = Basic.guid('uid_');
9740
9741					form = document.createElement('form');
9742					form.setAttribute('id', uid + '_form');
9743					form.setAttribute('method', meta.method);
9744					form.setAttribute('enctype', 'multipart/form-data');
9745					form.setAttribute('encoding', 'multipart/form-data');
9746
9747					I.getShimContainer().appendChild(form);
9748				}
9749
9750				// set upload target
9751				form.setAttribute('target', uid + '_iframe');
9752
9753				if (data instanceof FormData) {
9754					data.each(function(value, name) {
9755						if (value instanceof Blob) {
9756							if (input) {
9757								input.setAttribute('name', name);
9758							}
9759						} else {
9760							var hidden = document.createElement('input');
9761
9762							Basic.extend(hidden, {
9763								type : 'hidden',
9764								name : name,
9765								value : value
9766							});
9767
9768							// make sure that input[type="file"], if it's there, comes last
9769							if (input) {
9770								form.insertBefore(hidden, input);
9771							} else {
9772								form.appendChild(hidden);
9773							}
9774						}
9775					});
9776				}
9777
9778				// set destination url
9779				form.setAttribute("action", meta.url);
9780
9781				createIframe();
9782				form.submit();
9783				target.trigger('loadstart');
9784			},
9785
9786			getStatus: function() {
9787				return _status;
9788			},
9789
9790			getResponse: function(responseType) {
9791				if ('json' === responseType) {
9792					// strip off <pre>..</pre> tags that might be enclosing the response
9793					if (Basic.typeOf(_response) === 'string' && !!window.JSON) {
9794						try {
9795							return JSON.parse(_response.replace(/^\s*<pre[^>]*>/, '').replace(/<\/pre>\s*$/, ''));
9796						} catch (ex) {
9797							return null;
9798						}
9799					} 
9800				} else if ('document' === responseType) {
9801
9802				}
9803				return _response;
9804			},
9805
9806			abort: function() {
9807				var target = this;
9808
9809				if (_iframe && _iframe.contentWindow) {
9810					if (_iframe.contentWindow.stop) { // FireFox/Safari/Chrome
9811						_iframe.contentWindow.stop();
9812					} else if (_iframe.contentWindow.document.execCommand) { // IE
9813						_iframe.contentWindow.document.execCommand('Stop');
9814					} else {
9815						_iframe.src = "about:blank";
9816					}
9817				}
9818
9819				cleanup.call(this, function() {
9820					// target.dispatchEvent('readystatechange');
9821					target.dispatchEvent('abort');
9822				});
9823			}
9824		});
9825	}
9826
9827	return (extensions.XMLHttpRequest = XMLHttpRequest);
9828});
9829
9830// Included from: src/javascript/runtime/html4/image/Image.js
9831
9832/**
9833 * Image.js
9834 *
9835 * Copyright 2013, Moxiecode Systems AB
9836 * Released under GPL License.
9837 *
9838 * License: http://www.plupload.com/license
9839 * Contributing: http://www.plupload.com/contributing
9840 */
9841
9842/**
9843@class moxie/runtime/html4/image/Image
9844@private
9845*/
9846define("moxie/runtime/html4/image/Image", [
9847	"moxie/runtime/html4/Runtime",
9848	"moxie/runtime/html5/image/Image"
9849], function(extensions, Image) {
9850	return (extensions.Image = Image);
9851});
9852
9853expose(["moxie/core/utils/Basic","moxie/core/utils/Env","moxie/core/I18n","moxie/core/utils/Mime","moxie/core/utils/Dom","moxie/core/Exceptions","moxie/core/EventTarget","moxie/runtime/Runtime","moxie/runtime/RuntimeClient","moxie/file/FileInput","moxie/core/utils/Encode","moxie/file/Blob","moxie/file/File","moxie/file/FileDrop","moxie/file/FileReader","moxie/core/utils/Url","moxie/runtime/RuntimeTarget","moxie/file/FileReaderSync","moxie/xhr/FormData","moxie/xhr/XMLHttpRequest","moxie/runtime/Transporter","moxie/image/Image","moxie/core/utils/Events"]);
9854})(this);
9855/**
9856 * o.js
9857 *
9858 * Copyright 2013, Moxiecode Systems AB
9859 * Released under GPL License.
9860 *
9861 * License: http://www.plupload.com/license
9862 * Contributing: http://www.plupload.com/contributing
9863 */
9864
9865/*global moxie:true */
9866
9867/**
9868Globally exposed namespace with the most frequently used public classes and handy methods.
9869
9870@class o
9871@static
9872@private
9873*/
9874(function(exports) {
9875	"use strict";
9876
9877	var o = {}, inArray = exports.moxie.core.utils.Basic.inArray;
9878
9879	// directly add some public classes
9880	// (we do it dynamically here, since for custom builds we cannot know beforehand what modules were included)
9881	(function addAlias(ns) {
9882		var name, itemType;
9883		for (name in ns) {
9884			itemType = typeof(ns[name]);
9885			if (itemType === 'object' && !~inArray(name, ['Exceptions', 'Env', 'Mime'])) {
9886				addAlias(ns[name]);
9887			} else if (itemType === 'function') {
9888				o[name] = ns[name];
9889			}
9890		}
9891	})(exports.moxie);
9892
9893	// add some manually
9894	o.Env = exports.moxie.core.utils.Env;
9895	o.Mime = exports.moxie.core.utils.Mime;
9896	o.Exceptions = exports.moxie.core.Exceptions;
9897
9898	// expose globally
9899	exports.mOxie = o;
9900	if (!exports.o) {
9901		exports.o = o;
9902	}
9903	return o;
9904})(this);

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.