// JavaScript Document
//v1.0
//Copyright 2006 Adobe Systems, Inc. All rights reserved.
function AC_AddExtension(src, ext)
{
  if (src.indexOf('?') != -1)
    return src.replace(/\?/, ext+'?'); 
  else
    return src + ext;
}

function AC_Generateobj(objAttrs, params, embedAttrs) 
{ 
  var str = '<object ';
  for (var i in objAttrs)
    str += i + '="' + objAttrs[i] + '" ';
  str += '>';
  for (var i in params)
    str += '<param name="' + i + '" value="' + params[i] + '" /> ';
  str += '<embed ';
  for (var i in embedAttrs)
    str += i + '="' + embedAttrs[i] + '" ';
  str += ' ></embed></object>';

  document.write(str);
}

function AC_FL_RunContent(){
  var ret = 
    AC_GetArgs
    (  arguments, ".swf", "movie", "clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"
     , "application/x-shockwave-flash"
    );
  AC_Generateobj(ret.objAttrs, ret.params, ret.embedAttrs);
}

function AC_SW_RunContent(){
  var ret = 
    AC_GetArgs
    (  arguments, ".dcr", "src", "clsid:166B1BCA-3F9C-11CF-8075-444553540000"
     , null
    );
  AC_Generateobj(ret.objAttrs, ret.params, ret.embedAttrs);
}

function AC_GetArgs(args, ext, srcParamName, classid, mimeType){
  var ret = new Object();
  ret.embedAttrs = new Object();
  ret.params = new Object();
  ret.objAttrs = new Object();
  for (var i=0; i < args.length; i=i+2){
    var currArg = args[i].toLowerCase();    

    switch (currArg){	
      case "classid":
        break;
      case "pluginspage":
        ret.embedAttrs[args[i]] = args[i+1];
        break;
      case "src":
      case "movie":	
        args[i+1] = AC_AddExtension(args[i+1], ext);
        ret.embedAttrs["src"] = args[i+1];
        ret.params[srcParamName] = args[i+1];
        break;
      case "onafterupdate":
      case "onbeforeupdate":
      case "onblur":
      case "oncellchange":
      case "onclick":
      case "ondblClick":
      case "ondrag":
      case "ondragend":
      case "ondragenter":
      case "ondragleave":
      case "ondragover":
      case "ondrop":
      case "onfinish":
      case "onfocus":
      case "onhelp":
      case "onmousedown":
      case "onmouseup":
      case "onmouseover":
      case "onmousemove":
      case "onmouseout":
      case "onkeypress":
      case "onkeydown":
      case "onkeyup":
      case "onload":
      case "onlosecapture":
      case "onpropertychange":
      case "onreadystatechange":
      case "onrowsdelete":
      case "onrowenter":
      case "onrowexit":
      case "onrowsinserted":
      case "onstart":
      case "onscroll":
      case "onbeforeeditfocus":
      case "onactivate":
      case "onbeforedeactivate":
      case "ondeactivate":
      case "type":
      case "codebase":
        ret.objAttrs[args[i]] = args[i+1];
        break;
      case "width":
      case "height":
      case "align":
      case "vspace": 
      case "hspace":
      case "class":
      case "title":
      case "accesskey":
      case "name":
      case "id":
      case "tabindex":
        ret.embedAttrs[args[i]] = ret.objAttrs[args[i]] = args[i+1];
        break;
      default:
        ret.embedAttrs[args[i]] = ret.params[args[i]] = args[i+1];
    }
  }
  ret.objAttrs["classid"] = classid;
  if (mimeType) ret.embedAttrs["type"] = mimeType;
  return ret;
}

/*
 * DatePicker
 * @author Rick Hopkins
 * @modified by Micah Nolte and Martin Va?ina
 * @version 0.3.2
 * @classDescription A date picker object. Created with the help of MooTools v1.11
 * MIT-style License.

-- start it up by doing this in your domready:

$$('input.DatePicker').each( function(el){
	new DatePicker(el);
});

 */

