balmet.com

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

moxie.js (254084B)


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