whole_func_string: function computeLayout(layoutConfig, layoutData, itemLayoutData) {
  
  	var laidOutItems = [],
  		itemAdded,
  		currentRow,
  		nextToLastRowHeight;
  
  	// Apply forced aspect ratio if specified, and set a flag.
  	if (layoutConfig.forceAspectRatio) {
  		itemLayoutData.forEach(function (itemData) {
  			itemData.forcedAspectRatio = true;
  			itemData.aspectRatio = layoutConfig.forceAspectRatio;
  		});
  	}
  
  	// Loop through the items
  	itemLayoutData.some(function (itemData, i) {
  
  		if (isNaN(itemData.aspectRatio)) {
  			throw new Error("Item " + i + " has an invalid aspect ratio");
  		}
  
  		// If not currently building up a row, make a new one.
  		if (!currentRow) {
  			currentRow = createNewRow(layoutConfig, layoutData);
  		}
  
  		// Attempt to add item to the current row.
  		itemAdded = currentRow.addItem(itemData);
  
  		if (currentRow.isLayoutComplete()) {
  
  			// Row is filled; add it and start a new one
  			laidOutItems = laidOutItems.concat(addRow(layoutConfig, layoutData, currentRow));
  
  			if (layoutData._rows.length >= layoutConfig.maxNumRows) {
  				currentRow = null;
  				return true;
  			}
  
  			currentRow = createNewRow(layoutConfig, layoutData);
  
  			// Item was rejected; add it to its own row
  			if (!itemAdded) {
  
  				itemAdded = currentRow.addItem(itemData);
  
  				if (currentRow.isLayoutComplete()) {
  
  					// If the rejected item fills a row on its own, add the row and start another new one
  					laidOutItems = laidOutItems.concat(addRow(layoutConfig, layoutData, currentRow));
  					if (layoutData._rows.length >= layoutConfig.maxNumRows) {
  						currentRow = null;
  						return true;
  					}
  					currentRow = createNewRow(layoutConfig, layoutData);
  				}
  			}
  		}
  
  	});
  
  	// Handle any leftover content (orphans) depending on where they lie
  	// in this layout update, and in the total content set.
  	if (currentRow && currentRow.getItems().length && layoutConfig.showWidows) {
  
  		// Last page of all content or orphan suppression is suppressed; lay out orphans.
  		if (layoutData._rows.length) {
  
  			// Only Match previous row's height if it exists and it isn't a breakout row
  			if (layoutData._rows[layoutData._rows.length - 1].isBreakoutRow) {
  				nextToLastRowHeight = layoutData._rows[layoutData._rows.length - 1].targetRowHeight;
  			} else {
  				nextToLastRowHeight = layoutData._rows[layoutData._rows.length - 1].height;
  			}
  
  			currentRow.forceComplete(false, nextToLastRowHeight);
  
  		} else {
  
  			// ...else use target height if there is no other row height to reference.
  			currentRow.forceComplete(false);
  
  		}
  
  		laidOutItems = laidOutItems.concat(addRow(layoutConfig, layoutData, currentRow));
  		layoutConfig._widowCount = currentRow.getItems().length;
  
  	}
  
  	// We need to clean up the bottom container padding
  	// First remove the height added for box spacing
  	layoutData._containerHeight = layoutData._containerHeight - layoutConfig.boxSpacing.vertical;
  	// Then add our bottom container padding
  	layoutData._containerHeight = layoutData._containerHeight + layoutConfig.containerPadding.bottom;
  
  	return {
  		containerHeight: layoutData._containerHeight,
  		widowCount: layoutConfig._widowCount,
  		boxes: layoutData._layoutItems
  	};
  
  }
func_code_string: function computeLayout(layoutConfig, layoutData, itemLayoutData) {
  
  	var laidOutItems = [],
  		itemAdded,
  		currentRow,
  		nextToLastRowHeight;
  
  	// Apply forced aspect ratio if specified, and set a flag.
  	if (layoutConfig.forceAspectRatio) {
  		itemLayoutData.forEach(function (itemData) {
  			itemData.forcedAspectRatio = true;
  			itemData.aspectRatio = layoutConfig.forceAspectRatio;
  		});
  	}
  
  	// Loop through the items
  	itemLayoutData.some(function (itemData, i) {
  
  		if (isNaN(itemData.aspectRatio)) {
  			throw new Error("Item " + i + " has an invalid aspect ratio");
  		}
  
  		// If not currently building up a row, make a new one.
  		if (!currentRow) {
  			currentRow = createNewRow(layoutConfig, layoutData);
  		}
  
  		// Attempt to add item to the current row.
  		itemAdded = currentRow.addItem(itemData);
  
  		if (currentRow.isLayoutComplete()) {
  
  			// Row is filled; add it and start a new one
  			laidOutItems = laidOutItems.concat(addRow(layoutConfig, layoutData, currentRow));
  
  			if (layoutData._rows.length >= layoutConfig.maxNumRows) {
  				currentRow = null;
  				return true;
  			}
  
  			currentRow = createNewRow(layoutConfig, layoutData);
  
  			// Item was rejected; add it to its own row
  			if (!itemAdded) {
  
  				itemAdded = currentRow.addItem(itemData);
  
  				if (currentRow.isLayoutComplete()) {
  
  					// If the rejected item fills a row on its own, add the row and start another new one
  					laidOutItems = laidOutItems.concat(addRow(layoutConfig, layoutData, currentRow));
  					if (layoutData._rows.length >= layoutConfig.maxNumRows) {
  						currentRow = null;
  						return true;
  					}
  					currentRow = createNewRow(layoutConfig, layoutData);
  				}
  			}
  		}
  
  	});
  
  	// Handle any leftover content (orphans) depending on where they lie
  	// in this layout update, and in the total content set.
  	if (currentRow && currentRow.getItems().length && layoutConfig.showWidows) {
  
  		// Last page of all content or orphan suppression is suppressed; lay out orphans.
  		if (layoutData._rows.length) {
  
  			// Only Match previous row's height if it exists and it isn't a breakout row
  			if (layoutData._rows[layoutData._rows.length - 1].isBreakoutRow) {
  				nextToLastRowHeight = layoutData._rows[layoutData._rows.length - 1].targetRowHeight;
  			} else {
  				nextToLastRowHeight = layoutData._rows[layoutData._rows.length - 1].height;
  			}
  
  			currentRow.forceComplete(false, nextToLastRowHeight);
  
  		} else {
  
  			// ...else use target height if there is no other row height to reference.
  			currentRow.forceComplete(false);
  
  		}
  
  		laidOutItems = laidOutItems.concat(addRow(layoutConfig, layoutData, currentRow));
  		layoutConfig._widowCount = currentRow.getItems().length;
  
  	}
  
  	// We need to clean up the bottom container padding
  	// First remove the height added for box spacing
  	layoutData._containerHeight = layoutData._containerHeight - layoutConfig.boxSpacing.vertical;
  	// Then add our bottom container padding
  	layoutData._containerHeight = layoutData._containerHeight + layoutConfig.containerPadding.bottom;
  
  	return {
  		containerHeight: layoutData._containerHeight,
  		widowCount: layoutConfig._widowCount,
  		boxes: layoutData._layoutItems
  	};
  
  }
func_documentation_string: Calculate the current layout for all items in the list that require layout.
  "Layout" means geometry: position within container and size
  
  @method computeLayout
  @param layoutConfig {Object} The layout configuration
  @param layoutData {Object} The current state of the layout
  @param itemLayoutData {Array} Array of items to lay out, with data required to lay out each item
  @return {Object} The newly-calculated layout, containing the new container height, and lists of layout items