var DatePicker = new Class({

	/* set and create the date picker text box */
	initialize: function(dp) {

		// Options defaults
		this.dayChars = 1; // number of characters in day names abbreviation
		this.dayNames = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
		this.daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
		this.format = 'mm/dd/yyyy';
		this.monthNames = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
		this.startDay = 7; // 1 = week starts on Monday, 7 = week starts on Sunday
		this.yearOrder = 'asc';
		this.yearRange = 10;
		this.yearStart = (new Date().getFullYear());


		// Finds the entered date, or uses the current date
		if(dp.value != '') {
			dp.then = new Date(dp.value);
			dp.today = new Date();
		} else {
			dp.then = dp.today = new Date();
		}
		// Set beginning time and today, remember the original
		dp.oldYear = dp.year = dp.then.getFullYear();
		dp.oldMonth = dp.month = dp.then.getMonth();
		dp.oldDay = dp.then.getDate();
		dp.nowYear = dp.today.getFullYear();
		dp.nowMonth = dp.today.getMonth();
		dp.nowDay = dp.today.getDate();

		// Pull the rest of the options from the alt attr
		if(dp.alt) {
			options = JSON.decode(dp.alt);
		} else {
			options = [];
		}
		dp.options = {
			monthNames: (options.monthNames && options.monthNames.length == 12 ? options.monthNames : this.monthNames) || this.monthNames, 
			daysInMonth: (options.daysInMonth && options.daysInMonth.length == 12 ? options.daysInMonth : this.daysInMonth) || this.daysInMonth, 
			dayNames: (options.dayNames && options.dayNames.length == 7 ? options.dayNames : this.dayNames) || this.dayNames,
			startDay : options.startDay || this.startDay,
			dayChars : options.dayChars || this.dayChars, 
			format: options.format || this.format,
			yearStart: options.yearStart || this.yearStart,
			yearRange: options.yearRange || this.yearRange,
			yearOrder: options.yearOrder || this.yearOrder
		};
		dp.setProperties({'id':dp.getProperty('name'), 'readonly':true});
		dp.container = false;
		dp.calendar = false;
		dp.interval = null;
		dp.active = false;
		dp.onclick = dp.onfocus = this.create.pass(dp, this);
	},

	/* create the calendar */
	create: function(dp) {
		if (dp.calendar) return false;

		// Hide select boxes while calendar is up
		if(window.ie6){
			$$('select').addClass('dp_hide');
		}
		
		/* create the outer container */
		dp.container = new Element('div', {'class':'dp_container'}).injectBefore(dp);
		
		/* create timers */
		dp.container.onmouseover = dp.onmouseover = function(){
			$clear(dp.interval);
		};
		dp.container.onmouseout = dp.onmouseout = function(){
			dp.interval = setInterval(function(){
				if (!dp.active) this.remove(dp);
			}.bind(this), 500);
		}.bind(this);
		
		/* create the calendar */
		dp.calendar = new Element('div', {'class':'dp_cal'}).injectInside(dp.container);
		
		/* create the date object */
		var date = new Date();
		
		/* create the date object */
		if (dp.month && dp.year) {
			date.setFullYear(dp.year, dp.month, 1);
		} else {
			dp.month = date.getMonth();
			dp.year = date.getFullYear();
			date.setDate(1);
		}
		dp.year % 4 == 0 ? dp.options.daysInMonth[1] = 29 : dp.options.daysInMonth[1] = 28;
		
		/* set the day to first of the month */
		var firstDay = (1-(7+date.getDay()-dp.options.startDay)%7);
		
		
		
		/* create the month select box */
		monthSel = new Element('select', {'id':dp.id + '_monthSelect'});
		for (var m = 0; m < dp.options.monthNames.length; m++){
			monthSel.options[m] = new Option(dp.options.monthNames[m], m);
			if (dp.month == m) monthSel.options[m].selected = true;
		}
		
		/* create the year select box */
		yearSel = new Element('select', {'id':dp.id + '_yearSelect'});
		i = 0;
		dp.options.yearStart ? dp.options.yearStart : dp.options.yearStart = date.getFullYear();
		if (dp.options.yearOrder == 'desc'){
			for (var y = dp.options.yearStart; y > (dp.options.yearStart - dp.options.yearRange - 1); y--){
				yearSel.options[i] = new Option(y, y);
				if (dp.year == y) yearSel.options[i].selected = true;
				i++;
			}
		} else {
			for (var y = dp.options.yearStart; y < (dp.options.yearStart + dp.options.yearRange + 1); y++){
				yearSel.options[i] = new Option(y, y);
				if (dp.year == y) yearSel.options[i].selected = true;
				i++;
			}
		}
		
		/* start creating calendar */
		calTable = new Element('table');
		calTableThead = new Element('thead');
		calSelRow = new Element('tr');
		calSelCell = new Element('th', {'colspan':'7'});
		monthSel.injectInside(calSelCell);
		yearSel.injectInside(calSelCell);
		calSelCell.injectInside(calSelRow);
		calSelRow.injectInside(calTableThead);
		calTableTbody = new Element('tbody');
		
		/* create day names */
		calDayNameRow = new Element('tr');
		for (var i = 0; i < dp.options.dayNames.length; i++) {
			calDayNameCell = new Element('th');
			calDayNameCell.appendText(dp.options.dayNames[(dp.options.startDay+i)%7].substr(0, dp.options.dayChars)); 
			calDayNameCell.injectInside(calDayNameRow);
		}
		calDayNameRow.injectInside(calTableTbody);
		
		/* create the day cells */
		while (firstDay <= dp.options.daysInMonth[dp.month]){
			calDayRow = new Element('tr');
			for (i = 0; i < 7; i++){
				if ((firstDay <= dp.options.daysInMonth[dp.month]) && (firstDay > 0)){
					calDayCell = new Element('td', {'class':dp.id + '_calDay', 'axis':dp.year + '|' + (parseInt(dp.month) + 1) + '|' + firstDay}).appendText(firstDay).injectInside(calDayRow);
				} else {
					calDayCell = new Element('td', {'class':'dp_empty'}).appendText(' ').injectInside(calDayRow);
				}
				// Show the previous day
				if ( (firstDay == dp.oldDay) && (dp.month == dp.oldMonth ) && (dp.year == dp.oldYear) ) {
					calDayCell.addClass('dp_selected');
				}
				// Show today
				if ( (firstDay == dp.nowDay) && (dp.month == dp.nowMonth ) && (dp.year == dp.nowYear) ) {
					calDayCell.addClass('dp_today');
				}
				firstDay++;
			}
			calDayRow.injectInside(calTableTbody);
		}
		
		/* table into the calendar div */
		calTableThead.injectInside(calTable);
		calTableTbody.injectInside(calTable);
		calTable.injectInside(dp.calendar);
		
		/* set the onmouseover events for all calendar days */
		$$('td.' + dp.id + '_calDay').each(function(el) {
			el.onmouseover = function() {
				el.addClass('dp_roll');
			}.bind(this);
		}.bind(this));
		
		/* set the onmouseout events for all calendar days */
		$$('td.' + dp.id + '_calDay').each(function(el) {
			el.onmouseout = function(){
				el.removeClass('dp_roll');
			}.bind(this);
		}.bind(this));
		
		/* set the onclick events for all calendar days */
		$$('td.' + dp.id + '_calDay').each(function(el) {
			el.onclick = function(){
				ds = el.axis.split('|');
				dp.value = this.formatValue(dp, ds[0], ds[1], ds[2]);
				this.remove(dp);
			}.bind(this);
		}.bind(this));
		
		/* set the onchange event for the month & year select boxes */
		monthSel.onfocus = function() { dp.active = true; };
		monthSel.onchange = function(){
			dp.month = monthSel.value;
			dp.year = yearSel.value;
			this.remove(dp);
			this.create(dp);
		}.bind(this);
		
		yearSel.onfocus = function() { dp.active = true; };
		yearSel.onchange = function(){
			dp.month = monthSel.value;
			dp.year = yearSel.value;
			this.remove(dp);
			this.create(dp);
		}.bind(this);
		return true;
	},
	
	/* Format the returning date value according to the selected formation */
	formatValue: function(dp, year, month, day) {
		/* setup the date string variable */
		var dateStr = '';
		
		/* check the length of day */
		if (day < 10) day = '0' + day;
		if (month < 10) month = '0' + month;
		
		/* check the format & replace parts // thanks O'Rey */
		dateStr = dp.options.format.replace( /dd/i, day ).replace( /mm/i, month ).replace( /yyyy/i, year );
		dp.month = dp.oldMonth = '' + (month - 1) + '';
		dp.year = dp.oldYear = year;
		dp.oldDay = day;
		
		/* return the date string value */
		return dateStr;
	},
	
	/* Remove the calendar from the page */
	remove: function(dp){
		$clear(dp.interval);
		dp.active = false;
		if (window.opera) dp.container.empty();
		else if (dp.container) dp.container.empty();
		dp.calendar = false;
		dp.container = false;
		$$('select.dp_hide').removeClass('dp_hide');
	}
});

