[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/js/plupload/ -> moxie.js (source)

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


Generated : Sun Mar 9 08:20:01 2025 Cross-referenced by PHPXref