function ZoolooGraffiti(){
    var _singlePost = false;
    var _followerPage = 1;
	var _followeePage = 1;
    var _objectTypeId = 7;
	var _enableAnonymousComment = 0;
	
    this.setup = function(graffitiURL, singlePost, enableAnonymousComment){
		
		_enableAnonymousComment = enableAnonymousComment;
        _singlePost = singlePost;
        
        if($('#my_follower_area').length>0) _getFollower();
        if($('#my_followee_area').length>0) _getFollowee();
        
        $('div .zgraffiti_items').hover(function(){
            $('.zgraffiti_delete', this).show();
        }, function(){
            $('.zgraffiti_delete', this).hide();
        });
        
        $('#z_graffiti_follow').click(function(e){
            ZGraffiti.follow($(this).attr('name'));
            e.preventDefault();
        });
        
        $('.zgraffiti_sharelink').click(function(e){
            var id = $(this).attr('id').split('_')[1];
            $('#zshare_' + id).toggle();
            e.preventDefault();
        });
        
        $('.zgraffiti_repost').click(function(e){
            var postId = $(this).attr('name');
            ZFramework.openWindow(graffitiURL + 'repost=1&post_id=' + postId, 'zbutton', '',
                function() {
                    window.location.reload(true);
                });
            e.preventDefault();
        });
        
        $('.zgraffiti_edit_button').click(function(e){
            var postId = $(this).attr('name');
            ZFramework.openWindow(graffitiURL + 'edit=1&post_id=' + postId, 'zbutton', '',
                function() {
                    window.location.reload(true);
                });
            e.preventDefault();
        });
        
        $('.zgraffiti_delete_button').unbind('click').click(function(e){
            var postId = $(this).attr('name');
            ZFramework.confirm(ZFramework.i18n(ZMsg.ZGRAFFITI_CONFIRM_DELETE), '', function(){
                ZFramework.zfAjaxPost('/zGraffiti/deletePost', {
                    post_id: postId
                }, false, function(response){
                    if (response.status == 1) {
                        if (_singlePost) {
                            window.location = '/?page_name=_Graffiti';
                        } else {
                            $('#z_graffiti_post_' + postId).slideUp('fast', function(){
                                $(this).remove()
                            });
                            ZFramework.notify(ZFramework.i18n(ZMsg.ZGRAFFITI_DELETE_SUCCESS));
                        }
                    }
                    else {
                        ZFramework.alert(ZFramework.i18n(ZMsg.DEFAULT_MESSAGE))
                    }
                }, function(){
                        ZFramework.alert(ZFramework.i18n(ZMsg.DEFAULT_MESSAGE))
                });
            });
            e.preventDefault();
        });
        
        
        $('.zgraffiti_img').unbind('click').click(function(e){
            var postId = $(this).attr('name');
            $('#home_zgraffiti_photo_' + postId + ' a').lightbox({
                start: true,
                events: false
            });
            e.preventDefault();
        });
        
        $('#show_more_followers').click(function(e){
			_followerPage++;
            _getFollower();
            e.preventDefault();
        });
		
		$('#show_more_followees').click(function(e){
			_followeePage++;
            _getFollowee();
            e.preventDefault();
        });
		
		$('#zg_connact_me').click(function(e){
			if($(this).attr('name') == 'not_login') {
				$('#follow_promo').modal({
					onClose: function(dialog) {
						$.modal.close(false);
					}
				});
				e.preventDefault();
			}
		});
		
		$('#zg_type_selector').change(function(){
			window.location.href = $(this).val();
		});

		_setupRating();
		
		$('.zg_archive_year').click(function(e){
			var year = $(this).attr('name');
			$('.zg_archive_year_item[name!='+year+']').hide();
			$('.zg_archive_year_item[name='+year+']').toggle();
			e.preventDefault();
		});
		
        ZFramework.tooltip('.followTooltip', {className:'skin_border_color skin_text_color skin_background_color'});
    };
    
	this.addCommentCallback = function(){
		var postId = $('.zg_comment_active').attr('name').split('_')[0];
		var commentCount = $('.zg_comment_active').attr('name').split('_')[1]*1;
		commentCount++;
		if(commentCount == 1) {
			var words = '1 Comment';
		} else {
			var words = commentCount + ' Comments';
		}
		$('.zg_comment_active').attr('name', postId+'_'+commentCount).html(words);
	};
	
	this.deleteCommentCallback = function() {
		var postId = $('.zg_comment_active').attr('name').split('_')[0];
		var commentCount = $('.zg_comment_active').attr('name').split('_')[1]*1;
		commentCount--;
		if(commentCount == 1) {
			var words = '1 Comment';
		} else if(commentCount == 0) {
			var words = 'Comment';
		} else {
			var words = commentCount + ' Comments';
		}
		$('.zg_comment_active').attr('name', postId+'_'+commentCount).html(words);
	};
	
    this.follow = function(type){
        ZFramework.zfAjaxPost('/zInvite/follow', {
            type: type
        }, true, function(response){
            if (response.status == 1) {
                if (response.login == false) {
                    $('#follow_promo').modal({
                        onClose: function(dialog){
                            $.modal.close(false);
                        }
                    });
                }
                else {
                    if (type == 'follow') {
                        //ZFramework.alert(response.data.message, 'Follow');
                        $('#z_graffiti_follow').html('<span></span><p>Unfollow</p>').attr('name', 'unfollow');
                    }
                    else {
                        //ZFramework.alert(response.data.message, 'Unfollow');
                        $('#z_graffiti_follow').html('<span></span><p>Follow</p>').attr('name', 'follow');
                    }
                }
            }
            else {
                ZFramework.alert(response.error);
            }
        });
    };
    
    function _getFollower(){
        ZFramework.zfAjaxPost('/zGraffiti/getFollowers', {
            page: _followerPage
        }, false, function(response){
            if (response.status == 1) {
                $('#my_follower_area').append(response.data.html);
                $('.followTooltip').unbind();
        		ZFramework.tooltip('.followTooltip', {className:'skin_border_color skin_text_color skin_background_color'});
        		var total = response.data.total;
                if (_followerPage == response.data.maxPages || total == 0) {
                    $('#show_more_followers').hide();
                }
                else $('#show_more_followers').show();
                $('#zgraffiti_followers_count').html(total);
            }
            else {
                ZFramework.alert(response.error);
            }
        });
    }
	
	function _getFollowee(){
        ZFramework.zfAjaxPost('/zGraffiti/getFollowees', {
            page: _followeePage
        }, false, function(response){
            if (response.status == 1) {
                $('#my_followee_area').append(response.data.html);
                $('.followTooltip').unbind();
        		ZFramework.tooltip('.followTooltip', {className:'skin_border_color skin_text_color skin_background_color'});
        		var total = response.data.total;
                if (_followeePage == response.data.maxPages || total == 0) {
                    $('#show_more_followees').hide();
                }
                else $('#show_more_followees').show();
                $('#zgraffiti_followees_count').html(total);
            }
            else {
                ZFramework.alert(response.error);
            }
        });
    }
	
	function _setupRating() {
		$('.home_zgraffiti_rating').unbind('click').click(function(e){
			var data = $(this).attr('name').split('_');
			var postId = data[0];
			var ratingType = data[1];
			var target = $(this);
			var rated = false;
			if (target.hasClass('home_zgraffiti_rating_voted')) {
				rated = true;
			}
			ZFramework.zfAjaxPost('/zConnect/addRating', {
				object_id: postId,
				object_type: _objectTypeId,
				rating_type: ratingType,
				rated: rated
			}, true,
				function(response) {
					if (response.status == '1') {
						if (response.login == false) {
		                    $('#follow_promo').modal({
		                        onClose: function(dialog){
		                            $.modal.close(false);
		                        }
		                    });
		                } else {
							var likeNum = $('.zgraffiti_post_rank[name='+postId+']').parent().attr('name')*1;
							likeNum++;
							likeplural='';
							if (likeNum == 1) {
								likeplural = 's';
							}
							$('.zgraffiti_post_rank[name='+postId+']').html('<strong>'+likeNum+'</strong> <span> Like'+likeplural+' It</span>');
							target.parent().html('You Like This');
							$('.zgraffiti_post_rank[name='+postId+']').parent().attr('name', likeNum).show();
						}
					} else {
		            	ZFramework.alert(response.error);
		            }
				},
				function(){}
			);
			e.preventDefault();
		});
	}
}
ZGraffiti = new ZoolooGraffiti();function ZoolooGraffitiShare(){
    this.postType = '';
    this.urlDetails = {};
    this.queryParams = ZFramework.getQueryParams();
    this.setup = function(postType){
        this.postType = postType;
        $('.zgraffitiType').unbind('click').click(function(e){
            $('.zgraffitiType').removeClass('zgraffitiTypeHover');
            $(this).addClass('zgraffitiTypeHover');
            var type = $(this).attr('name');
            ZGraffitiShare.postType = type;
            ZGraffitiShare.setupEditor(type);
            $('#z_graffiti_post_' + type).css('display', '');
            $('.zgraffitiForm').not('#z_graffiti_post_' + type).css('display', 'none');
            $('#z_graffiti_post_' + type).find('.zgraffitiInputField a:first').select().focus();
        });
        
        $('#z_graffiti_link_url').change(function() {
            ZGraffitiShare.getURLDetails($(this).val());
        });
        
        $('#z_graffiti_cancel').click(function(e){
            ZGraffitiShare.closeModal();
        });
        
        $('#z_graffiti_post').click(function(e){
            var post_type = $('#z_graffiti_type .zgraffitiTypeHover').attr('name');
            var post_data = {};
            var services = {};
            var edit = $('#z_graffiti_edit').val();
            var repost = $('#z_graffiti_repost').val();
            var post_id = $('#z_graffiti_post_id').val();
            
            $('#z_graffiti_post_' + post_type).find('.zgraffitiInputField').each(function(){
                var id = $(this).attr('id');
                var field = id.split('z_graffiti_' + post_type + '_')[1]
                if ($(this).hasClass('zgraffitiHTML')) {
                    post_data[field] = FCKeditorAPI.GetInstance(id).GetHTML();
                }
                else {
                    post_data[field] = $(this).val();
                }
            });
            
            var services = [];
            $('#z_graffiti_services input:checked').each(function(){
                services.push($(this).val());
            });
            if (services.length === 0) {
                ZFramework.alert(ZFramework.i18n(ZMsg.INVALID_SERVICE_NONE));
                return;
            }
            
            ZGraffitiShare.post(post_type, post_data, edit, repost, post_id, services, function(){
                $('.zgraffitiFrame').css('display', 'none');
                $('#z_graffiti_done_overlay').show();
                setTimeout(ZGraffitiShare.closeModal, 1000);
            }, function(result){
                ZFramework.alert(result.error);
                return;
            });
            e.preventDefault();
        });
        
        if (this.queryParams.u) {
            this.getURLDetails(this.queryParams.u);
        }
        
        $('').keydown(function(e){
            if (e.keyCode == 27) {
                e.preventDefault();
                ZGraffitiShare.closeModal();
            }
        });
        $('#z_graffiti_type a[name=' + postType + ']').click();
        window.focus();
    };
    
    this.setupThumbListener = function(){
        $('.zgraffitiImages img').click(function(e){
            if ($(this).hasClass('zgraffitiImagesSelected')) {
                $(this).removeClass('zgraffitiImagesSelected');
                $('#z_graffiti_' + ZGraffitiShare.postType + '_img_url').val('');
            }
            else {
                $('#z_graffiti_' + ZGraffitiShare.postType + '_img_url').val($(this).attr('src'));
                $(this).addClass('zgraffitiImagesSelected');
            }
            $(this).siblings().removeClass('zgraffitiImagesSelected');
        });
    };
    
    this.setupEditor = function(type){
        $('#z_graffiti_post_' + type).find('.zgraffitiHTML').each(function(){
            if (ZGraffitiShare.urlDetails && ZGraffitiShare.urlDetails.meta && ZGraffitiShare.urlDetails.meta.description) {
                if ($('#z_graffiti_' + type + '_body').attr('id')) {
                    $('#z_graffiti_' + type + '_body').val(ZGraffitiShare.urlDetails.meta.description);
                }
                if ($('#z_graffiti_' + type + '_caption').attr('id')) {
                    $('#z_graffiti_' + type + '_caption').val(ZGraffitiShare.urlDetails.meta.description);
                }
            }
            
            ZGraffitiShare.oFCKeditor = new FCKeditor($(this).attr('id'));
            ZGraffitiShare.oFCKeditor.Height = $('#zgraffiti_share').height() - 330;
            ZGraffitiShare.oFCKeditor.ToolbarSet = 'Graffiti';
            ZGraffitiShare.oFCKeditor.BasePath = ZFramework.getEditorBasePath();
            ZGraffitiShare.oFCKeditor.ReplaceTextarea();
        });
    };
    
    this.closeModal = function(){
        $('.zgraffitiFrame').css('display', '');
        $('#z_graffiti_done_overlay').hide();
        window.close();
    };
    
    this.getURLDetails = function(url) {
        ZFramework.zfAjaxPost('/zGraffiti/getURLDetails', {
            url: url,
            all_images: true
        }, true, function(result){
            if (result.status) {
                var imageTestTarget = $('#zgraffiti_imagetest');
                if (typeof result.data == 'object') {
                    ZGraffitiShare.urlDetails = result.data;
                    if (typeof result.data.images == 'object' && typeof result.data.oembed != 'object') {
                        var imghtml = '';
                        for (img in result.data.images) {
                            imageTestTarget.append('<img src="' + result.data.images[img].src + '" />');
                        }
                        var first = true;
                        setTimeout(function(){
                            var images = ZGraffitiShare.getImages();
                            var count = 0;
                            for (img in images) {
                                if (count >= 9) break;
                                if (first) {
                                    $('.zgraffitiImgURL').val(images[img]);
                                }
                                imghtml += '<img src="' + images[img] + '" width="50" height="50"';
                                imghtml += (first) ? ' class="zgraffitiImagesSelected" />' : '/>';
                                first = false;
                                count++;
                            }
                            if (imghtml) {
                                $('.zgraffitiImages').html(imghtml);
                                $('.zgraffitiPhoto').css('display', '');
                            }
                            ZGraffitiShare.setupThumbListener();
                            if (first) {
                                $('.zgraffitiImages').css('display', 'none');
                                $('.zgraffitiPhoto').css('display', 'none');
                            }
                            else {
                                $('.zgraffitiImages').css('display', '');
                                $('.zgraffitiPhoto').css('display', '');
                            }
                        }, 400);
                    }
                    
                    if (result.data.oembed && result.data.oembed.thumbnail_url) {
                        $('#z_graffiti_video_thumbnail').html('<img class="zgraffitiImagesSelected" src="' + result.data.oembed.thumbnail_url + '" height="50" />');
                        $('.zgraffitiVideoThumbnail').css('display', '');
                        $('.zgraffiti_video').css('display', '');
                    }
                    else {
                        $('.zgraffiti_video').css('display', 'none');
                    }
                    
                    if (result.data.title) {
                        $('#z_graffiti_' + ZGraffitiShare.postType + '_title').val(result.data.title);
                    }
                    if (result.data.meta && result.data.meta.description && !ZGraffitiShare.queryParams.s) {
                        if ($('#z_graffiti_' + ZGraffitiShare.postType + '_body').attr('id')) {
                            $('#z_graffiti_' + ZGraffitiShare.postType + '_body').val(result.data.meta.description);
                            FCKeditorAPI.GetInstance('z_graffiti_' + ZGraffitiShare.postType + '_body').SetHTML(result.data.meta.description);
                        }
                        if ($('#z_graffiti_' + ZGraffitiShare.postType + '_caption').attr('id')) {
                            $('#z_graffiti_' + ZGraffitiShare.postType + '_caption').val(result.data.meta.description);
                            FCKeditorAPI.GetInstance('z_graffiti_' + ZGraffitiShare.postType + '_caption').SetHTML(result.data.meta.description);
                        }
                    }
                }
            }
        });
    };
    
    this.post = function(post_type, post_data, edit, repost, post_id, services, successCallback, failureCallback){
        ZFramework.zfAjaxPost('/zGraffiti/post', {
            post_type: post_type,
            post_data: JSON.stringify(post_data),
            edit: edit,
            repost: repost,
            post_id: post_id,
            services: JSON.stringify(services)
        }, true, function(result){
            if (result.status == 1) {
                successCallback(result);
            }
            else {
                failureCallback(result);
            }
        });
    };
    
    this.getImages = function(){
        var imgList = {};
        $('#zgraffiti_imagetest img').each(function(){
            if (this.offsetWidth >= 75 && this.src !== '' && $.inArray(this.src, imgList) == -1) {
                var ratio = this.offsetWidth / this.offsetHeight;
                if (ratio < 0) {
                    ratio = this.offsetHeight / this.offsetWidth;
                }
                if (ratio < 3) {
                    imgList[this.src] = this.offsetHeight * this.offsetWidth;
                }
            }
        });
        var sortedList = ZGraffitiShare.sortAssoc(imgList);
        $('#zgraffiti_imagetest').css('display', 'none');
        return sortedList;
    };
    
    this.sortAssoc = function(aInput){
        var aTemp = [];
        for (var sKey in aInput) {
            aTemp.push([sKey, aInput[sKey]]);
        }
        
        aTemp.sort(function(){
            return arguments[0][1] < arguments[1][1];
        });
        
        var aOutput = [];
        var idx = 0;
        for (var nIndex = 0; nIndex < aTemp.length; nIndex++) {
            aOutput[idx] = aTemp[nIndex][0];
            idx++;
        }
        return aOutput;
    }
    
    
}

