docs: function(data) {
  		var self   = this,
  			fileFilter = (function() {
  				var func, filter;
  				if (filter = self.options.fileFilter) {
  					if (typeof filter === 'function') {
  						func = function(file) {
  							return filter.call(self, file);
  						};
  					} else if (filter instanceof RegExp) {
  						func = function(file) {
  							return filter.test(file.name);
  						};
  					}
  				}
  				return func? func : null;
  			})(),
  			chkCmdMap = function(opts) {
  				// Disable command to replace with other command
  				var disabled;
  				if (opts.uiCmdMap) {
  					if ($.isPlainObject(opts.uiCmdMap) && Object.keys(opts.uiCmdMap).length) {
  						if (!opts.disabledFlip) {
  							opts.disabledFlip = {};
  						}
  						disabled = opts.disabledFlip;
  						$.each(opts.uiCmdMap, function(f, t) {
  							if (t === 'hidden' && !disabled[f]) {
  								opts.disabled.push(f);
  								opts.disabledFlip[f] = true;
  							}
  						});
  					} else {
  						delete opts.uiCmdMap;
  					}
  				}
  			},
  			normalizeOptions = function(opts) {
  				var getType = function(v) {
  					var type = typeof v;
  					if (type === 'object' && Array.isArray(v)) {
  						type = 'array';
  					}
  					return type;
  				};
  				$.each(self.optionProperties, function(k, empty) {
  					if (empty !== void(0)) {
  						if (opts[k] && getType(opts[k]) !== getType(empty)) {
  							opts[k] = empty;
  						}
  					}
  				});
  				if (opts['disabled']) {
  					opts['disabledFlip'] = self.arrayFlip(opts['disabled'], true);
  				} else {
  					opts['disabledFlip'] = {};
  				}
  				return opts;
  			},
  			filter = function(file, asMap, type) { 
  				var res = asMap? file : true,
  					ign = asMap? null : false,
  					vid, targetOptions, isRoot, rootNames;
  				
  				if (file && file.hash && file.name && file.mime) {
  					if (file.mime === 'application/x-empty') {
  						file.mime = 'text/plain';
  					}
  					
  					isRoot = self.isRoot(file);
  					if (isRoot && ! file.volumeid) {
  						self.debug('warning', 'The volume root statuses requires `volumeid` property.');
  					}
  					if (isRoot || file.mime === 'directory') {
  						// Prevention of circular reference
  						if (file.phash) {
  							if (file.phash === file.hash) {
  								error = error.concat(['Parent folder of "$1" is itself.', file.name]);
  								return ign;
  							}
  							if (isRoot && file.volumeid && file.phash.indexOf(file.volumeid) === 0) {
  								error = error.concat(['Parent folder of "$1" is inner itself.', file.name]);
  								return ign;
  							}
  						}
  						
  						// set options, tmbUrls for each volume
  						if (file.volumeid) {
  							vid = file.volumeid;
  							
  							if (isRoot) {
  								// make or update of leaf roots cache
  								if (file.phash) {
  									if (! self.leafRoots[file.phash]) {
  										self.leafRoots[file.phash] = [ file.hash ];
  									} else {
  										if ($.inArray(file.hash, self.leafRoots[file.phash]) === -1) {
  											self.leafRoots[file.phash].push(file.hash);
  										}
  									}
  								}
  
  								self.hasVolOptions = true;
  								if (! self.volOptions[vid]) {
  									self.volOptions[vid] = {
  										// set dispInlineRegex
  										dispInlineRegex: self.options.dispInlineRegex
  									};
  								}
  								
  								targetOptions = self.volOptions[vid];
  								
  								if (file.options) {
  									// >= v.2.1.14 has file.options
  									Object.assign(targetOptions, file.options);
  								}
  								
  								// for compat <= v2.1.13
  								if (file.disabled) {
  									targetOptions.disabled = file.disabled;
  									targetOptions.disabledFlip = self.arrayFlip(file.disabled, true);
  								}
  								if (file.tmbUrl) {
  									targetOptions.tmbUrl = file.tmbUrl;
  								}
  								
  								// '/' required at the end of url
  								if (targetOptions.url && targetOptions.url.substr(-1) !== '/') {
  									targetOptions.url += '/';
  								}
  
  								// check uiCmdMap
  								chkCmdMap(targetOptions);
  								
  								// check trash bin hash
  								if (targetOptions.trashHash) {
  									if (self.trashes[targetOptions.trashHash] === false) {
  										delete targetOptions.trashHash;
  									} else {
  										self.trashes[targetOptions.trashHash] = file.hash;
  									}
  								}
  								
  								// set immediate properties
  								$.each(self.optionProperties, function(k) {
  									if (targetOptions[k]) {
  										file[k] = targetOptions[k];
  									}
  								});
  
  								// regist fm.roots
  								if (type !== 'cwd') {
  									self.roots[vid] = file.hash;
  								}
  
  								// regist fm.volumeExpires
  								if (file.expires) {
  									self.volumeExpires[vid] = file.expires;
  								}
  							}
  							
  							if (prevId !== vid) {
  								prevId = vid;
  								i18nFolderName = self.option('i18nFolderName', vid);
  							}
  						}
  						
  						// volume root i18n name
  						if (isRoot && ! file.i18) {
  							name = 'volume_' + file.name,
  							i18 = self.i18n(false, name);
  	
  							if (name !== i18) {
  								file.i18 = i18;
  							}
  						}
  						
  						// i18nFolderName
  						if (i18nFolderName && ! file.i18) {
  							name = 'folder_' + file.name,
  							i18 = self.i18n(false, name);
  	
  							if (name !== i18) {
  								file.i18 = i18;
  							}
  						}
  						
  						if (isRoot) {
  							if (rootNames = self.storage('rootNames')) {
  								if (rootNames[file.hash]) {
  									file._name = file.name;
  									file._i18 = file.i18;
  									file.name = rootNames[file.hash] = rootNames[file.hash];
  									delete file.i18;
  								}
  								self.storage('rootNames', rootNames);
  							}
  						}
  
  						// lock trash bins holder
  						if (self.trashes[file.hash]) {
  							file.locked = true;
  						}
  					} else if (fileFilter) {
  						try {
  							if (! fileFilter(file)) {
  								return ign;
  							}
  						} catch(e) {
  							self.debug(e);
  						}
  					}
  					
  					if (file.options) {
  						self.optionsByHashes[file.hash] = normalizeOptions(file.options);
  					}
  					
  					delete file.options;
  					
  					return res;
  				}
  				return ign;
  			},
  			getDescendants = function(hashes) {
  				var res = [];
  				$.each(self.files(), function(h, f) {
  					$.each(self.parents(h), function(i, ph) {
  						if ($.inArray(ph, hashes) !== -1 && $.inArray(h, hashes) === -1) {
  							res.push(h);
  							return false;
  						}
  					});
  				});
  				return res;
  			},
  			applyLeafRootStats = function(dataArr, type) {
  				$.each(dataArr, function(i, f) {
  					var pfile, done;
  					if (self.leafRoots[f.hash]) {
  						self.applyLeafRootStats(f);
  					}
  					// update leaf root parent stat
  					if (type !== 'change' && f.phash && self.isRoot(f) && (pfile = self.file(f.phash))) {
  						self.applyLeafRootStats(pfile);
  						// add to data.changed
  						if (!data.changed) {
  							data.changed = [pfile];
  						} else {
  							$.each(data.changed, function(i, f) {
  								if (f.hash === pfile.hash) {
  									data.changed[i] = pfile;
  									done = true;
  									return false;
  								}
  							});
  							if (!done) {
  								data.changed.push(pfile);
  							}
  						}
  					}
  				});
  			},
  			error = [],
  			name, i18, i18nFolderName, prevId, cData;
  		
  		// set cunstom data
  		if (data.customData && data.customData !== self.prevCustomData) {
  			self.prevCustomData = data.customData;
  			try {
  				cData = JSON.parse(data.customData);
  				if ($.isPlainObject(cData)) {
  					self.prevCustomData = cData;
  					$.each(Object.keys(cData), function(i, key) {
  						if (cData[key] === null) {
  							delete cData[key];
  							delete self.optsCustomData[key];
  						}
  					});
  					self.customData = Object.assign({}, self.optsCustomData, cData);
  				}
  			} catch(e) {}
  		}
  
  		if (data.options) {
  			normalizeOptions(data.options);
  		}
  		
  		if (data.cwd) {
  			if (data.cwd.volumeid && data.options && Object.keys(data.options).length && self.isRoot(data.cwd)) {
  				self.hasVolOptions = true;
  				self.volOptions[data.cwd.volumeid] = data.options;
  			}
  			data.cwd = filter(data.cwd, true, 'cwd');
  		}
  		if (data.files) {
  			data.files = $.grep(data.files, filter);
  		} 
  		if (data.tree) {
  			data.tree = $.grep(data.tree, filter);
  		}
  		if (data.added) {
  			data.added = $.grep(data.added, filter);
  		}
  		if (data.changed) {
  			data.changed = $.grep(data.changed, filter);
  		}
  		if (data.removed && data.removed.length && self.searchStatus.state === 2) {
  			data.removed = data.removed.concat(getDescendants(data.removed));
  		}
  		if (data.api) {
  			data.init = true;
  		}
  
  		if (Object.keys(self.leafRoots).length) {
  			data.files && applyLeafRootStats(data.files);
  			data.tree && applyLeafRootStats(data.tree);
  			data.added && applyLeafRootStats(data.added);
  			data.changed && applyLeafRootStats(data.changed, 'change');
  		}
  
  		// merge options that apply only to cwd
  		if (data.cwd && data.cwd.options && data.options) {
  			Object.assign(data.options, normalizeOptions(data.cwd.options));
  		}
  
  		// '/' required at the end of url
  		if (data.options && data.options.url && data.options.url.substr(-1) !== '/') {
  			data.options.url += '/';
  		}
  		
  		// check error
  		if (error.length) {
  			data.norError = ['errResponse'].concat(error);
  		}
  		
  		return data;
  	}