code: function listdir(dir, rules, root, included) {
    return fs.readdir(dir)
    .then(function(files) {
      return when.all(files.map(function(f) {
        f = path.join(dir, f);
        return when(fs.stat(f), function(stat) {
          return {
            path: f,
            isDirectory: stat.isDirectory()
          };
        });
      }));
    })
    .then(function(arr) {
      var files = [];
      var subdirs = [];
      arr.forEach(function(e) {
        if (e.isDirectory) {
          subdirs.push(e.path);
        } else {
          files.push(e.path);
        }
      });
      files = files.filter(function(f) {
        return filter(f, rules, root, false, included);
      });
      return when.all(subdirs.map(function(d) {
        return listdir(d, rules, root, filter(d, rules, root, true, included));
      }))
      .then(function(list) {
        list = list.reduce(function(ret, i) {
          return ret.concat(i);
        }, files);
        // include current dir only if at least one of its children is included
        if (list.length > 0) {
          list.push(dir);
        }
        return list;
      });
    });
  }
docs: filter a dir based on filter rules
  
  @param {String}  dir
  @param {Array}   rules
  @param {Array}   root
  @param {Boolean} included
  @return {Promise}