whole_func_string: function (newHeight, widowLayoutStyle) {
  
  		var itemWidthSum = this.left,
  			rowWidthWithoutSpacing = this.width - (this.items.length - 1) * this.spacing,
  			clampedToNativeRatio,
  			clampedHeight,
  			errorWidthPerItem,
  			roundedCumulativeErrors,
  			singleItemGeometry,
  			centerOffset;
  
  		// Justify unless explicitly specified otherwise.
  		if (typeof widowLayoutStyle === 'undefined' || ['justify', 'center', 'left'].indexOf(widowLayoutStyle) < 0) {
  			widowLayoutStyle = 'left';
  		}
  
  		// Clamp row height to edge case minimum/maximum.
  		clampedHeight = Math.max(this.edgeCaseMinRowHeight, Math.min(newHeight, this.edgeCaseMaxRowHeight));
  
  		if (newHeight !== clampedHeight) {
  
  			// If row height was clamped, the resulting row/item aspect ratio will be off,
  			// so force it to fit the width (recalculate aspectRatio to match clamped height).
  			// NOTE: this will result in cropping/padding commensurate to the amount of clamping.
  			this.height = clampedHeight;
  			clampedToNativeRatio = (rowWidthWithoutSpacing / clampedHeight) / (rowWidthWithoutSpacing / newHeight);
  
  		} else {
  
  			// If not clamped, leave ratio at 1.0.
  			this.height = newHeight;
  			clampedToNativeRatio = 1.0;
  
  		}
  
  		// Compute item geometry based on newHeight.
  		this.items.forEach(function (item) {
  
  			item.top = this.top;
  			item.width = item.aspectRatio * this.height * clampedToNativeRatio;
  			item.height = this.height;
  
  			// Left-to-right.
  			// TODO right to left
  			// item.left = this.width - itemWidthSum - item.width;
  			item.left = itemWidthSum;
  
  			// Increment width.
  			itemWidthSum += item.width + this.spacing;
  
  		}, this);
  
  		// If specified, ensure items fill row and distribute error
  		// caused by rounding width and height across all items.
  		if (widowLayoutStyle === 'justify') {
  
  			itemWidthSum -= (this.spacing + this.left);
  
  			errorWidthPerItem = (itemWidthSum - this.width) / this.items.length;
  			roundedCumulativeErrors = this.items.map(function (item, i) {
  				return Math.round((i + 1) * errorWidthPerItem);
  			});
  
  
  			if (this.items.length === 1) {
  
  				// For rows with only one item, adjust item width to fill row.
  				singleItemGeometry = this.items[0];
  				singleItemGeometry.width -= Math.round(errorWidthPerItem);
  
  			} else {
  
  				// For rows with multiple items, adjust item width and shift items to fill the row,
  				// while maintaining equal spacing between items in the row.
  				this.items.forEach(function (item, i) {
  					if (i > 0) {
  						item.left -= roundedCumulativeErrors[i - 1];
  						item.width -= (roundedCumulativeErrors[i] - roundedCumulativeErrors[i - 1]);
  					} else {
  						item.width -= roundedCumulativeErrors[i];
  					}
  				});
  
  			}
  
  		} else if (widowLayoutStyle === 'center') {
  
  			// Center widows
  			centerOffset = (this.width - itemWidthSum) / 2;
  
  			this.items.forEach(function (item) {
  				item.left += centerOffset + this.spacing;
  			}, this);
  
  		}
  
  	}
func_code_string: function (newHeight, widowLayoutStyle) {
  
  		var itemWidthSum = this.left,
  			rowWidthWithoutSpacing = this.width - (this.items.length - 1) * this.spacing,
  			clampedToNativeRatio,
  			clampedHeight,
  			errorWidthPerItem,
  			roundedCumulativeErrors,
  			singleItemGeometry,
  			centerOffset;
  
  		// Justify unless explicitly specified otherwise.
  		if (typeof widowLayoutStyle === 'undefined' || ['justify', 'center', 'left'].indexOf(widowLayoutStyle) < 0) {
  			widowLayoutStyle = 'left';
  		}
  
  		// Clamp row height to edge case minimum/maximum.
  		clampedHeight = Math.max(this.edgeCaseMinRowHeight, Math.min(newHeight, this.edgeCaseMaxRowHeight));
  
  		if (newHeight !== clampedHeight) {
  
  			// If row height was clamped, the resulting row/item aspect ratio will be off,
  			// so force it to fit the width (recalculate aspectRatio to match clamped height).
  			// NOTE: this will result in cropping/padding commensurate to the amount of clamping.
  			this.height = clampedHeight;
  			clampedToNativeRatio = (rowWidthWithoutSpacing / clampedHeight) / (rowWidthWithoutSpacing / newHeight);
  
  		} else {
  
  			// If not clamped, leave ratio at 1.0.
  			this.height = newHeight;
  			clampedToNativeRatio = 1.0;
  
  		}
  
  		// Compute item geometry based on newHeight.
  		this.items.forEach(function (item) {
  
  			item.top = this.top;
  			item.width = item.aspectRatio * this.height * clampedToNativeRatio;
  			item.height = this.height;
  
  			// Left-to-right.
  			// TODO right to left
  			// item.left = this.width - itemWidthSum - item.width;
  			item.left = itemWidthSum;
  
  			// Increment width.
  			itemWidthSum += item.width + this.spacing;
  
  		}, this);
  
  		// If specified, ensure items fill row and distribute error
  		// caused by rounding width and height across all items.
  		if (widowLayoutStyle === 'justify') {
  
  			itemWidthSum -= (this.spacing + this.left);
  
  			errorWidthPerItem = (itemWidthSum - this.width) / this.items.length;
  			roundedCumulativeErrors = this.items.map(function (item, i) {
  				return Math.round((i + 1) * errorWidthPerItem);
  			});
  
  
  			if (this.items.length === 1) {
  
  				// For rows with only one item, adjust item width to fill row.
  				singleItemGeometry = this.items[0];
  				singleItemGeometry.width -= Math.round(errorWidthPerItem);
  
  			} else {
  
  				// For rows with multiple items, adjust item width and shift items to fill the row,
  				// while maintaining equal spacing between items in the row.
  				this.items.forEach(function (item, i) {
  					if (i > 0) {
  						item.left -= roundedCumulativeErrors[i - 1];
  						item.width -= (roundedCumulativeErrors[i] - roundedCumulativeErrors[i - 1]);
  					} else {
  						item.width -= roundedCumulativeErrors[i];
  					}
  				});
  
  			}
  
  		} else if (widowLayoutStyle === 'center') {
  
  			// Center widows
  			centerOffset = (this.width - itemWidthSum) / 2;
  
  			this.items.forEach(function (item) {
  				item.left += centerOffset + this.spacing;
  			}, this);
  
  		}
  
  	}
func_documentation_string: Set row height and compute item geometry from that height.
  Will justify items within the row unless instructed not to.
  
  @method completeLayout
  @param newHeight {Number} Set row height to this value.
  @param widowLayoutStyle {String} How should widows display? Supported: left | justify | center