ZGraffitiShare = new ZoolooGraffitiShare();
/**
 * jQuery Lightbox Plugin (balupton edition) - Lightboxes for jQuery
 * Copyright (C) 2008 Benjamin Arthur Lupton
 * http://jquery.com/plugins/project/jquerylightbox_bal
 *
 * This file is part of jQuery Lightbox (balupton edition).
 * 
 * jQuery Lightbox (balupton edition) is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 * 
 * jQuery Lightbox (balupton edition) is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 * 
 * You should have received a copy of the GNU Affero General Public License
 * along with jQuery Lightbox (balupton edition).  If not, see <http://www.gnu.org/licenses/>.
 *
 * @name jquery_lightbox: jquery-lightbox.js
 * @package jQuery Lightbox Plugin (balupton edition)
 * @version 1.3.4-final
 * @date September 12, 2008
 * @category jQuery plugin
 * @author Benjamin "balupton" Lupton {@link http://www.balupton.com}
 * @copyright (c) 2008 Benjamin Arthur Lupton {@link http://www.balupton.com}
 * @license GNU Affero General Public License - {@link http://www.gnu.org/licenses/agpl.html}
 * @example Visit {@link http://jquery.com/plugins/project/jquerylightbox_bal} for more information.
 */

// Start of our jQuery Plugin
(function($)
{	// Create our Plugin function, with $ as the argument (we pass the jQuery object over later)
	// More info: http://docs.jquery.com/Plugins/Authoring#Custom_Alias
	
	// Debug
	if ( !$.browser.safari && typeof window.console !== 'undefined' && typeof window.console.log === 'function' )
	{	// Use window.console
		//$.log = window.console.log;
		$.log = function ( ) { };
	}
	else
	{	// Don't use anything
		$.log = function ( ) { };
	}
	
	// Pre-Req
	$.params_to_json = $.params_to_json || function ( params )
	{	// Turns a params string or url into an array of params
		// Adjust
		params = String(params);
		// Remove url if need be
		params = params.substring(params.indexOf('?')+1);
		// params = params.substring(params.indexOf('#')+1);
		// Change + to %20, the %20 is fixed up later with the decode
		params = params.replace(/\+/g, '%20');
		// Do we have JSON string
		if ( params.substring(0,1) === '{' && params.substring(params.length-1) === '}' )
		{	// We have a JSON string
			return eval(decodeURIComponent(params));
		}
		// We have a params string
		params = params.split(/\&|\&amp\;/);
		var json = {};
		// We have params
		for ( var i = 0, n = params.length; i < n; ++i )
		{
			// Adjust
			var param = params[i] || null;
			if ( param === null ) { continue; }
			param = param.split('=');
			if ( param === null ) { continue; }
			// ^ We now have "var=blah" into ["var","blah"]
			
			// Get
			var key = param[0] || null;
			if ( key === null ) { continue; }
			if ( typeof param[1] === 'undefined' ) { continue; }
			var value = param[1];
			// ^ We now have the parts
			
			// Fix
			key = decodeURIComponent(key);
			value = decodeURIComponent(value);
			try {
			    // value can be converted
			    value = eval(value);
			} catch ( e ) {
			    // value is a normal string
			}
			
			// Set
			// console.log({'key':key,'value':value}, split);
			var keys = key.split('.');
			if ( keys.length === 1 )
			{	// Simple
				json[key] = value;
			}
			else
			{	// Advanced
				var path = '';
				for ( ii in keys )
				{	//
					key = keys[ii];
					path += '.'+key;
					eval('json'+path+' = json'+path+' || {}');
				}
				eval('json'+path+' = value');
			}
			// ^ We now have the parts added to your JSON object
		}
		return json;
	};
	
	// Declare our class
	$.LightboxClass = function ( )
	{	// This is the handler for our constructor
		this.construct();
	};

	// Extend jQuery elements for Lightbox
	$.fn.lightbox = function ( options )
	{	// Init a el for Lightbox
		// Eg. $('#gallery a').lightbox();
		
		// If need be: Instantiate $.LightboxClass to $.Lightbox
		$.Lightbox = $.Lightbox || new $.LightboxClass();
		
		// Handle IE6 appropriatly
		if ( $.Lightbox.ie6 && !$.Lightbox.ie6_support )
		{	// We are IE6 and we want to ignore
			return this; // chain
		}
		
		// Establish options
		options = $.extend({start:false,events:true} /* default options */, options);
		
		// Get group
		var group = $(this);
		
		// Events?
		if ( options.events )
		{	// Add events
			$(group).unbind().click(function(){
				// Get obj
				var obj = $(this);
				// Get rel
				// var rel = $(obj).attr('rel');
				// Init group
				if ( !$.Lightbox.init($(obj)[0], group) )
				{	return false;	}
				// Display lightbox
				if ( !$.Lightbox.start() )
				{	return false;	}
				// Cancel href
				return false;
			});
			// Add style
			$(group).addClass('lightbox-enabled');
		}
		
		// Start?
		if ( options.start )
		{	// Start
			// Get obj
			var obj = $(this);
			// Get rel
			// var rel = $(obj).attr('rel');
			// Init group
			if ( !$.Lightbox.init($(obj)[0], group) )
			{	return this;	}
			// Display lightbox
			if ( !$.Lightbox.start() )
			{	return this;	}
		}
		
		// And chain
		return this;
	};
	
	// Define our class
	$.extend($.LightboxClass.prototype,
	{	// Our LightboxClass definition
		
		// -----------------
		// Everyting to do with images
		
		images: {
			
			// -----------------
			// Variables
			
			// Our array of images
			list:[], /* [ {
				src: 'url to image',
				link: 'a link to a page',
				title: 'title of the image',
				name: 'name of the image',
				description: 'description of the image'
			} ], */
			
			// The current active image
			image: false,
			
			// -----------------
			// Functions
			
			prev: function ( image )
			{	// Get previous image
				
				// Get previous from current?
				if ( typeof image === 'undefined' )
				{	image = this.active();
					if ( !image ) { return image; }
				}
				
				// Is there a previous?
				if ( this.first(image) )
				{	return false;	}
				
				// Get the previous
				return this.get(image.index-1);
			},
			
			next: function ( image )
			{	// Get next image
				
				// Get next from current?
				if ( typeof image === 'undefined' )
				{	image = this.active();
					if ( !image ) { return image; }
				}
				
				// Is there a next?
				if ( this.last(image) )
				{	return false;	}
				
				// Get the next
				return this.get(image.index+1);
			},
			
			first: function ( image )
			{	//
				// Get the first image?
				if ( typeof image === 'undefined' )
				{	return this.get(0);	}
				
				// Are we the first?
				return image.index === 0;
			},
			
			last: function ( image )
			{	//
				// Get the last image?
				if ( typeof image === 'undefined' )
				{	return this.get(this.size()-1);	}
				
				// Are we the last?
				return image.index === this.size()-1;
			},
		
			single: function ( )
			{	// Are we only one
				return this.size() === 1;
			},
			
			size: function ( )
			{	// How many images do we have
				return this.list.length;
			},
			
			empty: function ( )
			{	// Are we empty
				return this.size() === 0;
			},
			
			clear: function ( )
			{	// Clear image arrray
				this.list = [];
				this.image = false;
			},
		
			active: function ( image )
			{	// Set or get the active image
				// Use false to reset
				
				// Get the active image?
				if ( typeof image === 'undefined' )
				{	return this.image;	}
				
				// Set the ative image
				if ( image !== false )
				{	// Make sure image exists
					image = this.get(image);
					if ( !image )
					{	// Error
						return image;
					}
				}
				
				// Set the active image
				this.image = image;
				return true;
			},
		
			add: function ( obj )
			{
				// Do we need to recurse?
				if ( obj[0] )
				{	// We have a lot of images
					for ( var i = 0; i < obj.length; i++ )
					{	this.add(obj[i]);	}
					return true;
				}
				
				// Default image
				
				// Try and create a image
				var image = this.create(obj);
				if ( !image ) { return image; }
				
				// Set image index
				image.index = this.size();
				
				// Push image
				this.list.push(image);
				
				// Success
				return true;
			},
			
			create: function ( obj )
			{	// Create image
				
				// Define
				var image = { // default
					src:	'',
					title:	'Untitled',
					description:	'',
					name:	'',
					index:	-1,
					color:	null,
					width:	null,
					height:	null,
					image:	true
				};
				
				// Create
				if ( obj.image )
				{	// Already a image, so copy over values
					image.src = obj.src || image.src;
					image.title = obj.title;
					image.description = obj.description || image.description;
					image.name = obj.name || image.name;
					image.color = obj.color || image.color;
					image.width = obj.width || image.width;
					image.height = obj.height || image.height;
					image.index = obj.index || image.index;
					
					if (image.title != 'Untitled') {
						$('#lightbox-infoBox').show();
					} else {
						$('#lightbox-infoBox').hide();
					}
				}
				else if ( obj.tagName )
				{	// We are an element
					obj = $(obj);
					if ( obj.attr('src') || obj.attr('href') )
					{
						image.src = obj.attr('src') || obj.attr('href');
						image.title = obj.attr('title') || obj.attr('alt') || image.title;
						image.name = obj.attr('name') || '';
						image.color = obj.css('backgroundColor');
						// Extract description from title
						var s = image.title.indexOf(': ');
						if ( s > 0 )
						{	// Description exists
							image.description = image.title.substring(s+2) || image.description;
							image.title = image.title.substring(0,s) || image.title;
						}
					}
					else
					{	// Unsupported element
						image = false;
					}
				}
				else
				{	// Unknown
					image = false;
				}
				
				if ( !image )
				{	// Error
					$.log('ERROR', 'We dont know what we have:', obj);
					return false;
				}
				
				// Success
				return image;
			},
			
			get: function ( image )
			{	// Get the active, or specified image
				
				// Establish image
				if ( typeof image === 'undefined' || image === null )
				{	// Get the active image
					return this.active();
				}
				else
				if ( typeof image === 'number' )
				{	// We have a index
					
					// Get image
					image = this.list[image] || false;
				}
				else
				{	// Create
					image = this.create(image);
					if ( !image ) { return false; }
					
					// Find
					var f = false;
					for ( var i = 0; i < this.size(); i++ )
					{
						var c = this.list[i];
						if ( c.src === image.src && c.title === image.title && c.description === image.description )
						{	f = c;	}
					}
					
					// Found?
					image = f;
				}
				
				// Determine image
				if ( !image )
				{	// Image doesn't exist
					$.log('ERROR', 'The desired image doesn\'t exist: ', image, this.list);
					return false;
				}
				
				// Return image
				return image;
			},
			
			debug: function ( )
			{
				return $.Lightbox.debug(arguments);
			}
			
		},
		
		// -----------------
		// Options
		
		constructed:		false,
		
		src:				null,		// the source location of our js file
		baseurl:			null,
		
		files: {
			// If you are doing a repack with packer (http://dean.edwards.name/packer/) then append ".packed" onto the js and css files before you pack it.
			js: {
			},
			css: {
			},
            images: {
                prev:       '/images/lightbox/prev.gif',
                next:       '/images/lightbox/next.gif',
                loading:    '/images/loading.gif'
            }
		},
		
		text: {
			// For translating
			image:		'Image',
			of:			'of',
			close:		'Close X',
			closeInfo:	'You can also click anywhere outside the image to close.',
			download:	'Direct link to download the image.',
			/*help: {
				close:		'Close'
				//interact:	'Hover to interact'
			},*/
			about: {
				text: 	'',
				title:	'',
				link:	''
			}
		},
		
		keys: {
			close:	'c',
			prev:	'p',
			next:	'n'
		},
		
		handlers: {
			// For custom actions
			show:	null
		},
		
		opacity:		0.9,
		padding:		null,		// if null - autodetect
		
		speed:			400,		// Duration of effect, milliseconds
		
		rel:			'lightbox',	// What to look for in the rels
		
		auto_relify:	true,		// should we automaticly do the rels?
		
		auto_scroll:	'follow',	// should the lightbox scroll with the page? follow, disabled, ignore
		auto_resize:	true,		// true or false
		
		ie6:			null,		// are we ie6?
		ie6_support:	true,		// have ie6 support
		ie6_upgrade:	true,		// show ie6 upgrade message
		
		colorBlend:		null,		// null - auto-detect, true - force, false - no
		
		download_link:	true,		// Display the download link
		
		show_linkback:		true,	// true, false
		show_info:			'auto',	// auto - automaticly handle, true - force
		show_extended_info:	'auto',	// auto - automaticly handle, true - force	
		
		// names of the options that can be modified
		options:	['auto_scroll', 'auto_resize', 'download_link', 'show_info', 'show_extended_info', 'ie6_support', 'ie6_upgrade', 'colorBlend', 'baseurl', 'files', 'text', 'show_linkback', 'keys', 'opacity', 'padding', 'speed', 'rel', 'auto_relify'],
		
		// -----------------
		// Functions
		
		construct: function ( options )
		{	// Construct our Lightbox
			
			// -------------------
			// Prepare
			
			// Initial construct
			var initial = typeof this.constructed === 'undefined' || this.constructed === false;
			this.constructed = true;
			
			// Perform domReady
			var domReady = true;
			
			// Prepare options
			options = $.extend({}, options);
			
			// -------------------
			// Apply options
			
			for ( i in this.options )
			{	// Cycle through the options
				var name = this.options[i];
				if ( (typeof options[name] === 'object') && (typeof this[name] === 'object') )
				{	// We have a group like text or files
					this[name] = $.extend(this[name], options[name]);
				}
				else if ( typeof options[name] !== 'undefined' )
				{	// We have that option, so apply it
					this[name] = options[name];
				}
			}
			
			// -------------------
			// Figure out what to do
			
			// Handle IE6
			if ( initial && navigator.userAgent.indexOf('MSIE 6') >= 0 )
			{	// Is IE6
				this.ie6 = true;
			}
			else
			{	// We are not IE6
				this.ie6 = false;
			}
			
			// -------------------
			// Handle our DOM
			
			if ( domReady || typeof options.download_link !== 'undefined' ||  typeof options.colorBlend !== 'undefined' || typeof options.files === 'object' || typeof options.text === 'object' || typeof options.show_linkback !== 'undefined' || typeof options.scroll_with !== 'undefined' )
			{	// We have reason to handle the dom
				$(function() {
					// DOM is ready, so fire our DOM handler
					$.Lightbox.domReady();
				});
			}
			
			// -------------------
			// Finish Up
			
			// All good
			return true;
		},
		
		domReady: function ( )
		{
			// -------------------
			// Include resources
			
			// Grab resources
			var bodyEl = document.getElementsByTagName($.browser.safari ? 'head' : 'body')[0];
			var stylesheets = this.files.css;
			var scripts = this.files.js;
			
			delete scripts.lightbox; // obviously we've loaded ourself
			
			// Handle IE6 appropriatly
			if ( this.ie6 && this.ie6_upgrade )
			{	// Add the upgrade message
				//scripts.ie6 = 'http://www.savethedevelopers.org/say.no.to.ie.6.js';
			}
			
			// colorBlend
			if ( this.colorBlend === true && typeof $.colorBlend === 'undefined' )
			{	// Force colorBlend
				this.colorBlend = true;
				// Leave file in place to be loaded
			}
			else
			{	// We either have colorBlend or we don't
				this.colorBlend = typeof $.colorBlend !== 'undefined';
				// Remove colorBlend file
				delete scripts.colorBlend;
			}
			
			// Include stylesheets
			for ( stylesheet in stylesheets )
			{
				var linkEl = document.createElement('link');
				linkEl.type = 'text/css';
				linkEl.rel = 'stylesheet';
				linkEl.media = 'screen';
				linkEl.href = stylesheets[stylesheet];
				linkEl.id = 'lightbox-stylesheet-'+stylesheet.replace(/[^a-zA-Z0-9]/g, '');
				$('#'+linkEl.id).remove();
				bodyEl.appendChild(linkEl);
			}
			
			// Include javascripts
			for ( script in scripts )
			{
				var scriptEl = document.createElement('script');
				scriptEl.type = 'text/javascript';
				scriptEl.src = scripts[script];
				scriptEl.id = 'lightbox-script-'+script.replace(/[^a-zA-Z0-9]/g, '');
				$('#'+scriptEl.id).remove();
				bodyEl.appendChild(scriptEl);
			}
			
			// Cleanup
			delete scripts;
			delete stylesheets;
			delete bodyEl;
			
			// -------------------
			// Append display
			
			// Append markup
			$('#lightbox,#lightbox-overlay').remove();
			$('body').append('<div id="lightbox-overlay"></div><div id="lightbox"><div id="lightbox-imageBox"><div id="lightbox-imageContainer"><div id="lightbox-overlay-text"><p><span id="lightbox-overlay-text-close"></span></p></div><img id="lightbox-image" /><div id="lightbox-nav"><a href="#" id="lightbox-nav-btnPrev"></a><a href="#" id="lightbox-nav-btnNext"></a></div><div id="lightbox-loading"><a href="#" id="lightbox-loading-link"><img src="' + this.files.images.loading + '" /></a></div></div></div><div id="lightbox-infoBox"><div id="lightbox-infoHeader"><span id="lightbox-caption">'+(this.download_link ? '<a href="#" title="' + this.text.download + '" id="lightbox-caption-title"></a>' : '<span id="lightbox-caption-title"></span>')+'<span id="lightbox-caption-seperator"></span><span id="lightbox-caption-description"></span></span><div id="lightbox-infoFooter"><span id="lightbox-currentNumber"></span></div></div></div></div>');
			
			// Update Boxes - for some crazy reason this has to be before the hide in safari and konqueror
			this.resizeBoxes();
			this.repositionBoxes();
			
			// Hide
			$('#lightbox,#lightbox-overlay').hide();
			
			// -------------------
			// Browser specifics
			
			// Handle IE6
			if ( this.ie6 && this.ie6_support )
			{	// Support IE6
				// IE6 does not support fixed positioning so absolute it
				// ^ This is okay as we disable scrolling
				$('#lightbox-overlay').css({
					position:	'absolute',
					top:		'0px',
					left:		'0px'
				});
			}
			
			// -------------------
			// Preload Images
			
			// Cycle and preload
			$.each(this.files.images, function()
			{	// Proload the image
				var preloader = new Image();
				preloader.onload = function() {
					preloader.onload = null;
					preloader = null;
				};	preloader.src = this;
			});
			
			// -------------------
			// Apply events
			
			// If the window resizes, act appropriatly
			$(window).resize(function ()
			{	// The window has been resized
				$.Lightbox.resizeBoxes('resized');
			});
			
			// If the window scrolls, act appropriatly
			if ( this.scroll === 'follow' )
			{	// We want to
				$(window).scroll(function ()
				{	// The window has scrolled
					$.Lightbox.repositionBoxes();
				});
			}
			
			// Prev
			$('#lightbox-nav-btnPrev').unbind().hover(function() { // over
				$(this).css({ 'background' : 'url(' + $.Lightbox.files.images.prev + ') left 45% no-repeat' });
			},function() { // out
				$(this).css({ 'background' : 'transparent' });
			}).click(function() {
				$.Lightbox.showImage($.Lightbox.images.prev());
				return false;
			});
					
			// Next
			$('#lightbox-nav-btnNext').unbind().hover(function() { // over
				$(this).css({ 'background' : 'url(' + $.Lightbox.files.images.next + ') right 45% no-repeat' });
			},function() { // out
				$(this).css({ 'background' : 'transparent' });
			}).click(function() {
				$.Lightbox.showImage($.Lightbox.images.next());
				return false;
			});
			
			// Help
			if ( this.show_linkback )
			{	// Linkback exists so add handler
				$('#lightbox-overlay-text-about a').click(function(){window.open($.Lightbox.text.about.link); return false;});
			}
			
			// Image link
			$('#lightbox-caption-title').click(function(){window.open($(this).attr('href')); return false;});
			
			// Assign close clicks
			$('#lightbox-overlay, #lightbox, #lightbox-loading-link, #lightbox-btnClose').unbind().click(function() {
				$.Lightbox.finish();
				return false;	
			});
			
			// -------------------
			// Finish Up
			
			// Relify
			if ( this.auto_relify )
			{	// We want to relify, no the user
				this.relify();
			}
			
			// All good
			return true;
		},
		
		relify: function ( )
		{	// Create event
		
			//
			var groups = {};
			var groups_n = 0;
			var orig_rel = this.rel;
			// Create the groups
			$.each($('[@rel*='+orig_rel+']'), function(index, obj){
				// Get the group
				var rel = $(obj).attr('rel');
				// Are we really a group
				if ( rel === orig_rel )
				{	// We aren't
					rel = groups_n; // we are individual
				}
				// Does the group exist
				if ( typeof groups[rel] === 'undefined' )
				{	// Make the group
					groups[rel] = [];
					groups_n++;
				}
				// Append the image
				groups[rel].push(obj);
			});
			// Lightbox groups
			$.each(groups, function(index, group){
				$(group).lightbox();
			});
			// Done
			return true;
		},
		
		init: function ( image, images )
		{	// Init a batch of lightboxes
			
			// Establish images
			if ( typeof images === 'undefined' )
			{
				images = image;
				image = 0;
			}
			
			// Clear
			this.images.clear();
			
			// Add images
			if ( !this.images.add(images) )
			{	return false;	}
			
			// Do we need to bother
			if ( this.images.empty() )
			{	// No images
				$.log('WARNING', 'Lightbox started, but no images: ', image, images);
				return false;
			}
			
			// Set active
			if ( !this.images.active(image) )
			{	return false;	}
			
			// Done
			return true;
		},
		
		start: function ( )
		{	// Display the lightbox
				
			// We are alive
			this.visible = true;
			
			// Adjust scrolling
			if ( this.scroll === 'disable' )
			{	// 
				$(document.body).css('overflow', 'hidden');
			}
			
			// Fix attention seekers
			$('embed, object, select').css('visibility', 'hidden');//.hide(); - don't use this, give it a go, find out why!
			
			// Resize the boxes appropriatly
			this.resizeBoxes('general');
			
			// Reposition the Boxes
			this.repositionBoxes({'speed':0});
			
			// !Hide things
			$('#lightbox-infoFooter').hide(); // we hide this here because it makes the display smoother
			$('#lightbox-image,#lightbox-nav,#lightbox-nav-btnPrev,#lightbox-nav-btnNext').hide();
					
			// Display the boxes
			$('#lightbox-overlay').fadeIn(400, function(){
				// Show the lightbox
				$('#lightbox').fadeIn(300);
				
				// Display first image
				if ( !$.Lightbox.showImage($.Lightbox.images.active()) )
				{	$.Lightbox.finish();	return false;	}
			});
			
			// All done
			return true;
		},
		
		finish: function ( )
		{	// Get rid of lightbox
		
			// Hide lightbox
			$('#lightbox').hide();
			$('#lightbox-overlay').fadeOut(function() { $('#lightbox-overlay').hide(); });
			
			// Fix attention seekers
			$('embed, object, select').css({ 'visibility' : 'visible' });//.show();
			
			// Kill active image
			this.images.active(false);
			
			// Adjust scrolling
			if ( this.scroll === 'disable' )
			{	// 
				$(document.body).css('overflow', 'visible');
			}
			
			// We are dead
			this.visible = false;
			
		},
		
		resizeBoxes: function ( type )
		{	// Resize the boxes
			// Used on transition or window resize
			
			// Resize Overlay
			if ( type !== 'transition' )
			{	// We don't care for transition
				var $body = $(this.ie6 ? document.body : document);
				$('#lightbox-overlay').css({
					width:		$body.width(),
					height:		$body.height()
				});
				delete $body;
			}
			
			// Handle cases
			switch ( type )
			{
				case 'general': // general resize (start of lightbox)
					return true;
					break;
				case 'resized': // window was resized
					if ( this.auto_resize === false )
					{	// Stop
						// Reposition
						this.repositionBoxes({'nHeight':nHeight, 'speed':this.speed});
						return true;
					}
				case 'transition': // transition between images
				default: // unknown
					break;
			}
			
			// Get image
			var image = this.images.active();
			if ( !image || !image.width || !this.visible )
			{	// No image or no visible lightbox, so we don't care
				$.log('WARNING', 'A resize occured while no image or no lightbox...');
				return false;
			}
			
			// Resize image box
			// i:image, w:window, b:box, c:current, n:new, d:difference
			
			// Get image dimensions
			var iWidth  = image.width;
			var iHeight = image.height;
			
			// Get window dimensions
			var wWidth  = $(window).width();
			var wHeight = $(window).height();
			
			// Check if we are in size
			// Lightbox can take up 4/5 of size
			if ( this.auto_resize !== false )
			{	// We want to auto resize
				var maxWidth  = Math.floor(wWidth*(4/5));
				var maxHeight = Math.floor(wHeight*(4/5));
				var resizeRatio;
				while ( iWidth > maxWidth || iHeight > maxHeight )
				{	// We need to resize
					if ( iWidth > maxWidth )
					{	// Resize width, then height proportionally
						resizeRatio = maxWidth/iWidth;
						iWidth = maxWidth;
						iHeight = Math.floor(iHeight*resizeRatio);
					}
					if ( iHeight > maxHeight )
					{	// Resize height, then width proportionally
						resizeRatio = maxHeight/iHeight;
						iHeight = maxHeight;
						iWidth = Math.floor(iWidth*resizeRatio);
					}
				}
			}
			
			// Get current width and height
			var cWidth  = $('#lightbox-imageBox').width();
			var cHeight = $('#lightbox-imageBox').height();
	
			// Get the width and height of the selected image plus the padding
			// padding*2 for both sides (left+right || top+bottom)
			var nWidth	= (iWidth  + (this.padding * 2));
			var nHeight	= (iHeight + (this.padding * 2));
			
			// Diferences
			var dWidth  = cWidth  - nWidth;
			var dHeight = cHeight - nHeight;
			
			// Set the overlay buttons height and the infobox width
			// Other dimensions specified by CSS
			$('#lightbox-nav-btnPrev,#lightbox-nav-btnNext').css('height', nHeight); 
			//$('#lightbox-infoBox').css('width', nWidth);
			
			// Handle final action
			if ( type === 'transition' )
			{	// We are transition
				// Do we need to wait? (just a nice effect to counter the other
				if ( dWidth === 0 && dHeight === 0 )
				{	// We are the same size
					this.pause(this.speed/3);
					this.showImage(null, 3);
				}
				else
				{	// We are not the same size
					// Animate
					$('#lightbox-image').width(iWidth).height(iHeight);
					$('#lightbox-infoBox').animate({width:nWidth}, this.speed);
					$('#lightbox-imageBox').animate({width: nWidth, height: nHeight}, this.speed, function ( ) { $.Lightbox.showImage(null, 3); } );
				}
			}
			else
			{	// We are a resize
				// Animate Lightbox
				$('#lightbox-image').animate({width:iWidth, height:iHeight}, this.speed);
				$('#lightbox-infoBox').animate({width:nWidth}, this.speed);
				$('#lightbox-imageBox').animate({width: nWidth, height: nHeight}, this.speed);
			}
			
			// Reposition
			this.repositionBoxes({'nHeight':nHeight, 'speed':this.speed});
			
			// Done
			return true;
		},
		
		repositioning:			false,	// are we currently repositioning
		reposition_failsafe:	false,	// failsafe
		repositionBoxes: function ( options )
		{
			// Prepare
			if ( this.repositioning )
			{	// Already here
				this.reposition_failsafe = true;
				return null;
			}
			this.repositioning = true;
			
			// Options
			options = $.extend({}, options);
			options.callback = options.callback || null;
			options.speed = options.speed || 'slow';
			
			// Get page scroll
			var pageScroll = this.getPageScroll();
			
			// Figure it out
			// alert($(window).height()+"\n"+$(document.body).height()+"\n"+$(document).height());
			// var nHeight = options.nHeight || parseInt($('#lightbox').height(),10) || $(document).height()/3;
			var nHeight = options.nHeight || parseInt($('#lightbox').height(),10);
			
			// Display lightbox in center
			// var nTop = pageScroll.yScroll + ($(document.body).height() /*frame height*/ - nHeight) / 2.5;
			var nTop = pageScroll.yScroll + ($(window).height() /*frame height*/ - nHeight) / 2.5;
			var nLeft = pageScroll.xScroll;
			
			// Animate
			var css = {
				left: nLeft,
				top: nTop
			};
			if (options.speed) {
				$('#lightbox').animate(css, 'slow', function(){
					if ( $.Lightbox.reposition_failsafe )
					{	// Fire again
						$.Lightbox.repositioning = $.Lightbox.reposition_failsafe = false;
						$.Lightbox.repositionBoxes(options);
					}
					else
					{	// Done
						$.Lightbox.repositioning = false;
						if ( options.callback )
						{	// Call the user callback
							options.callback();
						}
					}
				});
			}
			else
			{
				$('#lightbox').css(css);
				if ( this.reposition_failsafe )
				{	// Fire again
					this.repositioning = this.reposition_failsafe = false;
					this.repositionBoxes(options);
				}
				else
				{	// Done
					this.repositioning = false;
				}
			}
			
			// Done
			return true;
		},
		
		visible: false,
		showImage: function ( image, step )
		{
			// Establish image
			image = this.images.get(image);
			if ( !image ) { return image; }
			
			// Default step
			step = step || 1;
			
			// Split up below for jsLint compliance
			var skipped_step_1 = step > 1 && this.images.active().src !== image.src;
			var skipped_step_2 = step > 2 && $('#lightbox-image').attr('src') !== image.src;
			if ( skipped_step_1 || skipped_step_2 )
			{	// Force step 1
				$.log('We wanted to skip a few steps: ', image, step, skipped_step_1, skipped_step_2);
				step = 1;
			}
			
			// What do we need to do
			switch ( step )
			{
				// ---------------------------------
				// We need to preload
				case 1:
				
					// Disable keyboard nav
					this.KeyboardNav_Disable();
					
					// Show the loading image
					$('#lightbox-loading').show();
					
					// Hide things
					$('#lightbox-image,#lightbox-nav,#lightbox-nav-btnPrev,#lightbox-nav-btnNext').hide();
					
					// Remove show info events
					$('#lightbox-imageBox').unbind();
					// ^ Why? Because otherwise when the image is changing, the info pops out, not good!
					
					// Make the image the active image
					if ( !this.images.active(image) ) { return false; }
					
					// Check if we need to preload
					if ( image.width && image.height )
					{	// We don't
						// Continue to next step
						this.showImage(null, 2);
					}
					else
					{	// We do
						// Create preloader
						var preloader = new Image();
						// Set callback
						preloader.onload = function()
						{	// We have preloaded the image
							// Update image with our new info
							image.width  = preloader.width;
							image.height = preloader.height;
							// Continue to next step
							$.Lightbox.showImage(null, 2);
							// Kill preloader
							preloader.onload = null;
							preloader = null;
						};
						// Start preload
						preloader.src = image.src;
					}
					
					// Done
					break;
				
				
				// ---------------------------------
				// Resize the container
				case 2:
					
					// Apply image changes
					$('#lightbox-image').attr('src', image.src);
					
					// Set container border (Moved here for Konqueror fix - Credits to Blueyed)
					if ( typeof this.padding === 'undefined' || this.padding === null || isNaN(this.padding) )
					{	// Autodetect
						this.padding = parseInt($('#lightbox-imageContainer').css('padding-left'), 10) || parseInt($('#lightbox-imageContainer').css('padding'), 10) || 0;
					}
					
					// Use colorBlend?
					if ( this.colorBlend )
					{	// We have colorBlend
						// Background
						$('#lightbox-overlay').animate({'backgroundColor':image.color}, this.speed*2);
						// Border
						$('#lightbox-imageBox').css('borderColor', image.color);
					}
					
					// Resize boxes
					this.resizeBoxes('transition');
					// ^ contains callback to next step
					
					// Done
					break;
				
				
				// ---------------------------------
				// Display the image
				case 3:
					
					// Hide loading
					$('#lightbox-loading').hide();
					
					// Animate image
					$('#lightbox-image').fadeIn(this.speed*1.5, function() {$.Lightbox.showImage(null, 4); });
					
					// Start the proloading of other images
					this.preloadNeighbours();
					
					// Fire custom handler show
					if ( this.handlers.show !== null )
					{	// Fire it
						this.handlers.show(image);
					}
					
					// Done
					break;
				
				
				// ---------------------------------
				// Set image info / Set navigation
				case 4:
					
					// ---------------------------------
					// Set image info
					
					// Hide and set image info
					var $title = $('#lightbox-caption-title').html(image.title);
					if (this.download_link) {
						$title.attr('href', this.download_link ? image.src : '');
					}
					if (image.title == null) {
						alert('test');
					}
					delete $title;
					$('#lightbox-caption-seperator').html(image.description ? ': ' : '');
					$('#lightbox-caption-description').html(image.description || '&nbsp;');
					
					// If we have a set, display image position
					if ( this.images.size() > 1 )
					{	// Display
						$('#lightbox-currentNumber').html(this.text.image + '&nbsp;' + ( image.index + 1 ) + '&nbsp;' + this.text.of + '&nbsp;' + this.images.size());
					} else
					{	// Empty
						$('#lightbox-currentNumber').html('&nbsp;');
					}
					
					// ---------------------------------
					// Info events
					
					// Apply event
					/*$('#lightbox-imageBox').unbind('mouseover').mouseover(function(){
						$('#lightbox-infoBox').slideDown('fast');
					});*/
					
					// Apply event
					/*$('#lightbox-infoBox').unbind('mouseover').mouseover(function(){
						$('#lightbox-infoFooter').slideDown('fast');
					});*/
					
					// Forced show?
					/*if ( this.show_extended_info === true )
					{	// Force show
						$('#lightbox-imageBox').trigger('mouseover');
						$('#lightbox-infoBox').trigger('mouseover');
					}
					else if ( this.show_info === true )
					{	// Force show
						$('#lightbox-imageBox').trigger('mouseover');
					}*/
					
					// ---------------------------------
					// Set navigation
		
					// Instead to define this configuration in CSS file, we define here. And it's need to IE. Just.
					$('#lightbox-nav-btnPrev, #lightbox-nav-btnNext').css({ 'background' : 'transparent' });
					
					// If not first, show previous button
					if ( !this.images.first(image) ) {
						// Not first, show button
						$('#lightbox-nav-btnPrev').show();
					}
					
					// If not last, show next button
					if ( !this.images.last(image) ) {
						// Not first, show button
						$('#lightbox-nav-btnNext').show();
					}
					
					// Make navigation active / show it
					$('#lightbox-nav').show();
					
					// Enable keyboard navigation
					this.KeyboardNav_Enable();
					
					// Done
					break;
					
					
				// ---------------------------------
				// Error handling
				default:
					$.log('ERROR', 'Don\'t know what to do: ', image, step);
					return this.showImage(image, 1);
					// break;
				
			}
			
			// All done
			return true;
		},
		
		preloadNeighbours: function ( )
		{	// Preload all neighbour images
			
			// Do we need to do this?
			if ( this.images.single() || this.images.empty() )
			{	return true;	}
			
			// Get active image
			var image = this.images.active();
			if ( !image ) { return image; }
			
			// Load previous
			var prev = this.images.prev(image);
			var objNext;
			if ( prev ) {
				objNext = new Image();
				objNext.src = prev.src;
			}
			
			// Load next
			var next = this.images.next(image);
			if ( next ) {
				objNext = new Image();
				objNext.src = next.src;
			}
		},
		
		// --------------------------------------------------
		// Things we don't really care about
		
		KeyboardNav_Enable: function ( ) {
			$(document).keydown(function(objEvent) {
				$.Lightbox.KeyboardNav_Action(objEvent);
			});
		},
		
		KeyboardNav_Disable: function ( ) {
			$(document).unbind();
		},
		
		KeyboardNav_Action: function ( objEvent ) {
			// Prepare
			objEvent = objEvent || window.event;
			
			// Get the keycode
			var keycode = objEvent.keyCode;
			var escapeKey = objEvent.DOM_VK_ESCAPE /* moz */ || 27;
			
			// Get key
			var key = String.fromCharCode(keycode).toLowerCase();
			
			// Close?
			if ( key === this.keys.close || keycode === escapeKey )
			{	return $.Lightbox.finish();		}
			
			// Prev?
			if ( key === this.keys.prev || keycode === 37 )
			{	// We want previous
				return $.Lightbox.showImage($.Lightbox.images.prev());
			}
			
			// Next?
			if ( key === this.keys.next || keycode === 39 )
			{	// We want next
				return $.Lightbox.showImage($.Lightbox.images.next());
			}
			
			// Unknown
			return true;
		},
		
		getPageScroll: function ( ) {
			var xScroll, yScroll;
			if (self.pageYOffset)
			{	// Some browser
				yScroll = self.pageYOffset;
				xScroll = self.pageXOffset;
			} else if (document.documentElement && document.documentElement.scrollTop)
			{	// Explorer 6 Strict
				yScroll = document.documentElement.scrollTop;
				xScroll = document.documentElement.scrollLeft;
			} else if (document.body)
			{	// All other browsers
				yScroll = document.body.scrollTop;
				xScroll = document.body.scrollLeft;	
			}
			var arrayPageScroll = {'xScroll':xScroll,'yScroll':yScroll};
			return arrayPageScroll;
		},
		
		pause: function ( ms ) {
			var date = new Date();
			var curDate = null;
			do { curDate = new Date(); }
			while ( curDate - date < ms);
		}
	
	}); // We have finished extending/defining our LightboxClass


	// --------------------------------------------------
	// Finish up
	
	// Instantiate
	if ( typeof $.Lightbox === 'undefined' )
	{	// 
		$.Lightbox = new $.LightboxClass();
	}

// Finished definition

})(jQuery); // We are done with our plugin, so lets call it with jQuery as the argument
/*
 * jQuery Color Animations
 * Copyright 2007 John Resig
 * Released under the MIT and GPL licenses.
 */