/**
*
*  URL encode / decode
*  http://www.webtoolkit.info/
*
**/

var Url = {
    // public method for url encoding
    encode : function (string) {
        return escape(this._utf8_encode(string));
    },
    // public method for url decoding
    decode : function (string) {
        return this._utf8_decode(unescape(string));
    },
    // private method for UTF-8 encoding
    _utf8_encode : function (string) {
        string = string.replace(/\r\n/g,"\n");
        var utftext = "";
        for (var n = 0; n < string.length; n++) {
            var c = string.charCodeAt(n);
            if (c < 128) {
                utftext += String.fromCharCode(c);
            } else if((c > 127) && (c < 2048)) {
                utftext += String.fromCharCode((c >> 6) | 192);
                utftext += String.fromCharCode((c & 63) | 128);
            } else {
                utftext += String.fromCharCode((c >> 12) | 224);
                utftext += String.fromCharCode(((c >> 6) & 63) | 128);
                utftext += String.fromCharCode((c & 63) | 128);
            }
        }
        return utftext;
    },
    // private method for UTF-8 decoding
    _utf8_decode : function (utftext) {
        var string = "";
        var i = 0;
        var c = c1 = c2 = 0;
        while ( i < utftext.length ) {
            c = utftext.charCodeAt(i);
            if (c < 128) {
                string += String.fromCharCode(c);
                i++;
            } else if((c > 191) && (c < 224)) {
                c2 = utftext.charCodeAt(i+1);
                string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
                i += 2;
            } else {
                c2 = utftext.charCodeAt(i+1);
                c3 = utftext.charCodeAt(i+2);
                string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
                i += 3;
            }
        }
        return string;
    }
}

