/**
 * @fileoverview frozTabs plugin
 * @author Lawrence Natividad
 * @copyright Copyright ( c ) 2010 Frozynart Designs
 * @license Licensed under MIT ( http://www.frozynart.com/license/mit )
 * @version: 1.0 2010-04-28
 */

( function( $ ) {
    /**
     * Strict mark-up required
     * Places contents in tabs
     * @namespace frozTabs
     * @requires jQuery 1.2.6 and above / jQuery scrollTo / jqueryhashchange / frozTabs.css
     * @example jQuery( "#id-of-block-that-contains-links and contents" ).frozTabs
     * @return {jQuery Object}
     */
    jQuery.fn.frozTabs = function( options ) {
        var opts                     = jQuery.extend( {}, jQuery.fn.frozTabs.defaults, options );
        jQuery.fn.frozTabs.opts      = opts;
        var $this                    = jQuery( this );
        
        var storeData = function(set){
            var contentArray = new Array();
            var heightArray = new Array();
               
            jQuery('.' + opts.tabContainerClass, set).children('div').each( function(){
            	jQuery(this).addClass(opts.mainTabClass);
                contentArray.push('#' + jQuery(this).attr('id'));
                heightArray.push(jQuery(this).outerHeight(true));
            })
            
            set.data('contentArray', contentArray)
               .data('heightArray', heightArray)
               .data('contentLength', contentArray.length);
            
            return set;
        }
        
        var setupTabs = function(set){
        
            var tabs = new Array();
            var links = new Array();

            if ( opts.slider !== null ){
                jQuery('.' + opts.tabContainerClass, set).wrapInner(jQuery('<div class="' + opts.slider + '"></div>'));
                set.data('slider', jQuery('.' + opts.tabContainerClass, set).children())
                jQuery('.' + opts.tabContainerClass, set).children('div').children('div').each( function(){
                    tabs.push(jQuery(this));
                })
                set.data('slider').css({
                    overflow: 'hidden',
                    display: 'block',
                    position: 'relative'
                });
            } else {
                jQuery('.' + opts.tabContainerClass, set).children('div').each( function(){
                    tabs.push(jQuery(this).css({position: 'absolute'}).hide());
                })
            }
            
            jQuery('.' + opts.linkContainerClass, set).children('li').children('a').each( function(){
                links.push(jQuery(this));
            })
            
            set.data('tabs', tabs);
            set.data('links', links);
            
            setStarter(set);
            
            return set;
        }
        
        var setStarter = function(set){
            var finalIndex = 0;
            
            if ( opts.hashing === true ){
                var loc = checkHash();
                for ( index in set.data('contentArray') ){
                    if ( set.data('contentArray')[index] === loc ){
                        finalIndex = index;
                        break;
                    }
                }
            jQuery(window).data('tabhashclicked', false);
            } else {
                for( index in set.data('tabs') ){
                    if ( index == opts.selected ){
                        finalIndex = index;
                        break;
                    }
                }
            }
            
			activate(set, finalIndex);
            set.data('activeTabCount', finalIndex );
            var height = getContentHeight(set, finalIndex)

            if ( opts.slider !== null ){
                var top = getContentTop(set, finalIndex);
                jQuery('.' + opts.tabContainerClass, set).css({height: height + 'px'});
                set.data('slider').css({top: top + 'px'})
            } else {
            	showContent(set, finalIndex, height);
//                set.data('tabs')[finalIndex].show();
            }
            
            handleAutoScroll(set);
        }
        
        var activate = function(set, finalIndex){
        	for ( index in set.data('links') ){
        		set.data('links')[index].closest('li').removeClass(opts.activeClass);
        	}
        	
        	for ( index in set.data('tabs') ){
        		set.data('tabs')[index].removeClass(opts.activeClass);
        	}
        	
        	var baseIndex = opts.tabZIndexBase;
        	var liCount = set.data('links').length;
        	
        	set.data('links')[finalIndex].closest('li').addClass(opts.activeClass);
        	set.data('tabs')[finalIndex].addClass(opts.activeClass);
        	
        }
        
        var handleAutoScroll = function(set){
        	if (opts.autoScroll === true){
    	        jQuery.scrollTo(('#' + set.attr('id')), opts.autoScrollSpeed);   //scroll to tab
    	    } else if (opts.autoScroll === false){
    	        jQuery.scrollTo('body', opts.autoScrollSpeed);   //scroll to body
    	    } else {
    	        if (opts.autoScroll !== null){
    	            jQuery.scrollTo(opts.autoScroll, opts.autoScrollSpeed);  //scroll to specified element
    	        }
    	    } 
        }
        
        var checkHash = function(){
            if ( (jQuery.browser.msie === true) && (jQuery.browser.version === '7.0') ) {
            	var tabParam = window.location.toString().substring(window.location.toString().indexOf('#'));
            } else {
            	var tabParam = window.location.hash;
            }

            return tabParam;
        }
        
        var getContentHeight = function(set, index){
            
            return set.data('heightArray')[index];
        }
        
        var getContentTop = function(set, index){
            
            var finalTop = 0;
            
            for ( count in set.data('heightArray') ){
                if ( !(count > (index - 1)) ){
                    finalTop += set.data('heightArray')[count];
                }
            }
            
            return -(finalTop);            
        }
        
        var setupBehavior = function(set){
        	
        	for ( linkCount in set.data('links') ){
		        set.data('links')[linkCount].closest('li').click( function(){
		        	if ( !jQuery(this).hasClass(opts.activeClass) ){

				        var href = jQuery(this).children('a').attr('href');
				        var finalCount = 0;
				        
				        for ( count in set.data('contentArray') ){
				            if ( set.data('contentArray')[count] === href ){
				                finalCount = count;
				                break;
				            }
				        }
				            
			            var height = getContentHeight(set, finalCount);
				        if ( opts.slider !== null ){
				            var top = getContentTop(set, finalCount);
				            slideContent(set, height, top);
				        } else if ( opts.tabFade === true ){
				            fadeContent(set, finalCount, height);
				        } else {
				            showContent(set, finalCount, height);
				        }
				        
						activate(set, finalCount);
				        set.data('activeTabCount', finalCount );
				            
				        if ( opts.hashing === true ){
				        	jQuery(window).data('tabhashclicked', true);
				            updateHash(set, finalCount, href);
				        }
				        
		            }
		            return false;
		        })
            }
            return set;
        }
        
        var slideContent = function(set, height, top){
            jQuery('.' + opts.tabContainerClass, set).stop( false, true )
               .animate({height: height + 'px'}, opts.easingDuration, opts.slideEasing );
               
            set.data('slider').stop( false, true )
               .animate({top: top + 'px'}, opts.easingDuration, opts.slideEasing);
        }
        
        var fadeContent = function(set, finalCount, height){
            jQuery('.' + opts.tabContainerClass, set).stop( false, true )
               .animate({height: height + 'px'}, opts.easingDuration, opts.slideEasing );
            set.data('tabs')[set.data('activeTabCount')].stop( false, true ).fadeOut(opts.fadeTime);
            set.data('tabs')[finalCount].stop( false, true ).fadeIn(opts.fadeTime);
        }
        
        var showContent = function(set, finalCount, height){
            jQuery('.' + opts.tabContainerClass, set).stop( false, true )
               .css({height: height + 'px'});
            set.data('tabs')[set.data('activeTabCount')].stop( false, true ).hide();
            set.data('tabs')[finalCount].stop( false, true ).show();
        }
        
        var setupLinks = function(set){
        	var linkHead = jQuery('ul.' + opts.linkContainerClass, set);
        	var baseIndex = opts.tabZIndexBase;
        	var liCount = linkHead.children('li').length;

        	if ( opts.roundCorner === true ){
        		linkHead.addClass(opts.roundCornerClass)
        	}
        	
        	if ( opts.alignReverse === true ){
        		linkHead.addClass(opts.alignRightClass)
        		alignListRight(set, linkHead, liCount);
        	} 
        	
        	if ( opts.tabRightPos > 0 ){
        		linkHead.addClass(opts.alignRightClass)
        		alignListRight(set, linkHead, liCount);
        		
        		for ( index in set.data('links') ){
        			var parentLi = set.data('links')[index].closest('li');
        			parentLi.css({
        				zIndex: (baseIndex + (liCount - index)), 
        				left: (opts.tabRightPos * (liCount - index - 1))
        			});
        		}
        	
        	} else if ( opts.tabLeftPos > 0 ){
        		for ( index in set.data('links') ){
        			var parentLi = set.data('links')[index].closest('li');
        			parentLi.css({zIndex: (baseIndex + (liCount - index)), left: -(index * opts.tabLeftPos) + 'px'});
        		}
        	}
        
        	return set;
        }
        
        var alignListRight = function(set, linkHead, liCount){
        	var linkArray = new Array();
        	var dataLinks = new Array();
        	
        	linkHead.children('li').each( function(){
        		var clone = jQuery(this).clone(); 
        		
        		if ((jQuery.browser.msie === true) && (jQuery.browser.version === '7.0')){
		    		clone.children('a').attr('href', 
		    			clone.children('a').attr('href').slice(clone.children('a').attr('href').indexOf('#'))
		    		)
        		}	
        		
        		if (jQuery(this).nextAll().length === 0){
        			linkArray.push(clone);
        			dataLinks.push(clone.children('a'))
        			for ( ctr = 0; ctr < liCount; ctr++){
        				jQuery(this).after(linkArray[ctr]);
        			}
        			jQuery(this).remove();
        		} else {     	
        			linkArray.push(clone);
        			dataLinks.push(clone.children('a'))
        			jQuery(this).remove();
        		}
        	});      
        	
        	set.data('links', dataLinks);  
        }
        
        var updateHash = function(set, finalCount, href){
        	
        	var target = set.data('tabs')[finalCount]
        	var temp = target.attr('id');
        	
        	target.attr('id', '');
        
            if((jQuery.browser.msie === true) && (jQuery.browser.version === '7.0')){
		    	window.location = window.location.toString().substring(0, window.location.toString().indexOf('#')) + href;
		    } else {
            	window.location.hash = href;
		    }
		    
		    target.attr('id', temp);
		    
        }
        
        var handleHashchange = function(set){
        	if ( jQuery(window).data('tabhashclicked') === false ){
        		var href = checkHash();
        		var finalCount = null;
        		for ( index in set.data('contentArray') ){
        			if ( href === set.data('contentArray')[index] ){
        				finalCount = index;
        			}
        		}
        		
        		if ( finalCount !== null ){
        			set.data('links')[finalCount].trigger('click');
        			jQuery(window).data('tabhashclicked', false);
        		}
        	} else {
        		jQuery(window).data('tabhashclicked', false);
        	}
        }
        
        if ( $this.length > 0 ){
            jQuery(window).load( function(){
            	
            	$this.each( function(){
            	    var set = storeData(jQuery(this));
            	    set = setupTabs(set);
            	    set = setupLinks(set);
            	    set = setupBehavior(set);
		        
		    	    jQuery(window).bind( 'hashchange', function(event) {
						if ( opts.hashing === true ){
							handleHashchange(set);	
						}
		        	})
			    });
            	
            });
        }
         
	 	return $this;
    };
    
    /** 
     * Sends a message to the console
     * @private
     */
    var _debug = function( message ) {
        if ( true === jQuery.fn.frozTabs.opts.debug ) {
            console.log( message );
        }
    };
	    
    jQuery.fn.frozTabs.defaults =   {
    selected: 0,
	slider: null,
	slideEasing: 'easeInOutExpo',
	easingDuration: 'slow',
    roundCorner: false,
    tabZIndexBase: 1,
    tabLeftPos: 0,
    tabRightPos: 0,
    alignReverse: false, 					//should be true if links are aligned to the right but tabRightPos=0
    activeClass: 'froz-tab-active',
    alignRightClass: 'froz-tab-link-right',
    roundCornerClass: 'froz-tab-link-round',
    linkContainerClass: 'link-container',
    tabContainerClass: 'tab-container',     //div containing contents
    mainTabClass: 'tab-main',
    tabFade: true,
    fadeTime: 400,
    hashing: true,                          //determines if hash is used and updated along with tab usage
    autoScrollSpeed: 0,
    autoScroll: null                        //true: page auto-scrolls to tab
                                            //false: page auto scrolls to body
                                            //null: page does not autoscroll
                                            //if selectors are declared here, page auto-scrolls to declared element
    };          

} )(jQuery);
/**
 * @fileoverview frozAlbumGallery plugin
 * @author Lawrence Natividad
 * @copyright Copyright ( c ) 2010 Frozynart Designs
 * @license Licensed under MIT ( http://www.frozynart.com/license/mit )
 * @version: 1.0 2010-04-28
 */
 
