/**
 *  Module dependencies.
 */
var fs   = require('fs')
  , path = require('path');
 

/**
 * Utility functions to synchronously test whether the giving path 
 * is a file or a directory.
 */
var is = (function(ret) {
  ['File', 'Directory'].forEach(function(method) {
    var memo = {}
      , fileObj;
    ret[method] = function(fpath) {
      if (memo[fpath] !== undefined) {
        return memo[fpath];
      }
      if (path.existsSync(fpath)) {
        return memo[fpath] = fs.statSync(fpath)['is'+method](); 
      }
      return memo[fpath] = false;
    }
  });
  return ret;
}({}));


/**
 *  Filtering files and sub-directories in a directory.
 */
var filter = function(dir) {
  var ret = {};
  ['File', 'Directory'].forEach(function(method){
    ret[method] = function(cb) {
      if (is.Directory(dir)) {
        fs.readdir(dir, function(err, files) {
          files && files
            .filter(function(n) { return is[method](path.join(dir, n)) })
            .map(function(n) { cb.call(null, path.join(dir, n)) });
        });
      }
    };
  });
  return ret;
};

 
/**
 *  A Container for storing unique and valid filenames.
 */
var fileNameCache = (function(cache) {
  return {
    push: function(name) {
      cache[name] = 1;
      return this;
    },
    each: function() {
      var temp = [];
      for (var name in cache) {
        if (cache.hasOwnProperty(name) && is.File(name)) {
          temp.push(name);
        }
      }
      Array.prototype.forEach.apply(temp, arguments);
      return this;
    },
    clear: function(){
      cache = {};
      return this;
    }
  };
}({}));     


/**
 * Abstracting the way of avoiding duplicate function call.
 */
var worker = (function() {
  var free = true;
  return {
    busydoing: function(cb) {
      if (free) {
        free = false;
        cb.call();
      }
    },
    free: function() {
      free = true;
    }
  }
}());


/**
 * Delay function call and ignore invalid filenames.
 */
var normalizeCall = function(cb, fname) {
  // Store each name of the modifying or temporary files generated by an editor.
  fileNameCache.push(fname);
     
  worker.busydoing(function() {
    // A heuristic delay of the write-to-file process.  
    setTimeout(function() {
      
      // When the write-to-file process is done, send all filtered filenames
      // to the callback function and call it.
      fileNameCache
        .each(function(f) { cb.call(null, f); })
        .clear();

      worker.free();

    }, 100);
  });
};


/**
 * Watch a file or a directory recursively.
 *  
 * @param {String} fpath
 * @param {Function} cb
 * 
 *   watch('fpath', function(file) {
 *     console.log(file, ' changed');
 *   });
 */
function watch(fpath, cb) {
  if (is.File(fpath)) {
    fs.watchFile(fpath, function(err) {
      normalizeCall(cb, fpath);
    });
    return;
  } else if (is.Directory(fpath)) {
    var filtered = filter(fpath);
    try { 
      fs.watch(fpath, function(err, fname) {
        normalizeCall(cb,  
          path.join(fpath, fname)
        );
      });
    } catch(e) {
      //In case the system limit of watching a directory using fs.watch method.
      //https://github.com/joyent/node/issues/2479
      filtered.File(function(file) {
        watch(file, cb);
      });
    }
    filtered.Directory(function(dir) {
      watch(dir, cb);
    }); 
  } else {
    console.log("Invalid filename or directory.");
  }
}; 
          

// Expose.
module.exports = watch;
          

@@ -275,26 +275,8 @@
  var
- memo = %7B%7D%0A      ,
  fil
@@ -331,108 +331,111 @@
 if (
-memo%5Bfpath%5D !== undefined) %7B%0A        return memo%5Bfpath%5D;%0A      %7D%0A      if (path.existsSync(fpath)) %7B
+path.existsSync(fpath)) %7B%0A        //memorize each file and directory.%0A        memo.push(fpath, method);
 %0A   
@@ -445,30 +445,16 @@
   return
- memo%5Bfpath%5D =
  fs.stat
@@ -506,22 +506,8 @@
 turn
- memo%5Bfpath%5D =
  fal
@@ -1034,16 +1034,435 @@
 et;%0A%7D;%0A%0A
+%0A/**%0A * A container for memorizing names of files or directories.%0A */%0Avar memo = (function(memo) %7B%0A  return %7B%0A    push: function(name, type) %7B%0A      memo%5Bname%5D = type;%0A    %7D, %0A    has: function(name) %7B%0A      return memo.hasOwnProperty(name) ? true : false;%0A    %7D,%0A    update: function(name) %7B%0A      if (!is.File(name) %7C%7C !is.Directory(name)) %7B%0A        delete memo%5Bname%5D;%0A      %7D%0A      return true;%0A    %7D%0A  %7D;%0A%7D(%7B%7D));%0A%0A 
  %0A/**%0A *
@@ -1689,169 +1689,140 @@
 p = 
-%5B%5D;%0A      for (var name in cache) %7B%0A        if (cache.hasOwnProperty(name) && is.File(name)) %7B%0A          temp.push(name);%0A        %7D%0A      %7D%0A      Array.prototype
+Object.keys(cache).filter(function(name)%7B %0A        return is.File(name) %7C%7C memo.has(name) && memo.update(name);%0A      %7D);%0A      temp
 .for
@@ -3256,24 +3256,25 @@
 ter(fpath);%0A
+%0A
     try %7B %0A 
@@ -3621,24 +3621,41 @@
    %7D);%0A    %7D
+%0A%0A    //recursion
 %0A    filtere
@@ -3783,26 +3783,16 @@
   %7D%0A%7D; %0A
-          
 %0A%0A// Exp

make sure to emit the filename correctly when deleting a file by adding an object for storing every file. While it is less eficient, it is helpful when extending the program in the future.