var Playlist = new Class({

		Implements: [Events, Options],

		options: {
			'swfLocation': 'MooSound.swf'
		},

		initialize: function(options) {
			this.setOptions(options);
			window.addEvent('domready', function() { 
				this.swiffHome = new Element('div', {id: 'swiffHome'}).setStyles({position:'absolute','top':1,'left':1}).inject(document.body);
				this.obj = new Swiff(this.options.swfLocation, {width: 1, height: 1, container: this.swiffHome, swLiveConnect: true}); 
			}.bind(this));
			this.flashLoaded = false;
			this.loadQueue = [];
			this.sounds = new Hash();	
			this.playing = []; 
		},

		loadSounds: function(sounds, options) {
			if (!this.flashLoaded) {
				this.loadQueue.push([sounds,options]);
			} else {
				sounds = sounds || [];
				sounds.each(function(url) {
					this.loadSound(url, options);
				}, this);
			}
			return this;
		},

		loadSound: function(url, options) {
			if (!this.flashLoaded) { this.loadQueue.push([url,options]); }
			this.sounds.set(url, new Sound(url, this, options));
			return this;
		},

		stopSounds: function() {
			this.playing.each( function(sound) { sound.stop(); });
			return this;
		},

		playRandom: function() {
			var randomKey = this.sounds.getKeys().getRandom();
			this.stopSounds();
			var sound = this.sounds.get(randomKey);
			sound.start(0);
			return this;
		},

		onSoundLoaded: function(url) {
			this.sounds.get(url).fireEvent('onLoad');
		},

		onSoundComplete: function(url) {
			this.sounds.get(url).fireEvent('onComplete').fireEvent('onStop');
			return this;
		},

		onFlashLoaded: function() {
			this.flashLoaded = true;
			this.loadQueue.each(function(arr) { this.loadSounds(arr[0], arr[1]); }.bind(this));
		},

		registerID3: function(url, tag, value) {
			var sound = this.getSound(url);
			sound.id3.set(tag, value);
			sound.fireEvent('onID3', [tag, value]);
		},

		getSound: function(key) {
			return this.sounds.get(key);
		}

});

