docs: function(data, fm) { 
  			var self   = fm ? fm : this,
  				node        = self.getUI(),
  				xhr         = new XMLHttpRequest(),
  				notifyto    = null, notifyto2 = null,
  				dataChecked = data.checked,
  				isDataType  = (data.isDataType || data.type == 'data'),
  				target      = (data.target || self.cwd().hash),
  				dropEvt     = (data.dropEvt || null),
  				chunkEnable = (self.option('uploadMaxConn', target) != -1),
  				multiMax    = Math.min(5, Math.max(1, self.option('uploadMaxConn', target))),
  				retryWait   = 10000, // 10 sec
  				retryMax    = 30, // 10 sec * 30 = 300 secs (Max 5 mins)
  				retry       = 0,
  				getFile     = function(files) {
  					var dfd = $.Deferred(),
  						file;
  					if (files.promise) {
  						files.always(function(f) {
  							dfd.resolve(Array.isArray(f) && f.length? (isDataType? f[0][0] : f[0]) : {});
  						});
  					} else {
  						dfd.resolve(files.length? (isDataType? files[0][0] : files[0]) : {});
  					}
  					return dfd;
  				},
  				dfrd   = $.Deferred()
  					.fail(function(error) {
  						var userAbort;
  						if (error === 'userabort') {
  							userAbort = true;
  							error = void 0;
  						}
  						if (files && (self.uploads.xhrUploading || userAbort)) {
  							// send request om fail
  							getFile(files).done(function(file) {
  								if (! file._cid) {
  									// send sync request
  									self.uploads.failSyncTm && clearTimeout(self.uploads.failSyncTm);
  									self.uploads.failSyncTm = setTimeout(function() {
  										self.sync(target);
  									}, 1000);
  								} else if (! self.uploads.chunkfailReq[file._cid]) {
  									// send chunkfail request
  									self.uploads.chunkfailReq[file._cid] = true;
  									setTimeout(function() {
  										fm.request({
  											data : {
  												cmd: 'upload',
  												target: target,
  												chunk: file._chunk,
  												cid: file._cid,
  												upload: ['chunkfail'],
  												mimes: 'chunkfail'
  											},
  											options : {
  												type: 'post',
  												url: self.uploadURL
  											},
  											preventDefault: true
  										}).always(function() {
  											delete self.uploads.chunkfailReq[file._chunk];
  										});
  									}, 1000);
  								}
  							});
  						}
  						!userAbort && self.sync();
  						self.uploads.xhrUploading = false;
  						files = null;
  						error && self.error(error);
  					})
  					.done(function(data) {
  						self.uploads.xhrUploading = false;
  						files = null;
  						if (data) {
  							self.currentReqCmd = 'upload';
  							data.warning && self.error(data.warning);
  							self.updateCache(data);
  							data.removed && data.removed.length && self.remove(data);
  							data.added   && data.added.length   && self.add(data);
  							data.changed && data.changed.length && self.change(data);
  							self.trigger('upload', data, false);
  							self.trigger('uploaddone');
  							data.sync && self.sync();
  							data.debug && fm.debug('backend-debug', data);
  						}
  					})
  					.always(function() {
  						self.abortXHR(xhr);
  						// unregist fnAbort function
  						node.off('uploadabort', fnAbort);
  						$(window).off('unload', fnAbort);
  						notifyto && clearTimeout(notifyto);
  						notifyto2 && clearTimeout(notifyto2);
  						dataChecked && !data.multiupload && checkNotify() && self.notify({type : 'upload', cnt : -cnt, progress : 0, size : 0});
  						chunkMerge && notifyElm.children('.elfinder-notify-chunkmerge').length && self.notify({type : 'chunkmerge', cnt : -1});
  					}),
  				formData    = new FormData(),
  				files       = data.input ? data.input.files : self.uploads.checkFile(data, self, target), 
  				cnt         = data.checked? (isDataType? files[0].length : files.length) : files.length,
  				loaded      = 0,
  				prev        = 0,
  				filesize    = 0,
  				notify      = false,
  				notifyElm   = self.ui.notify,
  				cancelBtn   = true,
  				abort       = false,
  				checkNotify = function() {
  					if (!notify && (ntfUpload = notifyElm.children('.elfinder-notify-upload')).length) {
  						notify = true;
  					}
  					return notify;
  				},
  				fnAbort     = function(e, error) {
  					abort = true;
  					self.abortXHR(xhr, { quiet: true, abort: true });
  					dfrd.reject(error);
  					if (checkNotify()) {
  						self.notify({type : 'upload', cnt : ntfUpload.data('cnt') * -1, progress : 0, size : 0});
  					}
  				},
  				cancelToggle = function(show) {
  					ntfUpload.children('.elfinder-notify-cancel')[show? 'show':'hide']();
  				},
  				startNotify = function(size) {
  					if (!size) size = filesize;
  					return setTimeout(function() {
  						notify = true;
  						self.notify({type : 'upload', cnt : cnt, progress : loaded - prev, size : size,
  							cancel: function() {
  								node.trigger('uploadabort', 'userabort');
  							}
  						});
  						ntfUpload = notifyElm.children('.elfinder-notify-upload');
  						prev = loaded;
  						if (data.multiupload) {
  							cancelBtn && cancelToggle(true);
  						} else {
  							cancelToggle(cancelBtn && loaded < size);
  						}
  					}, self.options.notifyDelay);
  				},
  				doRetry = function() {
  					if (retry++ <= retryMax) {
  						if (checkNotify() && prev) {
  							self.notify({type : 'upload', cnt : 0, progress : 0, size : prev});
  						}
  						self.abortXHR(xhr, { quiet: true });
  						prev = loaded = 0;
  						setTimeout(function() {
  							var reqId;
  							if (! abort) {
  								xhr.open('POST', self.uploadURL, true);
  								if (self.api >= 2.1029) {
  									reqId = (+ new Date()).toString(16) + Math.floor(1000 * Math.random()).toString(16);
  									(typeof formData['delete'] === 'function') && formData['delete']('reqid');
  									formData.append('reqid', reqId);
  									xhr._requestId = reqId;
  								}
  								xhr.send(formData);
  							}
  						}, retryWait);
  					} else {
  						node.trigger('uploadabort', ['errAbort', 'errTimeout']);
  					}
  				},
  				progress = function() {
  					var node;
  					if (notify) {
  						dfrd.notifyWith(ntfUpload, [{
  							cnt: ntfUpload.data('cnt'),
  							progress: ntfUpload.data('progress'),
  							total: ntfUpload.data('total')
  						}]);
  					}
  				},
  				renames = (data.renames || null),
  				hashes = (data.hashes || null),
  				chunkMerge = false,
  				ntfUpload = $();
  			
  			// regist fnAbort function
  			node.one('uploadabort', fnAbort);
  			$(window).one('unload.' + fm.namespace, fnAbort);
  			
  			!chunkMerge && (prev = loaded);
  			
  			if (!isDataType && !cnt) {
  				return dfrd.reject(['errUploadNoFiles']);
  			}
  			
  			xhr.addEventListener('error', function() {
  				if (xhr.status == 0) {
  					if (abort) {
  						dfrd.reject();
  					} else {
  						// ff bug while send zero sized file
  						// for safari - send directory
  						if (!isDataType && data.files && $.grep(data.files, function(f){return ! f.type && f.size === (self.UA.Safari? 1802 : 0)? true : false;}).length) {
  							errors.push('errFolderUpload');
  							dfrd.reject(['errAbort', 'errFolderUpload']);
  						} else if (data.input && $.grep(data.input.files, function(f){return ! f.type && f.size === (self.UA.Safari? 1802 : 0)? true : false;}).length) {
  							dfrd.reject(['errUploadNoFiles']);
  						} else {
  							doRetry();
  						}
  					}
  				} else {
  					node.trigger('uploadabort', 'errConnect');
  				}
  			}, false);
  			
  			xhr.addEventListener('load', function(e) {
  				var status = xhr.status, res, curr = 0, error = '';
  				
  				if (status >= 400) {
  					if (status > 500) {
  						error = 'errResponse';
  					} else {
  						error = ['errResponse', 'errServerError'];
  					}
  				} else {
  					if (!xhr.responseText) {
  						error = ['errResponse', 'errDataEmpty'];
  					}
  				}
  				
  				if (error) {
  					node.trigger('uploadabort');
  					getFile(files).done(function(file) {
  						return dfrd.reject(file._cid? null : error);
  					});
  				}
  				
  				loaded = filesize;
  				
  				if (checkNotify() && (curr = loaded - prev)) {
  					self.notify({type : 'upload', cnt : 0, progress : curr, size : 0});
  					progress();
  				}
  
  				res = self.parseUploadData(xhr.responseText);
  				
  				// chunked upload commit
  				if (res._chunkmerged) {
  					formData = new FormData();
  					var _file = [{_chunkmerged: res._chunkmerged, _name: res._name, _mtime: res._mtime}];
  					chunkMerge = true;
  					node.off('uploadabort', fnAbort);
  					notifyto2 = setTimeout(function() {
  						self.notify({type : 'chunkmerge', cnt : 1});
  					}, self.options.notifyDelay);
  					isDataType? send(_file, files[1]) : send(_file);
  					return;
  				}
  				
  				res._multiupload = data.multiupload? true : false;
  				if (res.error) {
  					self.trigger('uploadfail', res);
  					if (res._chunkfailure || res._multiupload) {
  						abort = true;
  						self.uploads.xhrUploading = false;
  						notifyto && clearTimeout(notifyto);
  						if (ntfUpload.length) {
  							self.notify({type : 'upload', cnt : -cnt, progress : 0, size : 0});
  							dfrd.reject(res.error);
  						} else {
  							// for multi connection
  							dfrd.reject();
  						}
  					} else {
  						dfrd.reject(res.error);
  					}
  				} else {
  					dfrd.resolve(res);
  				}
  			}, false);
  			
  			xhr.upload.addEventListener('loadstart', function(e) {
  				if (!chunkMerge && e.lengthComputable) {
  					loaded = e.loaded;
  					retry && (loaded = 0);
  					filesize = e.total;
  					if (!loaded) {
  						loaded = parseInt(filesize * 0.05);
  					}
  					if (checkNotify()) {
  						self.notify({type : 'upload', cnt : 0, progress : loaded - prev, size : data.multiupload? 0 : filesize});
  						prev = loaded;
  						progress();
  					}
  				}
  			}, false);
  			
  			xhr.upload.addEventListener('progress', function(e) {
  				var curr;
  
  				if (e.lengthComputable && !chunkMerge && xhr.readyState < 2) {
  					
  					loaded = e.loaded;
  
  					// to avoid strange bug in safari (not in chrome) with drag&drop.
  					// bug: macos finder opened in any folder,
  					// reset safari cache (option+command+e), reload elfinder page,
  					// drop file from finder
  					// on first attempt request starts (progress callback called ones) but never ends.
  					// any next drop - successfull.
  					if (!data.checked && loaded > 0 && !notifyto) {
  						notifyto = startNotify(xhr._totalSize - loaded);
  					}
  					
  					if (!filesize) {
  						filesize = e.total;
  						if (!loaded) {
  							loaded = parseInt(filesize * 0.05);
  						}
  					}
  					
  					curr = loaded - prev;
  					if (checkNotify() && (curr/e.total) >= 0.05) {
  						self.notify({type : 'upload', cnt : 0, progress : curr, size : 0});
  						prev = loaded;
  						progress();
  					}
  					
  					if (! data.multiupload && loaded >= filesize) {
  						cancelBtn = false;
  						cancelToggle(false);
  					}
  				}
  			}, false);
  			
  			var send = function(files, paths){
  				var size = 0,
  				fcnt = 1,
  				sfiles = [],
  				c = 0,
  				total = cnt,
  				maxFileSize,
  				totalSize = 0,
  				chunked = [],
  				chunkID = new Date().getTime().toString().substr(-9), // for take care of the 32bit backend system
  				BYTES_PER_CHUNK = Math.min((fm.uplMaxSize? fm.uplMaxSize : 2097152) - 8190, fm.options.uploadMaxChunkSize), // uplMaxSize margin 8kb or options.uploadMaxChunkSize
  				blobSlice = chunkEnable? false : '',
  				blobSize, blobMtime, i, start, end, chunks, blob, chunk, added, done, last, failChunk,
  				multi = function(files, num){
  					var sfiles = [], cid, sfilesLen = 0, cancelChk;
  					if (!abort) {
  						while(files.length && sfiles.length < num) {
  							sfiles.push(files.shift());
  						}
  						sfilesLen = sfiles.length;
  						if (sfilesLen) {
  							cancelChk = sfilesLen;
  							for (var i=0; i < sfilesLen; i++) {
  								if (abort) {
  									break;
  								}
  								cid = isDataType? (sfiles[i][0][0]._cid || null) : (sfiles[i][0]._cid || null);
  								if (!!failChunk[cid]) {
  									last--;
  									continue;
  								}
  								fm.exec('upload', {
  									type: data.type,
  									isDataType: isDataType,
  									files: sfiles[i],
  									checked: true,
  									target: target,
  									dropEvt: dropEvt,
  									renames: renames,
  									hashes: hashes,
  									multiupload: true,
  									overwrite: data.overwrite === 0? 0 : void 0
  								}, void 0, target)
  								.fail(function(error) {
  									if (error && error === 'No such command') {
  										abort = true;
  										fm.error(['errUpload', 'errPerm']);
  									}
  									if (cid) {	
  										failChunk[cid] = true;
  									}
  								})
  								.always(function(e) {
  									if (e && e.added) added = $.merge(added, e.added);
  									if (last <= ++done) {
  										fm.trigger('multiupload', {added: added});
  										notifyto && clearTimeout(notifyto);
  										if (checkNotify()) {
  											self.notify({type : 'upload', cnt : -cnt, progress : 0, size : 0});
  										}
  									}
  									if (files.length) {
  										multi(files, 1); // Next one
  									} else {
  										if (--cancelChk <= 1) {
  											cancelBtn = false;
  											cancelToggle(false);
  										}
  									}
  								});
  							}
  						}
  					}
  					if (sfiles.length < 1 || abort) {
  						if (abort) {
  							notifyto && clearTimeout(notifyto);
  							if (cid) {
  								failChunk[cid] = true;
  							}
  							dfrd.reject();
  						} else {
  							dfrd.resolve();
  							self.uploads.xhrUploading = false;
  						}
  					}
  				},
  				check = function(){
  					if (!self.uploads.xhrUploading) {
  						self.uploads.xhrUploading = true;
  						multi(sfiles, multiMax); // Max connection: 3
  					} else {
  						setTimeout(check, 100);
  					}
  				},
  				reqId;
  
  				if (! dataChecked && (isDataType || data.type == 'files')) {
  					if (! (maxFileSize = fm.option('uploadMaxSize', target))) {
  						maxFileSize = 0;
  					}
  					for (i=0; i < files.length; i++) {
  						try {
  							blob = files[i];
  							blobSize = blob.size;
  							if (blobSlice === false) {
  								blobSlice = '';
  								if (self.api >= 2.1) {
  									if ('slice' in blob) {
  										blobSlice = 'slice';
  									} else if ('mozSlice' in blob) {
  										blobSlice = 'mozSlice';
  									} else if ('webkitSlice' in blob) {
  										blobSlice = 'webkitSlice';
  									}
  								}
  							}
  						} catch(e) {
  							cnt--;
  							total--;
  							continue;
  						}
  						
  						// file size check
  						if ((maxFileSize && blobSize > maxFileSize) || (!blobSlice && fm.uplMaxSize && blobSize > fm.uplMaxSize)) {
  							self.error(self.i18n('errUploadFile', blob.name) + ' ' + self.i18n('errUploadFileSize'));
  							cnt--;
  							total--;
  							continue;
  						}
  						
  						// file mime check
  						if (blob.type && ! self.uploadMimeCheck(blob.type, target)) {
  							self.error(self.i18n('errUploadFile', blob.name) + ' ' + self.i18n('errUploadMime') + ' (' + self.escape(blob.type) + ')');
  							cnt--;
  							total--;
  							continue;
  						}
  						
  						if (blobSlice && blobSize > BYTES_PER_CHUNK) {
  							start = 0;
  							end = BYTES_PER_CHUNK;
  							chunks = -1;
  							total = Math.floor(blobSize / BYTES_PER_CHUNK);
  							blobMtime = blob.lastModified? Math.round(blob.lastModified/1000) : 0;
  
  							totalSize += blobSize;
  							chunked[chunkID] = 0;
  							while(start <= blobSize) {
  								chunk = blob[blobSlice](start, end);
  								chunk._chunk = blob.name + '.' + (++chunks) + '_' + total + '.part';
  								chunk._cid   = chunkID;
  								chunk._range = start + ',' + chunk.size + ',' + blobSize;
  								chunk._mtime = blobMtime;
  								chunked[chunkID]++;
  								
  								if (size) {
  									c++;
  								}
  								if (typeof sfiles[c] == 'undefined') {
  									sfiles[c] = [];
  									if (isDataType) {
  										sfiles[c][0] = [];
  										sfiles[c][1] = [];
  									}
  								}
  								size = BYTES_PER_CHUNK;
  								fcnt = 1;
  								if (isDataType) {
  									sfiles[c][0].push(chunk);
  									sfiles[c][1].push(paths[i]);
  								} else {
  									sfiles[c].push(chunk);
  								}
  
  								start = end;
  								end = start + BYTES_PER_CHUNK;
  							}
  							if (chunk == null) {
  								self.error(self.i18n('errUploadFile', blob.name) + ' ' + self.i18n('errUploadFileSize'));
  								cnt--;
  								total--;
  							} else {
  								total += chunks;
  								size = 0;
  								fcnt = 1;
  								c++;
  							}
  							continue;
  						}
  						if ((fm.uplMaxSize && size + blobSize >= fm.uplMaxSize) || fcnt > fm.uplMaxFile) {
  							size = 0;
  							fcnt = 1;
  							c++;
  						}
  						if (typeof sfiles[c] == 'undefined') {
  							sfiles[c] = [];
  							if (isDataType) {
  								sfiles[c][0] = [];
  								sfiles[c][1] = [];
  							}
  						}
  						if (isDataType) {
  							sfiles[c][0].push(blob);
  							sfiles[c][1].push(paths[i]);
  						} else {
  							sfiles[c].push(blob);
  						}
  						size += blobSize;
  						totalSize += blobSize;
  						fcnt++;
  					}
  					
  					if (sfiles.length == 0) {
  						// no data
  						data.checked = true;
  						return false;
  					}
  					
  					if (sfiles.length > 1) {
  						// multi upload
  						notifyto = startNotify(totalSize);
  						added = [];
  						done = 0;
  						last = sfiles.length;
  						failChunk = [];
  						check();
  						return true;
  					}
  					
  					// single upload
  					if (isDataType) {
  						files = sfiles[0][0];
  						paths = sfiles[0][1];
  					} else {
  						files = sfiles[0];
  					}
  				}
  				
  				if (!dataChecked) {
  					if (!fm.UA.Safari || !data.files) {
  						notifyto = startNotify(totalSize);
  					} else {
  						xhr._totalSize = totalSize;
  					}
  				}
  				
  				dataChecked = true;
  				
  				if (! files.length) {
  					dfrd.reject(['errUploadNoFiles']);
  				}
  				
  				xhr.open('POST', self.uploadURL, true);
  				
  				// set request headers
  				if (fm.customHeaders) {
  					$.each(fm.customHeaders, function(key) {
  						xhr.setRequestHeader(key, this);
  					});
  				}
  				
  				// set xhrFields
  				if (fm.xhrFields) {
  					$.each(fm.xhrFields, function(key) {
  						if (key in xhr) {
  							xhr[key] = this;
  						}
  					});
  				}
  
  				if (self.api >= 2.1029) {
  					// request ID
  					reqId = (+ new Date()).toString(16) + Math.floor(1000 * Math.random()).toString(16);
  					formData.append('reqid', reqId);
  					xhr._requestId = reqId;
  				}
  				formData.append('cmd', 'upload');
  				formData.append(self.newAPI ? 'target' : 'current', target);
  				if (renames && renames.length) {
  					$.each(renames, function(i, v) {
  						formData.append('renames[]', v);
  					});
  					formData.append('suffix', fm.options.backupSuffix);
  				}
  				if (hashes) {
  					$.each(hashes, function(i, v) {
  						formData.append('hashes['+ i +']', v);
  					});
  				}
  				$.each(self.customData, function(key, val) {
  					formData.append(key, val);
  				});
  				$.each(self.options.onlyMimes, function(i, mime) {
  					formData.append('mimes[]', mime);
  				});
  				
  				$.each(files, function(i, file) {
  					if (file._chunkmerged) {
  						formData.append('chunk', file._chunkmerged);
  						formData.append('upload[]', file._name);
  						formData.append('mtime[]', file._mtime);
  					} else {
  						if (file._chunkfail) {
  							formData.append('upload[]', 'chunkfail');
  							formData.append('mimes', 'chunkfail');
  						} else {
  							formData.append('upload[]', file);
  							if (data.clipdata) {
  								data.overwrite = 0;
  								formData.append('name[]', fm.date(fm.nonameDateFormat) + '.png');
  							}
  							if (file.name && fm.UA.iOS) {
  								if (file.name.match(/^image\.jpe?g$/i)) {
  									data.overwrite = 0;
  									formData.append('name[]', fm.date(fm.nonameDateFormat) + '.jpg');
  								} else if (file.name.match(/^capturedvideo\.mov$/i)) {
  									data.overwrite = 0;
  									formData.append('name[]', fm.date(fm.nonameDateFormat) + '.mov');
  								}
  							}
  						}
  						if (file._chunk) {
  							formData.append('chunk', file._chunk);
  							formData.append('cid'  , file._cid);
  							formData.append('range', file._range);
  							formData.append('mtime[]', file._mtime);
  						} else {
  							formData.append('mtime[]', file.lastModified? Math.round(file.lastModified/1000) : 0);
  						}
  					}
  				});
  				
  				if (isDataType) {
  					$.each(paths, function(i, path) {
  						formData.append('upload_path[]', path);
  					});
  				}
  				
  				if (data.overwrite === 0) {
  					formData.append('overwrite', 0);
  				}
  				
  				// send int value that which meta key was pressed when dropped  as `dropWith`
  				if (dropEvt) {
  					formData.append('dropWith', parseInt(
  						(dropEvt.altKey  ? '1' : '0')+
  						(dropEvt.ctrlKey ? '1' : '0')+
  						(dropEvt.metaKey ? '1' : '0')+
  						(dropEvt.shiftKey? '1' : '0'), 2));
  				}
  				
  				xhr.send(formData);
  				
  				return true;
  			};
  			
  			if (! isDataType) {
  				if (files.length > 0) {
  					if (! data.clipdata && renames == null) {
  						var mkdirs = [],
  							paths = [],
  							excludes = fm.options.folderUploadExclude[fm.OS] || null;
  						$.each(files, function(i, file) {
  							var relPath = file.webkitRelativePath || file.relativePath || '',
  								idx, rootDir;
  							if (! relPath) {
  								return false;
  							}
  							if (excludes && file.name.match(excludes)) {
  								file._remove = true;
  								relPath = void(0);
  							} else {
  								relPath = relPath.replace(/\/[^\/]*$/, '');
  								if (relPath && $.inArray(relPath, mkdirs) === -1) {
  									mkdirs.push(relPath);
  									// checking the root directory to supports <input type="file" webkitdirectory> see #2378
  									idx = relPath.indexOf('/');
  									if (idx !== -1 && (rootDir = relPath.substr(0, idx)) && $.inArray(rootDir, mkdirs) === -1) {
  										mkdirs.unshift(rootDir);
  									}
  								}
  							}
  							paths.push(relPath);
  						});
  						renames = [];
  						hashes = {};
  						if (mkdirs.length) {
  							(function() {
  								var checkDirs = $.map(mkdirs, function(name) { return name.indexOf('/') === -1 ? {name: name} : null;}),
  									cancelDirs = [];
  								fm.uploads.checkExists(checkDirs, target, fm, true).done(
  									function(res, res2) {
  										var dfds = [], dfd, bak, hash;
  										if (fm.options.overwriteUploadConfirm && fm.option('uploadOverwrite', target)) {
  											cancelDirs = $.map(checkDirs, function(dir) { return dir._remove? dir.name : null ;} );
  											checkDirs = $.grep(checkDirs, function(dir) { return !dir._remove? true : false ;} );
  										}
  										if (cancelDirs.length) {
  											$.each(paths.concat(), function(i, path) {
  												if ($.inArray(path, cancelDirs) === 0) {
  													files[i]._remove = true;
  													delete paths[i];
  												}
  											});
  										}
  										files = $.grep(files, function(file) { return file._remove? false : true; });
  										paths = $.grep(paths, function(path) { return path === void 0 ? false : true; });
  										if (checkDirs.length) {
  											dfd = $.Deferred();
  											if (res.length) {
  												$.each(res, function(i, existName) {
  													// backup
  													bak = fm.uniqueName(existName + fm.options.backupSuffix , null, '');
  													$.each(res2, function(h, name) {
  														if (res[0] == name) {
  															hash = h;
  															return false;
  														}
  													});
  													if (! hash) {
  														hash = fm.fileByName(res[0], target).hash;
  													}
  													fm.lockfiles({files : [hash]});
  													dfds.push(
  														fm.request({
  															data   : {cmd : 'rename', target : hash, name : bak},
  															notify : {type : 'rename', cnt : 1}
  														})
  														.fail(function(error) {
  															dfrd.reject(error);
  															fm.sync();
  														})
  														.always(function() {
  															fm.unlockfiles({files : [hash]});
  														})
  													);
  												});
  											} else {
  												dfds.push(null);
  											}
  											
  											$.when.apply($, dfds).done(function() {
  												// ensure directories
  												fm.request({
  													data   : {cmd : 'mkdir', target : target, dirs : mkdirs},
  													notify : {type : 'mkdir', cnt : mkdirs.length},
  													preventFail: true
  												})
  												.fail(function(error) {
  													error = error || ['errUnknown'];
  													if (error[0] === 'errCmdParams') {
  														multiMax = 1;
  													} else {
  														multiMax = 0;
  														dfrd.reject(error);
  													}
  												})
  												.done(function(data) {
  													if (data.hashes) {
  														paths = $.map(paths.concat(), function(p) {
  															if (p === '') {
  																return target;
  															} else {
  																return data.hashes['/' + p];
  															}
  														});
  													}
  												})
  												.always(function(data) {
  													if (multiMax) {
  														isDataType = true;
  														if (! send(files, paths)) {
  															dfrd.reject();
  														}
  													}
  												});
  											});
  										} else {
  											dfrd.reject();
  										}
  									}
  								);
  							})();
  						} else {
  							fm.uploads.checkExists(files, target, fm).done(
  								function(res, res2){
  									if (fm.options.overwriteUploadConfirm && fm.option('uploadOverwrite', target)) {
  										hashes = res2;
  										if (res === null) {
  											data.overwrite = 0;
  										} else {
  											renames = res;
  										}
  										files = $.grep(files, function(file){return !file._remove? true : false ;});
  									}
  									cnt = files.length;
  									if (cnt > 0) {
  										if (! send(files)) {
  											dfrd.reject();
  										}
  									} else {
  										dfrd.reject();
  									}
  								}
  							);
  						}
  					} else {
  						if (! send(files)) {
  							dfrd.reject();
  						}
  					}
  				} else {
  					dfrd.reject();
  				}
  			} else {
  				if (dataChecked) {
  					send(files[0], files[1]);
  				} else {
  					files.done(function(result) { // result: [files, paths, renames, hashes, mkdirs]
  						renames = [];
  						cnt = result[0].length;
  						if (cnt) {
  							if (result[4] && result[4].length) {
  								// ensure directories
  								fm.request({
  									data   : {cmd : 'mkdir', target : target, dirs : result[4]},
  									notify : {type : 'mkdir', cnt : result[4].length},
  									preventFail: true
  								})
  								.fail(function(error) {
  									error = error || ['errUnknown'];
  									if (error[0] === 'errCmdParams') {
  										multiMax = 1;
  									} else {
  										multiMax = 0;
  										dfrd.reject(error);
  									}
  								})
  								.done(function(data) {
  									if (data.hashes) {
  										result[1] = $.map(result[1], function(p) {
  											p = p.replace(/\/[^\/]*$/, '');
  											if (p === '') {
  												return target;
  											} else {
  												return data.hashes[p];
  											}
  										});
  									}
  								})
  								.always(function(data) {
  									if (multiMax) {
  										renames = result[2];
  										hashes = result[3];
  										send(result[0], result[1]);
  									}
  								});
  								return;
  							} else {
  								result[1] = $.map(result[1], function() { return target; });
  							}
  							renames = result[2];
  							hashes = result[3];
  							send(result[0], result[1]);
  						} else {
  							dfrd.reject(['errUploadNoFiles']);
  						}
  					}).fail(function(){
  						dfrd.reject();
  					});
  				}
  			}
  
  			return dfrd;
  		}