(function(jQuery){

    // We override the animation for all of these color styles
    jQuery.each(['backgroundColor', 'borderBottomColor', 'borderLeftColor', 'borderRightColor', 'borderTopColor', 'color', 'outlineColor'], function(i,attr){
        jQuery.fx.step[attr] = function(fx){
            if ( fx.state == 0 ) {
                fx.start = getColor( fx.elem, attr );
                fx.end = getRGB( fx.end );
            }

            fx.elem.style[attr] = "rgb(" + [
                Math.max(Math.min( parseInt((fx.pos * (fx.end[0] - fx.start[0])) + fx.start[0]), 255), 0),
                Math.max(Math.min( parseInt((fx.pos * (fx.end[1] - fx.start[1])) + fx.start[1]), 255), 0),
                Math.max(Math.min( parseInt((fx.pos * (fx.end[2] - fx.start[2])) + fx.start[2]), 255), 0)
            ].join(",") + ")";
        }
    });

    // Color Conversion functions from highlightFade
    // By Blair Mitchelmore
    // http://jquery.offput.ca/highlightFade/

    // Parse strings looking for color tuples [255,255,255]
    function getRGB(color) {
        var result;

        // Check if we're already dealing with an array of colors
        if ( color && color.constructor == Array && color.length == 3 )
            return color;

        // Look for rgb(num,num,num)
        if (result = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(color))
            return [parseInt(result[1]), parseInt(result[2]), parseInt(result[3])];

        // Look for rgb(num%,num%,num%)
        if (result = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(color))
            return [parseFloat(result[1])*2.55, parseFloat(result[2])*2.55, parseFloat(result[3])*2.55];

        // Look for #a0b1c2
        if (result = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(color))
            return [parseInt(result[1],16), parseInt(result[2],16), parseInt(result[3],16)];

        // Look for #fff
        if (result = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(color))
            return [parseInt(result[1]+result[1],16), parseInt(result[2]+result[2],16), parseInt(result[3]+result[3],16)];

        // Look for rgba(0, 0, 0, 0) == transparent in Safari 3
        if (result = /rgba\(0, 0, 0, 0\)/.exec(color))
            return colors['transparent'];

        // Otherwise, we're most likely dealing with a named color
        return colors[jQuery.trim(color).toLowerCase()];
    }

    function getColor(elem, attr) {
        var color;

        do {
            color = jQuery.curCSS(elem, attr);

            // Keep going until we find an element that has color, or we hit the body
            if ( color != '' && color != 'transparent' || jQuery.nodeName(elem, "body") )
                break;

            attr = "backgroundColor";
        } while ( elem = elem.parentNode );

        return getRGB(color);
    };

    // Some named colors to work with
    // From Interface by Stefan Petre
    // http://interface.eyecon.ro/

    var colors = {
        aqua:[0,255,255],
        azure:[240,255,255],
        beige:[245,245,220],
        black:[0,0,0],
        blue:[0,0,255],
        brown:[165,42,42],
        cyan:[0,255,255],
        darkblue:[0,0,139],
        darkcyan:[0,139,139],
        darkgrey:[169,169,169],
        darkgreen:[0,100,0],
        darkkhaki:[189,183,107],
        darkmagenta:[139,0,139],
        darkolivegreen:[85,107,47],
        darkorange:[255,140,0],
        darkorchid:[153,50,204],
        darkred:[139,0,0],
        darksalmon:[233,150,122],
        darkviolet:[148,0,211],
        fuchsia:[255,0,255],
        gold:[255,215,0],
        green:[0,128,0],
        indigo:[75,0,130],
        khaki:[240,230,140],
        lightblue:[173,216,230],
        lightcyan:[224,255,255],
        lightgreen:[144,238,144],
        lightgrey:[211,211,211],
        lightpink:[255,182,193],
        lightyellow:[255,255,224],
        lime:[0,255,0],
        magenta:[255,0,255],
        maroon:[128,0,0],
        navy:[0,0,128],
        olive:[128,128,0],
        orange:[255,165,0],
        pink:[255,192,203],
        purple:[128,0,128],
        violet:[128,0,128],
        red:[255,0,0],
        silver:[192,192,192],
        white:[255,255,255],
        yellow:[255,255,0],
        transparent: [255,255,255]
    };

})(jQuery);