( function( $ ) {
    /**
     * all parameters
     * <ul> passes must have ID
     * all content banners must have the same dimensions
     * When thumbnails are clicked, contents slide over accordingly
     * @namespace frozAlbumGallery Plugin Namespace
     * @requires jQuery 1.4.2 and above / jQuery Easing / jquery gallerific(new) / jQuery fancybox
     * @example jQuery( "#id-of-list-that-contains-contents" ).frozAlbumGallery
     * @return {jQuery Object}
     */
    jQuery.fn.frozAlbumGallery = function( options ) {
        var opts                            = jQuery.extend( {}, jQuery.fn.frozAlbumGallery.defaults, options );
        jQuery.fn.frozAlbumGallery.opts      = opts;
        var $this                           = jQuery( this );
		
        var setupClick = function(){		
            $this.children('li').children('a').click( function(){
            	changeHash(jQuery(this).parent('li').attr('id'));
            	var count = null
                var container = detectContainer(jQuery(this).closest('li'));
            	var href = jQuery(this).attr('href');
            	jQuery.fancybox.showActivity();
            	jQuery.ajax({
            	    url: href,
            	    success: function(data){
            	    	appendData(container, data);
//            	    	gallerify(container);
            	    	container.frozGallerify();
            	    	jQuery.fancybox({
            	    		content: container.show(),
            	    		overlayOpacity: 0.9,
//            	    		centerOnScroll: true,
            	    		autoDimensions: true,
            	    		speedIn: 100,
            	    		speedOut: 100,
            	    		onClosed: function(){
            	    			container.hide();
            	    		}
            	    	})
            	    }
            	})  
            	
            	return false;
            })
		
		}
		
		var defineDimensions = function(container){
			var height = container.outerHeight(true);
			var width = container.outerWidth(true);
			container.css({height: height, width: width})
		}
		
		var appendData = function(container, data){
			if ( container.contents().length < 1 ){
				container.append(data);
			}
		}
		
		var detectContainer = function(list){
		    var container = jQuery(list).find('div.' + opts.containerClass);
		    
		    if ( container.length < 1 ){
		    	list.append('<div class="' + opts.containerClass + '"></div>');
		    	container = jQuery('.' + opts.containerClass, list)
		    	.hide();
		    }
		    
		    return container;
		}
		
		var changeHash = function(hash){
			
			if((jQuery.browser.msie === true) && (jQuery.browser.version === '7.0')){
        		window.location = window.location.toString().substring(0, window.location.toString().indexOf('#')) +'#'+hash;
            } else {
            	window.location.hash = '#' + hash;
            }
            
		}
		
		var detectHash = function(){
		
            if((jQuery.browser.msie === true) && (jQuery.browser.version === '7.0')){
            	if ( window.location.toString().indexOf('#') < 0 ){
            		var hash = '';
            	} else {
            		var hash = window.location.toString().substring(window.location.toString().indexOf('#'));
            	}
            } else {
            	var hash = window.location.hash;
            }
            
            if ( !(hash == '') ){
            	jQuery(hash, $this).find('a:first').trigger('click');
            }
		}
		
		var setupHashBehavior = function(){
			jQuery(window).bind( 'hashchange', function(e) {
                detectHash();
            });  
		}
		
		if ( $this.length > 0 ){
		    
		    setupClick();
		    
		    detectHash();
		    
		    setupHashBehavior();
		
		}
		
		
        return $this;
    };

    /** 
     * Sends a message to the console
     * @private
     */
    var _debug = function( message ) {
        if ( true === jQuery.fn.frozAlbumGallery.opts.debug ) {
            console.log( message );
        }
    };
    
    jQuery.fn.frozAlbumGallery.defaults =   {
    	containerClass: 'album-ajax-content-container',
    	fadeTime: 500,
    	
    	galleryContainerClass: 'froz-gallery-initialized',
        mainGalleryClass: 'froz-album-gallery',
        thumbnailsId: 'thumbs',
        navigationId: 'gallery',
        controlsId: 'controls',
        slideshowContainer: 'slideshow-container',
        captionId: 'caption',
        loadingId: 'loading',
        slideshowId: 'slideshow',
        captionClass: 'caption',
        downloadClass: 'download',
        imageTitleClass: 'image-title',
        imageDescClass: 'image-desc',
        
        hashPrefix: 'album-'
    };
} )(jQuery);
/**
 * @fileoverview frozGallerify plugin
 * @author Lawrence Natividad
 * @copyright Copyright ( c ) 2010 Frozynart Designs
 * @license Licensed under MIT ( http://www.frozynart.com/license/mit )
 * @version: 1.0 2010-04-28
 */
 
