function analyze( options ) {
	var results;
	var gopts;
	var files;
	var sopts;
	var opts;
	var err;
	var dir;
	var i;

	opts = copy( defaults );
	if ( arguments.length ) {
		err = validate( opts, options );
		if ( err ) {
			throw err;
		}
	}
	debug( 'Options: %s', JSON.stringify( opts ) );

	if ( opts.dir ) {
		dir = resolve( cwd(), opts.dir );
	} else {
		dir = cwd();
	}
	debug( 'Search directory: %s', dir );

	gopts = {
		'cwd': dir,
		'ignore': opts.ignore,
		'realpath': true // return absolute file paths
	};
	debug( 'Glob options: %s', JSON.stringify( gopts ) );

	debug( 'Searching for files...' );
	files = glob( opts.pattern, gopts );

	debug( 'Found %d files.', files.length );
	if ( files.length === 0 ) {
		debug( 'Skipping analysis...' );
		if ( opts.cumulative ) {
			return null;
		}
		return [];
	}
	sopts = {
		'cumulative': opts.cumulative
	};
	debug( 'Analysis options: %s', JSON.stringify( sopts ) );

	debug( 'Performing analysis...' );
	results = lloc( files, sopts );
	if ( results instanceof Error ) {
		debug( 'Encountered an error when analyzing files: %s', results.message );
		return results;
	}
	for ( i = 0; i < results.length; i++ ) {
		// NOTE: We assume that results are returned in the same order as the provided file list...
		results[ i ] = [ files[ i ], results[ i ] ];
	}
	debug( 'Finished analysis.' );
	return results;
}
Synchronously calculates logical lines of code (LLOC) on a file glob.

@param {Options} [options] - function options
@param {string} [options.dir] - root directory from which to search for files
@param {string} [options.pattern='**\/*.js'] - glob pattern
@param {StringArray} [options.ignore] - glob pattern(s) to exclude matches
@throws {TypeError} options argument must be an object
@throws {TypeError} must provide valid options
@returns {(Error|Object|null)} analysis results or an error object

@example
var opts = {
    'dir': __dirname
};

var results = analyze( opts );
if ( results instanceof Error ) {
    throw results;
}
console.log( JSON.stringify( results ) );