/****************************************************************************************
              Script to create a slideshow from an accessible image gallery
                       Written by Mark Wilton-Jones, 03-05/01/2009
            Version 2.0.2 updated 03/03/2011 to prevent scroll jumps in Opera
                      Updated 12/11/2009 for better caption widths
            Updated 06/11/2009 with shrink-to-fit, transitions, loop control,
         thumbnail positioning and DHTML scrolling, embedding and other features
                     Updated 24/03/2009 to support keyboard controls
                          Updated 18/03/2009 to control caching
*****************************************************************************************

Please see http://www.howtocreate.co.uk/jslibs/ for details and a demo of this script
Please see http://www.howtocreate.co.uk/tutorials/jsexamples/slideshow.html for detailed instructions
Please see http://www.howtocreate.co.uk/jslibs/termsOfUse.html for terms of use
_____________________________________________________________________________________________________*/

//initialise instance properties
function GallerySlideshow() {
	this.imageList = [];
	this.slideList = [];
	this.transitions = this.showingNumber = this.lastActive = 0;
	this.looptype = 1;
	this.transitionDuration = 500;
	this.isShowing = false;
	this.userLoopString = '';
	this.el = {}; //element references (short because it is written multiple times)
	this.layout = {
		//things the user can choose using the API
		embedded: true,
		thumbsOnTop: true,
		shrinkImg: false,
		shrinkImgToggle: false,
		captionToggle: false,
		showCaption: true,
		dhtmlThumbs: false,
		//things the user can set using CSS, which will need to be measured later
		fixedHeight: true,
		positionedCaption: false,
		captionXPad: 0,
		captionYPad: 0,
		imageXPad: 0,
		imageYPad: 0,
		slideXPad: 0,
		slideYPad: 0
	};
	this.keys = {
		nextKey: null,
		prevKey: null,
		closeKey: null,
		shrinkKey: null,
		captionKey: null
	};
	this.mousetimeout = this.heightinterval = this.transinterval = this.nextCache = this.prevCache = this.handleKeyPress = this.onchange = null;
	this.pagexy = [0,0];
}
//methods to add images to a slideshow
GallerySlideshow.prototype.prepareImagesFromCollection = function (collectionObject) {
	if( !this.canWork() ) { return false; }
	//find all links containing thumbnails within the collection, and store their details
	var linkObject, thumbImage, collectionLength = collectionObject.length, thumbImage, pageHref = location.href.replace(/#.*$/,'');
	if( this.isShowing ) {
		//modifying the slideshow while it is being displayed will break it - close it before modifying
		this.closeSlideshow();
	}
	this.lastActive = this.showingNumber = 0;
	this.imageList = [];
	for( var i = 0; i < collectionLength; i++ ) {
		linkObject = collectionObject[i];
		thumbImage = linkObject.getElementsByTagName('img')[0];
		//ignore links with no thumbnails, links to javascript: URLs, and links to fragments on the current page
		if( thumbImage && thumbImage.src && linkObject.href && linkObject.href.indexOf('javascript:') && linkObject.href.replace(/#.*$/,'') != pageHref ) {
			this.imageList[this.imageList.length] = {
				thumbnail: thumbImage.src,
				fullImage: linkObject.href,
				text: linkObject.textContent ? linkObject.textContent : ( linkObject.text ? linkObject.text : ( linkObject.innerText ? linkObject.innerText : '' ) ),
				altText: thumbImage.alt ? thumbImage.alt : ''
			};
		}
	}
	return this.imageList.length;
};
GallerySlideshow.prototype.prepareImagesFromElement = function (nodeObject) {
	return this.prepareImagesFromCollection( ( nodeObject && nodeObject.getElementsByTagName ) ? nodeObject.getElementsByTagName('a') : [] );
};
//methods to change which slide is shown
GallerySlideshow.prototype.setCurrent = function (indexNumber,blockTransition) {
	//set the new image to be drawn (within limits), and draw it if it is being displayed
	if( this.el.transition && !blockTransition ) { return this.showingNumber; } //ignore during transition
	var beforeNum = this.showingNumber;
	indexNumber = Math.round(indexNumber) || 0;
	if( indexNumber >= this.imageList.length ) { indexNumber = this.imageList.length - 1; }
	if( indexNumber < 0 ) { indexNumber = 0; }
	this.showingNumber = indexNumber;
	this.drawNewImage( !blockTransition && beforeNum != indexNumber, 'setCurrent', beforeNum, indexNumber );
	return indexNumber;
};
GallerySlideshow.prototype.showPrevious = function (blockTransition) {
	if( this.el.transition && !blockTransition ) { return this.showingNumber; }
	var beforeNum = this.showingNumber;
	this.showingNumber--;
	if( this.showingNumber < 0 ) {
		if( this.looptype ) {
			this.showingNumber = ( this.imageList.length ? this.imageList.length : 1 ) - ( ( this.looptype == 1 ) ? 1 : 0 );
		} else {
			this.showingNumber = 0;
			return 0;
		}
	}
	this.drawNewImage( !blockTransition, 'showPrevious', beforeNum, this.showingNumber );
	return this.showingNumber;
};
GallerySlideshow.prototype.showNext = function (blockTransition) {
	if( this.el.transition && !blockTransition ) { return this.showingNumber; }
	var beforeNum = this.showingNumber;
	this.showingNumber++;
	if( this.showingNumber >= this.imageList.length + ( this.looptype == 2 ) ? 1 : 0 ) {
		if( this.looptype ) {
			this.showingNumber = 0;
		} else {
			this.showingNumber--;
			return this.showingNumber;
		}
	}
	this.drawNewImage( !blockTransition, 'showNext', beforeNum, this.showingNumber );
	return this.showingNumber;
};
GallerySlideshow.prototype.setLooping = function (oAllowed,oMsg) {
	if( !oAllowed ) {
		this.looptype = 0;
	} else if( oMsg ) {
		this.looptype = 2;
	} else {
		this.looptype = 1;
	}
};
//methods controlling layout options
GallerySlideshow.prototype.setThumbPosition = function (oPosition) {
	if( this.isShowing ) { return false; }
	this.layout.thumbsOnTop = !!oPosition;
	return true;
};
GallerySlideshow.prototype.setThumbScrollbar = function (thumbType) {
	if( this.isShowing ) { return false; }
	this.layout.dhtmlThumbs = !thumbType;
	return true;
};
GallerySlideshow.prototype.shrinkToFit = function (oShrink,blockTransition) {
	if( this.el.transition && !blockTransition ) {
		if( this.el.sCheck && this.el.sCheck.checked != this.layout.shrinkImg ) {
			this.el.sCheck.checked = this.layout.shrinkImg;
		}
		return false;
	}
	var beforeVal = this.layout.shrinkImg;
	this.layout.shrinkImg = !!oShrink;
	if( this.isShowing ) {
		if( this.el.sCheck && this.el.sCheck.checked != this.layout.shrinkImg ) {
			this.el.sCheck.checked = this.layout.shrinkImg;
		}
		this.setVariantStyles(false);
		this.drawNewImage( false, 'shrinkToFit', beforeVal, this.layout.shrinkImg );
	}
	return true;
};
GallerySlideshow.prototype.getShrinkToFit = function () {
	return this.layout.shrinkImg;
};
GallerySlideshow.prototype.showShrinkToggle = function (oShow) {
	if( this.isShowing ) { return false; }
	this.layout.shrinkImgToggle = !!oShow;
	return true;
};
GallerySlideshow.prototype.showCaption = function (showCaption,blockTransition) {
	if( this.el.transition && !blockTransition ) {
		if( this.el.tCheck && this.el.tCheck.checked != this.layout.showCaption ) {
			this.el.tCheck.checked = this.layout.showCaption;
		}
		return false;
	}
	var beforeVal = this.layout.showCaption;
	this.layout.showCaption = !!showCaption;
	if( this.isShowing ) {
		if( this.el.tCheck && this.el.tCheck.checked != this.layout.showCaption ) {
			this.el.tCheck.checked = this.layout.showCaption;
		}
		this.drawNewImage( false, 'showCaption', beforeVal, this.layout.showCaption );
	}
	return true;
};
GallerySlideshow.prototype.getShowCaption = function () {
	return this.layout.showCaption;
};
GallerySlideshow.prototype.showCaptionToggle = function (oShow) {
	if( this.isShowing ) { return false; }
	this.layout.captionToggle = !!oShow;
	return true;
};
GallerySlideshow.prototype.appendMarkup = function (oMarkup,inPosition) {
	var tmpdiv, oParent = inPosition ? ( this.el.listDiv && this.el.prvnxt ) : this.el.rootElement;
	if( oParent ) {
		if( oMarkup && ( oMarkup.nodeType == 1 || oMarkup.nodeType == 3 || oMarkup.nodeType == 4 || oMarkup.nodeType == 11 ) ) {
			oParent.appendChild(oMarkup);
		} else {
			tmpdiv = document.createElement('div');
			tmpdiv.innerHTML = oMarkup;
			while( tmpdiv.firstChild ) {
				oParent.appendChild(tmpdiv.firstChild);
			}
		}
		this.setHeight();
		return true;
	}
	return false;
};
//methods to show and hide the slideshow
GallerySlideshow.prototype.showSlideshow = function (prevString,nextString,closeString,loopString,shrinkString,captionString,leftString,rightString,lastOne) {
	var templink, tempthumb, thisShow = this;
	if( !this.canWork() || !this.imageList.length || this.isShowing ) { return false; }
	//remember that this is now showing, and lots of actions are off-limits
	this.isShowing = true;
	//work out if this is replacing the document, or appending to an element, and prepare params accordingly
	if( prevString && ( prevString.nodeType == 1 || prevString.nodeType == 11 ) ) {
		//shift parameters over by 1
		this.el.parentEl = prevString;
		prevString = nextString;
		nextString = closeString;
		closeString = loopString;
		loopString = shrinkString;
		shrinkString = captionString,
		captionString = leftString;
		leftString = rightString;
		rightString = lastOne;
		this.layout.embedded = true;
	} else {
		this.el.parentEl = document.body;
		this.layout.embedded = false;
		if( this.currentSlideshow ) {
			this.currentSlideshow.closeSlideshow();
		}
		//store this as the current slideshow
		this.constructor.prototype.currentSlideshow = this;
	}
	this.userLoopString = loopString;
	if( !this.layout.embedded ) {
		if( document.activeElement && document.activeElement.blur ) {
			document.activeElement.blur(); //try to prevent Enter from re-opening the slideshow
		}
		//store the scrolling offset so it can be restored when the slideshow is closed
		if( typeof( window.pageYOffset ) == 'number' ) {
			this.pagexy = [window.pageXOffset,window.pageYOffset];
		} else if( document.body.scrollLeft || document.body.scrollTop ) {
			this.pagexy = [document.body.scrollLeft,document.body.scrollTop];
		} else if( document.documentElement.scrollLeft || document.documentElement.scrollTop ) {
			this.pagexy = [document.documentElement.scrollLeft,document.documentElement.scrollTop];
		} else {
			this.pagexy = [0,0];
		}
	}
	//create the required elements
	this.el.rootElement = document.createElement('div');
	this.el.rootElement.className = 'galleryslideshow';
	this.el.listDiv = document.createElement('div');
	this.el.listDiv.className = 'slidelist';
	this.setStyles(this.el.listDiv,'marginLeft:0;marginRight:0;paddingLeft:0;paddingRight:0;borderLeft:none;borderRight:none');
	this.el.listDiv.appendChild( this.el.prvnxt = document.createElement('div') );
	this.el.prvnxt.className = 'prvnxt';
	this.el.prvnxt.style.textAlign = 'center';
	this.el.listDiv.appendChild( this.el.slideScroll = document.createElement('div') );
	this.el.slideScroll.className = 'slidescroll';
	this.setStyles(this.el.slideScroll,'whiteSpace:nowrap;width:auto;marginLeft:0;marginRight:0;paddingLeft:0;paddingRight:0;borderLeft:none;borderRight:none');
	this.el.slideDiv = document.createElement('div');
	this.el.slideDiv.className = 'slideimage';
	//special styles that depend on how it is being displayed
	if( this.layout.embedded ) {
		this.el.listDiv.style.position = 'relative';
		this.setStyles(this.el.rootElement,'position:relative;zoom:1'); //also trigger hasLayout or IE 7 gets transition offsets wrong
	} else {
		this.setStyles(this.el.listDiv,'zIndex:2;left:0;width:100%');
		if( this.layout.thumbsOnTop ) {
			this.setStyles(this.el.listDiv,'position:fixed;top:0'); //IE 6 does not respect it but does understand it, so there is no error and currentStyle is 'fixed'
		} else {
			this.setStyles(this.el.listDiv,'position:absolute;bottom:0'); //fixed also works but is pointless - absolute makes it work in IE 6
		}
	}
	//append divs in the right order, to allow static positioning to work as well
	if( this.layout.thumbsOnTop ) {
		this.el.rootElement.appendChild(this.el.listDiv);
		this.el.rootElement.appendChild(this.el.slideDiv);
	} else {
		this.el.rootElement.appendChild(this.el.slideDiv);
		this.el.rootElement.appendChild(this.el.listDiv);
	}
	//add the prev/next/close links
	if( !this.layout.embedded ) {
		this.el.cLink = document.createElement('a');
		this.el.cLink.appendChild(document.createTextNode( ( typeof(closeString) == 'undefined' || closeString === null ) ? this.strings.closeString : closeString ));
		this.el.cLink.href = '#';
		this.el.cLink.onclick = function () {
			thisShow.closeSlideshow();
			return false;
		};
		this.setStyles(this.el.cLink,'styleFloat:right;cssFloat:right');
		this.el.cLink.className = 'closebutton';
		this.el.prvnxt.appendChild(this.el.cLink);
	}
	this.el.pLink = document.createElement('a');
	this.el.pLink.appendChild(document.createTextNode( ( typeof(prevString) == 'undefined' || prevString === null ) ? this.strings.prevString : prevString ));
	this.el.pLink.href = '#';
	this.el.pLink.onclick = function () {
		thisShow.showPrevious();
		return false;
	};
	this.el.pLink.onmousedown = this.el.pLink.onselectstart = function () { return false; };
	this.el.pLink.className = 'prevbutton';
	this.el.prvnxt.appendChild(this.el.pLink);
	this.el.nLink = document.createElement('a');
	this.el.nLink.appendChild(document.createTextNode( ( typeof(nextString) == 'undefined' || nextString === null ) ? this.strings.nextString : nextString ));
	this.el.nLink.href = '#';
	this.el.nLink.onclick = function () {
		thisShow.showNext();
		return false;
	};
	this.el.nLink.onmousedown = this.el.nLink.onselectstart = function () { return false; };
	if( window.opera ) {
		while( this.el.nLink.firstChild.nodeValue.length > 1 ) {
			//hack to stop it pointlessly triggering Opera's Fast Forward
			this.el.nLink.insertBefore(document.createElement('span'),this.el.nLink.firstChild.splitText(this.el.nLink.firstChild.nodeValue.length-1)).appendChild(document.createTextNode('=')).parentNode.style.display = 'none';
		}
	}
	this.el.nLink.className = 'nextbutton';
	this.el.prvnxt.appendChild(this.el.nLink);
	this.el.nLink.onmouseover = this.el.pLink.onmouseover = this.el.slideDiv.onmouseover = function () {
		if( thisShow.mousetimeout ) {
			clearTimeout(thisShow.mousetimeout);
			thisShow.mousetimeout = null;
		}
		if( thisShow.el.rootElement.className == 'galleryslideshow' ) {
			thisShow.el.rootElement.className = 'galleryslideshow mouseover';
		}
	};
	this.el.nLink.onmouseout = this.el.pLink.onmouseout = this.el.slideDiv.onmouseout = function () {
		if( thisShow.mousetimeout ) { clearTimeout(thisShow.mousetimeout); }
		thisShow.mousetimeout = setTimeout(function () {
			thisShow.mousetimeout = null;
			if( thisShow.el.rootElement.className != 'galleryslideshow' ) {
				thisShow.el.rootElement.className = 'galleryslideshow';
			}
		},750);
	};
	if( this.layout.shrinkImgToggle ) {
		this.el.sLabel = document.createElement('label');
		this.el.sCheck = document.createElement('input');
		this.el.sCheck.setAttribute('type','checkbox');
		this.el.sCheck.onclick = function () { //don't use onchange or IE gets it backwards...
			thisShow.shrinkToFit(this.checked);
			this.blur(); //make space not retick the box, to allow it to work as a shortcut
		};
		this.el.sLabel.appendChild(this.el.sCheck);
		this.el.sCheck.checked = this.layout.shrinkImg; //after appending, or IE 7 ignores it
		this.el.sLabel.appendChild(document.createTextNode( ' ' + ( ( typeof(shrinkString) == 'undefined' || shrinkString === null ) ? this.strings.shrinkString : shrinkString ) ));
		this.el.sLabel.className = 'shrinklabel';
		this.el.prvnxt.appendChild(this.el.sLabel);
	}
	if( this.layout.captionToggle ) {
		this.el.tLabel = document.createElement('label');
		this.el.tCheck = document.createElement('input');
		this.el.tCheck.setAttribute('type','checkbox');
		this.el.tCheck.onclick = function () { //don't use onchange or IE gets it backwards...
			thisShow.showCaption(this.checked);
			this.blur(); //make space not retick the box, to allow it to work as a shortcut
		};
		this.el.tLabel.appendChild(this.el.tCheck);
		this.el.tCheck.checked = this.layout.showCaption; //after appending, or IE 7 ignores it
		this.el.tLabel.appendChild(document.createTextNode( ' ' + ( ( typeof(captionString) == 'undefined' || captionString === null ) ? this.strings.captionString : captionString ) ));
		this.el.tLabel.className = 'captionlabel';
		this.el.prvnxt.appendChild(this.el.tLabel);
	}
	if( this.layout.dhtmlThumbs ) {
		this.el.slideScroll.appendChild( this.el.dhtmlThumbs = document.createElement('span') ).className = 'thumblayer';
		this.el.slideScroll.appendChild( this.el.slideLeft = document.createElement('a') ).className = 'slideleft';
		this.el.slideScroll.appendChild( this.el.slideRight = document.createElement('a') ).className = 'slideright';
		this.setStyles(this.el.slideScroll,'overflow:hidden;position:relative');
		//IE 7 need inline-block to get offsetLeft and offsetWidth values correct - early Moz can harmlessly fall back to inline
		this.setStyles(this.el.dhtmlThumbs,'position:relative;display:inline-block;verticalAlign:middle;top:0;left:0;width:auto;margin:0;padding:0;borderWidth:0');
		this.setStyles(this.el.slideLeft,'position:absolute;top:0;bottom:0;left:0;margin:0');
		this.setStyles(this.el.slideRight,'position:absolute;top:0;bottom:0;right:0;margin:0');
		this.el.slideLeft.appendChild(document.createTextNode( ( typeof(leftString) == 'undefined' || leftString === null ) ? this.strings.leftString : leftString ));
		this.el.slideLeft.href = '#';
		this.el.slideLeft.onclick = function () {
			thisShow.scrollDHTMLThumbs( ( thisShow.el.slideLeft.offsetWidth + thisShow.el.slideRight.offsetWidth - thisShow.el.slideDiv.offsetWidth ) / 2,true);
			return false;
		};
		this.el.slideRight.appendChild(document.createTextNode( ( typeof(rightString) == 'undefined' || rightString === null ) ? this.strings.rightString : rightString ));
		this.el.slideRight.href = '#';
		this.el.slideRight.onclick = function () {
			thisShow.scrollDHTMLThumbs( ( thisShow.el.slideDiv.offsetWidth - ( thisShow.el.slideLeft.offsetWidth + thisShow.el.slideRight.offsetWidth ) ) / 2,true);
			return false;
		};
	} else {
		this.el.slideScroll.style.overflow = 'auto';
	}
	//add all the thumbnails
	this.slideList = [];
	for( var i = 0; i < this.imageList.length; i++ ) {
		templink = document.createElement('a');
		tempthumb = document.createElement('img');
		tempthumb.src = this.imageList[i].thumbnail;
		tempthumb.alt = this.imageList[i].altText;
		tempthumb.style.verticalAlign = templink.style.verticalAlign = 'middle';
		templink.href = '#';
		templink.indexNum = i;
		templink.onclick = function () {
			thisShow.setCurrent(this.indexNum);
			return false;
		};
		templink.appendChild(tempthumb);
		this.slideList[this.slideList.length] = templink;
		(this.layout.dhtmlThumbs?this.el.dhtmlThumbs:this.el.slideScroll).appendChild(templink);
	}
	if( !this.layout.embedded ) {
		//store the styles and classes that will be destroyed so they can be restored later
		document.documentElement.defaultDisplay = document.documentElement.style.display;
		document.documentElement.defaultBorder = document.documentElement.style.borderWidth;
		document.documentElement.defaultMargin = document.documentElement.style.margin;
		document.documentElement.defaultPadding = document.documentElement.style.padding;
		document.documentElement.defaultOverflowY = document.documentElement.style.overflowY;
		document.documentElement.defaultOverflowX = document.documentElement.style.overflowX;
		document.documentElement.defaultClass = document.documentElement.className;
		document.body.defaultBorder = document.body.style.borderWidth;
		document.body.defaultMargin = document.body.style.margin;
		document.body.defaultPadding = document.body.style.padding;
		document.body.defaultPosition = document.body.style.position;
		document.body.defaultWidth = document.body.style.width;
		document.body.defaultMaxWidth = document.body.style.maxWidth;
		//swap out the old content for the new content
		for( var p = 0; p < document.body.childNodes.length; p++ ) {
			if( document.body.childNodes[p].style ) {
				document.body.childNodes[p].defaultDisplay = document.body.childNodes[p].style.display;
				document.body.childNodes[p].style.display = 'none';
			}
		}
		document.documentElement.className = 'showingslides'; //set before making measurements
	}
	this.el.parentEl.appendChild(this.el.rootElement);
	//measure various things to store in .layout (more of this later)
	this.setStyles(this.el.slideDiv,'position:static;styleFloat:left;cssFloat:left;height:0;width:0;');
	this.layout.slideXPad = this.el.slideDiv.clientWidth;
	this.layout.slideYPad = this.el.slideDiv.clientHeight;
	this.setStyles(this.el.slideDiv,'position:;styleFloat:;cssFloat:;height:;width:');
	//special styles that depend on how it is being displayed
	if( this.layout.embedded ) {
		this.el.slideDiv.style.position = 'relative';
	} else {
		if( this.el.rootElement.focus ) { this.el.rootElement.focus(); } //once again try to blur the link, for Opera
		this.setStyles(this.el.slideDiv,'position:absolute;top:0;right:0;bottom:0;left:0;zIndex:1');
		//set temporary styles on HTML and BODY
		this.setStyles(document.documentElement,'display:block;borderWidth:0;margin:0;padding:0');
		if( !this.layout.thumbsOnTop ) {
			this.setStyles(document.documentElement,'overflowX:hidden;overflowY:hidden');
		}
		this.setStyles(document.body,'borderWidth:0;margin:0;padding:0;position:static;width:auto;maxWidth:none');
	}
	//if thumbnails are not yet loaded, it's possible the maximum height of the div has not yet been established
	for( var j = 0; j < this.imageList.length; j++ ) {
		this.slideList[j].firstChild.thumbIndex = j;
		this.slideList[j].firstChild.onload = function () {
			thisShow.setHeight();
			//reset scrolling of the thumb list if needed - try to avoid too much flickering;
			//only scroll for the ones that affect whether the current one, and the thumb to its right, are properly visible
			if( thisShow.showingNumber > 1 && this.thumbIndex < thisShow.showingNumber + 2 ) {
				thisShow.scrollToThumb();
			}
		};
	}
	//measure various things to store in .layout
	if( !this.layout.embedded ) {
		this.layout.fixedHeight = true;
	} else {
		this.layout.fixedHeight = this.el.slideDiv.offsetHeight;
		this.el.slideDiv.appendChild(document.createTextNode('Loading...'));
		this.layout.fixedHeight = ( this.layout.fixedHeight == this.el.slideDiv.offsetHeight );
		this.el.slideDiv.removeChild(this.el.slideDiv.firstChild);
	}
	this.el.slideDiv.appendChild(document.createElement('div')); //slideWrap
	this.el.slideDiv.firstChild.appendChild(document.createElement('div')).className = 'slidecaption';
	if( window.getComputedStyle ) {
		templink = getComputedStyle(this.el.slideDiv.firstChild.firstChild,null);
		this.layout.positionedCaption = ( templink.position == 'absolute' || templink.position == 'fixed' );
	} else if( this.el.slideDiv.currentStyle ) {
		this.layout.positionedCaption = ( this.el.slideDiv.firstChild.firstChild.currentStyle.position == 'absolute' || this.el.slideDiv.firstChild.firstChild.currentStyle.position == 'fixed' );
	}
	this.setStyles(this.el.slideDiv.firstChild,'height:auto;position:static;styleFloat:left;cssFloat:left;border:1px solid transparent;padding:0;display:block');
	if( !this.layout.positionedCaption ) {
		//IE 7 needs some text inside it
		this.setStyles(this.el.slideDiv.firstChild.firstChild,'height:auto;position:static;styleFloat:none;cssFloat:none;display:block');
		this.el.slideDiv.firstChild.firstChild.appendChild(document.createElement('div')).appendChild(document.createTextNode('Loading...'));
		this.setStyles(this.el.slideDiv.firstChild.firstChild.firstChild,'height:auto;position:static;styleFloat:none;cssFloat:none;border:none;padding:0;margin:0;display:block');
		this.layout.captionYPad = this.el.slideDiv.firstChild.clientHeight - this.el.slideDiv.firstChild.firstChild.offsetHeight;
		this.layout.captionXPad = this.el.slideDiv.firstChild.clientWidth - this.el.slideDiv.firstChild.firstChild.firstChild.offsetWidth;
	}
	this.el.slideDiv.firstChild.replaceChild(document.createElement('img'),this.el.slideDiv.firstChild.firstChild);
	//IE 7- creates a block placeholder which also works - need real image for Firefox or it creates a stupid inline
	this.el.slideDiv.firstChild.firstChild.style.display = 'block';
	this.el.slideDiv.firstChild.firstChild.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAFS3GZcAAAAK3RFWHRDcmVhdGlvbiBUaW1lAFN1biAxIE5vdiAyMDA5IDExOjA3OjI1IC0wMDAwFuRsfwAAAAd0SU1FB9kLAQsJJNcdAUoAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAEZ0FNQQAAsY8L%2FGEFAAAABlBMVEUAAAD%2F%2F%2F%2Bl2Z%2FdAAAACklEQVR42mNoAAAAggCB2kUIOwAAAABJRU5ErkJggg%3D%3D';
	this.layout.imageYPad = this.el.slideDiv.firstChild.clientHeight - ( this.el.slideDiv.firstChild.firstChild.clientHeight || this.el.slideDiv.firstChild.firstChild.height || 0 );
	this.layout.imageXPad = this.el.slideDiv.firstChild.clientWidth - ( this.el.slideDiv.firstChild.firstChild.clientWidth || this.el.slideDiv.firstChild.firstChild.width || 0 );
	this.el.slideDiv.removeChild(this.el.slideDiv.firstChild);
	//set styles that depend on the current layout, but can change later
	this.setVariantStyles(false);
	//check for resize at intervals - do NOT use onresize, since setHeight can cause a scrollbar to change, which triggers onresize - infinite loop
	this.heightinterval = setInterval( function () { thisShow.setHeight(); }, this.layout.embedded ? 300 : 100 );
	//if loop message is the first slide shown, thumbs will have tucked behind slideLeft with a DHTML scroller
	if( this.layout.dhtmlThumbs ) {
		this.scrollDHTMLThumbs(0);
	}
	this.handleKeyPress = function (e) {
		//created in scope so it can reference thisShow cleanly
		function cancelIt() {
			if( e.stopPropagation ) { e.stopPropagation(); }
			if( e.preventDefault ) { e.preventDefault(); }
			e.cancelBubble = true;
			return false;
		}
		//opera 10.00- has element under mouse as target
		if( !window.opera || thisShow.layout.embedded || !e.target || !document.activeElement || e.target == document.activeElement || ( e.target != thisShow.el.sCheck && e.target != thisShow.el.tCheck ) ) {
			//play nice when input elements are focused and the slideshow is embedded
			if( thisShow.layout.embedded && ( e.target || e.srcElement ).type ) { return true; }
			//lots of browsers use space to tick checkboxes - don't double up the functionality
			if( ( e.target || e.srcElement ).type == 'checkbox' && e.keyCode == 32 ) { return true; }
		}
		//Safari does not fire keypress for non-printing keys, but other browsers need to cancel keypress default actions
		//the script detects both, and ignores keydown for printing characters and non-safari
		if( e.type == 'keydown' && ( document.all || navigator.taintEnabled || e.charCode || !e.keyCode || ( e.keyCode > 8 && e.keyCode < 14 ) || ( e.keyCode > 31 && e.keyCode < 127 ) ) ) { return true; }
		var keyCode = e.keyCode || e.charCode; //Gecko returns 0 for printable character keys onkeypress, but charCode is right in those cases
		var modifierMap = !!e.shiftKey*1+!!e.altKey*2+!!e.ctrlKey*4+!!e.metaKey*8; //see getKeyArray
		if( thisShow.keys.nextKey && thisShow.keys.nextKey[0] == keyCode && thisShow.keys.nextKey[1] == modifierMap ) {
			thisShow.showNext();
			return cancelIt();
		}
		if( thisShow.keys.prevKey && thisShow.keys.prevKey[0] == keyCode && thisShow.keys.prevKey[1] == modifierMap ) {
			thisShow.showPrevious();
			return cancelIt();
		}
		if( thisShow.keys.closeKey && thisShow.keys.closeKey[0] == keyCode && thisShow.keys.closeKey[1] == modifierMap ) {
			thisShow.closeSlideshow();
			return cancelIt();
		}
		if( thisShow.keys.shrinkKey && thisShow.keys.shrinkKey[0] == keyCode && thisShow.keys.shrinkKey[1] == modifierMap ) {
			thisShow.shrinkToFit(!thisShow.layout.shrinkImg);
			return cancelIt();
		}
		if( thisShow.keys.captionKey && thisShow.keys.captionKey[0] == keyCode && thisShow.keys.captionKey[1] == modifierMap ) {
			thisShow.showCaption(!thisShow.layout.showCaption);
			return cancelIt();
		}
		return true;
	};
	//always add the key listeners, in case they are enabled after showing the slideshow instead of before
	if( document.addEventListener ) {
		document.addEventListener('keypress',this.handleKeyPress,true);
		document.addEventListener('keydown',this.handleKeyPress,true);
	} else if( document.attachEvent ) {
		document.attachEvent('onkeypress',this.handleKeyPress);
	}
	templink = tempthumb = null; //allow GC
	//ready to show the first picture (will also setHeight)
	this.drawNewImage( false, 'showSlideshow', null, null );
	return true;
};
GallerySlideshow.prototype.closeSlideshow = function () {
	//if this slideshow is currently being displayed, clean up, and restore previous styles and scrolling
	if( !this.isShowing ) { return false; }
	clearInterval(this.heightinterval);
	if( this.mousetimeout ) { clearTimeout(this.mousetimeout); }
	this.cancelTransition();
	this.el.parentEl.removeChild(this.el.rootElement);
	if( document.removeEventListener ) {
		document.removeEventListener('keypress',this.handleKeyPress,true);
		document.removeEventListener('keydown',this.handleKeyPress,true);
	} else if( document.detachEvent ) {
		document.detachEvent('onkeypress',this.handleKeyPress);
	}
	//allow loads of GC
	this.handleKeyPress = this.mousetimeout = null;
	this.el = {};
	this.slideList = [];
	this.lastActive = 0;
	if( this.isCurrentSlideshow() ) {
		document.body.style.display = document.body.defaultDisplay || '';
		document.documentElement.style.display = document.documentElement.defaultDisplay || '';
		document.documentElement.style.borderWidth = document.documentElement.defaultBorder || '';
		document.documentElement.style.margin = document.documentElement.defaultMargin || '';
		document.documentElement.style.padding = document.documentElement.defaultPadding || '';
		document.documentElement.style.overflowY = document.documentElement.defaultOverflowY || '';
		document.documentElement.style.overflowX = document.documentElement.defaultOverflowX || '';
		document.documentElement.className = document.documentElement.defaultClass || '';
		document.body.style.borderWidth = document.body.defaultBorder || '';
		document.body.style.margin = document.body.defaultMargin || '';
		document.body.style.padding = document.body.defaultPadding || '';
		document.body.style.position = document.body.defaultPosition || '';
		document.body.style.width = document.body.defaultWidth || '';
		document.body.style.maxWidth = document.body.defaultMaxWidth || '';
		for( var p = 0; p < document.body.childNodes.length; p++ ) {
			if( document.body.childNodes[p].style ) {
				document.body.childNodes[p].style.display = document.body.childNodes[p].defaultDisplay || '';
			}
		}
		window.scrollTo(this.pagexy[0],this.pagexy[1]);
		this.constructor.prototype.currentSlideshow = null;
	}
	this.isShowing = false;
	if( this.showingNumber == this.imageList.length ) {
		//don't show loop message when restarting
		this.setCurrent(0);
	}
	if( this.onchange ) { this.onchange({type:'closeSlideshow',from:null,to:null}); }
	return true;
};
//methods that change content/styling of the slideshow after it has been displayed
GallerySlideshow.prototype.setVariantStyles = function (oType) {
	//styles that depend on .layout, and can be set after displaying the slideshow
	if( !this.isShowing ) { return; }
	if( oType ) {
		//children of slideDiv - max width (and height if fixedHeight) applied in setHeight
		this.setStyles(this.el.slideWrap,'display:block;position:static;styleFloat:none;cssFloat:none;borderWidth:0;padding:0;margin:0');
		if( this.layout.shrinkImg && this.layout.fixedHeight && this.el.slideCaption && !this.layout.positionedCaption ) {
			//slideCaption (if it exists and is not already positioned) is overlaid at the bottom of the area when shrinking height
			this.setStyles(this.el.slideCaption,'position:absolute;bottom:0;left:0;right:0;overflow:auto;maxHeight:30%');
		} else if( !this.layout.shrinkImg && this.el.slideImg && this.el.slideCaption && !this.layout.positionedCaption ) {
			//both non-positioned caption and an image, use float and clear
			this.setStyles(this.el.slideImg,'styleFloat:left;cssFloat:left');
			this.el.slideCaption.style.clear = 'right';
		}
		if( !this.layout.shrinkImg && ( this.el.slideImg || !this.layout.positionedCaption ) ) {
			//both non-positioned caption and an image, use float and clear
			try {
				//ensure that it wraps around any margins, and does not drop them on block/floating children - Firefox defaults to 4px cellspacing
				this.setStyles(this.el.slideWrap,'display:table;borderSpacing:0;width:100%;height:100%');
			} catch(e) { /* Nobody cares about you, IE 6 */ }
		}
	} else {
		//non-regenerating elements
		if( !this.layout.embedded && this.layout.thumbsOnTop ) {
			if( this.layout.shrinkImg ) {
				this.setStyles(document.documentElement,'overflowX:hidden;overflowY:hidden');
			} else {
				this.setStyles(document.documentElement,'overflowX:auto;overflowY:scroll'); //scroll stops the scrollbar flicker when the image loads
			}
		} else {
			if( this.layout.shrinkImg ) {
				this.el.slideDiv.style.overflow = 'visible';
			} else {
				this.el.slideDiv.style.overflow = 'auto';
			}
		}
	}
};
GallerySlideshow.prototype.scrollToThumb = function () {
	//scroll the thumbnails to show the one before the one that is currently selected
	if( !this.isShowing ) { return; }
	//the loop message can be shown while thumbs are loading, and they call this method
	if( this.showingNumber < this.slideList.length ) {
		if( this.layout.dhtmlThumbs ) {
			if( this.showingNumber > 1 ) {
				this.scrollDHTMLThumbs(this.slideList[this.showingNumber-1].offsetLeft);
			} else {
				this.scrollDHTMLThumbs(0);
			}
		} else {
			try {
				//some browsers may make this property read-only but it's read/write in most of them
				this.el.slideScroll.scrollLeft = 0;
				//scroll it to 0 first (because some browsers [inc. IE8] add on the scrolling offset), then get the new position, and scroll to that -
				//this creates a small flicker that is unavoidable.
				if( this.showingNumber > 1 ) {
					this.el.slideScroll.scrollLeft = this.slideList[this.showingNumber-1].offsetLeft;
				}
			} catch(e) {}
		}
	}
};
GallerySlideshow.prototype.scrollDHTMLThumbs = function (oTo,oRelative) {
	if( !this.isShowing || !this.layout.dhtmlThumbs ) { return; }
	//measure all aspects of the thumbnail strip
	var currentLeft = parseInt(this.el.dhtmlThumbs.style.left);
	var thumbWidth = this.el.dhtmlThumbs.offsetWidth;
	var totalWidth = this.el.slideDiv.offsetWidth;
	var leftWidth = this.el.slideLeft.offsetWidth;
	var rightWidth = this.el.slideRight.offsetWidth;
	var notRight = totalWidth - rightWidth;
	oTo = Math.round(oTo);
	//work out where you want it, shifted over by leftWidth or relative to the current position
	if( oRelative ) {
		oTo = currentLeft - oTo;
	} else {
		oTo = leftWidth - oTo;
	}
	//if that is too far from the right edge, put it at the right edge
	if( oTo + thumbWidth < notRight ) {
		oTo = notRight - thumbWidth;
	}
	//if that is too far from the left edge, put it at the left edge
	if( oTo > leftWidth ) {
		oTo = leftWidth;
	}
	this.el.dhtmlThumbs.style.left = oTo + 'px';
	if( oTo < leftWidth ) {
		if( this.el.slideLeft.className != 'slideleft' ) { this.el.slideLeft.className = 'slideleft'; }
	} else {
		if( this.el.slideLeft.className == 'slideleft' ) { this.el.slideLeft.className = 'slideleft notenabled'; }
	}
	if( oTo + thumbWidth > notRight ) {
		if( this.el.slideRight.className != 'slideright' ) { this.el.slideRight.className = 'slideright'; }
	} else {
		if( this.el.slideRight.className == 'slideright' ) { this.el.slideRight.className = 'slideright notenabled'; }
	}
};
GallerySlideshow.prototype.setHeight = function () {
	if( !this.isShowing || !this.el.slideScroll ) { return; }
	if( this.layout.dhtmlThumbs ) {
		this.scrollDHTMLThumbs(0,true);
	} else {
		var outerwidth = this.el.slideScroll.offsetWidth, innerwidth = this.el.slideScroll.clientWidth, avHeight, avWidth;
		if( !this.el.slideScroll.style.paddingBottom && outerwidth && innerwidth && outerwidth > innerwidth ) {
			//IE 7 bug that overlaps the horizontal scrollbar over the content, and creates a vertical scrollbar
			this.el.slideScroll.style.paddingBottom = ( outerwidth - innerwidth ) + 'px';
			this.el.slideScroll.style.overflowY = 'hidden';
		} else if( this.el.slideScroll.style.paddingBottom && outerwidth >= this.el.slideScroll.scrollWidth ) {
			//remove the IE 7 bug fix so it does not leave a gap when there is no scrollbar
			this.el.slideScroll.style.paddingBottom = '';
			this.el.slideScroll.style.overflowY = '';
		}
	}
	//all browsers - push the image down enough that it appears below the fixed position thumbnail strip
	if( !this.layout.embedded ) {
		this.el.slideDiv.style[this.layout.thumbsOnTop?'marginTop':'marginBottom'] = this.el.listDiv.offsetHeight + 'px';
	}
	//set max-height and max-width accordingly - can't use percentages, since they relate to content box, not margin box
	if( this.layout.shrinkImg && this.el.slideImg ) {
		avWidth = this.el.slideDiv.clientWidth - ( this.layout.imageXPad + this.layout.slideXPad );
		if( this.layout.fixedHeight ) {
			avHeight = this.el.slideDiv.clientHeight - ( this.layout.imageYPad + this.layout.slideYPad );
			if( !this.layout.positionedCaption && this.el.slideCaption ) {
				avHeight -= this.layout.captionYPad + this.el.slideCaption.offsetHeight;
			}
			this.el.slideImg.style.maxHeight = Math.max(avHeight,1) + 'px';
		}
		this.el.slideImg.style.maxWidth = Math.max(avWidth,1) + 'px';
	}
	//table display may retain margins, but it also allows the text to become wider than the scrolling area, making it hard to read
	if( !this.layout.shrinkImg && !this.layout.positionedCaption && this.el.slideCaption ) {
		this.el.slideCaption.style.maxWidth = Math.max( this.el.slideDiv.clientWidth - this.layout.captionXPad, 1 ) + 'px';
	}
};
GallerySlideshow.prototype.drawNewImage = function (allowTransition,type,from,to) {
	var thisShow;
	function drawTransitionStep() {
		var curamt = (new Date()).getTime() - allowTransition;
		if( curamt >= thisShow.transitionDuration ) {
			thisShow.cancelTransition();
		} else if( thisShow.el.transition ) {
			curamt = 1 - ( curamt / thisShow.transitionDuration );
			if( thisShow.transitions & 1 ) {
				thisShow.el.transition.style.opacity = curamt;
				thisShow.el.transition.style.filter = 'alpha(opacity='+(100*curamt)+')';
			}
			if( thisShow.transitions & 2 ) {
				var heightamt = thisShow.el.transition.halfheight * curamt, widthamt = thisShow.el.transition.halfwidth * curamt;
				thisShow.el.transition.style.clip =
					'rect(' + Math.round( thisShow.el.transition.halfheight - heightamt ) +
					'px,' + Math.round( thisShow.el.transition.halfwidth + widthamt ) +
					'px,' + Math.round( thisShow.el.transition.halfheight + heightamt ) +
					'px,' + Math.round( thisShow.el.transition.halfwidth - widthamt ) + 'px)';
			}
		}
	}
	//draw or redraw the current image and associated caption
	if( !this.isShowing ) { return; }
	if( this.el.transition ) { this.cancelTransition(); }
	if( !this.layout.embedded ) {
		window.scrollTo(0,0);
	}
	try {
		this.el.slideDiv.scrollLeft = 0;
		this.el.slideDiv.scrollTop = 0;
	} catch(e) {}
	this.cacheImg(this.showingNumber);
	if( this.transitions && allowTransition && this.el.slideDiv.firstChild ) {
		this.el.transition = this.el.slideDiv.cloneNode(true);
		if( this.layout.embedded ) {
			this.el.transition.style.position = 'absolute';
			this.el.transition.style.left = this.el.slideDiv.offsetLeft + 'px';
			this.el.transition.style.top = this.el.slideDiv.offsetTop + 'px';
			this.el.transition.style.width = ( this.el.slideDiv.offsetWidth - this.layout.slideXPad ) + 'px';
			this.el.transition.style.height = ( this.el.slideDiv.offsetHeight - this.layout.slideYPad ) + 'px';
		}
		this.el.rootElement.appendChild(this.el.transition);
		this.el.transition.halfwidth = this.el.transition.offsetWidth / 2;
		this.el.transition.halfheight = this.el.transition.offsetHeight / 2;
		allowTransition = (new Date()).getTime();
		thisShow = this;
		this.transinterval = setInterval(drawTransitionStep,25);
		drawTransitionStep();
	}
	//remove the old IMG element and create a new one (avoids resize problems when browsers reuse an IMG)
	if( window.opera && !document.isEqualNode && !this.layout.embedded ) { this.el.slideDiv.style.display = 'none'; } //redraw bug fix
	this.el.slideWrap = this.el.slideImg = this.el.minSize = this.el.slideCaption = this.el.underCaption = null;
	while( this.el.slideDiv.firstChild ) {
		this.el.slideDiv.removeChild(this.el.slideDiv.firstChild);
	}
	if( window.opera && !document.isEqualNode && !this.layout.embedded ) {
		//fix is only active in Opera 10- since redraw bug cannot be reproduced in 11, and fix may cause scrolling jump
		var ignoreme = this.el.slideDiv.offsetWidth;
		this.el.slideDiv.style.display = '';
	}
	if( this.showingNumber == this.imageList.length ) {
		//time to display the loop message
		this.el.slideDiv.appendChild( this.el.slideWrap = document.createElement('div') ).appendChild( this.el.slideCaption = document.createElement('div') ).className = 'slidecaption';
		this.el.slideCaption.appendChild(document.createTextNode( ( typeof(this.userLoopString) == 'undefined' || this.userLoopString === null ) ? this.strings.loopString : this.userLoopString ));
		if( this.slideList[this.lastActive] && this.slideList[this.lastActive].className ) {
			this.slideList[this.lastActive].className = '';
		}
		//set styles that depend on the current layout, but can change later
		this.setVariantStyles(true);
		this.setHeight();
		if( this.onchange ) { this.onchange({type:type,from:from,to:to}); }
		return;
	}
	if( !this.looptype && !this.showingNumber ) {
		//set the prev link to disabled class
		this.el.pLink.className = 'prevbutton notenabled';
	} else if( this.el.pLink.className != 'prevbutton' ) {
		this.el.pLink.className = 'prevbutton';
	}
	if( !this.looptype && this.showingNumber == this.imageList.length - 1 ) {
		//set the next link to disabled class
		this.el.nLink.className = 'nextbutton notenabled';
	} else if( this.el.nLink.className != 'nextbutton' ) {
		this.el.nLink.className = 'nextbutton';
	}
	this.el.slideImg = document.createElement('img');
	this.el.slideImg.style.display = 'block';
	var slideShow = this;
	if( this.nextCache || this.prevCache ) {
		this.el.slideImg.onload = function () {
			//cache next/prev as needed once the main image has loaded (and if it's still showing), then allow GC
			if( !slideShow.isShowing ) { return; }
			if( slideShow.nextCache ) {
				slideShow.cacheImg((slideShow.showingNumber+1<slideShow.imageList.length)?(slideShow.showingNumber+1):0);
			}
			if( slideShow.prevCache ) {
				//can end up negative or out of range if they deleted all in between and re-displayed, but the GC did not remove the onload function,
				//so cacheImage checks if the index is valid
				slideShow.cacheImg((slideShow.showingNumber?slideShow.showingNumber:slideShow.imageList.length)-1);
			}
			//IE invents these attributes even though I never put them there, and they mess up the aspect ratio with shrink to fit
			this.removeAttribute('height');
			this.removeAttribute('width');
			this.onload = null;
			if( slideShow.layout.shrinkImg ) { slideShow.setHeight(); }
		};
	} else {
		this.el.slideImg.onload = function () {
			//IE invents these attributes even though I never put them there, and they mess up the aspect ratio with shrink to fit
			this.removeAttribute('height');
			this.removeAttribute('width');
			this.onload = null;
			if( slideShow.layout.shrinkImg ) { slideShow.setHeight(); }
		};
	}
	this.el.slideImg.src = this.imageList[this.showingNumber].fullImage;
	this.el.slideImg.alt = this.imageList[this.showingNumber].altText;
	this.el.slideDiv.appendChild( this.el.slideWrap = document.createElement('div') ).appendChild(this.el.slideImg);
	if( this.layout.showCaption && this.imageList[this.showingNumber].text.replace(/\s+/,'') ) {
		if( !this.layout.positionedCaption && !this.layout.shrinkImg ) {
			//min-width (with block formatting context) breaks in various cases in most browsers when used here
			//fake it by forcing it to clear a float which will clear the earlier float - adds a 1px gap but it works well
			this.el.slideWrap.appendChild( this.el.minSize = document.createElement('span') );
			this.setStyles(this.el.minSize,'styleFloat:right;cssFloat:right;minWidth:10em;height:1px');
		}
		this.el.slideWrap.appendChild( this.el.slideCaption = document.createElement('div') ).className = 'slidecaption';
		this.el.slideCaption.appendChild(document.createTextNode(this.imageList[this.showingNumber].text));
		if( this.layout.embedded && !this.layout.fixedHeight && !this.layout.positionedCaption && !this.layout.shrinkImg ) {
			//force clearance to prevent overlapping following content - put in slideWrap not slideDiv or it creates a scrollbar when transitions give height
			this.el.slideWrap.appendChild( this.el.underCaption = document.createElement('span') );
			this.setStyles(this.el.underCaption,'display:block;height:1px;clear:both');
		}
	}
	//set styles that depend on the current layout, but can change later
	this.setVariantStyles(true);
	//highlight current thumb
	if( this.lastActive != this.showingNumber && this.slideList[this.lastActive].className ) {
		this.slideList[this.lastActive].className = '';
	}
	this.slideList[this.showingNumber].className = 'current';
	this.lastActive = this.showingNumber;
	this.scrollToThumb();
	this.setHeight();
	if( this.onchange ) { this.onchange({type:type,from:from,to:to}); }
};
//transitions
GallerySlideshow.prototype.setTransitions = function (oOpacity,oClip) {
	this.transitions = ( oOpacity ? 1 : 0 ) + ( oClip ? 2 : 0 ); //if it happens to be in the middle of a transition, it will alter itself accordingly
};
GallerySlideshow.prototype.setTransitionDuration = function (oTime) {
	oTime = Math.round(oTime) || 50;
	this.transitionDuration = Math.min(Math.max(oTime,50),120000); //if it happens to be in the middle of a transition, it will alter itself accordingly
};
GallerySlideshow.prototype.cancelTransition = function () {
	if( this.transinterval ) { clearInterval(this.transinterval); }
	if( this.el.transition && this.el.rootElement && this.el.rootElement == this.el.transition.parentNode ) {
		this.el.rootElement.removeChild(this.el.transition);
	}
	this.el.transition = null;
};
GallerySlideshow.prototype.isTransitioning = function () {
	return !!this.el.transition;
};
//methods to control caching
GallerySlideshow.prototype.cacheImg = function (cacheIndex) {
	if( cacheIndex < 0 || cacheIndex >= this.imageList.length ) { return; }
	//cache the image
	if( !this.massiveCache[this.imageList[cacheIndex].fullImage] ) {
		this.massiveCache[this.imageList[cacheIndex].fullImage] = new Image();
		this.massiveCache[this.imageList[cacheIndex].fullImage].src = this.imageList[cacheIndex].fullImage;
	}
};
GallerySlideshow.prototype.setCacheNext = function (cacheNext) {
	this.nextCache = cacheNext;
};
GallerySlideshow.prototype.setCachePrev = function (cachePrev) {
	this.prevCache = cachePrev;
};
//keyboard methods
GallerySlideshow.prototype.getKeyArray = function (keys,keyCode,defaultMap) {
	if( !keys[0] || typeof(keys[0]) == typeof(true) ) {
		return keys[0] ? [keyCode,defaultMap] : null;
	}
	//use a bitmask - implicit cast of boolean to number 1/0
	return [keys[0],!!keys[1]*1+!!keys[2]*2+!!keys[3]*4+!!keys[4]*8];
};
GallerySlideshow.prototype.setKeyNext = function () {
	this.keys.nextKey = this.getKeyArray(arguments,32,0);
};
GallerySlideshow.prototype.setKeyPrev = function () {
	this.keys.prevKey = this.getKeyArray(arguments,32,1);
};
GallerySlideshow.prototype.setKeyClose = function () {
	this.keys.closeKey = this.getKeyArray(arguments,27,0);
};
GallerySlideshow.prototype.setKeyShrink = function () {
	this.keys.shrinkKey = this.getKeyArray(arguments,83,1);
};
GallerySlideshow.prototype.setKeyCaption = function () {
	this.keys.captionKey = this.getKeyArray(arguments,67,1);
};
//utility methods
GallerySlideshow.prototype.setStyles = function (oElement,oStyles) {
	//set multiple styles to avoid using huge amounts of code
	//setAttribute and style.cssText are unreliably supported and are not cumulative, so set individually
	oStyles = oStyles.split(/;/);
	for( var i = 0, splitStyle; i < oStyles.length; i++ ) {
		splitStyle = oStyles[i].split(/:/);
		oElement.style[splitStyle[0]] = splitStyle[1] || '';
	}
};
GallerySlideshow.prototype.getCurrent = function () {
	return this.showingNumber;
};
GallerySlideshow.prototype.getTotal = function () {
	return this.imageList.length;
};
GallerySlideshow.prototype.canWork = function () {
	//is the browser good enough, and has the page loaded enough
	return document.documentElement && document.body && document.getElementsByTagName && document.createElement && document.childNodes;
};
GallerySlideshow.prototype.isCurrentSlideshow = function () {
	//says if this slideshow is being displayed as an overlay
	return this.currentSlideshow == this;
};
GallerySlideshow.prototype.isShowingSlideshow = function () {
	//says if this slideshow is being displayed
	return this.isShowing;
};
//global properties for use by internal methods
GallerySlideshow.prototype.strings = {
	prevString: '<< Previous',
	nextString: 'Next >>',
	closeString: 'Close slideshow',
	loopString: 'You have reached the end of this gallery.',
	shrinkString: 'Shrink image to fit',
	captionString: 'Show captions',
	leftString: '<',
	rightString: '>'
};
GallerySlideshow.prototype.massiveCache = {};
GallerySlideshow.prototype.currentSlideshow = null;