function createTOC( options ) {
	var pkgKeywords;
	var forbidden;
	var contents;
	var keywords;
	var allowed;
	var include;
	var aliases;
	var files;
	var paths;
	var omit;
	var word;
	var opts;
	var json;
	var err;
	var ns;
	var i;
	var j;

	opts = {};
	if ( arguments.length ) {
		err = validate( opts, options );
		if ( err ) {
			throw err;
		}
	}
	if ( opts.dir ) {
		opts.dir = resolve( cwd(), opts.dir );
	} else {
		opts.dir = cwd();
	}
	if ( opts.pattern ) {
		opts.pattern += '/package.json';
	}
	debug( 'Options:  %s', JSON.stringify( opts ) );
	files = findPkgs( opts );
	debug( 'Matched packages: %s', files.join( ', ' ) );

	if ( opts.keywords ) {
		keywords = opts.keywords.split( ',' );
		allowed = [];
		forbidden = [];
		for ( i = 0; i < keywords.length; i++ ) {
			word = trim( keywords[ i ] );
			if ( startsWith( word, '+' ) ) {
				allowed.push( removeFirst( word ) );
			} else if ( startsWith( word, '-' ) ) {
				forbidden.push( removeFirst( word ) );
			}
		}
		paths = [];
		for ( i = 0; i < files.length; i++ ) {
			json = readJSON( resolve( opts.dir, files[ i ], 'package.json' ) );
			if ( json instanceof Error ) {
				debug( 'Encountered an error: %s', json.message );
				continue;
			}
			pkgKeywords = json.keywords;
			debug( 'Keywords: ' + pkgKeywords.join( ', ' ) );
			omit = false;
			include = false;
			if ( allowed.length > 0 && forbidden.length > 0 ) {
				debug( 'Case: Include packages containing allowed keyword(s) and not containing forbidden keyword(s)' );
				for ( j = 0; j < pkgKeywords.length; j++ ) {
					if ( contains( forbidden, pkgKeywords[ j ] ) ) {
						omit = true;
						break;
					} else if ( contains( allowed, pkgKeywords[ j ] ) ) {
						include = true;
					}
				}
			} else if ( allowed.length === 0 && forbidden.length > 0 ) {
				debug( 'Case: Omit packages containing "forbidden" keywords' );
				for ( j = 0; j < pkgKeywords.length; j++ ) {
					if ( contains( forbidden, pkgKeywords[ j ] ) ) {
						omit = true;
						break;
					}
				}
				include = true;
			} else if ( allowed.length > 0 && forbidden.length === 0 ) {
				debug( 'Case: Only include packages containing "allowed" keywords' );
				for ( j = 0; j < pkgKeywords.length; j++ ) {
					if ( contains( allowed, pkgKeywords[ j ] ) ) {
						include = true;
						break;
					}
				}
			} else {
				include = true;
			}
			if ( include && !omit ) {
				debug( 'Including `%s`...', files[ i ] );
				paths.push( resolve( opts.dir, files[ i ], 'README.md' ) );
			}
		}
	}
	else {
		paths = [];
		for ( i = 0; i < files.length; i++ ) {
			paths.push( resolve( opts.dir, files[ i ], 'README.md' ) );
		}
	}
	if ( paths.length === 0 ) {
		return {
			'toc': '',
			'links': []
		};
	}
	debug( 'Packages to include: %s', JSON.stringify( paths ) );
	contents = readFileList( paths );
	ns = readFile( resolve( opts.dir, 'lib', 'index.js' ) );
	aliases = extractAliases( ns.toString() );
	debug( 'Found aliases: %s', JSON.stringify( aliases ) );
	return toc( contents, aliases, opts.blacklist );
}
Synchronously creates a table of contents.

@param {Options} [options] - function options
@param {string} [options.dir] - root directory from which to search for files
@param {string} [options.pattern='**\/*'] - filename pattern
@param {StringArray} [options.ignore] - ignore pattern
@param {string} [options.keywords] - string of comma-separated keywords (preceded by `+` or `-` to indicate inclusion or exclusion, respectively)
@param {StringArray} [options.blacklist] - blacklisted packages
@throws {TypeError} options argument must be an object
@throws {TypeError} must provide valid options
@returns {Object} object with `toc` and `links`

@example
var resolve = require( 'path' ).resolve;

var opts = {
    'dir': resolve( __dirname, '..' )
};
var out = createTOC( opts );
// returns {...}