( function( $ ) {
    /**
     * all parameters
     * <ul> passes must have ID
     * all content banners must have the same dimensions
     * When thumbnails are clicked, contents slide over accordingly
     * @namespace frozGallerify Plugin Namespace
     * @requires jQuery 1.4.2 and above / jQuery Easing / jquery gallerific(new) / jQuery prettyphoto
     * @example jQuery( "#id-of-list-that-contains-contents" ).frozGallerify
     * @return {jQuery Object}
     */
    jQuery.fn.frozGallerify = function( options ) {
        var opts                            = jQuery.extend( {}, jQuery.fn.frozGallerify.defaults, options );
        jQuery.fn.frozGallerify.opts      = opts;
        var $this                           = jQuery( this );
		
		var container = $this;
		
		if ( container.hasClass(opts.galleryContainerClass) ){
			
		} else {
			var list = container.find('ul:first');
			galleryArray =  new Array(opts.thumbnailsId,            //0
	                                  opts.navigationId,            //1
	                                  opts.controlsId,              //2
	                                  opts.slideshowContainer,      //3
	                                  opts.captionId,               //4
	                                  opts.loadingId,               //5    
	                                  opts.slideshowId,             //6
	                                  opts.captionClass,            //7
	                                  opts.downloadClass,           //8
	                                  opts.imageTitleClass,         //9
	                                  opts.imageDescClass           //10
	                                  );           
	                             
	        list.addClass('thumbs').css({listStyleType: 'none'}).wrap('<div id="' + galleryArray[0] + '"></div>')
	            .children('li').children('a').addClass('thumb');
	            
	        var slideDiv = list.parent();
	        
	        slideDiv.wrap('<div class="' + opts.mainGalleryClass + '"></div>')
	        slideDiv.before('<div id="' + galleryArray[1] + '"></div>');
	        
	        var slideSibling = slideDiv.prev();
	        
	        slideSibling.append('<div id="' + galleryArray[2] + '"></div>');
	        slideSibling.append('<div id="' + galleryArray[3] + '"></div>');
	        slideSibling.append('<div id="' + galleryArray[4] + '"></div>');
	        slideSibling.children('#' + galleryArray[3]).append('<div id="' + galleryArray[5] + '"></div>');
	        slideSibling.children('#' + galleryArray[3]).append('<div id="' + galleryArray[6] + '"></div>');
	            
	        list.children().each( function(){
//                var href = jQuery(this).children('a').attr('href');
	            jQuery(this).children('.' + galleryArray[7]).append('<div class="' + galleryArray[8] + '"></div>')
															.append('<div class="' + galleryArray[9] + '"></div>')
															.append('<div class="' + galleryArray[10] + '"></div>');
//                jQuery('.' + galleryArray[8], this).append('<a href="' + href + '"></a>');
	        })
	        
	        for ( index in galleryArray ){
	            jQuery('#' + galleryArray[index]).addClass(galleryArray[index]);
	            galleryArray[index] = '#' + galleryArray[index];
	        }
	        
	        var presentSlide = null;
	        
	        list.parent().galleriffic({
				delay:                     2500,
				numThumbs:                 9,
				preloadAhead:              10,
				enableTopPager:            true,
				enableBottomPager:         false,
				maxPagesToShow:            7,
				imageContainerSel:         slideSibling.children('#' + galleryArray[3]).children('#' + galleryArray[6]),
				controlsContainerSel:      slideSibling.children('#' + galleryArray[2]),
				captionContainerSel:       slideSibling.children('#' + galleryArray[4]),
				loadingContainerSel:       slideSibling.children('#' + galleryArray[3]).children('#' + galleryArray[5]),
				renderSSControls:          true,
				renderNavControls:         true,
				playLinkText:              'Play Slideshow',
				pauseLinkText:             'Pause Slideshow',
				prevLinkText:              '&lsaquo; Prev',
				nextLinkText:              'Next &rsaquo;',
				nextPageLinkText:          'Next Page',
				prevPageLinkText:          'Previous Page',
				enableHistory:             false,
				autoStart:                 false,
				syncTransitions:           true,
				defaultTransitionDuration: 900
				,
				onSlideChange: function(prevIndex, nextIndex){
	        		jQuery('span', list.parent().parent().find('div#' + opts.slideshowId)).css({position: 'absolute'});
	        		if ( jQuery('div#' + opts.captionId, list.parent().parent()).children() > 1 ){
	        			jQuery('div#' + opts.captionId, list.parent().parent()).children(':last-child').prevAll().remove();
	        		}
				}
				,
				onTransitionOut: function(previousSlide, previousCaption, isSync, transitionOutCallback){
					if ( jQuery.browser.webkit === true ){
						previousSlide.remove();
					}
					previousSlide.fadeTo(opts.fadeTime, 0.0, transitionOutCallback);
				
					if (previousCaption)
						previousCaption.remove();
				}
				,
				onTransitionIn: function(newSlide, newCaption, isSync){
								
					if ( presentSlide !== jQuery('img', newSlide).attr('src') ){				
						newSlide.fadeTo(opts.fadeTime, 1.0);
					} else {
						newSlide.fadeTo(1, 1.0);
					}
				
					if (newCaption) {
						newCaption.fadeTo(opts.fadeTime, 1.0);
					}
				
					presentSlide = jQuery('img', newSlide).attr('src');
				}
				,
				onPageTransitionIn: function(){
					list.parent().fadeIn(opts.fadeTime)
				}
	        });
	        
	        container.addClass(opts.galleryContainerClass);
		
			var defineDimensions = function(container){
				var height = container.outerHeight(true);
				var width = container.outerWidth(true);
				container.css({height: height, width: width})
			}

	        defineDimensions(container)
	        
	    }
		
        return $this;
    };

    /** 
     * Sends a message to the console
     * @private
     */
    var _debug = function( message ) {
        if ( true === jQuery.fn.frozGallerify.opts.debug ) {
            console.log( message );
        }
    };
    
    jQuery.fn.frozGallerify.defaults =   {
    	fadeTime: 500,
    	
    	galleryContainerClass: 'froz-gallery-initialized',
        mainGalleryClass: 'froz-album-gallery',
        thumbnailsId: 'thumbs',
        navigationId: 'gallery',
        controlsId: 'controls',
        slideshowContainer: 'slideshow-container',
        captionId: 'caption',
        loadingId: 'loading',
        slideshowId: 'slideshow',
        captionClass: 'caption',
        downloadClass: 'download',
        imageTitleClass: 'image-title',
        imageDescClass: 'image-desc'
    };
} )(jQuery);
/**
 * jQuery Galleriffic plugin
 *
 * Copyright (c) 2008 Trent Foley (http://trentacular.com)
 * Licensed under the MIT License:
 *   http://www.opensource.org/licenses/mit-license.php
 *
 * Much thanks to primary contributer Ponticlaro (http://www.ponticlaro.com)
 */
