code: function copy(patterns, dir, options, cb) {
    if (arguments.length < 3) {
      return invalid.apply(null, arguments);
    }
  
    if (typeof options === 'function') {
      cb = options;
      options = {};
    }
  
    var opts = utils.extend({cwd: process.cwd()}, options);
    opts.cwd = path.resolve(opts.cwd);
    patterns = utils.arrayify(patterns);
  
    if (!utils.hasGlob(patterns)) {
      copyEach(patterns, dir, opts, cb);
      return;
    }
  
    opts.patterns = patterns;
    if (!opts.srcBase) {
      opts.srcBase = path.resolve(opts.cwd, utils.parent(patterns));
    }
  
    utils.glob(patterns, opts, function(err, files) {
      if (err) {
        cb(err);
        return;
      }
  
      copyEach(files, dir, opts, cb);
    });
  }
docs: Copy a filepath, vinyl file, array of files, or glob of files to the
  given destination `directory`, with `options` and callback function that
  exposes `err` and the array of vinyl files that are created by the copy
  operation.
  
  ```js
  copy('*.js', 'dist', function(err, file) {
  // exposes the vinyl `file` created when the file is copied
  });
  ```
  @param {String|Object|Array} `patterns` Filepath(s), vinyl file(s) or glob of files.
  @param {String} `dir` Destination directory
  @param {Object|Function} `options` or callback function
  @param {Function} `cb` Callback function if no options are specified
  @api public