home *** CD-ROM | disk | FTP | other *** search
/ HTML Examples / WP.iso / wordpress / wp-includes / js / plupload / moxie.js < prev    next >
Encoding:
JavaScript  |  2017-09-22  |  248.1 KB  |  9,902 lines

  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:""" 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);
  9902.