;(function($) {
	// Globally keep track of all images by their unique hash.  Each item is an image data object.
	var allImages = {};
	var imageCounter = 0;

	// Galleriffic static class
	$.galleriffic = {
		version: '2.0.1',

		// Strips invalid characters and any leading # characters
		normalizeHash: function(hash) {
			return hash.replace(/^.*#/, '').replace(/\?.*$/, '');
		},

		getImage: function(hash) {
			if (!hash)
				return undefined;

			hash = $.galleriffic.normalizeHash(hash);
			return allImages[hash];
		},

		// Global function that looks up an image by its hash and displays the image.
		// Returns false when an image is not found for the specified hash.
		// @param {String} hash This is the unique hash value assigned to an image.
		gotoImage: function(hash) {
			var imageData = $.galleriffic.getImage(hash);
			if (!imageData)
				return false;

			var gallery = imageData.gallery;
			gallery.gotoImage(imageData);
			
			return true;
		},

		// Removes an image from its respective gallery by its hash.
		// Returns false when an image is not found for the specified hash or the
		// specified owner gallery does match the located images gallery.
		// @param {String} hash This is the unique hash value assigned to an image.
		// @param {Object} ownerGallery (Optional) When supplied, the located images
		// gallery is verified to be the same as the specified owning gallery before
		// performing the remove operation.
		removeImageByHash: function(hash, ownerGallery) {
			var imageData = $.galleriffic.getImage(hash);
			if (!imageData)
				return false;

			var gallery = imageData.gallery;
			if (ownerGallery && ownerGallery != gallery)
				return false;

			return gallery.removeImageByIndex(imageData.index);
		}
	};

	var defaults = {
		delay:                     3000,
		numThumbs:                 20,
		preloadAhead:              40, // Set to -1 to preload all images
		enableTopPager:            false,
		enableBottomPager:         true,
		maxPagesToShow:            7,
		imageContainerSel:         '',
		captionContainerSel:       '',
		controlsContainerSel:      '',
		loadingContainerSel:       '',
		renderSSControls:          true,
		renderNavControls:         true,
		playLinkText:              'Play',
		pauseLinkText:             'Pause',
		prevLinkText:              'Previous',
		nextLinkText:              'Next',
		nextPageLinkText:          'Next &rsaquo;',
		prevPageLinkText:          '&lsaquo; Prev',
		enableHistory:             false,
		enableKeyboardNavigation:  true,
		autoStart:                 false,
		syncTransitions:           false,
		defaultTransitionDuration: 1000,
		onSlideChange:             undefined, // accepts a delegate like such: function(prevIndex, nextIndex) { ... }
		onTransitionOut:           undefined, // accepts a delegate like such: function(slide, caption, isSync, callback) { ... }
		onTransitionIn:            undefined, // accepts a delegate like such: function(slide, caption, isSync) { ... }
		onPageTransitionOut:       undefined, // accepts a delegate like such: function(callback) { ... }
		onPageTransitionIn:        undefined, // accepts a delegate like such: function() { ... }
		onImageAdded:              undefined, // accepts a delegate like such: function(imageData, $li) { ... }
		onImageRemoved:            undefined  // accepts a delegate like such: function(imageData, $li) { ... }
	};

	// Primary Galleriffic initialization function that should be called on the thumbnail container.
	$.fn.galleriffic = function(settings) {
		//  Extend Gallery Object
		$.extend(this, {
			// Returns the version of the script
			version: $.galleriffic.version,

			// Current state of the slideshow
			isSlideshowRunning: false,
			slideshowTimeout: undefined,

			// This function is attached to the click event of generated hyperlinks within the gallery
			clickHandler: function(e, link) {
				this.pause();

				if (!this.enableHistory) {
					// The href attribute holds the unique hash for an image
					var hash = $.galleriffic.normalizeHash($(link).attr('href'));
					$.galleriffic.gotoImage(hash);
					e.preventDefault();
				}
			},

			// Appends an image to the end of the set of images.  Argument listItem can be either a jQuery DOM element or arbitrary html.
			// @param listItem Either a jQuery object or a string of html of the list item that is to be added to the gallery.
			appendImage: function(listItem) {
				this.addImage(listItem, false, false);
				return this;
			},

			// Inserts an image into the set of images.  Argument listItem can be either a jQuery DOM element or arbitrary html.
			// @param listItem Either a jQuery object or a string of html of the list item that is to be added to the gallery.
			// @param {Integer} position The index within the gallery where the item shouold be added.
			insertImage: function(listItem, position) {
				this.addImage(listItem, false, true, position);
				return this;
			},

			// Adds an image to the gallery and optionally inserts/appends it to the DOM (thumbExists)
			// @param listItem Either a jQuery object or a string of html of the list item that is to be added to the gallery.
			// @param {Boolean} thumbExists Specifies whether the thumbnail already exists in the DOM or if it needs to be added.
			// @param {Boolean} insert Specifies whether the the image is appended to the end or inserted into the gallery.
			// @param {Integer} position The index within the gallery where the item shouold be added.
			addImage: function(listItem, thumbExists, insert, position) {
				var $li = ( typeof listItem === "string" ) ? $(listItem) : listItem;				
				var $aThumb = $li.find('a.thumb');
				var slideUrl = $aThumb.attr('href');
				var title = $aThumb.attr('title');
				var $caption = $li.find('.caption').remove();
				var hash = $aThumb.attr('name');

				// Increment the image counter
				imageCounter++;

				// Autogenerate a hash value if none is present or if it is a duplicate
				if (!hash || allImages[''+hash]) {
					hash = imageCounter;
				}

				// Set position to end when not specified
				if (!insert)
					position = this.data.length;
				
				var imageData = {
					title:title,
					slideUrl:slideUrl,
					caption:$caption,
					hash:hash,
					gallery:this,
					index:position
				};

				// Add the imageData to this gallery's array of images
				if (insert) {
					this.data.splice(position, 0, imageData);

					// Reset index value on all imageData objects
					this.updateIndices(position);
				}
				else {
					this.data.push(imageData);
				}

				var gallery = this;

				// Add the element to the DOM
				if (!thumbExists) {
					// Update thumbs passing in addition post transition out handler
					this.updateThumbs(function() {
						var $thumbsUl = gallery.find('ul.thumbs');
						if (insert)
							$thumbsUl.children(':eq('+position+')').before($li);
						else
							$thumbsUl.append($li);
						
						if (gallery.onImageAdded)
							gallery.onImageAdded(imageData, $li);
					});
				}

				// Register the image globally
				allImages[''+hash] = imageData;

				// Setup attributes and click handler
				$aThumb.attr('rel', 'history')
					.attr('href', '#'+hash)
					.removeAttr('name')
					.click(function(e) {
						gallery.clickHandler(e, this);
					});
				return this;
			},

			// Removes an image from the gallery based on its index.
			// Returns false when the index is out of range.
			removeImageByIndex: function(index) {
				if (index < 0 || index >= this.data.length)
					return false;
				
				var imageData = this.data[index];
				if (!imageData)
					return false;
				
				this.removeImage(imageData);
				
				return true;
			},

			// Convenience method that simply calls the global removeImageByHash method.
			removeImageByHash: function(hash) {
				return $.galleriffic.removeImageByHash(hash, this);
			},

			// Removes an image from the gallery.
			removeImage: function(imageData) {
				var index = imageData.index;
				
				// Remove the image from the gallery data array
				this.data.splice(index, 1);
				
				// Remove the global registration
				delete allImages[''+imageData.hash];
				
				// Remove the image's list item from the DOM
				this.updateThumbs(function() {
					var $li = gallery.find('ul.thumbs')
						.children(':eq('+index+')')
						.remove();

					if (gallery.onImageRemoved)
						gallery.onImageRemoved(imageData, $li);
				});

				// Update each image objects index value
				this.updateIndices(index);

				return this;
			},

			// Updates the index values of the each of the images in the gallery after the specified index
			updateIndices: function(startIndex) {
				for (i = startIndex; i < this.data.length; i++) {
					this.data[i].index = i;
				}
				
				return this;
			},

			// Scraped the thumbnail container for thumbs and adds each to the gallery
			initializeThumbs: function() {
				this.data = [];
				var gallery = this;

				this.find('ul.thumbs > li').each(function(i) {
					gallery.addImage($(this), true, false);
				});

				return this;
			},

			isPreloadComplete: false,

			// Initalizes the image preloader
			preloadInit: function() {
				if (this.preloadAhead == 0) return this;
				
				this.preloadStartIndex = this.currentImage.index;
				var nextIndex = this.getNextIndex(this.preloadStartIndex);
				return this.preloadRecursive(this.preloadStartIndex, nextIndex);
			},

			// Changes the location in the gallery the preloader should work
			// @param {Integer} index The index of the image where the preloader should restart at.
			preloadRelocate: function(index) {
				// By changing this startIndex, the current preload script will restart
				this.preloadStartIndex = index;
				return this;
			},

			// Recursive function that performs the image preloading
			// @param {Integer} startIndex The index of the first image the current preloader started on.
			// @param {Integer} currentIndex The index of the current image to preload.
			preloadRecursive: function(startIndex, currentIndex) {
				// Check if startIndex has been relocated
				if (startIndex != this.preloadStartIndex) {
					var nextIndex = this.getNextIndex(this.preloadStartIndex);
					return this.preloadRecursive(this.preloadStartIndex, nextIndex);
				}

				var gallery = this;

				// Now check for preloadAhead count
				var preloadCount = currentIndex - startIndex;
				if (preloadCount < 0)
					preloadCount = this.data.length-1-startIndex+currentIndex;
				if (this.preloadAhead >= 0 && preloadCount > this.preloadAhead) {
					// Do this in order to keep checking for relocated start index
					setTimeout(function() { gallery.preloadRecursive(startIndex, currentIndex); }, 500);
					return this;
				}

				var imageData = this.data[currentIndex];
				if (!imageData)
					return this;

				// If already loaded, continue
				if (imageData.image)
					return this.preloadNext(startIndex, currentIndex); 
				
				// Preload the image
				var image = new Image();
				
				image.onload = function() {
					imageData.image = this;
					gallery.preloadNext(startIndex, currentIndex);
				};

				image.alt = imageData.title;
				image.src = imageData.slideUrl;

				return this;
			},
			
			// Called by preloadRecursive in order to preload the next image after the previous has loaded.
			// @param {Integer} startIndex The index of the first image the current preloader started on.
			// @param {Integer} currentIndex The index of the current image to preload.
			preloadNext: function(startIndex, currentIndex) {
				var nextIndex = this.getNextIndex(currentIndex);
				if (nextIndex == startIndex) {
					this.isPreloadComplete = true;
				} else {
					// Use setTimeout to free up thread
					var gallery = this;
					setTimeout(function() { gallery.preloadRecursive(startIndex, nextIndex); }, 100);
				}

				return this;
			},

			// Safe way to get the next image index relative to the current image.
			// If the current image is the last, returns 0
			getNextIndex: function(index) {
				var nextIndex = index+1;
				if (nextIndex >= this.data.length)
					nextIndex = 0;
				return nextIndex;
			},

			// Safe way to get the previous image index relative to the current image.
			// If the current image is the first, return the index of the last image in the gallery.
			getPrevIndex: function(index) {
				var prevIndex = index-1;
				if (prevIndex < 0)
					prevIndex = this.data.length-1;
				return prevIndex;
			},

			// Pauses the slideshow
			pause: function() {
				this.isSlideshowRunning = false;
				if (this.slideshowTimeout) {
					clearTimeout(this.slideshowTimeout);
					this.slideshowTimeout = undefined;
				}

				if (this.$controlsContainer) {
					this.$controlsContainer
						.find('div.ss-controls a').removeClass().addClass('play')
						.attr('title', this.playLinkText)
						.attr('href', '#play')
						.html(this.playLinkText);
				}
				
				return this;
			},

			// Plays the slideshow
			play: function() {
				this.isSlideshowRunning = true;

				if (this.$controlsContainer) {
					this.$controlsContainer
						.find('div.ss-controls a').removeClass().addClass('pause')
						.attr('title', this.pauseLinkText)
						.attr('href', '#pause')
						.html(this.pauseLinkText);
				}

				if (!this.slideshowTimeout) {
					var gallery = this;
					this.slideshowTimeout = setTimeout(function() { gallery.ssAdvance(); }, this.delay);
				}

				return this;
			},

			// Toggles the state of the slideshow (playing/paused)
			toggleSlideshow: function() {
				if (this.isSlideshowRunning)
					this.pause();
				else
					this.play();

				return this;
			},

			// Advances the slideshow to the next image and delegates navigation to the
			// history plugin when history is enabled
			// enableHistory is true
			ssAdvance: function() {
				if (this.isSlideshowRunning)
					this.next(true);

				return this;
			},

			// Advances the gallery to the next image.
			// @param {Boolean} dontPause Specifies whether to pause the slideshow.
			// @param {Boolean} bypassHistory Specifies whether to delegate navigation to the history plugin when history is enabled.  
			next: function(dontPause, bypassHistory) {
				this.gotoIndex(this.getNextIndex(this.currentImage.index), dontPause, bypassHistory);
				return this;
			},

			// Navigates to the previous image in the gallery.
			// @param {Boolean} dontPause Specifies whether to pause the slideshow.
			// @param {Boolean} bypassHistory Specifies whether to delegate navigation to the history plugin when history is enabled.
			previous: function(dontPause, bypassHistory) {
				this.gotoIndex(this.getPrevIndex(this.currentImage.index), dontPause, bypassHistory);
				return this;
			},

			// Navigates to the next page in the gallery.
			// @param {Boolean} dontPause Specifies whether to pause the slideshow.
			// @param {Boolean} bypassHistory Specifies whether to delegate navigation to the history plugin when history is enabled.
			nextPage: function(dontPause, bypassHistory) {
				var page = this.getCurrentPage();
				var lastPage = this.getNumPages() - 1;
				if (page < lastPage) {
					var startIndex = page * this.numThumbs;
					var nextPage = startIndex + this.numThumbs;
					this.gotoIndex(nextPage, dontPause, bypassHistory);
				}

				return this;
			},

			// Navigates to the previous page in the gallery.
			// @param {Boolean} dontPause Specifies whether to pause the slideshow.
			// @param {Boolean} bypassHistory Specifies whether to delegate navigation to the history plugin when history is enabled.
			previousPage: function(dontPause, bypassHistory) {
				var page = this.getCurrentPage();
				if (page > 0) {
					var startIndex = page * this.numThumbs;
					var prevPage = startIndex - this.numThumbs;				
					this.gotoIndex(prevPage, dontPause, bypassHistory);
				}
				
				return this;
			},

			// Navigates to the image at the specified index in the gallery
			// @param {Integer} index The index of the image in the gallery to display.
			// @param {Boolean} dontPause Specifies whether to pause the slideshow.
			// @param {Boolean} bypassHistory Specifies whether to delegate navigation to the history plugin when history is enabled.
			gotoIndex: function(index, dontPause, bypassHistory) {
				if (!dontPause)
					this.pause();
				
				if (index < 0) index = 0;
				else if (index >= this.data.length) index = this.data.length-1;
				
				var imageData = this.data[index];
				
				if (!bypassHistory && this.enableHistory)
					$.historyLoad(String(imageData.hash));  // At the moment, historyLoad only accepts string arguments
				else
					this.gotoImage(imageData);

				return this;
			},

			// This function is garaunteed to be called anytime a gallery slide changes.
			// @param {Object} imageData An object holding the image metadata of the image to navigate to.
			gotoImage: function(imageData) {
				var index = imageData.index;

				if (this.onSlideChange)
					this.onSlideChange(this.currentImage.index, index);
				
				this.currentImage = imageData;
				this.preloadRelocate(index);
				
				this.refresh();
				
				return this;
			},

			// Returns the default transition duration value.  The value is halved when not
			// performing a synchronized transition.
			// @param {Boolean} isSync Specifies whether the transitions are synchronized.
			getDefaultTransitionDuration: function(isSync) {
				if (isSync)
					return this.defaultTransitionDuration;
				return this.defaultTransitionDuration / 2;
			},

			// Rebuilds the slideshow image and controls and performs transitions
			refresh: function() {
				var imageData = this.currentImage;
				if (!imageData)
					return this;

				var index = imageData.index;

				// Update Controls
				if (this.$controlsContainer) {
					this.$controlsContainer
						.find('div.nav-controls a.prev').attr('href', '#'+this.data[this.getPrevIndex(index)].hash).end()
						.find('div.nav-controls a.next').attr('href', '#'+this.data[this.getNextIndex(index)].hash);
				}

				var previousSlide = this.$imageContainer.find('span.current').addClass('previous').removeClass('current');
				var previousCaption = 0;

				if (this.$captionContainer) {
					previousCaption = this.$captionContainer.find('span.current').addClass('previous').removeClass('current');
				}

				// Perform transitions simultaneously if syncTransitions is true and the next image is already preloaded
				var isSync = this.syncTransitions && imageData.image;

				// Flag we are transitioning
				var isTransitioning = true;
				var gallery = this;

				var transitionOutCallback = function() {
					// Flag that the transition has completed
					isTransitioning = false;

					// Remove the old slide
					previousSlide.remove();

					// Remove old caption
					if (previousCaption)
						previousCaption.remove();

					if (!isSync) {
						if (imageData.image && imageData.hash == gallery.data[gallery.currentImage.index].hash) {
							gallery.buildImage(imageData, isSync);
						} else {
							// Show loading container
							if (gallery.$loadingContainer) {
								gallery.$loadingContainer.show();
							}
						}
					}
				};

				if (previousSlide.length == 0) {
					// For the first slide, the previous slide will be empty, so we will call the callback immediately
					transitionOutCallback();
				} else {
					if (this.onTransitionOut) {
						this.onTransitionOut(previousSlide, previousCaption, isSync, transitionOutCallback);
					} else {
						previousSlide.fadeTo(this.getDefaultTransitionDuration(isSync), 0.0, transitionOutCallback);
						if (previousCaption)
							previousCaption.fadeTo(this.getDefaultTransitionDuration(isSync), 0.0);
					}
				}

				// Go ahead and begin transitioning in of next image
				if (isSync)
					this.buildImage(imageData, isSync);

				if (!imageData.image) {
					var image = new Image();
					
					// Wire up mainImage onload event
					image.onload = function() {
						imageData.image = this;

						// Only build image if the out transition has completed and we are still on the same image hash
						if (!isTransitioning && imageData.hash == gallery.data[gallery.currentImage.index].hash) {
							gallery.buildImage(imageData, isSync);
						}
					};

					// set alt and src
					image.alt = imageData.title;
					image.src = imageData.slideUrl;
				}

				// This causes the preloader (if still running) to relocate out from the currentIndex
				this.relocatePreload = true;

				return this.syncThumbs();
			},

			// Called by the refresh method after the previous image has been transitioned out or at the same time
			// as the out transition when performing a synchronous transition.
			// @param {Object} imageData An object holding the image metadata of the image to build.
			// @param {Boolean} isSync Specifies whether the transitions are synchronized.
			buildImage: function(imageData, isSync) {
				var gallery = this;
				var nextIndex = this.getNextIndex(imageData.index);

				// Construct new hidden span for the image
				var newSlide = this.$imageContainer
					.append('<span class="image-wrapper current"><a class="advance-link" rel="history" href="#'+this.data[nextIndex].hash+'" title="'+imageData.title+'">&nbsp;</a></span>')
					.find('span.current').css('opacity', '0');
				
				newSlide.find('a')
					.append(imageData.image)
					.click(function(e) {
						gallery.clickHandler(e, this);
					});
				
				var newCaption = 0;
				if (this.$captionContainer) {
					// Construct new hidden caption for the image
					newCaption = this.$captionContainer
						.append('<span class="image-caption current"></span>')
						.find('span.current').css('opacity', '0')
						.append(imageData.caption);
				}

				// Hide the loading conatiner
				if (this.$loadingContainer) {
					this.$loadingContainer.hide();
				}

				// Transition in the new image
				if (this.onTransitionIn) {
					this.onTransitionIn(newSlide, newCaption, isSync);
				} else {
					newSlide.fadeTo(this.getDefaultTransitionDuration(isSync), 1.0);
					if (newCaption)
						newCaption.fadeTo(this.getDefaultTransitionDuration(isSync), 1.0);
				}
				
				if (this.isSlideshowRunning) {
					if (this.slideshowTimeout)
						clearTimeout(this.slideshowTimeout);

					this.slideshowTimeout = setTimeout(function() { gallery.ssAdvance(); }, this.delay);
				}

				return this;
			},

			// Returns the current page index that should be shown for the currentImage
			getCurrentPage: function() {
				return Math.floor(this.currentImage.index / this.numThumbs);
			},

			// Applies the selected class to the current image's corresponding thumbnail.
			// Also checks if the current page has changed and updates the displayed page of thumbnails if necessary.
			syncThumbs: function() {
				var page = this.getCurrentPage();
				if (page != this.displayedPage)
					this.updateThumbs();

				// Remove existing selected class and add selected class to new thumb
				var $thumbs = this.find('ul.thumbs').children();
				$thumbs.filter('.selected').removeClass('selected');
				$thumbs.eq(this.currentImage.index).addClass('selected');

				return this;
			},

			// Performs transitions on the thumbnails container and updates the set of
			// thumbnails that are to be displayed and the navigation controls.
			// @param {Delegate} postTransitionOutHandler An optional delegate that is called after
			// the thumbnails container has transitioned out and before the thumbnails are rebuilt.
			updateThumbs: function(postTransitionOutHandler) {
				var gallery = this;
				var transitionOutCallback = function() {
					// Call the Post-transition Out Handler
					if (postTransitionOutHandler)
						postTransitionOutHandler();
					
					gallery.rebuildThumbs();

					// Transition In the thumbsContainer
					if (gallery.onPageTransitionIn)
						gallery.onPageTransitionIn();
					else
						gallery.show();
				};

				// Transition Out the thumbsContainer
				if (this.onPageTransitionOut) {
					this.onPageTransitionOut(transitionOutCallback);
				} else {
					this.hide();
					transitionOutCallback();
				}

				return this;
			},

			// Updates the set of thumbnails that are to be displayed and the navigation controls.
			rebuildThumbs: function() {
				var needsPagination = this.data.length > this.numThumbs;

				// Rebuild top pager
				if (this.enableTopPager) {
					var $topPager = this.find('div.top');
					if ($topPager.length == 0)
						$topPager = this.prepend('<div class="top pagination"></div>').find('div.top');
					else
						$topPager.empty();

					if (needsPagination)
						this.buildPager($topPager);
				}

				// Rebuild bottom pager
				if (this.enableBottomPager) {
					var $bottomPager = this.find('div.bottom');
					if ($bottomPager.length == 0)
						$bottomPager = this.append('<div class="bottom pagination"></div>').find('div.bottom');
					else
						$bottomPager.empty();

					if (needsPagination)
						this.buildPager($bottomPager);
				}

				var page = this.getCurrentPage();
				var startIndex = page*this.numThumbs;
				var stopIndex = startIndex+this.numThumbs-1;
				if (stopIndex >= this.data.length)
					stopIndex = this.data.length-1;

				// Show/Hide thumbs
				var $thumbsUl = this.find('ul.thumbs');
				$thumbsUl.find('li').each(function(i) {
					var $li = $(this);
					if (i >= startIndex && i <= stopIndex) {
						$li.show();
					} else {
						$li.hide();
					}
				});

				this.displayedPage = page;

				// Remove the noscript class from the thumbs container ul
				$thumbsUl.removeClass('noscript');
				
				return this;
			},

			// Returns the total number of pages required to display all the thumbnails.
			getNumPages: function() {
				return Math.ceil(this.data.length/this.numThumbs);
			},

			// Rebuilds the pager control in the specified matched element.
			// @param {jQuery} pager A jQuery element set matching the particular pager to be rebuilt.
			buildPager: function(pager) {
				var gallery = this;
				var numPages = this.getNumPages();
				var page = this.getCurrentPage();
				var startIndex = page * this.numThumbs;
				var pagesRemaining = this.maxPagesToShow - 1;
				
				var pageNum = page - Math.floor((this.maxPagesToShow - 1) / 2) + 1;
				if (pageNum > 0) {
					var remainingPageCount = numPages - pageNum;
					if (remainingPageCount < pagesRemaining) {
						pageNum = pageNum - (pagesRemaining - remainingPageCount);
					}
				}

				if (pageNum < 0) {
					pageNum = 0;
				}

				// Prev Page Link
				if (page > 0) {
					var prevPage = startIndex - this.numThumbs;
					pager.append('<a rel="history" href="#'+this.data[prevPage].hash+'" title="'+this.prevPageLinkText+'">'+this.prevPageLinkText+'</a>');
				}

				// Create First Page link if needed
				if (pageNum > 0) {
					this.buildPageLink(pager, 0, numPages);
					if (pageNum > 1)
						pager.append('<span class="ellipsis">&hellip;</span>');
					
					pagesRemaining--;
				}

				// Page Index Links
				while (pagesRemaining > 0) {
					this.buildPageLink(pager, pageNum, numPages);
					pagesRemaining--;
					pageNum++;
				}

				// Create Last Page link if needed
				if (pageNum < numPages) {
					var lastPageNum = numPages - 1;
					if (pageNum < lastPageNum)
						pager.append('<span class="ellipsis">&hellip;</span>');

					this.buildPageLink(pager, lastPageNum, numPages);
				}

				// Next Page Link
				var nextPage = startIndex + this.numThumbs;
				if (nextPage < this.data.length) {
					pager.append('<a rel="history" href="#'+this.data[nextPage].hash+'" title="'+this.nextPageLinkText+'">'+this.nextPageLinkText+'</a>');
				}

				pager.find('a').click(function(e) {
					gallery.clickHandler(e, this);
				});

				return this;
			},

			// Builds a single page link within a pager.  This function is called by buildPager
			// @param {jQuery} pager A jQuery element set matching the particular pager to be rebuilt.
			// @param {Integer} pageNum The page number of the page link to build.
			// @param {Integer} numPages The total number of pages required to display all thumbnails.
			buildPageLink: function(pager, pageNum, numPages) {
				var pageLabel = pageNum + 1;
				var currentPage = this.getCurrentPage();
				if (pageNum == currentPage)
					pager.append('<span class="current">'+pageLabel+'</span>');
				else if (pageNum < numPages) {
					var imageIndex = pageNum*this.numThumbs;
					pager.append('<a rel="history" href="#'+this.data[imageIndex].hash+'" title="'+pageLabel+'">'+pageLabel+'</a>');
				}
				
				return this;
			}
		});

		// Now initialize the gallery
		$.extend(this, defaults, settings);
		
		// Verify the history plugin is available
		if (this.enableHistory && !$.historyInit)
			this.enableHistory = false;
		
		// Select containers
		if (this.imageContainerSel) this.$imageContainer = $(this.imageContainerSel);
		if (this.captionContainerSel) this.$captionContainer = $(this.captionContainerSel);
		if (this.loadingContainerSel) this.$loadingContainer = $(this.loadingContainerSel);

		// Initialize the thumbails
		this.initializeThumbs();
		
		if (this.maxPagesToShow < 3)
			this.maxPagesToShow = 3;

		this.displayedPage = -1;
		this.currentImage = this.data[0];
		var gallery = this;

		// Hide the loadingContainer
		if (this.$loadingContainer)
			this.$loadingContainer.hide();

		// Setup controls
		if (this.controlsContainerSel) {
			this.$controlsContainer = $(this.controlsContainerSel).empty();
			
			if (this.renderSSControls) {
				if (this.autoStart) {
					this.$controlsContainer
						.append('<div class="ss-controls"><a href="#pause" class="pause" title="'+this.pauseLinkText+'">'+this.pauseLinkText+'</a></div>');
				} else {
					this.$controlsContainer
						.append('<div class="ss-controls"><a href="#play" class="play" title="'+this.playLinkText+'">'+this.playLinkText+'</a></div>');
				}

				this.$controlsContainer.find('div.ss-controls a')
					.click(function(e) {
						gallery.toggleSlideshow();
						e.preventDefault();
						return false;
					});
			}
		
			if (this.renderNavControls) {
				this.$controlsContainer
					.append('<div class="nav-controls"><a class="prev" rel="history" title="'+this.prevLinkText+'">'+this.prevLinkText+'</a><a class="next" rel="history" title="'+this.nextLinkText+'">'+this.nextLinkText+'</a></div>')
					.find('div.nav-controls a')
					.click(function(e) {
						gallery.clickHandler(e, this);
					});
			}
		}

		var initFirstImage = !this.enableHistory || !location.hash;
		if (this.enableHistory && location.hash) {
			var hash = $.galleriffic.normalizeHash(location.hash);
			var imageData = allImages[hash];
			if (!imageData)
				initFirstImage = true;
		}

		// Setup gallery to show the first image
		if (initFirstImage)
			this.gotoIndex(0, false, true);

		// Setup Keyboard Navigation
		if (this.enableKeyboardNavigation) {
			$(document).keydown(function(e) {
				var key = e.charCode ? e.charCode : e.keyCode ? e.keyCode : 0;
				switch(key) {
					case 32: // space
						gallery.next();
						e.preventDefault();
						break;
					case 33: // Page Up
						gallery.previousPage();
						e.preventDefault();
						break;
					case 34: // Page Down
						gallery.nextPage();
						e.preventDefault();
						break;
					case 35: // End
						gallery.gotoIndex(gallery.data.length-1);
						e.preventDefault();
						break;
					case 36: // Home
						gallery.gotoIndex(0);
						e.preventDefault();
						break;
					case 37: // left arrow
						gallery.previous();
						e.preventDefault();
						break;
					case 39: // right arrow
						gallery.next();
						e.preventDefault();
						break;
				}
			});
		}

		// Auto start the slideshow
		if (this.autoStart)
			this.play();

		// Kickoff Image Preloader after 1 second
		setTimeout(function() { gallery.preloadInit(); }, 1000);

		return this;
	};
})(jQuery);


/**
 * @fileoverview frozThumbSlider plugin
 * @author Lawrence Natividad
 * @copyright Copyright ( c ) 2010 Frozynart Designs
 * @license Licensed under MIT ( http://www.frozynart.com/license/mit )
 * @version: 1.0 2010-04-28
 */
 
( function( $ ) {
    /**
     * all parameters
     * <ul> passes must have ID
     * all content banners must have the same dimensions
     * When thumbnails are clicked, contents slide over accordingly
     * @namespace frozThumbSlider Plugin Namespace
     * @requires jQuery 1.2.6 and above / jQuery Easing / jquery.color
     * @example jQuery( "#id-of-list-that-contains-contents" ).frozThumbSlider
     * @return {jQuery Object}
     */
    jQuery.fn.frozThumbSlider = function( options ) {
        var opts                            = jQuery.extend( {}, jQuery.fn.frozThumbSlider.defaults, options );
        jQuery.fn.frozThumbSlider.opts      = opts;
        var $this                           = jQuery( this );
        
        var descriptions = new Array();
        
        opts.wrapperId = opts.wrapperId + '-' + $this.attr('id');
        var mainContent = '#' + $this.attr('id');
        var wrapperId = '#' + opts.wrapperId;
        var contentCount = jQuery($this).children().length;
        
        jQuery( $this ).data( "activeSlide", 0 );
        
        var measureWidth = function( obj ){
            return obj.outerWidth();
        };
        
        var measureHeight = function( obj ){
            obj.load( function(){
                return obj.outerHeight();            
            })
        };
        
        var slideBack = function( diff, dimension, content ){
            jQuery( content ).animate( {"left": "+=" + ( diff * dimension ) + "px"}, 
                                       {duration: opts.easingDuration, easing: opts.slideEasing} );
        };

        var slideForward = function( diff, dimension, content ){
            jQuery( content ).animate( {"left": "-=" + ( diff * dimension ) + "px"}, 
                                       {duration: opts.easingDuration, easing: opts.slideEasing} );
        };

        var slideUp = function( diff, dimension, content ){
            jQuery( content ).animate( {"top": "+=" + ( diff * dimension ) + "px"}, 
                                       {duration: opts.easingDuration, easing: opts.slideEasing} );
        };

        var slideDown = function( diff, dimension, content ){
            jQuery( content ).animate( {"top": "-=" + ( diff * dimension ) + "px"}, 
                                       {duration: opts.easingDuration, easing: opts.slideEasing} );
        };
        
        var animateDescriptions = function(descBlock, count){
            var slideWidth = jQuery('span.front-slider-desc-bg:first', descBlock).outerWidth(true);
//            descBlock.animate({left: '+=' + slideWidth, width: '0'}, opts.descSlideTime, opts.descSlideEasing, function(){
//                    jQuery(this).contents().replaceWith(descriptions[count].css({visibility: 'visible'}));
//                }
//            );
            descBlock.animate({top: '-=' + 88}, opts.descSlideTime, opts.descSlideEasing, 
                function(){
                    jQuery(this).contents().replaceWith(descriptions[count].css({visibility: 'visible'}));
                    descBlock.animate({top: '+=' + 88}, opts.descSlideTime, opts.descSlideEasing)
                }
            )
        };
        
        var slideContent = function( count ){
        
            jQuery(opts.descBlock).stop( false, true );
        
            if (count > jQuery( $this ).data( "activeSlide")){
                difference = count - jQuery( $this ).data( "activeSlide");
                if (opts.slideVertical === false){
                    slideForward(difference, xDim, mainContent);
                } else {
                    slideDown(difference, yDim, mainContent);
                }
            } else {
                difference = jQuery( $this ).data( "activeSlide") - count;
                if (opts.slideVertical === false){
                    slideBack(difference, xDim, mainContent);
                } else {
                    slideUp(difference, yDim, mainContent);
                }
            };
            
            if ( opts.descBlock !== null ){
                animateDescriptions(jQuery(opts.descBlock), count);
            }
            
        };
        
        var setHoverBoxOffset = function( box, start ){
            var pos = jQuery(opts.thumbList).position();
            var offsetTop = (jQuery(opts.thumbList + ' > li:eq(' + start + ')').outerHeight()
                           - jQuery(box).height())/2;
            var offsetLeft = (jQuery(opts.thumbList + ' > li:eq(' + start + ')').outerWidth()
                            - jQuery(box).width ())/2;
            var posLeft = pos.left + offsetLeft + opts.boxOffsetLeft;
            var posTop = pos.top + offsetTop + opts.boxOffsetTop;
            jQuery(box).css({ left: posLeft, top: posTop })
        }
        
        var slideTab = function( count ){
            
            if (count > jQuery( $this ).data( "activeSlide")){
                difference = count - jQuery( $this ).data( "activeSlide");
                if (opts.thumbsVertical === false){
                    slideBack(difference, thumbsX, opts.hoverBox);
                } else {
                    slideUp(difference, thumbsY, opts.hoverBox);
                }
            } else {
                difference = jQuery( $this ).data( "activeSlide") - count;
                if (opts.thumbsVertical === false){
                    slideForward(difference, thumbsX, opts.hoverBox);
                } else {
                    slideDown(difference, thumbsY, opts.hoverBox);
                }
            };
        };
        
        var selectTab = function( obj ){
            jQuery(opts.thumbList + ' > li').each( function(){
               jQuery(this).removeClass('selected'); 
            });
            jQuery(obj).addClass('selected');
        };
        
        var detectDefaultBoxColor = function(){
            if ( jQuery(opts.hoverBox).css('background-color') == 'transparent' ){
                return opts.defaultColor;
            }
            return jQuery(opts.hoverBox).css('background-color');
        }
        
        var blockAnimate = function( obj, defColor ){
        
            if (jQuery(obj).attr('rel') !== undefined){
                var newColor = '#' + jQuery(obj).attr('rel').substring(1).toUpperCase();
            } else {
                var newColor = defColor;
            }
            
            jQuery(opts.hoverBox).animate({backgroundColor: newColor}, { queue: false, duration: opts.colorChangeTime });
            
        };
        
        var positionChildren = function(obj){
            obj.css({ position: 'relative'})
            if ( obj.children().length > 0){
                obj.children().each( function(){
                    positionChildren(jQuery(this));
                })
            }
        }
        
        xDim = measureWidth( jQuery('li:first', $this) );
        yDim = measureHeight( jQuery('li:first', $this) );
        
        $this.wrap( "<div id=" + opts.wrapperId + " />" );
        jQuery( wrapperId ).css( { position: "relative",
                                   width:xDim,
                                   overflow: 'hidden',
                                   height:yDim } );
                                  
        positionChildren($this);

        if ( true === opts.slideVertical ){
            jQuery( mainContent ).css( {height: (yDim * contentCount)} )
            jQuery( mainContent + " > li" ).each( function(){
                jQuery( this ).css( {float:"top"} );
            } );
        }
        else{
            jQuery( mainContent ).css( {width: (xDim * contentCount)} )
            jQuery( mainContent + " > li" ).each( function(){
                jQuery( this ).css( {float:"left"} );
            } );
        }
        
        if (jQuery( opts.thumbList + ' > li:eq(1)').length === 0){
            jQuery(opts.thumbList).remove();
            if (opts.hoverOption === true){
                jQuery(opts.hoverBox).remove();
            }
            return false;
        }
        
        offset1 = jQuery( opts.thumbList + ' > li:first > a:first').offset();
        offset2 = jQuery( opts.thumbList + ' > li:eq(1) > a:first').offset();
        thumbsX = offset2.left - offset1.left;
        thumbsY = offset2.top - offset1.top;
        
        jQuery(opts.descBlock).children('div.front-slider-description').each( function(){
            descriptions.push(jQuery(this));
        })
        
        if ( opts.starterSlide !== 0){
            slideContent( opts.starterSlide );
        }
        
        if (opts.hoverOption === true){
            setHoverBoxOffset( opts.hoverBox, opts.starterSlide );
            var defColor = detectDefaultBoxColor();
            blockAnimate( jQuery( opts.thumbList + ' > li:eq(' + opts.starterSlide + ')'), defColor );
            slideTab( opts.starterSlide );
        }
        
        var setAutoSlide = function(head, delay){

            mainTimer = jQuery.timer( delay, function(timer){
                var count = head.children('li').length - 1;
                if ( $this.data('activeSlide') >= count ){
                    var slideNum = 0;
                } else {
                    var slideNum = $this.data('activeSlide') + 1;
                }

                head.children('li:eq(' + slideNum + ')').find('a:first').click();
                
            });
            
            head.data('slideTimer', mainTimer);
            return head;

        }
        
        selectTab( opts.thumbList + ' > li:eq(' + opts.starterSlide + ')');
        jQuery( $this ).data( "activeSlide", opts.starterSlide );
                               
        jQuery( opts.thumbList + ' > li').each( function(){
            jQuery(this).click( function(){
                nthCount = jQuery(this).prevAll().length;
                if( nthCount !== jQuery( $this ).data( "activeSlide")){
                    if (opts.queueEffects === false){
                        jQuery( mainContent ).stop( false, true );
                        if (opts.hoverOption === true){
                            jQuery( opts.hoverBox ).stop( false, true );
                        }
                    }
                    slideContent( nthCount );
                    if (opts.hoverOption === true){
                        blockAnimate( this, defColor );
                        slideTab( nthCount );
                    }
                    selectTab( this );
                    jQuery( $this ).data( "activeSlide", nthCount )
                }
                return false;
            });
        });     
        
        if ( opts.timer > 0 ){
            var list = setAutoSlide(jQuery(opts.thumbList), opts.timer);
            
            jQuery('#header').mouseenter( function(){
                list.data('slideTimer').stop();
            }).mouseleave( function(){
                list.data('slideTimer').reset(opts.timer);
            })
        }
        
        return $this;
    };

    /** 
     * Sends a message to the console
     * @private
     */
    var _debug = function( message ) {
        if ( true === jQuery.fn.frozThumbSlider.opts.debug ) {
            console.log( message );
        }
    };
    
    jQuery.fn.frozThumbSlider.defaults =   {
        thumbList: null,
        descBlock: null,
        hoverOption: false,
        hoverBox: null,
        wrapperId: 'froz-thumb-slider-wrapper',
        slideVertical: false,
        thumbsVertical: false,
		slideEasing: "easeInOutExpo",
		easingDuration: 'normal',
		defaultColor: '#00AA00',
		boxOffsetLeft: 0,
		boxOffsetTop: 0,
		colorChangeTime: 700, //amount of time that is color effect is delayed
		queueEffects: false,
        starterSlide: 0,
        
        timer: 0,
        descSlideTime: 500,
        descSlideEasing: 'easeInOutExpo'
    };
} )(jQuery);
jQuery( document ).ready( function() {
        if ( navigator.appVersion.match('MSIE 7.0') !== null){
        jQuery("ul.sf-menu").superfish().supersubs({ 
              minWidth:    18,   
              maxWidth:    100, 
              extraWidth:  0 
        });
    } else {        
        jQuery("ul.sf-menu").supersubs({ 
              minWidth:    18,   
              maxWidth:    100, 
              extraWidth:  0 
        }).superfish();
    };
    
         jQuery('div.froz-carousel-enable').frozCarousel({
            showAmount: 3,
            controls: 'side',
            counter: null,
            loop: false
        })
        
        jQuery('#photo-gallery').frozAlbumGallery();
    
        jQuery('#tabs').frozTabs({slider: 'froz-tabs-slider', tabLeftPos: 10});
    
        jQuery('#tabs').frozTabs({slider: 'froz-tabs-slider', tabLeftPos: 10});
        
        jQuery('a.fancybox-enable').fancybox({
        cyclic: true,
        titlePosition: 'over',
        centerOnScroll: true
     });
    
    jQuery('.back-to-top').click(function(){
        jQuery.scrollTo('#content', 800);
        return false;
    });
    
});



