list = function(root, include, exclude, cb) {
  include = include || [];
  exclude = exclude || [];

  var folders = [root];
  var cache = {};
  var list = [];
  var node = null;
  var realpaths = {};

  iterator();

  function iterator(error) {
    if (error) console.warn('Access to ' + node + ' from ResourceTree denied. (' + error + ')');
    if (folders.length) return iterate(node = folders.pop());
    return cb(null, list);
  }

  function iterate(node) {
    async.waterfall([
      fs.readdir.bind(fs, node),
      function(paths, cb) {
        async.each(paths, function(child, cb) {
          var apath = path.join(node, child);
          var rpath = relative(apath);

          fs.realpath(apath, realpaths, function(err, realpath) {
            if (err) { return cb(err); }
            if (cache[realpath] || excluded(rpath)) return cb();
            cache[realpath] = true;

            fs.stat(realpath, function(error, pstat) {
              if (error) return cb(error);

              if (pstat.isDirectory()) folders.push(realpath);
              if (pstat.isFile() && included(rpath)) list.push(realpath);
              cb();
            });
          });
        }, cb);
      }
    ], iterator);
  }

  function included(rpath) {
    return include.some(function(rx) { return rx.test(rpath); });
  }

  function excluded(rpath) {
    return exclude.some(function(rx) { return rx.test(rpath); });
  }

  function relative(apath) {
    return path.relative(root, apath);
  }
}
@param {string} startDirectory
@param {string} mainScriptFile
@param {function(Object, Array.<string>)} callback
@this {ScriptFileStorage}