function summary( input ) {
	var comments;
	var results;
	var lines;
	var opts;
	var ast;

	if ( !isString( input ) && !isBuffer( input ) ) {
		throw new TypeError( format( 'invalid argument. Must provide either a string or a Buffer. Value: `%s`.', input ) );
	}
	// Ensure that provided input is a `string`:
	input = input.toString();

	// Split the input into individual lines:
	lines = input.split( RE_EOL );

	// Initialize a results object:
	results = resultsObject();

	// Initialize a comments array:
	comments = [];

	// Parse the source code input into an Abstract Syntax Tree (AST):
	opts = copy( DEFAULTS );
	opts.onComment = onComment;
	ast = parse( input, opts );

	// Analyze the AST:
	results = analyze( results, ast, input, comments, 0, 0 );

	// Return the summary results:
	return results;

	/**
	* Callback invoked upon encountering a comment.
	*
	* @private
	* @param {boolean} block - boolean indicating whether a comment is a block comment
	* @param {string} text - comment text
	* @param {NonNegativeInteger} start - character offset for comment start
	* @param {NonNegativeInteger} end - character offset for comment end
	* @param {Object} pos1 - start location
	* @param {Object} pos2 - end location
	*/
	function onComment( block, text, start, end, pos1, pos2 ) {
		var inline;
		var wchars;
		var jsdoc;
		var line;
		var key;
		var len;
		var obj;
		var N;

		// Determine the number of lines:
		N = pos2.line - pos1.line + 1;

		// Determine the comment length:
		len = end - start;

		// Determine the number of whitespace characters:
		wchars = whitespace( text );

		// Determine if the comment is inline...
		if ( N === 1 ) {
			line = lines[ pos1.line-1 ];
			line = line.substring( 0, pos1.column );
			inline = RE_NON_WHITESPACE.test( line );
		} else {
			inline = false;
		}
		inline = ( inline ) ? 1 : 0;

		// Determine if the comment is a JSDoc block comment...
		if ( block ) {
			line = lines[ pos1.line-1 ];
			line = line.substring( pos1.column, pos1.column+3 ); // only the first 3 chars are needed
			jsdoc = RE_JSDOC.test( line );
		}
		// Update sub-comment totals:
		if ( block ) {
			key = 'block';
		} else {
			key = 'line';
		}
		results.comments[ key ].count += 1;
		results.comments[ key ].length += len;
		results.comments[ key ].whitespace += wchars;
		results.comments[ key ].lines += N;
		results.comments[ key ].inline += inline;

		if ( jsdoc ) {
			results.comments.jsdoc.count += 1;
			results.comments.jsdoc.length += len;
			results.comments.jsdoc.whitespace += wchars;
			results.comments.jsdoc.lines += N;
			results.comments.jsdoc.inline += inline;
		}
		// Update total comment totals:
		results.comments.count += 1;
		results.comments.length += len;
		results.comments.whitespace += wchars;
		results.comments.lines += N;
		results.comments.inline += inline;

		// Append a comment summary:
		obj = {
			'type': key,
			'length': len,
			'whitespace': wchars,
			'lines': N,
			'inline': !!inline,
			'jsdoc': !!jsdoc
		};
		results.comments.data.push( obj );

		// Cache the comment data:
		comments.push({
			'start': start,
			'end': end,
			'summary': obj
		});
	}
}
Generates a summary of a JavaScript program.

@param {(string|Buffer)} input - source code input
@throws {TypeError} must provide either a string or Buffer
@returns {Object} summary

@example
var str = '"use strict";\n\nconsole.log( "beep" );\n';

var out = summary( str );
// returns {...}