var Sound = new Class({ 

	Implements: [Options, Events],

	options: {
		autostart: false,  //autostart
		streaming: true,   //streaming
		volume: 50,        //volume to start at
		pan: 0,            //pan between -100 (left) and 100 (right)
		progressInterval: 500, //milliseconds between getProgress(); calls
		positionInterval: 500,//milliseconds between getPosition(); calls
		onRegister: $empty,//fires when the sound is registered
		onLoad: $empty,    //fires when the sound is downloaded
		onPlay: $empty,    //fires when the sound begins playing
		onPause: $empty,   //fires when the sound is paused
		onStop: $empty,    //fires when the sound stops playing
		onComplete: $empty, //fires when the sound completes playing
		onProgress: $empty,//fires when download makes progress
		onPosition: $empty,//fires when position within the song changes
		onID3: $empty      //fires when ID3 tags become available
	},

	initialize: function(url, manager, options) {
		this.setOptions(options);
		this.url = url;
		this.id3 = new Hash();
		this.manager = manager || Playlist;
		this.swf = this.manager.obj.toElement();
		this.playing = false;
		this.listeners = {};
		this.filesize = null;
		this.duration = null;
		this.pausedAt = 0;
		this.position = 0;
		this.register();
	},

	start: function(position) {
		var pos = position || this.pausedAt;
		this.swf.startSound(this.url, pos, this.options.volume, this.options.pan);
		this.fireEvent('onPlay');
		this.pausedAt = 0;
		return this;
	},

	stop: function() {
		this.swf.stopSound(this.url);
		this.fireEvent('onStop');
		return this;
	},

	jumpTo: function(seconds) {
		$clear(this.listeners.position);
		this.start(seconds);
	},

	pause: function() {
		this.swf.stopSound(this.url);
		this.pausedAt = this.getPosition();
		this.fireEvent('onPause', this.pausedAt);
		this.fireEvent('onStop');
	},

	setVolume: function(volume) {
		this.obj.setVolume(this.url, volume);
		this.options.volume = volume;
		return this;
	},

	setPan: function(pan) {
		this.swf.setPan(this.url, pan);
		this.options.pan = pan;
		return this;
	},

	getVolume: function() {
		return this.options.volume;
	},

	getPan: function() {
		return this.options.pan;
	},

	getID3: function(tag) {
		return this.id3.get(tag);	
	},

	getBytesLoaded: function() {
		return this.swf.getBytesLoaded(this.url);
	}, 

	getFilesize: function() {
		return this.swf.getBytesTotal(this.url);
	},

	getPosition: function() {
		return this.swf.getPosition(this.url);
	}, 

	getDuration: function() {
		return this.swf.getDuration(this.url);
	},

	checkProgress: function() {
		if ($type(this.filesize) !== "number") { this.filesize = this.getFilesize(); }
		var loaded = this.getBytesLoaded(); 
		if ($type(loaded) === "number" && loaded !== this.listeners.lastProgress) { 
			var total = this.getFilesize();
			this.listeners.lastProgress = loaded;
			this.fireEvent('onProgress', [loaded, total]); 
		}
	},

	checkPosition: function() {
		var position = this.getPosition();
		this.duration = this.getDuration();
		if ($type(position) === "number" && position !== this.listeners.lastPosition) { 
			this.listeners.lastPosition = position;
			this.fireEvent('onPosition', [(position / 1000).round(), (this.duration / 1000).round()]);
		}
	},

	register: function() {
		this.fireEvent('onRegister');
		if (this.options.streaming === false) {
			this.swf.preloadSound(this.url);
			this.listeners.progress = this.checkProgress.periodical(this.options.progressInterval, this);
		}
		this.addEvents({'onLoad': this.onLoad, 'onStop': this.onStop, 'onPlay': this.onPlay});
	},

	onLoad: function() {
		$clear(this.listeners.progress);
		this.checkProgress();
	},

	onPlay: function() {
		if (this.options.streaming === true) {
			this.listeners.progress = this.checkProgress.periodical(this.options.progressInterval, this);
		}
		this.playing = true;
		this.listeners.position = this.checkPosition.periodical(this.options.positionInterval, this);
		this.manager.playing.push(this);
	},

	onStop: function() {
		$clear(this.listeners.position);
		if (this.pausedAt === 0) { this.fireEvent('onPosition', [0, this.duration]); }
		this.playing = false;
	}

});

//Comment out and reinstanciate if you want to add your own options.
Playlist = new Playlist();

/*!
	Slimbox v1.64 - The ultimate lightweight Lightbox clone
	(c) 2007-2008 Christophe Beyls <http://www.digitalia.be>
	MIT-style license.
*/

var Slimbox;

