docs: function(file, fileName) {
  			var self = this
  			, queue = [] 
  			, filesAdded = []
  			, ruid
  			;
  
  			function filterFile(file, cb) {
  				var queue = [];
  				o.each(self.settings.filters, function(rule, name) {
  					if (fileFilters[name]) {
  						queue.push(function(cb) {
  							fileFilters[name].call(self, rule, file, function(res) {
  								cb(!res);
  							});
  						});
  					}
  				});
  				o.inSeries(queue, cb);
  			}
  
  			/**
  			 * @method resolveFile
  			 * @private
  			 * @param {o.File|o.Blob|plupload.File|File|Blob|input[type="file"]} file
  			 */
  			function resolveFile(file) {
  				var type = o.typeOf(file);
  
  				// o.File
  				if (file instanceof o.File) { 
  					if (!file.ruid && !file.isDetached()) {
  						if (!ruid) { // weird case
  							return false;
  						}
  						file.ruid = ruid;
  						file.connectRuntime(ruid);
  					}
  					resolveFile(new plupload.File(file));
  				}
  				// o.Blob 
  				else if (file instanceof o.Blob) {
  					resolveFile(file.getSource());
  					file.destroy();
  				} 
  				// plupload.File - final step for other branches
  				else if (file instanceof plupload.File) {
  					if (fileName) {
  						file.name = fileName;
  					}
  					
  					queue.push(function(cb) {
  						// run through the internal and user-defined filters, if any
  						filterFile(file, function(err) {
  							if (!err) {
  								// make files available for the filters by updating the main queue directly
  								files.push(file);
  								// collect the files that will be passed to FilesAdded event
  								filesAdded.push(file); 
  
  								self.trigger("FileFiltered", file);
  							}
  							delay(cb, 1); // do not build up recursions or eventually we might hit the limits
  						});
  					});
  				} 
  				// native File or blob
  				else if (o.inArray(type, ['file', 'blob']) !== -1) {
  					resolveFile(new o.File(null, file));
  				} 
  				// input[type="file"]
  				else if (type === 'node' && o.typeOf(file.files) === 'filelist') {
  					// if we are dealing with input[type="file"]
  					o.each(file.files, resolveFile);
  				} 
  				// mixed array of any supported types (see above)
  				else if (type === 'array') {
  					fileName = null; // should never happen, but unset anyway to avoid funny situations
  					o.each(file, resolveFile);
  				}
  			}
  
  			ruid = getRUID();
  			
  			resolveFile(file);
  
  			if (queue.length) {
  				o.inSeries(queue, function() {
  					// if any files left after filtration, trigger FilesAdded
  					if (filesAdded.length) {
  						self.trigger("FilesAdded", filesAdded);
  					}
  				});
  			}
  		}