function CarouselHelper(o) {
  this.carouselId = o.carouselId; //the id of the <ul>, the carousel id;
  this.metadata = o.metadata; //an array of objects that contains the metadata for each <li>;
  this.template = o.template; //string that represents the html that will be appended to each <li> in the carousel;
  this.cacheLength = o.cacheLength || 2; //optional; default image cache is 2 (2 copies of each image); the reason there are two copies of each image is so there isn't any peekaboo behavior when an image is appended to the carousel when it's still visible in the dom;
  this.addImageHeight = o.addImageHeight === undefined ? true : false; //optional; when the placeholders are created, the images aren't in them so to get a true height for the placeholder the images height needs to be added to the placeholder's height; sometimes this doesn't need to occur, like when the dimensions are set on the server and the height is explicitly set inline via css in the template;
  this.imageHeight = []; //internal use; an array of integers that correspond to the height of each image in the cache; used to calculate the max height of the <li>s when this.addImageHeight is set to true;
}

CarouselHelper.prototype.buildHtml = function (o) {

  return this.template.replace(/\{([^}]+)\}/g, function (a, $1) {
    if (o[$1] || o[$1] === "") return o[$1];
  });

};

CarouselHelper.prototype.getCache = function () {

	var oImages = {}, //holds the image caches for both next and previous functionality;
	re = /(\d+)/g,
	bIsChrome = navigator.userAgent.toLowerCase().indexOf("chrome") > -1,
	that = this;

	$.each(this.metadata, function (i, elem) { //create the image caches;
		for (var n = 0; n < that.cacheLength; n++) {
			var oImg = null, aMatch = [], aChunks = [];

			if (elem.dimensions) { //not all metadata will contain an image so there will be no dimensions;
				while (aMatch = re.exec(elem.dimensions)) {
					aChunks.push(aMatch[0]);
				}

				if (typeof Image === "undefined") { //hack for ie8 bug (only happens when page is first loaded; when it's refreshed, it then correctly recognizes the Image constructor);
					oImg = document.createElement("img");
				} else {
					oImg = new Image(aChunks[0], aChunks[1]);
				}

				if (bIsChrome) { //chrome wasn't respecting the width and height values passed in the constructor, and other browsers, notably ie, don't respect values NOT passed in the constructor;
					oImg.height = aChunks[1];
					oImg.width = aChunks[0];
				}
				oImg.src = elem.imageURL;
				oImg.alt = elem.imageAltText;

				if (typeof Image === "undefined") { //hack for ie8 bug (for whatever reason setting the w/h right after creating the element didn't properly set the dimensions, the images instead assumed their default sizes);
					oImg.height = aChunks[1];
					oImg.width = aChunks[0];
				}

			} else { //when there's no image create a placeholder;
				oImg = document.createElement("img");
			}

			that.imageHeight.push(oImg.height);
			if (!oImages["a" + n]) oImages["a" + n] = [];
			oImages["a" + n].push(oImg);
		}
	});
	if (this.cacheLength === 1) {
		return oImages.a0;
	} else {
		var arr = [];
		for (var m = 0; m < that.cacheLength; m++) {
			arr = arr.concat(oImages["a" + m]);
		}
		return arr;
	}

};

CarouselHelper.prototype.getMaxHeight = function () {

  var that = this, aHeight = [];

  $("#" + this.carouselId + " li").each(function (i) {
	var iHeight = $(this).height();
	if (that.addImageHeight) iHeight += that.imageHeight[i];
    aHeight.push(iHeight);
  });
  return Math.max.apply(Math, aHeight);

};

CarouselHelper.prototype.setPlaceholders = function () {

  //append each list item into the dom, calculate its max height and then after the carousel has been rendered apply that height to the appropriate class;
  var that = this;
  $.each(this.metadata, function (i, o) {
    $("#" + that.carouselId).append("<li class='jcarousel-item'>" + that.buildHtml(o) + "</li>");
  });

};
CarouselHelper.getCacheLength = function (arr) { //class method;
  var iLen = arr.length;
  switch (true) {
    case iLen === 1: return 12;
    case iLen < 4: return 7;
    case iLen === 4: return 4;
    default: return 2;
  }
};