(function() {

	// Global variables, accessible to Slimbox only
	var state = 0, options, images, activeImage, prevImage, nextImage, top, fx, preload, preloadPrev = new Image(), preloadNext = new Image(),
	// State values: 0 (closed or closing), 1 (open and ready), 2+ (open and busy with animation)

	// DOM elements
	overlay, center, image, prevLink, nextLink, bottomContainer, bottom, caption, number;

	/*
		Initialization
	*/

	window.addEvent("domready", function() {
		// Append the Slimbox HTML code at the bottom of the document
		$(document.body).adopt(
			$$([
				overlay = new Element("div", {id: "lbOverlay"}).addEvent("click", close),
				center = new Element("div", {id: "lbCenter"}),
				bottomContainer = new Element("div", {id: "lbBottomContainer"})
			]).setStyle("display", "none")
		);

		image = new Element("div", {id: "lbImage"}).injectInside(center).adopt(
			prevLink = new Element("a", {id: "lbPrevLink", href: "#"}).addEvent("click", previous),
			nextLink = new Element("a", {id: "lbNextLink", href: "#"}).addEvent("click", next)
		);

		bottom = new Element("div", {id: "lbBottom"}).injectInside(bottomContainer).adopt(
			new Element("a", {id: "lbCloseLink", href: "#"}).addEvent("click", close),
			caption = new Element("div", {id: "lbCaption"}),
			number = new Element("div", {id: "lbNumber"}),
			new Element("div", {styles: {clear: "both"}})
		);

		fx = {
			overlay: new Fx.Tween(overlay, {property: "opacity", duration: 500}).set(0),
			image: new Fx.Tween(image, {property: "opacity", duration: 500, onComplete: nextEffect}),
			bottom: new Fx.Tween(bottom, {property: "margin-top", duration: 400})
		};
	});


	/*
		API
	*/

	Slimbox = {
		open: function(_images, startImage, _options) {
			options = $extend({
				loop: false,				// Allows to navigate between first and last images
				overlayOpacity: 0.8,			// 1 is opaque, 0 is completely transparent (change the color in the CSS file)
				resizeDuration: 400,			// Duration of each of the box resize animations (in milliseconds)
				resizeTransition: false,		// Default transition in mootools
				initialWidth: 250,			// Initial width of the box (in pixels)
				initialHeight: 250,			// Initial height of the box (in pixels)
				animateCaption: true,
				showCounter: true,			// If true, a counter will only be shown if there is more than 1 image to display
				counterText: "Image {x} of {y}"		// Translate or change as you wish
			}, _options || {});

			// The function is called for a single image, with URL and Title as first two arguments
			if (typeof _images == "string") {
				_images = [[_images,startImage]];
				startImage = 0;
			}

			images = _images;
			options.loop = options.loop && (images.length > 1);
			position();
			setup(true);
			top = window.getScrollTop() + (window.getHeight() / 15);
			fx.resize = new Fx.Morph(center, $extend({duration: options.resizeDuration, onComplete: nextEffect}, options.resizeTransition ? {transition: options.resizeTransition} : {}));
			center.setStyles({top: top, width: options.initialWidth, height: options.initialHeight, marginLeft: -(options.initialWidth/2), display: ""});
			fx.overlay.start(options.overlayOpacity);
			state = 1;
			return changeImage(startImage);
		}
	};

	Element.implement({
		slimbox: function(_options, linkMapper) {
			// The processing of a single element is similar to the processing of a collection with a single element
			$$(this).slimbox(_options, linkMapper);

			return this;
		}
	});

	Elements.implement({
		/*
			options:	Optional options object, see Slimbox.open()
			linkMapper:	Optional function taking a link DOM element and an index as arguments and returning an array containing 2 elements:
					the image URL and the image caption (may contain HTML)
			linksFilter:	Optional function taking a link DOM element and an index as arguments and returning true if the element is part of
					the image collection that will be shown on click, false if not. "this" refers to the element that was clicked.
					This function must always return true when the DOM element argument is "this".
		*/
		slimbox: function(_options, linkMapper, linksFilter) {
			linkMapper = linkMapper || function(el) {
				return [el.href, el.title];
			};

			linksFilter = linksFilter || function() {
				return true;
			};

			var links = this;

			links.removeEvents("click").addEvent("click", function() {
				// Build the list of images that will be displayed
				var filteredLinks = links.filter(linksFilter, this);
				return Slimbox.open(filteredLinks.map(linkMapper), filteredLinks.indexOf(this), _options);
			});

			return links;
		}
	});


	/*
		Internal functions
	*/

	function position() {
		overlay.setStyles({top: window.getScrollTop(), height: window.getHeight()});
	}

	function setup(open) {
		["object", window.ie ? "select" : "embed"].forEach(function(tag) {
			Array.forEach(document.getElementsByTagName(tag), function(el) {
				if (open) el._slimbox = el.style.visibility;
				el.style.visibility = open ? "hidden" : el._slimbox;
			});
		});

		overlay.style.display = open ? "" : "none";

		var fn = open ? "addEvent" : "removeEvent";
		window[fn]("scroll", position)[fn]("resize", position);
		document[fn]("keydown", keyDown);
	}

	function keyDown(event) {
		switch(event.code) {
			case 27:	// Esc
			case 88:	// 'x'
			case 67:	// 'c'
				close();
				break;
			case 37:	// Left arrow
			case 80:	// 'p'
				previous();
				break;	
			case 39:	// Right arrow
			case 78:	// 'n'
				next();
		}
		// Prevent default keyboard action (like navigating inside the page)
		return false;
	}

	function previous() {
		return changeImage(prevImage);
	}

	function next() {
		return changeImage(nextImage);
	}

	function changeImage(imageIndex) {
		if ((state == 1) && (imageIndex >= 0)) {
			state = 2;
			activeImage = imageIndex;
			prevImage = ((activeImage || !options.loop) ? activeImage : images.length) - 1;
			nextImage = activeImage + 1;
			if (nextImage == images.length) nextImage = options.loop ? 0 : -1;

			$$(prevLink, nextLink, image, bottomContainer).setStyle("display", "none");
			fx.bottom.cancel().set(0);
			fx.image.set(0);
			center.className = "lbLoading";

			preload = new Image();
			preload.onload = nextEffect;
			preload.src = images[imageIndex][0];
		}

		return false;
	}

	function nextEffect() {
		switch (state++) {
			case 2:
				center.className = "";
				image.setStyles({backgroundImage: "url(" + images[activeImage][0] + ")", display: ""});
				$$(image, bottom).setStyle("width", preload.width);
				$$(image, prevLink, nextLink).setStyle("height", preload.height);

				caption.set('html', images[activeImage][1] || "");
				number.set('html', (options.showCounter && (images.length > 1)) ? options.counterText.replace(/{x}/, activeImage + 1).replace(/{y}/, images.length) : "");

				if (prevImage >= 0) preloadPrev.src = images[prevImage][0];
				if (nextImage >= 0) preloadNext.src = images[nextImage][0];

				if (center.clientHeight != image.offsetHeight) {
					fx.resize.start({height: image.offsetHeight});
					break;
				}
				state++;
			case 3:
				if (center.clientWidth != image.offsetWidth) {
					fx.resize.start({width: image.offsetWidth, marginLeft: -image.offsetWidth/2});
					break;
				}
				state++;
			case 4:
				bottomContainer.setStyles({top: top + center.clientHeight, marginLeft: center.style.marginLeft, visibility: "hidden", display: ""});
				fx.image.start(1);
				break;
			case 5:
				if (prevImage >= 0) prevLink.style.display = "";
				if (nextImage >= 0) nextLink.style.display = "";
				if (options.animateCaption) {
					fx.bottom.set(-bottom.offsetHeight).start(0);
				}
				bottomContainer.style.visibility = "";
				state = 1;
		}
	}

	function close() {
		if (state) {
			state = 0;
			preload.onload = $empty;
			for (var f in fx) fx[f].cancel();
			$$(center, bottomContainer).setStyle("display", "none");
			fx.overlay.chain(setup).start(0);
		}

		return false;
	}

})();

// AUTOLOAD CODE BLOCK (MAY BE CHANGED OR REMOVED)
Slimbox.scanPage = function() {
	var links = $$("a").filter(function(el) {
		return el.rel && el.rel.test(/^lightbox/i);
	});
	$$(links).slimbox({'loop': true, 'overlayOpacity': 0.8, 'resizeDuration': 512, 'resizeTransition': Fx.Transitions.Expo.easeInOut, 'initialWidth': 160, 'initialHeight': 160, 'animateCaption': true, 'showCounter': true, 'counterText': 'Imagen {x} de {y}'}, null, function(el) {
		return (this == el) || ((this.rel.length > 8) && (this.rel == el.rel));
	});
};

window.addEvent("domready", Slimbox.scanPage);
