var WS_ROOT = "\/", _SEARCH_URL = "search.php", _CFG_PPP_PLAYER_SWF_MINFLASHVERSION = "9.0.115,0", CALENDAR_TYPE_HAC = "HAC", CALENDAR_TYPE_KIGO = "KIGO", TEXT_TYPE_TEXT = "TEXT", TEXT_TYPE_HTML = "HTML";

/* vkDom.js */

function	vkDomClass()
{
	this.loadCallbacks = new Array();
	this.unloadCallbacks = new Array();
	this.loadFirst = true;
	this.unloadFirst = true;
	this.loaded = false;
	this.loadIE = null;
}



/**************************************************************/
/* vkDom.onLoad() handling */

vkDomClass.prototype.onLoad = function(callback)
{
	// Simply queues the callback	
	this.loadCallbacks[this.loadCallbacks.length] = callback;

	// If this is the very first time we're called, fire up the events, according to the browser
	if(this.loadFirst)
	{
		// Intercept and remember IE which requires a very special handler
		var	ua = navigator.userAgent.toLowerCase();

		this.loadIE = /msie/.test(ua) && !/opera/.test(ua);

		// Deal with mozilla & friend.
		// But avoid browsers implementing document.readyState
		if(!document['readyState'] && document.addEventListener)
			document.addEventListener('DOMContentLoaded', function() { vkDom._setLoaded() }, false);
		else if(this.loadIE)	
		{
			// Thanks to:
			// http://blog.outofhanwell.com/2006/06/08/the-windowonload-problem-revisited/

			// document.write('<scr'+'ipt id="__vkDom_onLoad" defer="true" src="//[]"></scr'+'ipt>');
			// 14/05/2008
			// "[]" caused the browser to do a DNS lookup, try a fake IP
			//document.write('<scr'+'ipt id="__vkDom_onLoad" defer="true" src="//0.0.0.0"></scr'+'ipt>');
			// 20/02/2009 -> use src=/: as in swfobject
			// 20/02/2009 - Also, embed this in try/catch block
			try
			{
				document.write('<scr'+'ipt id="__vkDom_onLoad" defer="true" src="//:"></scr'+'ipt>');

				var	trickScript = document.getElementById('__vkDom_onLoad');

				if(trickScript)
				{
					trickScript.onreadystatechange = function()
					{
						if(this.readyState == 'complete')
							vkDom._setLoaded();
					}

					// Test it right now
					trickScript.onreadystatechange();

					trickScript = null;	// ie leaks?
				}
			}
			catch(e)
			{
			}
		}
		// Other browser will use readyState or getElementsByTagName('body') which worked fine till now...

		this.loadFirst = false;
	}

	if(this.loadCallbacks.length == 1)
		setTimeout('vkDom._wait4dom()', 75);	
}


// FRIEND
vkDomClass.prototype._setLoaded = function()
{
	this.loaded = true;
}

// PRIVATE
vkDomClass.prototype._wait4dom = function()
{
	if(!this.loaded)
	{
		if(document['readyState'])
		{
			if(	document.readyState == 'loaded' ||
				document.readyState == 'complete' )
				this.loaded = true;
		}
		else if(!document.addEventListener && !this.loadIE)	// Use old technique for non-mozilla & non-ie browsers
		{
			if(	
				//document.body != null ||
				(document.getElementsByTagName('body') != null &&
				document.getElementsByTagName('body')[0] != null) 
			)
				this.loaded = true;
		}
	}

	if(this.loaded)
	{
		var	i;

		for(i = 0; i < this.loadCallbacks.length; i++)
		{
			// 15/03/2010 - This is a kind of race condition, occurs when the document is unloaded (ie location changes) so fast that 
			// not all the onLoad() processing could achieve...
			if(!document.body)
				return;
			this.loadCallbacks[i]();
		}

		// Resets the list
		this.loadCallbacks = new Array();
	}
	else
		setTimeout('vkDom._wait4dom()', 75);
}


/*---------------------*/

/* This previous version failed miserably with IE

vkDomClass.prototype.loaded = function()
{
	if(	
		document.body != null ||
		(document.getElementsByTagName('body') != null &&
		document.getElementsByTagName('body')[0] != null) 
	)
		return true;

	return false;
}


vkDomClass.prototype.onLoad = function(callback)
{
	this.loadCallbacks[this.loadCallbacks.length] = callback;
	if(this.loadCallbacks.length == 1)
		setTimeout('vkDom.wait4dom()', 75);	
}

vkDomClass.prototype.wait4dom = function()
{
	if(this.loaded())
	{
		var	i;

		for(i = 0; i < this.loadCallbacks.length; i++)
			this.loadCallbacks[i]();

		// Resets the list
		this.loadCallbacks = new Array();
	}
	else
		setTimeout('vkDom.wait4dom()', 75);	
}


*/


/**************************************************************/
/* vkDom.onUnload() handling */

vkDomClass.prototype.onUnload = function(callback)
{
	this.unloadCallbacks[this.unloadCallbacks.length] = callback;

	if(this.unloadFirst)
	{
		/*
		if(document.addEventListener)
			document.addEventListener('unload', function() { vkDom._onUnload(); }, false);
		}
		else */
		
		if(window.attachEvent)
			window.attachEvent('onunload', function() { vkDom._onUnload(); });
		else
			window.onunload = function() { vkDom._onUnload(); };

		this.unloadFirst = false;
	}
}

// FRIEND
vkDomClass.prototype._onUnload = function()
{
	var	i;

	for(i = 0; i < this.unloadCallbacks.length; i++)
		this.unloadCallbacks[i]();

	// Resets the list
	this.unloadCallbacks = new Array();
}








// Usefull tool

vkDomClass.prototype.html = function(str)
{
	str = ''+str;
	str = str.replace(/&/g, '&amp;');
	str = str.replace(/\"/g, '&quot;');
	str = str.replace(/</g, '&lt;');
	return str.replace(/>/g, '&gt;');
}

vkDomClass.prototype.nl2br = function(str)
{
	str = ''+str;
	return str.replace(/\n/g, '<br />');
}

vkDomClass.prototype.htmlbr = function(str)
{
	return this.nl2br(this.html(str));
}


vkDomClass.prototype.js = function(str)
{
	str = ''+str;
	str = str.replace(/\'/g, '\\\'');
	// TODO: linebreaks and so on...
	return str;
}

vkDomClass.prototype.uri = function(str)
{
	return encodeURIComponent(str);
}


vkDomClass.prototype.el = function(id)
{
	// 15/10/2008 - takes either a string or the object itself, allowing other methods to transparently allow
	// both as primary params...

	if(typeof(id) == 'string')
		return document.getElementById(id);
	else if(typeof(id) == 'object')
		return id;
	else
		return null;
}	

vkDomClass.prototype.visibility = function(id)
{
	var	el = this.el(id);

	if(!el)
		return;

	if(arguments.length == 2 && !arguments[1])
		el.style.visibility = 'hidden';
	else
		el.style.visibility = 'visible';
}

vkDomClass.prototype.display = function(id)
{
	var	el = this.el(id);

	if(!el)
		return;

	if(arguments.length > 1)
	{
		if(typeof(arguments[1]) == 'string')
			el.style.display = arguments[1];
		else if(arguments[1])
			el.style.display = '';		// true
		else
			el.style.display = 'none';	// false
	}
	else
		el.style.display = '';		// true
}

vkDomClass.prototype.value = function(id)
{
	var	el = this.el(id);
	if(el)
		return el.value;
	return null;
}

vkDomClass.prototype.enable = function(id)
{
	var	el = this.el(id);
	if(el)
		el.disabled = !(arguments.length < 2 || arguments[1]);
}

vkDomClass.prototype.disable = function(id)
{
	var	el = this.el(id);
	if(el)
		el.disabled = true;
}

vkDomClass.prototype.focus = function(id)
{
	var	el = this.el(id);
	if(el && !el.disabled)
		el.focus();
}

vkDomClass.prototype.select = function(id)
{
	var	el = this.el(id);
	if(el && !el.disabled)
	{
		el.focus();
		el.select();
	}
}

vkDomClass.prototype.clean = function(id)
{
	var	el = this.el(id);
	if(el)
	{
		while(el.firstChild)
			el.removeChild(el.firstChild);
	}
}

vkDomClass.prototype.setHtml = function(id, html)
{
	var	el = this.el(id);
	if(el)
		el.innerHTML = html;
}

vkDomClass.prototype.setText = function(id, text)
{
	var	el = this.el(id);
	if(el)
		el.innerHTML = this.html(text);
}

vkDomClass.prototype.setTextBr = function(id, text)
{
	var	el = this.el(id);
	if(el)
		el.innerHTML = this.htmlbr(text);
}


vkDomClass.prototype.setFormValue = function(id, value)
{
	var	i, el = this.el(id);

	if(!el)
		return;

	switch(el.tagName)
	{
		case 'INPUT':
			switch(el.getAttribute('type').toUpperCase())
			{
				case 'TEXT':
				case 'PASSWORD':
				case 'HIDDEN':
					
					if(
						typeof(value) != 'string' &&
						typeof(value) != 'number'
					)
						value = '';

					el.value = value;
					break;

				case 'CHECKBOX':
				case 'RADIO':
					el.checked = value ? true : false;
					break;
			}
			break;

		case 'TEXTAREA':

			if(
				typeof(value) != 'string' &&
				typeof(value) != 'number'
			)
				value = '';
		
			el.value = value;
	
			break;

		case 'SELECT':

			if(el.selectedIndex >= 0)
			{
				el.selectedIndex = 0;

				if(
					typeof(value) == 'string' ||
					typeof(value) == 'number'
				)
				{
					for(i = 0; i < el.options.length; i++)
					{
						if(el.options[i].value == value)
						{
							el.selectedIndex = i;
							return;
						}
					}
				}
			}
	}
}


vkDomClass.prototype.getFormValue = function(id)
{
	var	i, el = this.el(id);

	if(!el)
		return null;

	switch(el.tagName)
	{
		case 'INPUT':
			switch(el.getAttribute('type').toUpperCase())
			{
				case 'TEXT':
				case 'PASSWORD':
				case 'HIDDEN':
					return el.value;

				case 'CHECKBOX':
				case 'RADIO':
					return el.checked;

				default:
					return null;
			}
			

		case 'TEXTAREA':
			return el.value;

		case 'SELECT':
			if(el.selectedIndex < 0)
				return null;
			return el.options[el.selectedIndex].value;


		default:
			return null;
	}
}





// Class-handling related

vkDomClass.prototype.listClass = function(id)
{
	var	el = this.el(id);

	if(!el)
		return null;

	return el.className.split(/\s+/);
}

vkDomClass.prototype.hasClass = function(id, name)
{
	var	el = this.el(id);
	var	cls;

	if(!el)
		return false;

	cls = this.listClass(id);

	for(var i = 0; i < cls.length; i++)
	{
		if(cls[i] == name)
			return true;
	}

	return false;
}


vkDomClass.prototype.addClass = function(id, name)
{
	var	el = this.el(id);
	var	cls;

	if(!el || this.hasClass(id, name))
		return;

	el.className = el.className.length ? ( el.className + ' ' + name ) : name;
}

vkDomClass.prototype.removeClass = function(id, name)
{
	var	el = this.el(id);
	var	oldCls, newCls;

	if(!el)
		return;
	
	oldCls = this.listClass(id);
	newCls = [];

	for(var i = 0; i < oldCls.length; i++)
	{
		if(oldCls[i] != name)
			newCls[newCls.length] = oldCls[i];
	}

	if(newCls.length)
		el.className = newCls.join(' ');
	else
		el.className = '';
}




vkDomClass.prototype.getAbsolutePosition = function(el)
{
/*
	if(	typeof(element) == 'string' && 
		!(element = vkDom.el(element))
	)
		return { x: 0, y : 0 };
*/
	
	el = this.el(el);

	if(!el)
		return { x: 0, y : 0 };

	var r = { x: el.offsetLeft - el.scrollLeft, y: el.offsetTop - el.scrollTop };

	if(el.offsetParent) 
	{
		var tmp = this.getAbsolutePosition(el.offsetParent);
		r.x += tmp.x;
		r.y += tmp.y;
	}

	return r;
}


// Cookies related

vkDomClass.prototype.setCookie = function(name, value, seconds, path, domain)
{
	var	str;

	if(seconds)
	{
		var	expiryDate = new Date();

		expiryDate.setTime(
			expiryDate.getTime() + seconds * 1000
		);

		//str = name + '=' + escape(value) + '; expires='+expiryDate.toGMTString();
		str = name + '=' + encodeURIComponent(value) + '; expires='+expiryDate.toGMTString();	// 04/08/2010 - escape() was not escaping the '+' character
	}
	else
		//str = name + '=' + escape(value);
		str = name + '=' + encodeURIComponent(value);	// 04/08/2010 - escape() was not escaping the '+' character
	
	if(path)
		str += '; path='+path;

	if(domain)
		str += '; domain='+domain;

	document.cookie = str;
}


vkDomClass.prototype.setSessionCookie = function(name, value, path, domain)
{
	this.setCookie(name, value, 0, path, domain);
}

vkDomClass.prototype.getCookie = function(name)	// [, default=null]
{
	var	i, search, parts;
	
	search = name+'=';
	parts = document.cookie.split('; ');

	for(i = 0; i < parts.length; i++)
	{
		if(parts[i].indexOf(search) == 0)
			return unescape(parts[i].substring(search.length));
	}

	if(arguments.length > 1)
		return arguments[1];

	return null;
}


vkDomClass.prototype.removeCookie = function(name, path, domain)
{
	this.setCookie(name, '', -1, path, domain);
}




/*
vkDomClass.prototype.getAbsoluteScrollPosition = function(element)
{
	if(	typeof(element) == 'string' && 
		!(element = vkDom.el(element))
	)
		return { x: 0, y : 0 };

	var r = { x: element.offsetLeft, y: element.offsetTop };

	if(element.offsetParent) 
	{
		var tmp = this.getAbsoluteScrollPosition(element.offsetParent);
		r.x += tmp.x;
		r.y += tmp.y;
	}

	return r;
}
*/


var	vkDom = new vkDomClass();

// vkDebug.js


function	vkDebug()
{
	this.container = null;
	this.log = null;
	this.buttons = null;
	this.enabled = false;
}

vkDebug.prototype.enable = function()	// (enable, jserrors)
{
	if(	arguments.length > 0 &&
		!arguments[0])
		this.enabled = false;
	else
		this.enabled = true;
}

vkDebug.prototype.text = function(string)
{
	if(this.enabled)
	{
		this._init();

		if(typeof(string) != 'string')
		{
			if(typeof(string) == 'number')
				string = ''+string;
			else if(string == null)
				string = 'null';
			else if(typeof(string) == 'object')
				string = string.toString();
			else
				return;
		}

		string = string.split('\n');

		for(var i = 0; i < string.length; i++)
		{
			this.log.appendChild(document.createTextNode(string[i].replace(new RegExp('^\t', 'g'), '    ').replace(new RegExp('^[\\s]', 'g'), '\u00a0')));
			this.log.appendChild(document.createElement('br'));
		}

		this.log.scrollTop = this.log.scrollHeight;
		//this._write(vkDom.nl2br(vkDom.html(string))+'<br />');
	}
}


vkDebug.prototype.html = function(string)
{
	if(this.enabled)
		this._write(string+'<br />');
}


vkDebug.prototype.domtree = function(element, skiptext)
{
	if(this.enabled)
	{
		this._init();
		this._domtree(element, skiptext, 0);
		this.log.scrollTop = this.log.scrollHeight;
	}
}

// PRIVATE



vkDebug.prototype._domtree = function(node, skiptext, depth)
{
	var	i, str;

	str = '+ ';

	switch(node.nodeType)
	{
		case 1:	// ELEMENT_NODE
			str += 'ELEMENT_NODE [1] ['+node.tagName+']';
			if(node.id)
				str += ' #'+node.id;
			break;

		case 2:	// ATTRIBUTE_NODE
			str = null;
			break;

		case 3:	// TEXT_NODE
			if(!skiptext)
				str += 'TEXT_NODE [3]';
			else
				str = null;
			break;

		case 4:	// CDATA_SECTION_NODE
			if(!skiptext)
				str += 'CDATA_SECTION_NODE [4]';
			else
				str = null;
			break;

		case 5:	// ENTITY_REFERENCE_NODE
			str += 'ENTITY_REFERENCE_NODE [5]';
			break;

		case 6:	// ENTITY_NODE
			str += 'ENTITY_NODE [6]';
			break;

		case 7:	// PROCESSING_INSTRUCTION_NODE
			str += 'PROCESSING_INSTRUCTION_NODE [7]';
			break;

		case 8:	// COMMENT_NODE
			if(!skiptext)
				str += 'COMMENT_NODE [8]';
			else
				str = null;
			break;

		case 9:	// DOCUMENT_NODE
			str += 'DOCUMENT_NODE [9]';
			break;

		case 10:// DOCUMENT_TYPE_NODE
			str += 'DOCUMENT_TYPE_NODE [10]';
			break;

		case 11:// DOCUMENT_FRAGMENT_NODE
			str += 'DOCUMENT_FRAGMENT_NODE [11]';
			break;

		case 12:// NOTATION_NODE
			str += 'NOTATION_NODE [12]';
			break;

		default:
			str += 'UNKNOWN_TYPE ['+node.nodeType+']';
	}

/*
	NodeType 	Named Constant
	1			ELEMENT_NODE
	2 			ATTRIBUTE_NODE
	3 			TEXT_NODE
	4 			CDATA_SECTION_NODE
	5 			ENTITY_REFERENCE_NODE
	6 			ENTITY_NODE
	7 			PROCESSING_INSTRUCTION_NODE
	8 			COMMENT_NODE
	9 			DOCUMENT_NODE
	10 			DOCUMENT_TYPE_NODE
	11 			DOCUMENT_FRAGMENT_NODE
	12 			NOTATION_NODE
*/


	if(str != null)
	{
		var	spacer = '';

		for(i = 0; i < depth*2; i++)
			spacer += '\u00a0';		// unfortunately, IE ignores "white-space: pre"

		//this._write(spacer+vkDom.html(str)+'<br />');
		this.log.appendChild(document.createTextNode(spacer+str));
		this.log.appendChild(document.createElement('br'));
	}

	// Try detecting any instance of vkDebug
	if(node.nodeType == 1 && node.tagName == 'DIV' && node.className == 'vkDebug')
		return;

	if(node.hasChildNodes())
	{
		depth++;
		for(i = 0; i < node.childNodes.length; i++)
			this._domtree(node.childNodes[i], skiptext, depth)
	}
}



vkDebug.prototype._write = function(string)
{
	this._init();
	this.log.innerHTML += string;
	this.log.scrollTop = this.log.scrollHeight;
}

/*
vkDebug.prototype._append = function(o)
{
	this._init();
	this.log.appendChild(o);
	this.log.scrollTop = this.log.scrollHeight;
}
*/

vkDebug.prototype._init = function()
{
	if(!this.log)
	{
		// Get last position and dimensions from cookie
		this._getParams();

		this.container = document.createElement('div');
		this.container.className = 'vkDebug';

		this.log = document.createElement('div');
		this.log.className = 'log';
		this.log.style.width = this.width+'px';
		this.log.style.height = this.height+'px';

		this.container.appendChild(this.log);

		document.body.appendChild(this.container);

		this._updatePosition();

		var	self = this;

		if(window.addEventListener)
		{
			window.addEventListener('resize', function() { self._updatePosition() }, false);
			window.addEventListener('scroll', function() { self._updatePosition() }, false);
		}
		else if(window.attachEvent)
		{
			window.attachEvent('onresize', function() { self._updatePosition() });
			window.attachEvent('onscroll', function() { self._updatePosition() });
		}
	}
	this.container.style.display = 'block';
}



vkDebug.prototype._getParams = function()
{
	var	cookie, parts;

	this.width = null;
	this.height = null;
	this.position = null;

	cookie = vkDom.getCookie('vkDebug');

	if(cookie)
	{
		parts = cookie.split('|');
		if(parts.length == 3)
		{
			this.width = parseInt(parts[0]);
			this.height = parseInt(parts[1]);
			this.position = parseInt(parts[2]);
		}
	}

	if(this.width == null)
	{
		this.width = 400;
		this.height = 50;
		this.position = 1;
	}

	this._normalizeParams();
}

vkDebug.prototype._updateParams = function()
{
	vkDom.setCookie('vkDebug', this.width+'|'+this.height+'|'+this.position, 7*24*60*60);
}

vkDebug.prototype._normalizeParams = function()
{
	if(this.width < 300)
		this.width = 300;
	else if(this.width > 2000)
		this.width = 2000;

	if(this.height < 100)
		this.height = 100;
	else if(this.height > 2000)
		this.height = 2000;

	if(this.position < 1 || this.position > 4)
		this.position = 1;
}

vkDebug.prototype._updatePosition = function()
{
	var	x, y;


	function createButton(text, action)
	{
		var	button;

		button = document.createElement('button');
		button.innerHTML = vkDom.html(text);
		button.onclick = function() { return action(); };

		return button;
	}


	if(this.buttons)
		this.container.removeChild(this.buttons);
	else
	{
		var	self = this;
		this.buttons = document.createElement('div');
		this.buttons.className = 'buttons';
		this.buttons.style.width = this.width+'px';


		function setpos()
		{
			self.position++;
			self._normalizeParams();
			self._updateParams();
			self._updatePosition();
			return false;
		}

		function	resize(width, more)
		{
			if(width)
			{
				if(more)
					self.width += 50;
				else
					self.width -= 50;
			}
			else
			{
				if(more)
					self.height += 50;
				else
					self.height -= 50;
			}

			self._normalizeParams();
			self._updateParams();

			self.log.style.width = self.width+'px';
			self.log.style.height = self.height+'px';

			self.buttons.style.width = self.width+'px';

			self._updatePosition();
			return false;
		}


		// Create buttons

		this.buttons.appendChild(createButton('Hide', function() { self.container.style.display = 'none'; }));
		this.buttons.appendChild(createButton('Pos', function() { setpos(); }));
		this.buttons.appendChild(createButton('W -', function() { resize(true, false); }));
		this.buttons.appendChild(createButton('W +', function() { resize(true, true); }));
		this.buttons.appendChild(createButton('H -', function() { resize(false, false); }));
		this.buttons.appendChild(createButton('H +', function() { resize(false, true); }));
		this.buttons.appendChild(createButton('Clear', function() { vkDom.clean(self.log); }));
	}

	switch(this.position)
	{
		case 1:	// LEFT/TOP
			this.buttons.style.textAlign = 'left';
			this.container.insertBefore(this.buttons, this.container.firstChild);
			x = 0;
			y = 0;
			break;

		case 2:	// RIGHT/TOP
			this.buttons.style.textAlign = 'right';
			this.container.insertBefore(this.buttons, this.container.firstChild);
			x = Math.max(document.documentElement.scrollLeft, document.body.scrollLeft) + document.documentElement.clientWidth-this.container.clientWidth;
			y = 0;
			break;

		case 3:	// RIGHT/BOTTOM
			this.buttons.style.textAlign = 'right';
			this.container.appendChild(this.buttons);
			x = Math.max(document.documentElement.scrollLeft, document.body.scrollLeft) + document.documentElement.clientWidth-this.container.clientWidth;
			y = Math.max(document.documentElement.scrollTop, document.body.scrollTop) + document.documentElement.clientHeight-this.container.clientHeight;
			break;

		case 4:	// LEFT/BOTTOM
			this.buttons.style.textAlign = 'left';
			this.container.appendChild(this.buttons);
			x = 0;
			y = Math.max(document.documentElement.scrollTop, document.body.scrollTop) + document.documentElement.clientHeight-this.container.clientHeight;
			break;

	}

	this.container.style.left = x+'px';
	this.container.style.top = y+'px';
}


/* vkImagePreload.js */

function	vkImagePreload(maxThreads)
{
	this.maxThreads = maxThreads;

	if(
		arguments.length > 1 &&
		typeof(arguments[1] == 'string')
	)
		this.instanceName = arguments[1];
	else
		this.instanceName = null;

	this.currentThreads = 0;
	this.queue = [];
	this.preloads = [];

	this.debug = null;
}


// bool
vkImagePreload.prototype.enableDebug = function(debug)
{
	if(
		debug == null ||
		(
			typeof(debug) == 'object' &&
			debug.constructor == vkDebug
		)
	)
	{
		this.debug = debug;
		return true;
	}
			
	this.debug = null;
	return false;
}

// bool
vkImagePreload.prototype.disableDebug = function()
{
	return this.enableDebug(null);
}


vkImagePreload.prototype.setThreads = function(threads)
{
	this.maxThreads = threads;
}

vkImagePreload.prototype.add = function(image)
{
	if(this.currentThreads < this.maxThreads)
		this._preload(image);
	else
	{
		this.writeDebug('Queueing '+image);
		this.queue[this.queue.length] = image;
	}
}



/********************************/
/* PRIVATE METHODS */

// void
vkImagePreload.prototype.writeDebug = function(text)
{
	if(this.debug)
		this.debug.text('vkImagePreload'+(this.instanceName != null ? ' (' + this.instanceName + ')': '')+': '+text);
}

vkImagePreload.prototype._preload = function(image)
{
	var	idx, self;

	this.writeDebug('Preloading '+image);

	++this.currentThreads;
	idx = this.preloads.length;

	this.preloads[idx] = new Image;

	self = this;

	if(window.addEventListener)
	{
		this.preloads[idx].addEventListener('load', function() { self._onLoad(idx); }, false);
		this.preloads[idx].addEventListener('error', function() { self._onLoad(idx); }, false);
	}
	else
	{
		this.preloads[idx].attachEvent('onload', function() { self._onLoad(idx); });
		this.preloads[idx].attachEvent('onerror', function() { self._onLoad(idx); });
	}

	this.preloads[idx].src = image;
}

vkImagePreload.prototype._onLoad = function(idx)
{
	var	tmp;

	this.writeDebug('Image #'+idx+' loaded');

	--this.currentThreads;

	for(var i = 0; this.currentThreads < this.maxThreads && i < this.queue.length; i++)
	{
		if(this.queue[i] != null)
		{
			tmp = this.queue[i];
			this.queue[i] = null;
			this._preload(tmp);
		}
	}

	if(!this.currentThreads)
	{
		this.writeDebug('Thread queue empty, cleaning-up references');
		// Cleanup references
		this.queue = [];
		this.preloads = [];
	}
}



/* vkJSONRemote.js */

/*

Interface to the vkJSONRemote.php counterpart.

*/



/*********************************************/
/* PUBLIC */


function	vkJSONRemote()
{
	this.xmlRequest = null;
	this.aborted = false;
	this.currentTimeout = null;
	this.debug = null;
}

// bool
vkJSONRemote.prototype.enableDebug = function(debug)
{
	if(
		debug == null ||
		(
			typeof(debug) == 'object' &&
			debug['enable'] != 'undefined' &&
			typeof(debug.enable) == 'function'
		)
	)
	{
		this.debug = debug;
		return true;
	}
			
	this.debug = null;
	return false;
}

// bool
vkJSONRemote.prototype.disableDebug = function()
{
	return this.enableDebug(null);
}

// bool
vkJSONRemote.prototype.get = function(url, timeout)
{
	var	self = this;

	if(!this._prepare())
		return false;

	if(timeout !== undefined)
		this.currentTimeout = window.setTimeout(
			function() { self._onTimeout(); },
			timeout);

	this.xmlRequest.open('GET', url);
	this.xmlRequest.setRequestHeader('Content-Type', 'text/plain; charset=UTF-8')

	this.xmlRequest.onreadystatechange = function()
	{
		if(self.aborted)
			return;

		switch(self.xmlRequest.readyState)
		{
			case 3:		// receiving
				self.onLoading();
				break;

			case 4:		// loaded
				self._onLoad();
				break;

			case 0:		// uninitialized
			case 1:		// open
			case 2:		// sent
			default:
				// we don't care
		}
	}

	this.xmlRequest.send(null);

	return true;
}





// bool
vkJSONRemote.prototype.post = function(url, data, timeout)
{
	var	self = this;

	if(!this._prepare())
		return false;

	if(timeout !== undefined)
		this.currentTimeout = window.setTimeout(
			function() { self._onTimeout() },
			timeout);

	this.xmlRequest.open('POST', url);
	this.xmlRequest.setRequestHeader('Content-Type', 'text/plain; charset=UTF-8')

	this.xmlRequest.onreadystatechange = function()
	{
		if(self.aborted)
			return;

		switch(self.xmlRequest.readyState)
		{
			case 3:		// receiving
				self.onLoading();
				break;

			case 4:		// loaded
				self._onLoad();
				break;

			case 0:		// uninitialized
			case 1:		// open
			case 2:		// sent
			default:
				// we don't care
		}
	}

	var	json;

	if(data == null)
		json = null;
	else
	{
		try
		{
			//json = JSON.stringify(data);
			// 23/06/2010 - Yet another stupid IE bug
			// http://blogs.msdn.com/b/jscript/archive/2009/06/23/serializing-the-value-of-empty-dom-elements-using-native-json-in-ie8.aspx
			// http://tech.groups.yahoo.com/group/json/message/1271
			json = JSON.stringify(data, function(k,v) { return v==='' ? '' : v});
		}
		catch (e)
		{
			if(this.debug)
			{
				this._writeDebug('========== vkJSONRemote ==========');
				this._writeDebug('EVENT: Failed building JSON string');
				this._writeDebug('ERROR NAME: '+e.name);
				this._writeDebug('ERROR MESSAGE:');
				this._writeDebug('----------------------------------');
				this._writeDebug(e.message);
				this._writeDebug('==================================');
			}

			//json = 'null';
			return false;
		}
	}

	this.xmlRequest.send(json);

	return true;
}


vkJSONRemote.prototype.abort = function()
{
	this.aborted = true;

	if(this.currentTimeout)
	{
		clearTimeout(this.currentTimeout);
		this.currentTimeout = null;
	}
}

vkJSONRemote.prototype.free = function()
{
	this.abort();

	// 20/01/2009
	if(this.xmlRequest && typeof(this.xmlRequest.abort) == 'function')
		this.xmlRequest.abort();
	
	this.xmlRequest = null;
}


/*********************************************/
/* PROTECTED */


// May be overriden
vkJSONRemote.prototype.onLoading = function()
{
	/* Default behaviour: don't do anything */
}

// Should be overriden
vkJSONRemote.prototype.onLoad = function(httpStatus, result)
{
	/* Default behaviour: don't do anything */
}

// May be overriden
vkJSONRemote.prototype.onTimeout = function()
{
	/* Default behaviour: don't do anything */
}



/*********************************************/
/* PRIVATE */

// bool
vkJSONRemote.prototype._prepare = function()
{
	//this.abort();
	this.free();	// 20/01/2009

	try
	{
		// Get the "right" XML request object
		if(!window.XMLHttpRequest)
		{
			if(document.all && window.ActiveXObject)
			{
				try
				{
					this.xmlRequest = new ActiveXObject('Msxml2.XMLHTTP');
				}
				catch (e1)
				{
					try
					{
						this.xmlRequest = new ActiveXObject('Microsoft.XMLHTTP');
					}
					catch (e2)
					{
						throw 'vkJSONRemote: Browser lacks XMLHttpRequest support';
					}
				}
			}
			else
				throw 'vkJSONRemote: Browser lacks XMLHttpRequest support';
		}
		else
			this.xmlRequest = new XMLHttpRequest();
	}
	catch(e0)
	{
		return false;
	}

	this.aborted = false;
	this.currentTimeout = null;

	return true;
}




// void
vkJSONRemote.prototype._writeDebug = function(text)
{
	if(this.debug)
		this.debug.text(text);
}

// void
vkJSONRemote.prototype._onLoad = function()
{
	var	status, result;

	this.abort();	// Clears the timeout
	
	status = this.xmlRequest.status;

	if(this.debug)
	{
		this._writeDebug('========== vkJSONRemote ==========');
		this._writeDebug('EVENT: Received reply');
		this._writeDebug('HTTP STATUS: '+status);
		this._writeDebug('DATA:');
		this._writeDebug('----------------------------------');
		this._writeDebug(this.xmlRequest.responseText);
		this._writeDebug('==================================');
	}

	if(status == 200)
	{
		var	xmlObject, nodeList;

		if(	(xmlObject = this.xmlRequest.responseXML) &&
			(nodeList = xmlObject.getElementsByTagName('JSON')) &&
			nodeList.length == 1 &&
			nodeList[0].firstChild )
		{
			// Some browsers (ie. Firefox) have limitation on maximum node length, and therefore split
			// the received data in multiple nodes...

			var	i, value = '';

			for(i = 0; i < nodeList[0].childNodes.length; i++)
				value += nodeList[0].childNodes[i].nodeValue;

			try
			{
				eval('result='+value);
			}
			catch (e)
			{
				if(this.debug)
				{
					this._writeDebug('========== vkJSONRemote ==========');
					this._writeDebug('EVENT: Failed parsing JSON reply');
					this._writeDebug('ERROR NAME: '+e.name);
					this._writeDebug('ERROR MESSAGE:');
					this._writeDebug('----------------------------------');
					this._writeDebug(e.message);
					this._writeDebug('==================================');
				}
				result = null;
			}
		}
		else
			result = null;
	}
	else
		result = null;

	this.onLoad(status, result);
}

vkJSONRemote.prototype._onTimeout = function()
{
	//this.abort();	// Clears the timeout and aborts the request
	this.free();	// 20/01/2009 - Makes sure the request is canceled

	if(this.debug)
	{
		this._writeDebug('========== vkJSONRemote ==========');
		this._writeDebug('EVENT: Request timed out');
		this._writeDebug('==================================');
	}
	
	
	this.onTimeout();
}




/***********************************************************************/
/* STOLEN FROM http://www.JSON.org/json2.js (Public Domain) */
/* then minified @ http://fmarcia.info/jsmin/test1.html */

if(!this.JSON){this.JSON={};}
(function(){function f(n){return n<10?'0'+n:n;}
if(typeof Date.prototype.toJSON!=='function'){Date.prototype.toJSON=function(key){return isFinite(this.valueOf())?this.getUTCFullYear()+'-'+
f(this.getUTCMonth()+1)+'-'+
f(this.getUTCDate())+'T'+
f(this.getUTCHours())+':'+
f(this.getUTCMinutes())+':'+
f(this.getUTCSeconds())+'Z':null;};String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(key){return this.valueOf();};}
var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'},rep;function quote(string){escapable.lastIndex=0;return escapable.test(string)?'"'+string.replace(escapable,function(a){var c=meta[a];return typeof c==='string'?c:'\\u'+('0000'+a.charCodeAt(0).toString(16)).slice(-4);})+'"':'"'+string+'"';}
function str(key,holder){var i,k,v,length,mind=gap,partial,value=holder[key];if(value&&typeof value==='object'&&typeof value.toJSON==='function'){value=value.toJSON(key);}
if(typeof rep==='function'){value=rep.call(holder,key,value);}
switch(typeof value){case'string':return quote(value);case'number':return isFinite(value)?String(value):'null';case'boolean':case'null':return String(value);case'object':if(!value){return'null';}
gap+=indent;partial=[];if(Object.prototype.toString.apply(value)==='[object Array]'){length=value.length;for(i=0;i<length;i+=1){partial[i]=str(i,value)||'null';}
v=partial.length===0?'[]':gap?'[\n'+gap+
partial.join(',\n'+gap)+'\n'+
mind+']':'['+partial.join(',')+']';gap=mind;return v;}
if(rep&&typeof rep==='object'){length=rep.length;for(i=0;i<length;i+=1){k=rep[i];if(typeof k==='string'){v=str(k,value);if(v){partial.push(quote(k)+(gap?': ':':')+v);}}}}else{for(k in value){if(Object.hasOwnProperty.call(value,k)){v=str(k,value);if(v){partial.push(quote(k)+(gap?': ':':')+v);}}}}
v=partial.length===0?'{}':gap?'{\n'+gap+partial.join(',\n'+gap)+'\n'+
mind+'}':'{'+partial.join(',')+'}';gap=mind;return v;}}
if(typeof JSON.stringify!=='function'){JSON.stringify=function(value,replacer,space){var i;gap='';indent='';if(typeof space==='number'){for(i=0;i<space;i+=1){indent+=' ';}}else if(typeof space==='string'){indent=space;}
rep=replacer;if(replacer&&typeof replacer!=='function'&&(typeof replacer!=='object'||typeof replacer.length!=='number')){throw new Error('JSON.stringify');}
return str('',{'':value});};}
if(typeof JSON.parse!=='function'){JSON.parse=function(text,reviver){var j;function walk(holder,key){var k,v,value=holder[key];if(value&&typeof value==='object'){for(k in value){if(Object.hasOwnProperty.call(value,k)){v=walk(value,k);if(v!==undefined){value[k]=v;}else{delete value[k];}}}}
return reviver.call(holder,key,value);}
text=String(text);cx.lastIndex=0;if(cx.test(text)){text=text.replace(cx,function(a){return'\\u'+
('0000'+a.charCodeAt(0).toString(16)).slice(-4);});}
if(/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,'@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']').replace(/(?:^|:|,)(?:\s*\[)+/g,''))){j=eval('('+text+')');return typeof reviver==='function'?walk({'':j},''):j;}
throw new SyntaxError('JSON.parse');};}}());


/* vkXMLRemote.js */


/*********************************************/
/* PUBLIC */


function	vkXMLRemote()
{
	this.xmlRequest = null;
	this.aborted = false;
	this.currentTimeout = null;
	this.debug = null;
}

// bool
vkXMLRemote.prototype.enableDebug = function(debug)
{
	if(
		debug == null ||
		(
			typeof(debug) == 'object' &&
			debug.constructor == vkDebug
		)
	)
	{
		this.debug = debug;
		return true;
	}
			
	this.debug = null;
	return false;
}

// bool
vkXMLRemote.prototype.disableDebug = function()
{
	return this.enableDebug(null);
}

// bool
vkXMLRemote.prototype.get = function(url, timeout)
{
	var	self = this;

	if(!this._prepare())
		return false;

	if(timeout !== undefined)
		this.currentTimeout = window.setTimeout(
			function() { self._onTimeout(); },
			timeout);

	this.xmlRequest.open('GET', url);
	this.xmlRequest.setRequestHeader('Content-Type', 'text/plain; charset=UTF-8')

	this.xmlRequest.onreadystatechange = function()
	{
		if(self.aborted)
			return;

		switch(self.xmlRequest.readyState)
		{
			case 3:		// receiving
				self.onLoading();
				break;

			case 4:		// loaded
				self._onLoad();
				break;

			case 0:		// uninitialized
			case 1:		// open
			case 2:		// sent
			default:
				// we don't care
		}
	}

	this.xmlRequest.send(null);

	return true;
}

vkXMLRemote.prototype.abort = function()
{
	this.aborted = true;

	if(this.currentTimeout)
	{
		clearTimeout(this.currentTimeout);
		this.currentTimeout = null;
	}
}

vkXMLRemote.prototype.free = function()
{
	this.abort();

	// 20/01/2009
	if(this.xmlRequest && typeof(this.xmlRequest.abort) == 'function')
		this.xmlRequest.abort();
	
	this.xmlRequest = null;
}


/*********************************************/
/* PROTECTED */


// May be overriden
vkXMLRemote.prototype.onLoading = function()
{
	/* Default behaviour: don't do anything */
}

// Should be overriden
vkXMLRemote.prototype.onLoad = function(httpStatus, result)
{
	/* Default behaviour: don't do anything */
}

// May be overriden
vkXMLRemote.prototype.onTimeout = function()
{
	/* Default behaviour: don't do anything */
}



/*********************************************/
/* PRIVATE */

// bool
vkXMLRemote.prototype._prepare = function()
{
	//this.abort();
	this.free();	// 20/01/2009

	try
	{
		// Get the "right" XML request object
		if(!window.XMLHttpRequest)
		{
			if(document.all && window.ActiveXObject)
			{
				try
				{
					this.xmlRequest = new ActiveXObject('Msxml2.XMLHTTP');
				}
				catch (e1)
				{
					try
					{
						this.xmlRequest = new ActiveXObject('Microsoft.XMLHTTP');
					}
					catch (e2)
					{
						throw 'vkXMLRemote: Browser lacks XMLHttpRequest support';
					}
				}
			}
			else
				throw 'vkXMLRemote: Browser lacks XMLHttpRequest support';
		}
		else
			this.xmlRequest = new XMLHttpRequest();
	}
	catch(e0)
	{
		return false;
	}

	this.aborted = false;
	this.currentTimeout = null;

	return true;
}




// void
vkXMLRemote.prototype._writeDebug = function(text)
{
	if(this.debug)
		this.debug.text(text);
}

// void
vkXMLRemote.prototype._onLoad = function()
{
	var	status, result;

	this.abort();	// Clears the timeout
	
	status = this.xmlRequest.status;

	if(this.debug)
	{
		this._writeDebug('=========== vkXMLRemote ==========');
		this._writeDebug('EVENT: Received reply');
		this._writeDebug('HTTP STATUS: '+status);
		this._writeDebug('DATA:');
		this._writeDebug('----------------------------------');
		this._writeDebug(this.xmlRequest.responseText);
		this._writeDebug('==================================');
	}

	if(status == 200 && this.xmlRequest.responseXML)
		result = this.xmlRequest.responseXML;
	else
		result = null;

	this.onLoad(status, result);
}

vkXMLRemote.prototype._onTimeout = function()
{
	//this.abort();	// Clears the timeout and aborts the request
	this.free();	// 20/01/2009 - Makes sure the request is canceled

	if(this.debug)
	{
		this._writeDebug('=========== vkXMLRemote ==========');
		this._writeDebug('EVENT: Request timed out');
		this._writeDebug('==================================');
	}
	
	
	this.onTimeout();
}



/* ws/fastSearch/static/js/ajax.js */

// 10/11/2009	Increased default timeout from 15 to 20 seconds

function	fsAjaxRequest()	// debug=false, timeout=20000
{
	if(arguments.length > 1)
		this.timeout = parseInt(arguments[1]);
	else
		this.timeout = 20000;	// Default

	// Use a single ajax instance for the whole lifetime
	this.ajax = new vkJSONRemote(true);

	if(arguments.length && arguments[0])
		this.ajax.enableDebug(debug);

	var	self = this;

	this.ajax.onLoad = function(status, data)
	{
		self.ajax.free();

		if(status == 200)
			self.onLoad(data);
		else
			self.onError();
	}

	this.ajax.onTimeout = function()
	{
		self.ajax.free();
		self.onTimeout();
	}
}

fsAjaxRequest.prototype.post = function(url, object)
{
	this.ajax.free();
	this.ajax.post(
		url,
		object,
		this.timeout
	);

}


fsAjaxRequest.prototype.abort = function()	// 01/12/2009
{
	this.ajax.free();
}


fsAjaxRequest.prototype.onLoad = function(data)
{
	/* To be extended */
}

fsAjaxRequest.prototype.onError = function(statut)
{
	/* To be extended */
}

fsAjaxRequest.prototype.onTimeout = function()
{
	/* To be extended */
}


/* /js/kigoCalendar.js */ /* UTF8 COOKIE: éa */




/**
 * Retrieve the absolute coordinates of an element.
 *
 * @param element
 *   A DOM element.
 * @return
 *   A hash containing keys 'x' and 'y'.
 */
function getAbsolutePosition(element) {
  var r = { x: element.offsetLeft, y: element.offsetTop };
  if (element.offsetParent) {
    var tmp = getAbsolutePosition(element.offsetParent);
    r.x += tmp.x;
    r.y += tmp.y;
  }
  return r;
};

/**
 * Retrieve the coordinates of the given event relative to the center
 * of the widget.
 *
 * @param event
 *   A mouse-related DOM event.
 * @param reference
 *   A DOM element whose position we want to transform the mouse coordinates to.
 * @return
 *    A hash containing keys 'x' and 'y'.
 */
function getRelativeCoordinates(event, reference) {
  var x, y;
  event = event || window.event;

  var el = event.target || event.srcElement;
    
  if (!window.opera && typeof event.offsetX != 'undefined') {
    // Use offset coordinates and find common offsetParent
    var pos = { x: event.offsetX, y: event.offsetY };

    // Send the coordinates upwards through the offsetParent chain.
    var e = el;
    while (e) {
      e.mouseX = pos.x;
      e.mouseY = pos.y;
      pos.x += e.offsetLeft;
      pos.y += e.offsetTop;
      e = e.offsetParent;
    }

    // Look for the coordinates starting from the reference element.
    var e = reference;
    var offset = { x: 0, y: 0 }
    while (e) {
      if (typeof e.mouseX != 'undefined') {
        x = e.mouseX - offset.x;
        y = e.mouseY - offset.y;
        break;
      }
      offset.x += e.offsetLeft;
      offset.y += e.offsetTop;
      e = e.offsetParent;
    }

    // Reset stored coordinates
    e = el;
    while (e) {
      e.mouseX = undefined;
      e.mouseY = undefined;
      e = e.offsetParent;
    }
  }
  else {
    // Use absolute coordinates
	  kigoDebug.text('absolute calculus');
    var pos = getAbsolutePosition(reference);
    x = event.pageX  - pos.x;
    y = event.pageY - pos.y;
  }
  // Subtract distance to middle
  return { x: x, y: y };
}



/*
 * 
 * @see details about rendering described after this function.
 * 
 * @param data { This info is used in the displaying of tool tips and additional informations
	'i'		:	Property Id
	'p'		:	Property Name
	'f'		:	Property Photo
	'a'		:	Property Address
	'o'		:	Property Owner ? (Check accuracy)
	'r'		:	reservations information. Set of reservations of the property.
	}			
 *	@param searchDate {
    's'		:	Start date
    'e'		:   End date
    }
 *  @param limits {
	'p'		:   Prior resevation for the entire group
	'e' 	: 	Next reservation for the group
    }
 *    
 */
function	kigoCalendar(startMonth, startYear, endMonth, endYear, datas, searchDate, limits)
{
	this.datas				=	{
			'i'		:	datas.i,
			'p'		:	datas.p,
			'f'		:	datas.f,
			'a'		:	datas.a,
			'o'		:	datas.o
	};
	this.sm					=	startMonth			;
	this.sy					=	startYear			;
	this.em					=	endMonth			;
	this.ey					=	endYear				;
	this.res				=	datas.r				;
	this.nbMonth									;
	this.resTooltips		=	new Array()			;
	this.areaTooltips		=	new Array()			;
	this.md					=	new Array()			;
	this.stack				=	new Array()			; 
	this.length										;
	this.onReservationClick	=	null				;
	this.onSearchClick		=	null				;
	this.onAvailableClick	=	null				;
	this.parent				=	null				;
	this.limits				=	limits	||	null	;
	this.lim				=	0					;
	this.search				=	null				;


	this.div = document.createElement('div');

	if(searchDate != null)
	{
		var searchStart		=	new Date.parseDate(searchDate.s, '%Y-%m-%d');
		var searchEnd		=	new Date.parseDate(searchDate.e, '%Y-%m-%d');
		var newResTab		=	new Array();
		var calStart		=	new Date(this.sy, this.sm - 1	);
		var calEnd			=	new Date(this.ey, this.em		);
		var isOk			=	true;
		
		if(this._compareDate(calStart, searchEnd) >0  || this._compareDate(searchStart, calEnd) >0)
		{
			isOk				=	false;
			this.onSearchClick	=	null;
		}

		if(isOk)
		{
			searchDate.t		=	{'n' : 'Your search' };
			if(this.res.length == 0){
				this.search = newResTab.length;
				newResTab.push(searchDate);
			}
			else{
				var added = false; 
				for(var nbr=0; nbr<this.res.length; nbr++)
				{
					if(!added){
						var resStart	=	new Date.parseDate(this.res[nbr].s, '%Y-%m-%d');
						if(this._compareDate(searchEnd, resStart) <=0){
							this.search	=	newResTab.length;
							newResTab.push(searchDate);
							added = true;
						}
					}
					newResTab.push(this.res[nbr]);
					if(!added && nbr == this.res.length-1){
						this.search	=	newResTab.length;
						newResTab.push(searchDate);
					}
				}
			}
			this.res	=	newResTab;
		}
	}
}

kigoCalendar.bei = 1;

/*
 * Calendar rendering
 * 
 * The calendar renders it's days and month labels plus a container with the availabilities.
 * 
 * The calendar reservation info is composed out of a series of divs.
 * Reservations, hold dates and available time. 
 * 
 * The availability area divs are displayed as blocks floating left. Their width and height is computed
 * based on the width and height of the day specified in the css. (See dump function for details).
 * 
 * 
 */

/*
 * Determines class for reservation div
 */
kigoCalendar.prototype._getClass = function(m, c)
{
	if((parseInt(m) != 0 && parseInt(m) != 1) || (parseInt(c) != 0 && parseInt(c) != 1)) return 's';
	else{
		m	=	parseInt(m);
		c	=	parseInt(c);
		if(m == c)
		{
			if(m == 0) 	return 'oh'; // other hold
			else		return 'mc'; // me confirmed
		}
		else if(m == 0)	return 'oc'; // other confirmed
		else			return 'mh'; // me confirmed
	}
}
/*
 * Date function helper
 */
kigoCalendar.prototype._getDaysBetween = function(d1, d2)
{
	var days;
	var d, m ,y;
	if(this._compareDate(d1, d2) == -1)	return	Math.round((d2.getTime() - d1.getTime()) / (1000*60*60*24));
	else								return	Math.round((d1.getTime() - d2.getTime()) / (1000*60*60*24));
}
/*
 * Date function helper
 */
kigoCalendar.prototype._compareDate = function(d1, d2)
{
	if		(d1.getYear() <  d2.getYear()																	)	return -1;
	else if	(d1.getYear() == d2.getYear() && d1.getMonth() <  d2.getMonth()									)	return -1;
	else if	(d1.getYear() == d2.getYear() && d1.getMonth() == d2.getMonth() && d1.getDate() <  d2.getDate()	)	return -1;
	else if	(d1.getYear() == d2.getYear() && d1.getMonth() == d2.getMonth() && d1.getDate() == d2.getDate()	)	return  0;
	else																										return  1;
}
/*
 * Compute the width of an availability element (reservetions, holds, free time).
 * It is computed based on the stack which represents how many days to exapnd the div, 5 more days left until end of month, then div should be extended to day.width * 5px.
 */
kigoCalendar.prototype._getWidth 				= 	function(){ return (this.length < this.stack[0]) ? this.length : this.stack[0]; }
/*
 * Dom helper
 */
kigoCalendar.prototype._createBlock				=	function(width, className)
{
	var b					 =	this.div.cloneNode(false);
	b.style.width			 =	width*this.daySize	+'px';
	b.className				 =	className;
	return b;
}
/*
 * Creates the first availability element if it is an availability
 */
kigoCalendar.prototype._createFirstArea			=	function(dateStart, dateEnd)
{
	var area;
	var self	=	this;
	this.length	=	this._getDaysBetween(dateStart, dateEnd);
	
	var i = 0;
	
	while(this.length != 0 && this.stack.length != 0)
	{
		area	=	this._createBlock(this._getWidth(), 'n');
		this.parent.appendChild(area);
		this._updateLengthAndStack(this._getWidth());
		
		var month = dateStart.getMonth();
		
		if (typeof(this.onAvailableClick) == 'function') 
		{
			area.modifiedMonth = month+i;
			area.onclick 	 = function(event){
				
				var e = event || window.event;
				var pos = getRelativeCoordinates(event, area.parentNode);
				var day = Math.ceil(pos.x/self.daySize);
				
				if (day==0) day = 1;
				
				var modifiedDate = new Date(
						dateStart.getFullYear() + (Math.floor(this.modifiedMonth/12))
						, (this.modifiedMonth%12)
						, day);
				
				self.onAvailableClick(self.datas,modifiedDate.print('%a, '+ day +' %b %Y')); return false;

				
			}
			area.className	+= ' clickable';
		}
		if (this.limits != null && typeof(this.limits) == 'object')
		{
			kigoToolTips.add(area, this.areaTooltips[0]);
		}
		i++;
		
	}
	this.length++;
	this._createBlockEnd('n', this._getClass(this.res[0].m, this.res[0].c), null, 0);
	if(this.lim != null)	this.lim++;
}
/*
 * Creates the first availability element if it is a reservation
 */
kigoCalendar.prototype._createFirstReservation	=	function(numRes, resStart, resEnd)
{
	var res;
	var self = this;
	this.length		=	this._getDaysBetween(resStart, resEnd);
	while(this.length != 0 && this.stack.length != 0)
	{
		res	=	this._createBlock(this._getWidth(), this._getClass(this.res[numRes].m, this.res[numRes].c));
		if (typeof(this.onReservationClick) == 'function' && this.res[numRes].i != null)
		{
			res.onclick 	 = function(){ self.onReservationClick(parseInt(self.res[numRes].i, 10)); return false; }
			res.className	+= ' clickable';
		}
		else if (typeof(this.onSearchClick) == 'function' && this.search == numRes) 
		{
			res.onclick 	= function(){ self.onSearchClick(self.datas); return false; }
			res.className	+= ' clickable';
		}
		this.parent.appendChild(res);
		if (this.res[0].t != null && typeof(this.res[0].t) == 'object')
		{
			kigoToolTips.add(res, this.resTooltips[0]);
		}
		this._updateLengthAndStack(this._getWidth());
	}
}
/*
 * Creates availability element of the available type used after the first element has been generated.
 */
kigoCalendar.prototype._createFreeArea			=	function(dateStart, dateEnd)
{
	var area;
	var self	=	this;
	this.length	=	this._getDaysBetween(dateStart, dateEnd)-1;		
	
	// prior reservation ended at end of the month
	if (parseInt(dateStart.print('%d')) == dateStart.getMonthDays()) {	
		var i = 1;
	} else {
		var i = 0;
	}
			
	while(this.length != 0 && this.stack.length != 0)
	{
		area	=	this._createBlock(this._getWidth(), 'n');
		this.parent.appendChild(area);
		this._updateLengthAndStack(this._getWidth());
		
		
		var month = dateStart.getMonth();
		
		if (typeof(this.onAvailableClick) == 'function') 
		{
			area.modifiedMonth = month+i;
			area.onclick 	 = function(event){ 
				
				var e = event || window.event;
				var pos = getRelativeCoordinates(event, area.parentNode);
								
				var day = Math.ceil(pos.x/self.daySize);
				
				if (day==0) day = 1;
				
				var modifiedDate = new Date(
						dateStart.getFullYear() + (Math.floor(this.modifiedMonth/12))
						, (this.modifiedMonth%12)
						, day);
				
				self.onAvailableClick(self.datas,modifiedDate.print('%a, '+ day +' %b %Y')); return false;
								
			}
			area.className	+= ' clickable';
		}
		
		i++;
		
		if(this.limits != null)
		{
			kigoToolTips.add(area, this.areaTooltips[this.lim]);
		}
	}
}
/*
 * Creates availability element of the reservation type used after the first element has been generated.
 */
kigoCalendar.prototype._createReservation		=	function(numRes, resStart, resEnd)
{
	var res;
	var self 	= this;
	this.length	=	this._getDaysBetween(resStart, resEnd)-1;
		
	while(this.length != 0 && this.stack.length != 0)
	{
		res	=	this._createBlock(this._getWidth(), this._getClass(this.res[numRes].m, this.res[numRes].c));
		if (typeof(this.onReservationClick) == 'function' && this.res[numRes].i != null) 
		{
			res.onclick = function(){ self.onReservationClick(parseInt(self.res[numRes].i, 10)); return false; }
			res.className	 += ' clickable';
		}
		else if (typeof(this.onSearchClick) == 'function' && this.search == numRes) 
		{
			res.onclick 	= function(){ self.onSearchClick(self.datas); return false; }
			res.className	+= ' clickable';
		}
		this.parent.appendChild(res);
		if (this.res[numRes].t != null && typeof(this.res[numRes].t) == 'object')
		{
			kigoToolTips.add(res, this.resTooltips[numRes]);
		}
		this._updateLengthAndStack(this._getWidth());
	}
}
/*
 * Creates a separation element between availability elements.
 * This element is a div that contains 2 othere divs each with the classes coresponding to the previous and next
 * availibility elements.
 *                 		   |---                           Separation element                           ---|
 * [Free time{class:cn1}] [ (Free time end block{class:'e'+cn1}) (Reservation start block{class:'b'+cn2}) ] [Reservation{class:cn2}]
 * 
 * @param cn1 prior element class
 * @param cn2 next element class
 * @param r1 prior reservation info
 * @param r2 next reservation info
 * 
 */
kigoCalendar.prototype._createBlockEnd			=	function(cn1, cn2, r1, r2)
{
	
		
	if(r1 != null || r2 != null){
		var date	=	(r1 == null)	?	new Date.parseDate(this.res[r2].s, '%Y-%m-%d')	:	new Date.parseDate(this.res[r1].e, '%Y-%m-%d');
	}
	
	var block;
	var self 	=	this;
	
	var area1	=	document.createElement('div')	;
	area1.className	+=	' e' +cn1+ ' ';
	
	var area2	=	document.createElement('div')	;
	area2.className	+=	' b' +cn2+ ' ';
	
	area1.style.width	= area2.style.width	=	(this.daySize/2) +'px';
	
	this._updateLengthAndStack(1);
	block	=	this._createBlock(1, 'start_end_block');
	block.style.display = "inline";
	//block.style.cssFloat = block.style.styleFloat = "left";	
	
	if(r1 != null && typeof(this.onReservationClick) == 'function' && this.res[r1].i != null)
	{
		area1.onclick = function(){ kigoDebug.text('reserv'); self.onReservationClick(parseInt(self.res[r1].i, 10)); return false; }
		area1.className	 += ' clickable';
	}
	else if (typeof(this.onSearchClick) == 'function' && this.search != null) 
	{
		if(this.search == r1){
		area1.onclick 	= 	function(){ kigoDebug.text('search'); self.onSearchClick(self.datas); return false; }
		area1.className	+= 	' clickable';
		}
	}
	else if (typeof(this.onAvailableClick) == 'function' && cn1 == 'n') 
	{
		area1.onclick 	 = function(event){ 
		
			var e = event || window.event;
			var pos = getRelativeCoordinates(event, area1.parentNode.parentNode);
			var day = Math.ceil(pos.x/self.daySize);					
			self.onAvailableClick(self.datas,date.print('%a, '+ day +' %b %Y')); 
			return false;
			
		}
		area1.className	+= ' clickable';
	}
	if(r1 != null && this.res[r1].t != null && typeof(this.res[r1].t) == 'object')
	{
		kigoToolTips.add(area1, this.resTooltips[r1]);
	}
	if(cn1 == 'n' && typeof(this.limits) == 'object' && this.limits != null )
	{
		kigoToolTips.add(area1, this.areaTooltips[this.lim]);
	}
	
	if(r2 != null && typeof(this.onReservationClick) == 'function' && this.res[r2].i != null)
	{
		area2.onclick = function(){ self.onReservationClick(parseInt(self.res[r2].i, 10)); return false; }
		area2.className	 += ' clickable';
		//area2.setAttribute('href', '#');
	}
	else if (typeof(this.onSearchClick) == 'function' && this.search != null) 
	{
		if(this.search == r2){		
		area2.onclick 	= 	function(){ self.onSearchClick(self.datas); return false;}
		area2.className	+= 	' clickable';
		//area2.setAttribute('href', '#');
		}
	}
	else if (typeof(this.onAvailableClick) == 'function' && cn2 == 'n') 
	{
		area2.onclick 	 = function(event){
			
			var e = event || window.event;
			var pos = getRelativeCoordinates(event, area1.parentNode.parentNode);
			var day = Math.ceil(pos.x/self.daySize);
			
			/*

			var pos2 = getAbsolutePosition (area2.parentNode.parentNode);									
			var pos = getAbsolutePosition (area2.parentNode);
			var day = Math.ceil((pos.x-pos2.x)/self.daySize)+1;
			*/
			
			self.onAvailableClick(self.datas,date.print('%a, '+ day +' %b %Y')); return false;
									
		}
		area2.className	+= ' clickable';
	}
	if(r2 != null && this.res[r2].t != null && typeof(this.res[r2].t) == 'object')
	{
		kigoToolTips.add(area2, this.resTooltips[r2]);
	}
	if(cn2 == 'n' && typeof(this.limits) == 'object' && this.limits != null )
	{
		kigoToolTips.add(area2, this.areaTooltips[this.lim]);
	}
	

	block.appendChild(area1);
	//block.appendChild(area3);
	block.appendChild(area2);
	//block.appendChild(img);
	//block.appendChild(map);
	
	
	//var bl = block; 

	
	if(r1 != null || r2 != null){
		var date	=	(r1 == null)	?	new Date.parseDate(this.res[r2].s, '%Y-%m-%d')	:	new Date.parseDate(this.res[r1].e, '%Y-%m-%d');
		if(date.getMonthDays() == date.getDate() && this.parent.lastChild.className == 'eom')	this.parent.insertBefore(block, this.parent.lastChild);
		else	this.parent.appendChild(block);
	}
	else 
		this.parent.appendChild(block);
	
	kigoCalendar.bei++;
}
/*
 * Appends and empty div for months that have less than 31 days.
 */
kigoCalendar.prototype._updateLengthAndStack	=	function(width)
{
	this.length		-=	width;
	this.stack[0]	-=	width;
	if(this.stack[0]	==	0)
	{
		this.stack.shift();
		var dif 	 =	31-this.md[0];
		if(dif > 0)	this.parent.appendChild(this._createBlock(dif, 'eom'));
		this.md.shift();
	}
}
/*
 * Create reservation tooltips and availability elements. 
 * See end of function for the latter.
 */
kigoCalendar.prototype._createReservations		=	function(parent)
{
	var calStart				=	new Date(this.sy, this.sm - 1	);
	var calEnd					=	new Date(this.ey, this.em		);
	var self					=	this;
	
	this.parent	=	parent;
	if(this.res.length == 0){
		var area;
		this.length	=	this._getDaysBetween(calStart, calEnd);
		if(this.limits != null)
		{
			var tt			=	this.div.cloneNode(false);
			tt.className	=	'tooltip';
			this.container.appendChild(tt);
			tt.setAttribute('pos', 's');
			
			
			
			var l5f				=	this.div.cloneNode(false);
			l5f.className		=	'ttClickForAction';
			l5f.appendChild(document.createTextNode('Click to reserve!'));
			tt.appendChild(l5f);
			
			var lf				=	this.div.cloneNode(false);
			lf.className		=	'ttFreeArea';
			lf.appendChild(document.createTextNode('Available dates'));
			tt.appendChild(lf);
			
			var l1			=	this.div.cloneNode(false);
			l1.className	=	'ttlcout';
			var lcout;
			if(this.limits.p == null)	lcout	=	'No earlier dates';
			else
			{
				var d 	=	new Date.parseDate(this.limits.p, '%Y-%m-%d');
				lcout	=	d.print('%a, %d %b %Y');
			}
			l1.appendChild(document.createTextNode('Last check-out : ' + lcout));
			tt.appendChild(l1);
			
			var l2			=	this.div.cloneNode(false);
			l2.className	=	'ttncin';
			var ncin;
			if(this.limits.n == null)	ncin	=	'No further dates';
			else
			{
				var d 	=	new Date.parseDate(this.limits.n, '%Y-%m-%d');
				ncin	=	d.print('%a, %d %b %Y');
			}
			l2.appendChild(document.createTextNode('Next check-in : ' + ncin));
			tt.appendChild(l2);

			
		}
		
		var month = calStart.getMonth(); 
		var i = 0;
		
		while(this.length != 0 && this.stack.length != 0)
		{
			area	=	this._createBlock(this._getWidth(), 'n');
			this.parent.appendChild(area);
			this._updateLengthAndStack(this._getWidth());
			if (typeof(this.onAvailableClick) == 'function') 
			{
				area.modifiedMonth = month + i;
				area.onclick 	 = function(event){ 
					
					var e = event || window.event;
					var pos = getRelativeCoordinates(event, area.parentNode);
					var day = Math.ceil(pos.x/self.daySize);
					
					if (day==0) day = 1;
					
					var modifiedDate = new Date(
							calStart.getFullYear() + (Math.floor(this.modifiedMonth/12))
							, (this.modifiedMonth%12)
							, day);
					
					self.onAvailableClick(self.datas,modifiedDate.print('%a, '+ day +' %b %Y')); return false;
								
					return false;
					}
				area.className	+= ' clickable';
			}
			if(this.limits != null)
			{
				kigoToolTips.add(area, tt);
			}
			i++;
		}
	}
	else
	{
		for(var nbr=0; nbr<this.res.length; nbr++)
		{
			var res = this.res[nbr];

			if(res.t != null && typeof(res.t) == 'object')
			{
				var resStart	=	new Date.parseDate(res.s, '%Y-%m-%d');
				var resEnd		=	new Date.parseDate(res.e, '%Y-%m-%d');
				
				var ttRes			=	this.div.cloneNode(false);
				ttRes.className	=	'tooltip';
				ttRes.setAttribute('pos', 's');
				
				if((parseInt(res.m) == 0 || parseInt(res.m) == 1) && (parseInt(res.c) == 0 || parseInt(res.c) == 1))
				{
					ttRes.className	+=	' m_'+res.m;
					ttRes.className	+=	' c_'+res.c;
					ttRes.className	+=	' resTooltip';
					
					var l1			=	this.div.cloneNode(false);
					l1.className	=	'ttAgency';
					l1.appendChild(document.createTextNode(res.t.a));
					ttRes.appendChild(l1);
					
					if(typeof(res.t.g) == 'string' && res.t.g.length)
					{
						var l2			=	this.div.cloneNode(false);
						l2.className	=	'ttGuest';
						l2.appendChild(document.createTextNode(res.t.g));
						ttRes.appendChild(l2);
					}
				}
				else
				{
					ttRes.className	+=	' searchTooltip';
					var l1			=	this.div.cloneNode(false);
					l1.className	=	'ttSearch';
					l1.appendChild(document.createTextNode(res.t.n));
					
					var l5f				=	this.div.cloneNode(false);
					l5f.className		=	'ttClickForAction';
					l5f.appendChild(document.createTextNode('Click to reserve!'));
					ttRes.appendChild(l5f);
					
					ttRes.appendChild(l1);
				}
				
				var l3			=	this.div.cloneNode(false);
				l3.className	=	'ttNights';
				var nights		=	this._getDaysBetween(resStart, resEnd);
				var l3t			=	nights +' night';
				if(nights >1)	l3t += 's';
				l3.appendChild(document.createTextNode(l3t));
				ttRes.appendChild(l3);
				
				var l4			=	this.div.cloneNode(false);
				l4.className	=	'ttCheckIn';
				l4.appendChild(document.createTextNode('Check-in : '));
				if(res.c)
				{
					if(res.t.i != null)	
						l4.appendChild(document.createTextNode(res.t.i +', '));
					else
					{
						var span		=	document.createElement('span');
						span.className	=	'warn2';
						span.appendChild(document.createTextNode('time? '));
						l4.appendChild(span);
					}
				}
				l4.appendChild(document.createTextNode(resStart.print('%a, %d %b %Y')));
				ttRes.appendChild(l4);
				
				var l5			=	this.div.cloneNode(false);
				l5.className	=	'ttCheckOut';
				l5.appendChild(document.createTextNode('Check-out : '));
				if(res.c)
				{
					if(res.t.o != null)	
						l5.appendChild(document.createTextNode(res.t.o +', '));
					else
					{
						var span		=	document.createElement('span');
						span.className	=	'warn2';
						span.appendChild(document.createTextNode('time? '));
						l5.appendChild(span);
					}
				}
				l5.appendChild(document.createTextNode(resEnd.print('%a, %d %b %Y')));
				ttRes.appendChild(l5);
				
				if(res.t.e!= null)
				{
					var l6			=	this.div.cloneNode(false);
					l6.className	=	'ttExpiry';
					var nbSec		=	res.t.e;
					if(nbSec < 0)	l6.appendChild(document.createTextNode('Expiry : About to expire.'));
					else
					{
						var fd		=	Math.floor(nbSec/86400);
						var fh		=	Math.floor((nbSec - (fd*86400))/3600);
						var fm		=	Math.floor((nbSec - (fd*86400) - (fh*3600)) / 60);
						if(fd != 0 && fh != 0)	l6.appendChild(document.createTextNode('Expiry : ' + fd + ' days ' + fh + 'h ' + fm + 'm'));
						else if(fh != 0)		l6.appendChild(document.createTextNode('Expiry : ' + fh + 'h ' + fm + 'm'));
						else					l6.appendChild(document.createTextNode('Expiry : ' + fm + 'm'));
					}

					ttRes.appendChild(l6);
				}
				

								
				this.container.appendChild(ttRes);
				this.resTooltips.push(ttRes);				
				
				if (typeof(this.limits) == 'object' && this.limits != null )
				{
					if(nbr == 0)
					{
						if(this._compareDate(resStart, calStart) >= 0)
						{
							var firstAreaStart	=	(this.limits.p != null)	?	new Date.parseDate(this.limits.p, '%Y-%m-%d')	:	new Date(this.sy, this.sm-1);
							var firstAreaEnd	=	resStart;
							
							var fTtArea			=	this.div.cloneNode(false);
							fTtArea.className	=	'tooltip';
							fTtArea.className	+=	' freeAreaTooltip';
							fTtArea.setAttribute('pos', 's');
							
							
							var l5f				=	this.div.cloneNode(false);
							l5f.className		=	'ttClickForAction';
							l5f.appendChild(document.createTextNode('Click to reserve!'));
							fTtArea.appendChild(l5f);								
							
							var l1f				=	this.div.cloneNode(false);
							l1f.className		=	'ttFreeArea';
							l1f.appendChild(document.createTextNode('Available dates'));
							fTtArea.appendChild(l1f);
							
							if(this._compareDate(firstAreaStart, calStart) != 0)
							{
								var l2f					=	this.div.cloneNode(false);
								l2f.className			=	'ttNights';
								var nights				=	this._getDaysBetween(firstAreaStart, firstAreaEnd);
								var l2tf				=	nights +' night';
								if(nights >1)	l2tf 	+= 's';
								l2f.appendChild(document.createTextNode(l2tf));
								fTtArea.appendChild(l2f);
							}
							
							var l3f				=	this.div.cloneNode(false);
							l3f.className		=	'ttCheckIn';
							l3f.appendChild(document.createTextNode('Last check-out : '));
							if(this._compareDate(firstAreaStart, calStart) == 0)	
								l3f.appendChild(document.createTextNode('No earlier dates'));
							else
								l3f.appendChild(document.createTextNode(firstAreaStart.print('%a, %d %b %Y')));
							fTtArea.appendChild(l3f);
							
							var l4f				=	this.div.cloneNode(false);
							l4f.className		=	'ttCheckOut';
							l4f.appendChild(document.createTextNode('Next check-in : '));
							l4f.appendChild(document.createTextNode(firstAreaEnd.print('%a, %d %b %Y')));
							fTtArea.appendChild(l4f);
												
							
							this.container.appendChild(fTtArea);
							
							this.areaTooltips.push(fTtArea);
						}
					}
					
					var dateStart		=	resEnd;
					var dateEnd			=	(nbr != this.res.length-1)	?	new Date.parseDate(this.res[nbr+1].s, '%Y-%m-%d')	:	new Date(this.ey, this.em);
					
					if(this._compareDate(dateStart, dateEnd) != 0)
					{
						if(this._compareDate(dateEnd, calEnd) == 0 && this.limits.n != null)
							dateEnd			=	new Date.parseDate(this.limits.n, '%Y-%m-%d');
						var ttArea			=	this.div.cloneNode(false);
						ttArea.className	=	'tooltip';
						ttArea.className	+=	' freeAreaTooltip';
						ttArea.setAttribute('pos', 's');
							
						
						var l5f				=	this.div.cloneNode(false);
						l5f.className		=	'ttClickForAction';
						l5f.appendChild(document.createTextNode('Click to reserve!'));
						ttArea.appendChild(l5f);						
						
						var l1			=	this.div.cloneNode(false);
						l1.className	=	'ttFreeArea';
						l1.appendChild(document.createTextNode('Available dates'));
						ttArea.appendChild(l1);
						
						if(this._compareDate(dateEnd, calEnd) != 0)
						{
							var l2			=	this.div.cloneNode(false);
							l2.className	=	'ttNights';
							var nights		=	this._getDaysBetween(dateStart, dateEnd);
							var l2t			=	nights +' night';
							if(nights >1)	l2t += 's';
							l2.appendChild(document.createTextNode(l2t));
							ttArea.appendChild(l2);
						}
						
						var l3			=	this.div.cloneNode(false);
						l3.className	=	'ttCheckIn';
						l3.appendChild(document.createTextNode('Check-in : '));
						l3.appendChild(document.createTextNode(dateStart.print('%a, %d %b %Y')));
						ttArea.appendChild(l3);
						
						var l4			=	this.div.cloneNode(false);
						l4.className	=	'ttCheckOut';
						l4.appendChild(document.createTextNode('Check-out : '));
						if(this._compareDate(dateEnd, calEnd) == 0)	
							l4.appendChild(document.createTextNode('No further dates'));
						else
							l4.appendChild(document.createTextNode(dateEnd.print('%a, %d %b %Y')));
						ttArea.appendChild(l4);

						
						this.container.appendChild(ttArea);
						
						this.areaTooltips.push(ttArea);
					}
				}
			}
			else	this.resTooltips.push('');
		}	
		
		for(var nbr=0; nbr<this.res.length; nbr++)
		{
			var res = this.res[nbr];
			var resStart			=	new Date.parseDate(res.s, '%Y-%m-%d');
			var resEnd				=	new Date.parseDate(res.e, '%Y-%m-%d');

			// if first reservation
			if(nbr == 0)
			{   // first block cand be empty, a reservation last day or reservation start
				switch(this._compareDate(calStart, resStart))
				{
					case -1:	this._createFirstArea(calStart, resStart);												
								break;
					case  0:	this._createBlockEnd('n', this._getClass(res.m, res.c), null, nbr);
								if(this.lim != null)	this.lim++;	
								break;
					case  1:	this._createFirstReservation(nbr, calStart, resEnd);break;
				}
				
			}
			// create reservation			
			if(this._compareDate(calStart, resStart) != 1)	this._createReservation(nbr, resStart, resEnd);
			// create reservation end and separation element
			if(nbr != this.res.length-1)
			{
				var nextResStart	=	new Date.parseDate(this.res[nbr+1].s, '%Y-%m-%d');
				
				if(this._compareDate(resEnd, nextResStart) != 0)
				{
					this._createBlockEnd(this._getClass(res.m, res.c), 'n', nbr, null);
					this._createFreeArea(resEnd, nextResStart);
					this._createBlockEnd('n', this._getClass(this.res[nbr+1].m, this.res[nbr+1].c), null, nbr+1);
					if(this.lim != null)	this.lim++;
				}
				else	this._createBlockEnd(this._getClass(res.m, res.c), this._getClass(this.res[nbr+1].m, this.res[nbr+1].c), nbr, nbr+1);
			}
			else if(this.stack.length > 0)
			{
				// fill with empty time
				this._createBlockEnd(this._getClass(res.m, res.c), 'n', nbr, null);
				this._createFreeArea(resEnd, calEnd);
				if(this.lim != null)	this.lim++;
			}
		}
	}
}
/*
 * Dump the calendar in a container DOM element.
 * 
 * Computes out of the css the dimensions for days and months.
 * To do this we'll be generating a  dummy container set to pick up the computed CSS values.
 * And then we remove it.	
 * 
 * Creates, days and months headers, then starts the generation of availability items.
 */
kigoCalendar.prototype.dump 					= 	function(elm)
{

	
	var months			        =	document.createElement('div');	
		elm.appendChild(months);								
		months.className		=	'months';
	
	var b	=	this.div.cloneNode(false);		
		b.className				=	'month';
		b.innerHTML = '<p>&nbsp;</p>';
		months.appendChild(b);					
	// we need to compute display values for the items out of CSS.
	// To do this we'll be generating a  dummy container set to pick up the computed CSS values.	
	//values required
	var dim = new Object();			
		dim.monthSize	=	b.clientWidth;
		dim.daySize	=	b.clientHeight;
						
	elm.removeChild(months);	
	//remove the dummy container
	
	var pointer =  elm.parentNode;
				
	// We are detaching the calendar from the DOM HERE in order to speed up the generation
	// Otherwise it will take too much time to render everything.
	
	this.container		=	vkDom.el(elm).cloneNode(false);		
	
	this.daySize		=	null;
	this.monthSize		=	null;
	var lines			=	(this.ey - this.sy) * 12 + (this.em - this.sm) + 1;
	var day, month;
	
	var days			=	this.div.cloneNode(false);	this.container.appendChild(days					);
	var months			=	this.div.cloneNode(false);	this.container.appendChild(months				);
	var reservations	=	this.div.cloneNode(false);	this.container.appendChild(reservations	);
	var clear			=	this.div.cloneNode(false);	this.container.appendChild(clear				);
	
	var todaysMonth = (new Date().print('%b %y'));
	var todaysDay = (new Date().print('%d'));
	
	
	for(month=0; month<lines; month++)
	{
		var m	=	this.sm + month - 1 - 12 * (Math.ceil((this.sm + month - 1) / 12) - 1);
		var y	=	this.sy + Math.ceil((this.sm + month - 1) / 12) - 1;
		var d	=	new Date(y, m);
		var b	=	this.div.cloneNode(false);
		var r	;
		var nbr	;
		
		this.md.push(d.getMonthDays());
		this.stack.push(d.getMonthDays());
		
		b.className				=	'month';
		b.appendChild(document.createTextNode(d.print('%b %y')));
		months.appendChild(b);
	
		if(this.monthSize 	== null)	this.monthSize	=	dim.monthSize;
		if(this.daySize 	== null)	this.daySize	=	dim.daySize;
		
		if(month == 0)				b.className	+=	' first';
		else if(month == lines-1)	b.className	+=	' last';
		else						b.className +=	' middle';
		
		if (d.print('%b %y') == todaysMonth) b.className +=	' today';
		
		b.className +=	(month % 2) ? ' even' : ' odd'; 
	}
	
	this.nbMonth	=	this.stack.length;
	
	for(day=0; day<=31; day++)
	{
		var b	=	this.div.cloneNode(false);
		var r;
		
		if (day == 0)	b.className				=	'month';
		else
		{
			b.className	=	'day';
			var z		=	(day<10)	?	'0'	:	'';
			b.appendChild(document.createTextNode(z+day));
		}
		if(day == 0 )		b.className +=	' corner';
		else if (day ==  1)	b.className += 	' first';
		else if (day == 31)	b.className += 	' last';
		else b.className += 	' middle';
		
		if (z+day == todaysDay) b.className +=	' today';
		
		if(day != 0)		b.className +=	(day % 2) ? ' odd' : ' even'; 
		days.appendChild(b);
	}
	
	days.style.width				=	this.monthSize	+ 	31*this.daySize		+'px';	days.style.height				=				this.daySize	+'px';	
	months.style.width				=	this.monthSize							+'px';	months.style.height				=	lines 	* 	this.daySize	+'px';	
	reservations.style.width	=							31*this.daySize		+'px';	reservations.style.height		=	lines	*	this.daySize	+'px';
	
	this.container.style.width		=	days.style.width;
	this.container.height			=	parseInt(days.style.height)	+	parseInt(months.style.height)	+'px';

	months.className			=	'months';
	days.className				=	'days';
	reservations.className		=	'reservations';
	clear.className				=	'clear';

	this._createReservations(reservations);
	
	pointer.replaceChild(this.container,elm);

	// 18/11/2009 - return the new container...
	return this.container;
}



/* ws/fastSearch/static/js/googleAnalytics.js */ /* UTF8-Côôkie */


vkDom.onLoad(
	function()
	{
		var	trackerLoaded = false;

		if(
			typeof(_GA) != 'undefined' &&
			_GA != null
		)
		{
			var	script = document.createElement('script');

			function	loadTracker()
			{
				if(trackerLoaded)
					return;
				trackerLoaded = true;

				try 
				{
					var pt = _gat._getTracker(_GA);
					pt._setAllowHash(false);
					pt._trackPageview();
				} catch(err) { }
			}

			if(vkDom.hasClass(document.body, 'ua-msie'))
			{
				// Only IE doesn't implement onload. 
				// Moreover, IE triggers "loaded" (but not "completed") on first load, and "completed" (but not "loaded") on subsequent calls
				script.onreadystatechange = function()
				{
					if(
						this.readyState == 'loaded' ||
						this.readyState == 'complete'
					)
						loadTracker();
				}
			}

			script.onload = loadTracker;

			script.type = 'text/javascript';

			if(typeof(script['defer']) != 'undefined')
				script.defer = true;

			script.src = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.") + 'google-analytics.com/ga.js';

			document.getElementsByTagName('head')[0].appendChild(script);
		}
	}
);


/*

Original code from Google:
--------------------------

<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
try {
var pageTracker = _gat._getTracker("UA-9438701-1");
pageTracker._trackPageview();
} catch(err) {}</script>

*/

/* ws/fastSearch/static/js/googleAdwords.js */ /* UTF8-Côôkie */


var	fsGoogleAdwords = function()
{
	var	obj = {
		'requests'	:	[],
		'record'	:	function(url)
		{
			var	img = new Image();
			img.src = url;
			this.requests.push(img);
		}
	};

	return obj;
}();


if(_GAW_PAGEVIEW != null)
{
	vkDom.onLoad(
		function()
		{
			fsGoogleAdwords.record(_GAW_PAGEVIEW);
		}
	);
}

/*  Copyright Mihai Bazon, 2002-2005  |  www.bazon.net/mishoo
 * -----------------------------------------------------------
 *
 * The DHTML Calendar, version 1.0 "It is happening again"
 *
 * Details and latest version at:
 * www.dynarch.com/projects/calendar
 *
 * This script is developed by Dynarch.com.  Visit us at www.dynarch.com.
 *
 * This script is distributed under the GNU Lesser General Public License.
 * Read the entire license text here: http://www.gnu.org/licenses/lgpl.html
 */

/*
28/06/2010 - Applied same bugfix as to the app's calendar.js - see related comments there
*/

 Calendar=function(firstDayOfWeek,dateStr,onSelected,onClose){this.activeDiv=null;this.currentDateEl=null;this.getDateStatus=null;this.getDateToolTip=null;this.getDateText=null;this.timeout=null;this.onSelected=onSelected||null;this.onClose=onClose||null;this.dragging=false;this.hidden=false;this.minYear=1970;this.maxYear=2050;this.dateFormat=Calendar._TT["DEF_DATE_FORMAT"];this.ttDateFormat=Calendar._TT["TT_DATE_FORMAT"];this.isPopup=true;this.weekNumbers=true;this.firstDayOfWeek=typeof firstDayOfWeek=="number"?firstDayOfWeek:Calendar._FD;this.showsOtherMonths=false;this.dateStr=dateStr;this.ar_days=null;this.showsTime=false;this.time24=true;this.yearStep=2;this.hiliteToday=true;this.multiple=null;this.table=null;this.element=null;this.tbody=null;this.firstdayname=null;this.monthsCombo=null;this.yearsCombo=null;this.hilitedMonth=null;this.activeMonth=null;this.hilitedYear=null;this.activeYear=null;this.dateClicked=false;if(typeof Calendar._SDN=="undefined"){if(typeof Calendar._SDN_len=="undefined")Calendar._SDN_len=3;var ar=new Array();for(var i=8;i>0;){ar[--i]=Calendar._DN[i].substr(0,Calendar._SDN_len);}Calendar._SDN=ar;if(typeof Calendar._SMN_len=="undefined")Calendar._SMN_len=3;ar=new Array();for(var i=12;i>0;){ar[--i]=Calendar._MN[i].substr(0,Calendar._SMN_len);}Calendar._SMN=ar;}};Calendar._C=null;Calendar.is_ie=(/msie/i.test(navigator.userAgent)&&!/opera/i.test(navigator.userAgent));Calendar.is_ie5=(Calendar.is_ie&&/msie 5\.0/i.test(navigator.userAgent));Calendar.is_opera=/opera/i.test(navigator.userAgent);Calendar.is_khtml=/Konqueror|Safari|KHTML/i.test(navigator.userAgent);Calendar.getAbsolutePos=function(el){var SL=0,ST=0;var is_div=/^div$/i.test(el.tagName);if(is_div&&el.scrollLeft)SL=el.scrollLeft;if(is_div&&el.scrollTop)ST=el.scrollTop;var r={x:el.offsetLeft-SL,y:el.offsetTop-ST};if(el.offsetParent){var tmp=this.getAbsolutePos(el.offsetParent);r.x+=tmp.x;r.y+=tmp.y;}return r;};Calendar.isRelated=function(el,evt){var related=evt.relatedTarget;if(!related){var type=evt.type;if(type=="mouseover"){related=evt.fromElement;}else if(type=="mouseout"){related=evt.toElement;}}while(related){if(related==el){return true;}related=related.parentNode;}return false;};Calendar.removeClass=function(el,className){if(!(el&&el.className)){return;}var cls=el.className.split(" ");var ar=new Array();for(var i=cls.length;i>0;){if(cls[--i]!=className){ar[ar.length]=cls[i];}}el.className=ar.join(" ");};Calendar.addClass=function(el,className){Calendar.removeClass(el,className);el.className+=" "+className;};Calendar.getElement=function(ev){var f=Calendar.is_ie?window.event.srcElement:ev.currentTarget;while(f.nodeType!=1||/^div$/i.test(f.tagName))f=f.parentNode;return f;};Calendar.getTargetElement=function(ev){var f=Calendar.is_ie?window.event.srcElement:ev.target;while(f.nodeType!=1)f=f.parentNode;return f;};Calendar.stopEvent=function(ev){ev||(ev=window.event);if(Calendar.is_ie){ev.cancelBubble=true;ev.returnValue=false;}else{ev.preventDefault();ev.stopPropagation();}return false;};Calendar.addEvent=function(el,evname,func){if(el.attachEvent){el.attachEvent("on"+evname,func);}else if(el.addEventListener){el.addEventListener(evname,func,true);}else{el["on"+evname]=func;}};Calendar.removeEvent=function(el,evname,func){if(el.detachEvent){el.detachEvent("on"+evname,func);}else if(el.removeEventListener){el.removeEventListener(evname,func,true);}else{el["on"+evname]=null;}};Calendar.createElement=function(type,parent){var el=null;if(document.createElementNS){el=document.createElementNS("http://www.w3.org/1999/xhtml",type);}else{el=document.createElement(type);}if(typeof parent!="undefined"){parent.appendChild(el);}return el;};Calendar._add_evs=function(el){with(Calendar){addEvent(el,"mouseover",dayMouseOver);addEvent(el,"mousedown",dayMouseDown);addEvent(el,"mouseout",dayMouseOut);if(is_ie){addEvent(el,"dblclick",dayMouseDblClick);el.setAttribute("unselectable",true);}}};Calendar.findMonth=function(el){if(typeof el.month!="undefined"){return el;}else if(typeof el.parentNode.month!="undefined"){return el.parentNode;}return null;};Calendar.findYear=function(el){if(typeof el.year!="undefined"){return el;}else if(typeof el.parentNode.year!="undefined"){return el.parentNode;}return null;};Calendar.showMonthsCombo=function(){var cal=Calendar._C;if(!cal){return false;}var cal=cal;var cd=cal.activeDiv;var mc=cal.monthsCombo;if(cal.hilitedMonth){Calendar.removeClass(cal.hilitedMonth,"hilite");}if(cal.activeMonth){Calendar.removeClass(cal.activeMonth,"active");}var mon=cal.monthsCombo.getElementsByTagName("div")[cal.date.getMonth()];Calendar.addClass(mon,"active");cal.activeMonth=mon;var s=mc.style;s.display="block";if(cd.navtype<0)s.left=cd.offsetLeft+"px";else{var mcw=mc.offsetWidth;if(typeof mcw=="undefined")mcw=50;s.left=(cd.offsetLeft+cd.offsetWidth-mcw)+"px";}s.top=(cd.offsetTop+cd.offsetHeight)+"px";};Calendar.showYearsCombo=function(fwd){var cal=Calendar._C;if(!cal){return false;}var cal=cal;var cd=cal.activeDiv;var yc=cal.yearsCombo;if(cal.hilitedYear){Calendar.removeClass(cal.hilitedYear,"hilite");}if(cal.activeYear){Calendar.removeClass(cal.activeYear,"active");}cal.activeYear=null;var Y=cal.date.getFullYear()+(fwd?1:-1);var yr=yc.firstChild;var show=false;for(var i=12;i>0;--i){if(Y>=cal.minYear&&Y<=cal.maxYear){yr.innerHTML=Y;yr.year=Y;yr.style.display="block";show=true;}else{yr.style.display="none";}yr=yr.nextSibling;Y+=fwd?cal.yearStep:-cal.yearStep;}if(show){var s=yc.style;s.display="block";if(cd.navtype<0)s.left=cd.offsetLeft+"px";else{var ycw=yc.offsetWidth;if(typeof ycw=="undefined")ycw=50;s.left=(cd.offsetLeft+cd.offsetWidth-ycw)+"px";}s.top=(cd.offsetTop+cd.offsetHeight)+"px";}};Calendar.tableMouseUp=function(ev){var cal=Calendar._C;if(!cal){return false;}if(cal.timeout){clearTimeout(cal.timeout);}var el=cal.activeDiv;if(!el){return false;}var target=Calendar.getTargetElement(ev);ev||(ev=window.event);Calendar.removeClass(el,"active");if(target==el||target.parentNode==el){Calendar.cellClick(el,ev);}var mon=Calendar.findMonth(target);var date=null;if(mon){date=new Date(cal.date);if(mon.month!=date.getMonth()){date.setMonth(mon.month);cal.setDate(date);cal.dateClicked=false;cal.callHandler();}}else{var year=Calendar.findYear(target);if(year){date=new Date(cal.date);if(year.year!=date.getFullYear()){date.setFullYear(year.year);cal.setDate(date);cal.dateClicked=false;cal.callHandler();}}}with(Calendar){removeEvent(document,"mouseup",tableMouseUp);removeEvent(document,"mouseover",tableMouseOver);removeEvent(document,"mousemove",tableMouseOver);cal._hideCombos();_C=null;return stopEvent(ev);}};Calendar.tableMouseOver=function(ev){var cal=Calendar._C;if(!cal){return;}var el=cal.activeDiv;var target=Calendar.getTargetElement(ev);if(target==el||target.parentNode==el){Calendar.addClass(el,"hilite active");Calendar.addClass(el.parentNode,"rowhilite");}else{if(typeof el.navtype=="undefined"||(el.navtype!=50&&(el.navtype==0||Math.abs(el.navtype)>2)))Calendar.removeClass(el,"active");Calendar.removeClass(el,"hilite");Calendar.removeClass(el.parentNode,"rowhilite");}ev||(ev=window.event);if(el.navtype==50&&target!=el){var pos=Calendar.getAbsolutePos(el);var w=el.offsetWidth;var x=ev.clientX;var dx;var decrease=true;if(x>pos.x+w){dx=x-pos.x-w;decrease=false;}else dx=pos.x-x;if(dx<0)dx=0;var range=el._range;var current=el._current;var count=Math.floor(dx/10)%range.length;for(var i=range.length;--i>=0;)if(range[i]==current)break;while(count-->0)if(decrease){if(--i<0)i=range.length-1;}else if(++i>=range.length)i=0;var newval=range[i];el.innerHTML=newval;cal.onUpdateTime();}var mon=Calendar.findMonth(target);if(mon){if(mon.month!=cal.date.getMonth()){if(cal.hilitedMonth){Calendar.removeClass(cal.hilitedMonth,"hilite");}Calendar.addClass(mon,"hilite");cal.hilitedMonth=mon;}else if(cal.hilitedMonth){Calendar.removeClass(cal.hilitedMonth,"hilite");}}else{if(cal.hilitedMonth){Calendar.removeClass(cal.hilitedMonth,"hilite");}var year=Calendar.findYear(target);if(year){if(year.year!=cal.date.getFullYear()){if(cal.hilitedYear){Calendar.removeClass(cal.hilitedYear,"hilite");}Calendar.addClass(year,"hilite");cal.hilitedYear=year;}else if(cal.hilitedYear){Calendar.removeClass(cal.hilitedYear,"hilite");}}else if(cal.hilitedYear){Calendar.removeClass(cal.hilitedYear,"hilite");}}return Calendar.stopEvent(ev);};Calendar.tableMouseDown=function(ev){if(Calendar.getTargetElement(ev)==Calendar.getElement(ev)){return Calendar.stopEvent(ev);}};Calendar.calDragIt=function(ev){var cal=Calendar._C;if(!(cal&&cal.dragging)){return false;}var posX;var posY;if(Calendar.is_ie){posY=window.event.clientY+document.body.scrollTop;posX=window.event.clientX+document.body.scrollLeft;}else{posX=ev.pageX;posY=ev.pageY;}cal.hideShowCovered();var st=cal.element.style;st.left=(posX-cal.xOffs)+"px";st.top=(posY-cal.yOffs)+"px";return Calendar.stopEvent(ev);};Calendar.calDragEnd=function(ev){var cal=Calendar._C;if(!cal){return false;}cal.dragging=false;with(Calendar){removeEvent(document,"mousemove",calDragIt);removeEvent(document,"mouseup",calDragEnd);tableMouseUp(ev);}cal.hideShowCovered();};Calendar.dayMouseDown=function(ev){var el=Calendar.getElement(ev);if(el.disabled){return false;}var cal=el.calendar;cal.activeDiv=el;Calendar._C=cal;if(el.navtype!=300)with(Calendar){if(el.navtype==50){el._current=el.innerHTML;addEvent(document,"mousemove",tableMouseOver);}else addEvent(document,Calendar.is_ie5?"mousemove":"mouseover",tableMouseOver);addClass(el,"hilite active");addEvent(document,"mouseup",tableMouseUp);}else if(cal.isPopup){cal._dragStart(ev);}if(el.navtype==-1||el.navtype==1){if(cal.timeout)clearTimeout(cal.timeout);cal.timeout=setTimeout("Calendar.showMonthsCombo()",250);}else if(el.navtype==-2||el.navtype==2){if(cal.timeout)clearTimeout(cal.timeout);cal.timeout=setTimeout((el.navtype>0)?"Calendar.showYearsCombo(true)":"Calendar.showYearsCombo(false)",250);}else{cal.timeout=null;}return Calendar.stopEvent(ev);};Calendar.dayMouseDblClick=function(ev){Calendar.cellClick(Calendar.getElement(ev),ev||window.event);if(Calendar.is_ie){document.selection.empty();}};Calendar.dayMouseOver=function(ev){var el=Calendar.getElement(ev);if(Calendar.isRelated(el,ev)||Calendar._C||el.disabled){return false;}if(el.ttip){if(el.ttip.substr(0,1)=="_"){el.ttip=el.caldate.print(el.calendar.ttDateFormat)+el.ttip.substr(1);}el.calendar.tooltips.innerHTML=el.ttip;}if(el.navtype!=300){Calendar.addClass(el,"hilite");if(el.caldate){Calendar.addClass(el.parentNode,"rowhilite");var cal=el.calendar;if(cal&&cal.getDateToolTip){var d=el.caldate;window.status=d;el.title=cal.getDateToolTip(d,d.getFullYear(),d.getMonth(),d.getDate());}}}return Calendar.stopEvent(ev);};Calendar.dayMouseOut=function(ev){with(Calendar){var el=getElement(ev);if(isRelated(el,ev)||_C||el.disabled)return false;removeClass(el,"hilite");if(el.caldate)removeClass(el.parentNode,"rowhilite");if(el.calendar)el.calendar.tooltips.innerHTML=_TT["SEL_DATE"];}};Calendar.cellClick=function(el,ev){var cal=el.calendar;var closing=false;var newdate=false;var date=null;if(typeof el.navtype=="undefined"){if(cal.currentDateEl){Calendar.removeClass(cal.currentDateEl,"selected");Calendar.addClass(el,"selected");closing=(cal.currentDateEl==el);if(!closing){cal.currentDateEl=el;}}cal.date.setDateOnly(el.caldate);date=cal.date;var other_month=!(cal.dateClicked=!el.otherMonth);if(!other_month&&!cal.currentDateEl&&cal.multiple)cal._toggleMultipleDate(new Date(date));else newdate=!el.disabled;if(other_month)cal._init(cal.firstDayOfWeek,date);}else{if(el.navtype==200){Calendar.removeClass(el,"hilite");cal.callCloseHandler();return;}date=new Date(cal.date);if(el.navtype==0)date.setDateOnly(new Date());cal.dateClicked=false;var year=date.getFullYear();var mon=date.getMonth();function setMonth(m){var day=date.getDate();var max=date.getMonthDays(m);if(day>max){date.setDate(max);}date.setMonth(m);};switch(el.navtype){case 400:Calendar.removeClass(el,"hilite");var text=Calendar._TT["ABOUT"];if(typeof text!="undefined"){text+=cal.showsTime?Calendar._TT["ABOUT_TIME"]:"";}else{text="Help and about box text is not translated into this language.\n"+"If you know this language and you feel generous please update\n"+"the corresponding file in \"lang\" subdir to match calendar-en.js\n"+"and send it back to <mihai_bazon@yahoo.com> to get it into the distribution  ;-)\n\n"+"Thank you!\n"+"http://dynarch.com/mishoo/calendar.epl\n";}alert(text);return;case-2:if(year>cal.minYear){date.setFullYear(year-1);}break;case-1:if(mon>0){setMonth(mon-1);}else if(year-->cal.minYear){date.setFullYear(year);setMonth(11);}break;case 1:if(mon<11){setMonth(mon+1);}else if(year<cal.maxYear){date.setFullYear(year+1);setMonth(0);}break;case 2:if(year<cal.maxYear){date.setFullYear(year+1);}break;case 100:cal.setFirstDayOfWeek(el.fdow);return;case 50:var range=el._range;var current=el.innerHTML;for(var i=range.length;--i>=0;)if(range[i]==current)break;if(ev&&ev.shiftKey){if(--i<0)i=range.length-1;}else if(++i>=range.length)i=0;var newval=range[i];el.innerHTML=newval;cal.onUpdateTime();return;case 0:if((typeof cal.getDateStatus=="function")&&cal.getDateStatus(date,date.getFullYear(),date.getMonth(),date.getDate())){return false;}break;}if(!date.equalsTo(cal.date)){cal.setDate(date);newdate=true;}else if(el.navtype==0)newdate=closing=true;}if(newdate){ev&&cal.callHandler();}if(closing){Calendar.removeClass(el,"hilite");ev&&cal.callCloseHandler();}};Calendar.prototype.create=function(_par){var parent=null;if(!_par){parent=document.getElementsByTagName("body")[0];this.isPopup=true;}else{parent=_par;this.isPopup=false;}this.date=this.dateStr?new Date(this.dateStr):new Date();var table=Calendar.createElement("table");this.table=table;table.cellSpacing=0;table.cellPadding=0;table.calendar=this;Calendar.addEvent(table,"mousedown",Calendar.tableMouseDown);var div=Calendar.createElement("div");this.element=div;div.className="calendar";if(this.isPopup){div.style.position="absolute";div.style.display="none";}div.appendChild(table);var thead=Calendar.createElement("thead",table);var cell=null;var row=null;var cal=this;var hh=function(text,cs,navtype){cell=Calendar.createElement("td",row);cell.colSpan=cs;cell.className="button";if(navtype!=0&&Math.abs(navtype)<=2)cell.className+=" nav";Calendar._add_evs(cell);cell.calendar=cal;cell.navtype=navtype;cell.innerHTML="<div unselectable='on'>"+text+"</div>";return cell;};row=Calendar.createElement("tr",thead);var title_length=6;(this.isPopup)&&--title_length;(this.weekNumbers)&&++title_length;hh("?",1,400).ttip=Calendar._TT["INFO"];this.title=hh("",title_length,300);this.title.className="title";if(this.isPopup){this.title.ttip=Calendar._TT["DRAG_TO_MOVE"];this.title.style.cursor="move";hh("&#x00d7;",1,200).ttip=Calendar._TT["CLOSE"];}row=Calendar.createElement("tr",thead);row.className="headrow";this._nav_py=hh("&#x00ab;",1,-2);this._nav_py.ttip=Calendar._TT["PREV_YEAR"];this._nav_pm=hh("&#x2039;",1,-1);this._nav_pm.ttip=Calendar._TT["PREV_MONTH"];this._nav_now=hh(Calendar._TT["TODAY"],this.weekNumbers?4:3,0);this._nav_now.ttip=Calendar._TT["GO_TODAY"];this._nav_nm=hh("&#x203a;",1,1);this._nav_nm.ttip=Calendar._TT["NEXT_MONTH"];this._nav_ny=hh("&#x00bb;",1,2);this._nav_ny.ttip=Calendar._TT["NEXT_YEAR"];row=Calendar.createElement("tr",thead);row.className="daynames";if(this.weekNumbers){cell=Calendar.createElement("td",row);cell.className="name wn";cell.innerHTML=Calendar._TT["WK"];}for(var i=7;i>0;--i){cell=Calendar.createElement("td",row);if(!i){cell.navtype=100;cell.calendar=this;Calendar._add_evs(cell);}}this.firstdayname=(this.weekNumbers)?row.firstChild.nextSibling:row.firstChild;this._displayWeekdays();var tbody=Calendar.createElement("tbody",table);this.tbody=tbody;for(i=6;i>0;--i){row=Calendar.createElement("tr",tbody);if(this.weekNumbers){cell=Calendar.createElement("td",row);}for(var j=7;j>0;--j){cell=Calendar.createElement("td",row);cell.calendar=this;Calendar._add_evs(cell);}}if(this.showsTime){row=Calendar.createElement("tr",tbody);row.className="time";cell=Calendar.createElement("td",row);cell.className="time";cell.colSpan=2;cell.innerHTML=Calendar._TT["TIME"]||"&nbsp;";cell=Calendar.createElement("td",row);cell.className="time";cell.colSpan=this.weekNumbers?4:3;(function(){function makeTimePart(className,init,range_start,range_end){var part=Calendar.createElement("span",cell);part.className=className;part.innerHTML=init;part.calendar=cal;part.ttip=Calendar._TT["TIME_PART"];part.navtype=50;part._range=[];if(typeof range_start!="number")part._range=range_start;else{for(var i=range_start;i<=range_end;++i){var txt;if(i<10&&range_end>=10)txt='0'+i;else txt=''+i;part._range[part._range.length]=txt;}}Calendar._add_evs(part);return part;};var hrs=cal.date.getHours();var mins=cal.date.getMinutes();var t12=!cal.time24;var pm=(hrs>12);if(t12&&pm)hrs-=12;var H=makeTimePart("hour",hrs,t12?1:0,t12?12:23);var span=Calendar.createElement("span",cell);span.innerHTML=":";span.className="colon";var M=makeTimePart("minute",mins,0,59);var AP=null;cell=Calendar.createElement("td",row);cell.className="time";cell.colSpan=2;if(t12)AP=makeTimePart("ampm",pm?"pm":"am",["am","pm"]);else cell.innerHTML="&nbsp;";cal.onSetTime=function(){var pm,hrs=this.date.getHours(),mins=this.date.getMinutes();if(t12){pm=(hrs>=12);if(pm)hrs-=12;if(hrs==0)hrs=12;AP.innerHTML=pm?"pm":"am";}H.innerHTML=(hrs<10)?("0"+hrs):hrs;M.innerHTML=(mins<10)?("0"+mins):mins;};cal.onUpdateTime=function(){var date=this.date;var h=parseInt(H.innerHTML,10);if(t12){if(/pm/i.test(AP.innerHTML)&&h<12)h+=12;else if(/am/i.test(AP.innerHTML)&&h==12)h=0;}var d=date.getDate();var m=date.getMonth();var y=date.getFullYear();date.setHours(h);date.setMinutes(parseInt(M.innerHTML,10));date.setFullYear(y);date.setMonth(m);date.setDate(d);this.dateClicked=false;this.callHandler();};})();}else{this.onSetTime=this.onUpdateTime=function(){};}var tfoot=Calendar.createElement("tfoot",table);row=Calendar.createElement("tr",tfoot);row.className="footrow";cell=hh(Calendar._TT["SEL_DATE"],this.weekNumbers?8:7,300);cell.className="ttip";if(this.isPopup){cell.ttip=Calendar._TT["DRAG_TO_MOVE"];cell.style.cursor="move";}this.tooltips=cell;div=Calendar.createElement("div",this.element);this.monthsCombo=div;div.className="combo";for(i=0;i<Calendar._MN.length;++i){var mn=Calendar.createElement("div");mn.className=Calendar.is_ie?"label-IEfix":"label";mn.month=i;mn.innerHTML=Calendar._SMN[i];div.appendChild(mn);}div=Calendar.createElement("div",this.element);this.yearsCombo=div;div.className="combo";for(i=12;i>0;--i){var yr=Calendar.createElement("div");yr.className=Calendar.is_ie?"label-IEfix":"label";div.appendChild(yr);}this._init(this.firstDayOfWeek,this.date);parent.appendChild(this.element);};Calendar._keyEvent=function(ev){var cal=window._dynarch_popupCalendar;if(!cal||cal.multiple)return false;(Calendar.is_ie)&&(ev=window.event);var act=(Calendar.is_ie||ev.type=="keypress"),K=ev.keyCode;if(ev.ctrlKey){switch(K){case 37:act&&Calendar.cellClick(cal._nav_pm);break;case 38:act&&Calendar.cellClick(cal._nav_py);break;case 39:act&&Calendar.cellClick(cal._nav_nm);break;case 40:act&&Calendar.cellClick(cal._nav_ny);break;default:return false;}}else switch(K){case 32:Calendar.cellClick(cal._nav_now);break;case 27:act&&cal.callCloseHandler();break;case 37:case 38:case 39:case 40:if(act){var prev,x,y,ne,el,step;prev=K==37||K==38;step=(K==37||K==39)?1:7;function setVars(){el=cal.currentDateEl;var p=el.pos;x=p&15;y=p>>4;ne=cal.ar_days[y][x];};setVars();function prevMonth(){var date=new Date(cal.date);date.setDate(date.getDate()-step);cal.setDate(date);};function nextMonth(){var date=new Date(cal.date);date.setDate(date.getDate()+step);cal.setDate(date);};while(1){switch(K){case 37:if(--x>=0)ne=cal.ar_days[y][x];else{x=6;K=38;continue;}break;case 38:if(--y>=0)ne=cal.ar_days[y][x];else{prevMonth();setVars();}break;case 39:if(++x<7)ne=cal.ar_days[y][x];else{x=0;K=40;continue;}break;case 40:if(++y<cal.ar_days.length)ne=cal.ar_days[y][x];else{nextMonth();setVars();}break;}break;}if(ne){if(!ne.disabled)Calendar.cellClick(ne);else if(prev)prevMonth();else nextMonth();}}break;case 13:if(act)Calendar.cellClick(cal.currentDateEl,ev);break;default:return false;}return Calendar.stopEvent(ev);};Calendar.prototype._init=function(firstDayOfWeek,date){var today=new Date(),TY=today.getFullYear(),TM=today.getMonth(),TD=today.getDate();this.table.style.visibility="hidden";var year=date.getFullYear();if(year<this.minYear){year=this.minYear;date.setFullYear(year);}else if(year>this.maxYear){year=this.maxYear;date.setFullYear(year);}this.firstDayOfWeek=firstDayOfWeek;this.date=new Date(date);var month=date.getMonth();var mday=date.getDate();var no_days=date.getMonthDays();date.setDate(1);var day1=(date.getDay()-this.firstDayOfWeek)%7;if(day1<0)day1+=7;date.setDate(day1 == 0 ? 0 : (day1 < 0 ? Math.abs(day1) : 0 - day1));date.setDate(date.getDate()+1);var row=this.tbody.firstChild;var MN=Calendar._SMN[month];var ar_days=this.ar_days=new Array();var weekend=Calendar._TT["WEEKEND"];var dates=this.multiple?(this.datesCells={}):null;for(var i=0;i<6;++i,row=row.nextSibling){var cell=row.firstChild;if(this.weekNumbers){cell.className="day wn";cell.innerHTML=date.getWeekNumber();cell=cell.nextSibling;}row.className="daysrow";var hasdays=false,iday,dpos=ar_days[i]=[];for(var j=0;j<7;++j,cell=cell.nextSibling,date.setDate(iday+1)){iday=date.getDate();var wday=date.getDay();cell.className="day";cell.pos=i<<4|j;dpos[j]=cell;var current_month=(date.getMonth()==month);if(!current_month){if(this.showsOtherMonths){cell.className+=" othermonth";cell.otherMonth=true;}else{cell.className="emptycell";cell.innerHTML="&nbsp;";cell.disabled=true;continue;}}else{cell.otherMonth=false;hasdays=true;}cell.disabled=false;cell.innerHTML=this.getDateText?this.getDateText(date,iday):iday;if(dates)dates[date.print("%Y%m%d")]=cell;if(this.getDateStatus){var status=this.getDateStatus(date,year,month,iday);if(status===true){cell.className+=" disabled";cell.disabled=true;}else{if(/disabled/i.test(status))cell.disabled=true;cell.className+=" "+status;}}if(!cell.disabled){cell.caldate=new Date(date);cell.ttip="_";if(!this.multiple&&current_month&&iday==mday&&this.hiliteToday){cell.className+=" selected";this.currentDateEl=cell;}if(date.getFullYear()==TY&&date.getMonth()==TM&&iday==TD){cell.className+=" today";cell.ttip+=Calendar._TT["PART_TODAY"];}if(weekend.indexOf(wday.toString())!=-1)cell.className+=cell.otherMonth?" oweekend":" weekend";}}if(!(hasdays||this.showsOtherMonths))row.className="emptyrow";}this.title.innerHTML=Calendar._MN[month]+", "+year;this.onSetTime();this.table.style.visibility="visible";this._initMultipleDates();};Calendar.prototype._initMultipleDates=function(){if(this.multiple){for(var i in this.multiple){var cell=this.datesCells[i];var d=this.multiple[i];if(!d)continue;if(cell)cell.className+=" selected";}}};Calendar.prototype._toggleMultipleDate=function(date){if(this.multiple){var ds=date.print("%Y%m%d");var cell=this.datesCells[ds];if(cell){var d=this.multiple[ds];if(!d){Calendar.addClass(cell,"selected");this.multiple[ds]=date;}else{Calendar.removeClass(cell,"selected");delete this.multiple[ds];}}}};Calendar.prototype.setDateToolTipHandler=function(unaryFunction){this.getDateToolTip=unaryFunction;};Calendar.prototype.setDate=function(date){if(!date.equalsTo(this.date)){this._init(this.firstDayOfWeek,date);}};Calendar.prototype.refresh=function(){this._init(this.firstDayOfWeek,this.date);};Calendar.prototype.setFirstDayOfWeek=function(firstDayOfWeek){this._init(firstDayOfWeek,this.date);this._displayWeekdays();};Calendar.prototype.setDateStatusHandler=Calendar.prototype.setDisabledHandler=function(unaryFunction){this.getDateStatus=unaryFunction;};Calendar.prototype.setRange=function(a,z){this.minYear=a;this.maxYear=z;};Calendar.prototype.callHandler=function(){if(this.onSelected){this.onSelected(this,this.date.print(this.dateFormat));}};Calendar.prototype.callCloseHandler=function(){if(this.onClose){this.onClose(this);}this.hideShowCovered();};Calendar.prototype.destroy=function(){var el=this.element.parentNode;el.removeChild(this.element);Calendar._C=null;window._dynarch_popupCalendar=null;};Calendar.prototype.reparent=function(new_parent){var el=this.element;el.parentNode.removeChild(el);new_parent.appendChild(el);};Calendar._checkCalendar=function(ev){var calendar=window._dynarch_popupCalendar;if(!calendar){return false;}var el=Calendar.is_ie?Calendar.getElement(ev):Calendar.getTargetElement(ev);for(;el!=null&&el!=calendar.element;el=el.parentNode);if(el==null){window._dynarch_popupCalendar.callCloseHandler();return Calendar.stopEvent(ev);}};Calendar.prototype.show=function(){var rows=this.table.getElementsByTagName("tr");for(var i=rows.length;i>0;){var row=rows[--i];Calendar.removeClass(row,"rowhilite");var cells=row.getElementsByTagName("td");for(var j=cells.length;j>0;){var cell=cells[--j];Calendar.removeClass(cell,"hilite");Calendar.removeClass(cell,"active");}}this.element.style.display="block";this.hidden=false;if(this.isPopup){window._dynarch_popupCalendar=this;Calendar.addEvent(document,"keydown",Calendar._keyEvent);Calendar.addEvent(document,"keypress",Calendar._keyEvent);Calendar.addEvent(document,"mousedown",Calendar._checkCalendar);}this.hideShowCovered();};Calendar.prototype.hide=function(){if(this.isPopup){Calendar.removeEvent(document,"keydown",Calendar._keyEvent);Calendar.removeEvent(document,"keypress",Calendar._keyEvent);Calendar.removeEvent(document,"mousedown",Calendar._checkCalendar);}this.element.style.display="none";this.hidden=true;this.hideShowCovered();};Calendar.prototype.showAt=function(x,y){var s=this.element.style;s.left=x+"px";s.top=y+"px";this.show();};Calendar.prototype.showAtElement=function(el,opts){var self=this;var p=Calendar.getAbsolutePos(el);if(!opts||typeof opts!="string"){this.showAt(p.x,p.y+el.offsetHeight);return true;}function fixPosition(box){if(box.x<0)box.x=0;if(box.y<0)box.y=0;var cp=document.createElement("div");var s=cp.style;s.position="absolute";s.right=s.bottom=s.width=s.height="0px";document.body.appendChild(cp);var br=Calendar.getAbsolutePos(cp);document.body.removeChild(cp);if(Calendar.is_ie){br.y+=document.body.scrollTop;br.x+=document.body.scrollLeft;}else{br.y+=window.scrollY;br.x+=window.scrollX;}var tmp=box.x+box.width-br.x;if(tmp>0)box.x-=tmp;tmp=box.y+box.height-br.y;if(tmp>0)box.y-=tmp;};this.element.style.display="block";Calendar.continuation_for_the_fucking_khtml_browser=function(){var w=self.element.offsetWidth;var h=self.element.offsetHeight;self.element.style.display="none";var valign=opts.substr(0,1);var halign="l";if(opts.length>1){halign=opts.substr(1,1);}switch(valign){case "T":p.y-=h;break;case "B":p.y+=el.offsetHeight;break;case "C":p.y+=(el.offsetHeight-h)/2;break;case "t":p.y+=el.offsetHeight-h;break;case "b":break;}switch(halign){case "L":p.x-=w;break;case "R":p.x+=el.offsetWidth;break;case "C":p.x+=(el.offsetWidth-w)/2;break;case "l":p.x+=el.offsetWidth-w;break;case "r":break;}p.width=w;p.height=h+40;self.monthsCombo.style.display="none";fixPosition(p);self.showAt(p.x,p.y);};if(Calendar.is_khtml)setTimeout("Calendar.continuation_for_the_fucking_khtml_browser()",10);else Calendar.continuation_for_the_fucking_khtml_browser();};Calendar.prototype.setDateFormat=function(str){this.dateFormat=str;};Calendar.prototype.setTtDateFormat=function(str){this.ttDateFormat=str;};Calendar.prototype.parseDate=function(str,fmt){if(!fmt)fmt=this.dateFormat;this.setDate(Date.parseDate(str,fmt));};Calendar.prototype.hideShowCovered=function(){if(!Calendar.is_ie&&!Calendar.is_opera)return;function getVisib(obj){var value=obj.style.visibility;if(!value){if(document.defaultView&&typeof(document.defaultView.getComputedStyle)=="function"){if(!Calendar.is_khtml)value=document.defaultView. getComputedStyle(obj,"").getPropertyValue("visibility");else value='';}else if(obj.currentStyle){value=obj.currentStyle.visibility;}else value='';}return value;};var tags=new Array("applet","iframe","select");var el=this.element;var p=Calendar.getAbsolutePos(el);var EX1=p.x;var EX2=el.offsetWidth+EX1;var EY1=p.y;var EY2=el.offsetHeight+EY1;for(var k=tags.length;k>0;){var ar=document.getElementsByTagName(tags[--k]);var cc=null;for(var i=ar.length;i>0;){cc=ar[--i];p=Calendar.getAbsolutePos(cc);var CX1=p.x;var CX2=cc.offsetWidth+CX1;var CY1=p.y;var CY2=cc.offsetHeight+CY1;if(this.hidden||(CX1>EX2)||(CX2<EX1)||(CY1>EY2)||(CY2<EY1)){if(!cc.__msh_save_visibility){cc.__msh_save_visibility=getVisib(cc);}cc.style.visibility=cc.__msh_save_visibility;}else{if(!cc.__msh_save_visibility){cc.__msh_save_visibility=getVisib(cc);}cc.style.visibility="hidden";}}}};Calendar.prototype._displayWeekdays=function(){var fdow=this.firstDayOfWeek;var cell=this.firstdayname;var weekend=Calendar._TT["WEEKEND"];for(var i=0;i<7;++i){cell.className="day name";var realday=(i+fdow)%7;if(i){cell.ttip=Calendar._TT["DAY_FIRST"].replace("%s",Calendar._DN[realday]);cell.navtype=100;cell.calendar=this;cell.fdow=realday;Calendar._add_evs(cell);}if(weekend.indexOf(realday.toString())!=-1){Calendar.addClass(cell,"weekend");}cell.innerHTML=Calendar._SDN[(i+fdow)%7];cell=cell.nextSibling;}};Calendar.prototype._hideCombos=function(){this.monthsCombo.style.display="none";this.yearsCombo.style.display="none";};Calendar.prototype._dragStart=function(ev){if(this.dragging){return;}this.dragging=true;var posX;var posY;if(Calendar.is_ie){posY=window.event.clientY+document.body.scrollTop;posX=window.event.clientX+document.body.scrollLeft;}else{posY=ev.clientY+window.scrollY;posX=ev.clientX+window.scrollX;}var st=this.element.style;this.xOffs=posX-parseInt(st.left);this.yOffs=posY-parseInt(st.top);with(Calendar){addEvent(document,"mousemove",calDragIt);addEvent(document,"mouseup",calDragEnd);}};Date._MD=new Array(31,28,31,30,31,30,31,31,30,31,30,31);Date.SECOND=1000;Date.MINUTE=60*Date.SECOND;Date.HOUR=60*Date.MINUTE;Date.DAY=24*Date.HOUR;Date.WEEK=7*Date.DAY;Date.parseDate=function(str,fmt){var today=new Date();var y=0;var m=-1;var d=0;var a=str.split(/\W+/);var b=fmt.match(/%./g);var i=0,j=0;var hr=0;var min=0;for(i=0;i<a.length;++i){if(!a[i])continue;switch(b[i]){case "%d":case "%e":d=parseInt(a[i],10);break;case "%m":m=parseInt(a[i],10)-1;break;case "%Y":case "%y":y=parseInt(a[i],10);(y<100)&&(y+=(y>29)?1900:2000);break;case "%b":case "%B":for(j=0;j<12;++j){if(Calendar._MN[j].substr(0,a[i].length).toLowerCase()==a[i].toLowerCase()){m=j;break;}}break;case "%H":case "%I":case "%k":case "%l":hr=parseInt(a[i],10);break;case "%P":case "%p":if(/pm/i.test(a[i])&&hr<12)hr+=12;else if(/am/i.test(a[i])&&hr>=12)hr-=12;break;case "%M":min=parseInt(a[i],10);break;}}if(isNaN(y))y=today.getFullYear();if(isNaN(m))m=today.getMonth();if(isNaN(d))d=today.getDate();if(isNaN(hr))hr=today.getHours();if(isNaN(min))min=today.getMinutes();if(y!=0&&m!=-1&&d!=0)return new Date(y,m,d,hr,min,0);y=0;m=-1;d=0;for(i=0;i<a.length;++i){if(a[i].search(/[a-zA-Z]+/)!=-1){var t=-1;for(j=0;j<12;++j){if(Calendar._MN[j].substr(0,a[i].length).toLowerCase()==a[i].toLowerCase()){t=j;break;}}if(t!=-1){if(m!=-1){d=m+1;}m=t;}}else if(parseInt(a[i],10)<=12&&m==-1){m=a[i]-1;}else if(parseInt(a[i],10)>31&&y==0){y=parseInt(a[i],10);(y<100)&&(y+=(y>29)?1900:2000);}else if(d==0){d=a[i];}}if(y==0)y=today.getFullYear();if(m!=-1&&d!=0)return new Date(y,m,d,hr,min,0);return today;};Date.prototype.getMonthDays=function(month){var year=this.getFullYear();if(typeof month=="undefined"){month=this.getMonth();}if(((0==(year%4))&&((0!=(year%100))||(0==(year%400))))&&month==1){return 29;}else{return Date._MD[month];}};Date.prototype.getDayOfYear=function(){var now=new Date(this.getFullYear(),this.getMonth(),this.getDate(),0,0,0);var then=new Date(this.getFullYear(),0,0,0,0,0);var time=now-then;return Math.floor(time/Date.DAY);};Date.prototype.getWeekNumber=function(){var d=new Date(this.getFullYear(),this.getMonth(),this.getDate(),0,0,0);var DoW=d.getDay();d.setDate(d.getDate()-(DoW+6)%7+3);var ms=d.valueOf();d.setMonth(0);d.setDate(4);return Math.round((ms-d.valueOf())/(7*864e5))+1;};Date.prototype.equalsTo=function(date){return((this.getFullYear()==date.getFullYear())&&(this.getMonth()==date.getMonth())&&(this.getDate()==date.getDate())&&(this.getHours()==date.getHours())&&(this.getMinutes()==date.getMinutes()));};Date.prototype.setDateOnly=function(date){var tmp=new Date(date);this.setDate(1);this.setFullYear(tmp.getFullYear());this.setMonth(tmp.getMonth());this.setDate(tmp.getDate());};Date.prototype.print=function(str){var m=this.getMonth();var d=this.getDate();var y=this.getFullYear();var wn=this.getWeekNumber();var w=this.getDay();var s={};var hr=this.getHours();var pm=(hr>=12);var ir=(pm)?(hr-12):hr;var dy=this.getDayOfYear();if(ir==0)ir=12;var min=this.getMinutes();var sec=this.getSeconds();s["%a"]=Calendar._SDN[w];s["%A"]=Calendar._DN[w];s["%b"]=Calendar._SMN[m];s["%B"]=Calendar._MN[m];s["%C"]=1+Math.floor(y/100);s["%d"]=(d<10)?("0"+d):d;s["%e"]=d;s["%H"]=(hr<10)?("0"+hr):hr;s["%I"]=(ir<10)?("0"+ir):ir;s["%j"]=(dy<100)?((dy<10)?("00"+dy):("0"+dy)):dy;s["%k"]=hr;s["%l"]=ir;s["%m"]=(m<9)?("0"+(1+m)):(1+m);s["%M"]=(min<10)?("0"+min):min;s["%n"]="\n";s["%p"]=pm?"PM":"AM";s["%P"]=pm?"pm":"am";s["%s"]=Math.floor(this.getTime()/1000);s["%S"]=(sec<10)?("0"+sec):sec;s["%t"]="\t";s["%U"]=s["%W"]=s["%V"]=(wn<10)?("0"+wn):wn;s["%u"]=w+1;s["%w"]=w;s["%y"]=(''+y).substr(2,2);s["%Y"]=y;s["%%"]="%";var re=/%./g;if(!Calendar.is_ie5&&!Calendar.is_khtml)return str.replace(re,function(par){return s[par]||par;});var a=str.match(re);for(var i=0;i<a.length;i++){var tmp=s[a[i]];if(tmp){re=new RegExp(a[i],'g');str=str.replace(re,tmp);}}return str;};Date.prototype.__msh_oldSetFullYear=Date.prototype.setFullYear;Date.prototype.setFullYear=function(y){var d=new Date(this);d.__msh_oldSetFullYear(y);if(d.getMonth()!=this.getMonth())this.setDate(28);this.__msh_oldSetFullYear(y);};window._dynarch_popupCalendar=null;
/*  Copyright Mihai Bazon, 2002, 2003  |  http://dynarch.com/mishoo/
 * ---------------------------------------------------------------------------
 *
 * The DHTML Calendar
 *
 * Details and latest version at:
 * http://dynarch.com/mishoo/calendar.epl
 *
 * This script is distributed under the GNU Lesser General Public License.
 * Read the entire license text here: http://www.gnu.org/licenses/lgpl.html
 *
 * This file defines helper functions for setting up the calendar.  They are
 * intended to help non-programmers get a working calendar on their site
 * quickly.  This script should not be seen as part of the calendar.  It just
 * shows you what one can do with the calendar, while in the same time
 * providing a quick and simple method for setting it up.  If you need
 * exhaustive customization of the calendar creation process feel free to
 * modify this code to suit your needs (this is recommended and much better
 * than modifying calendar.js itself).
 */
 Calendar.setup=function(params){function param_default(pname,def){if(typeof params[pname]=="undefined"){params[pname]=def;}};param_default("inputField",null);param_default("displayArea",null);param_default("button",null);param_default("eventName","click");param_default("ifFormat","%Y/%m/%d");param_default("daFormat","%Y/%m/%d");param_default("singleClick",true);param_default("disableFunc",null);param_default("dateStatusFunc",params["disableFunc"]);param_default("dateTooltipFunc",null);param_default("dateText",null);param_default("firstDay",null);param_default("align","Br");param_default("range",[1900,2999]);param_default("weekNumbers",true);param_default("flat",null);param_default("flatCallback",null);param_default("onSelect",null);param_default("onClose",null);param_default("onUpdate",null);param_default("date",null);param_default("showsTime",false);param_default("timeFormat","24");param_default("electric",true);param_default("step",2);param_default("position",null);param_default("cache",false);param_default("showOthers",false);param_default("multiple",null);var tmp=["inputField","displayArea","button"];for(var i in tmp){if(typeof params[tmp[i]]=="string"){params[tmp[i]]=document.getElementById(params[tmp[i]]);}}if(!(params.flat||params.multiple||params.inputField||params.displayArea||params.button)){alert("Calendar.setup:\n  Nothing to setup (no fields found).  Please check your code");return false;}function onSelect(cal){var p=cal.params;var update=(cal.dateClicked||p.electric);if(update&&p.inputField){p.inputField.value=cal.date.print(p.ifFormat);if(typeof p.inputField.onchange=="function")p.inputField.onchange();}if(update&&p.displayArea)p.displayArea.innerHTML=cal.date.print(p.daFormat);if(update&&typeof p.onUpdate=="function")p.onUpdate(cal);if(update&&p.flat){if(typeof p.flatCallback=="function")p.flatCallback(cal);}if(update&&p.singleClick&&cal.dateClicked)cal.callCloseHandler();};if(params.flat!=null){if(typeof params.flat=="string")params.flat=document.getElementById(params.flat);if(!params.flat){alert("Calendar.setup:\n  Flat specified but can't find parent.");return false;}var cal=new Calendar(params.firstDay,params.date,params.onSelect||onSelect);cal.setDateToolTipHandler(params.dateTooltipFunc);cal.showsOtherMonths=params.showOthers;cal.showsTime=params.showsTime;cal.time24=(params.timeFormat=="24");cal.params=params;cal.weekNumbers=params.weekNumbers;cal.setRange(params.range[0],params.range[1]);cal.setDateStatusHandler(params.dateStatusFunc);cal.getDateText=params.dateText;if(params.ifFormat){cal.setDateFormat(params.ifFormat);}if(params.inputField&&typeof params.inputField.value=="string"){cal.parseDate(params.inputField.value);}cal.create(params.flat);cal.show();return false;}var triggerEl=params.button||params.displayArea||params.inputField;triggerEl["on"+params.eventName]=function(){var dateEl=params.inputField||params.displayArea;var dateFmt=params.inputField?params.ifFormat:params.daFormat;var mustCreate=false;var cal=window.calendar;if(dateEl)params.date=Date.parseDate(dateEl.value||dateEl.innerHTML,dateFmt);if(!(cal&&params.cache)){window.calendar=cal=new Calendar(params.firstDay,params.date,params.onSelect||onSelect,params.onClose||function(cal){cal.hide();});cal.setDateToolTipHandler(params.dateTooltipFunc);cal.showsTime=params.showsTime;cal.time24=(params.timeFormat=="24");cal.weekNumbers=params.weekNumbers;mustCreate=true;}else{if(params.date)cal.setDate(params.date);cal.hide();}if(params.multiple){cal.multiple={};for(var i=params.multiple.length;--i>=0;){var d=params.multiple[i];var ds=d.print("%Y%m%d");cal.multiple[ds]=d;}}cal.showsOtherMonths=params.showOthers;cal.yearStep=params.step;cal.setRange(params.range[0],params.range[1]);cal.params=params;cal.setDateStatusHandler(params.dateStatusFunc);cal.getDateText=params.dateText;cal.setDateFormat(dateFmt);if(mustCreate)cal.create();cal.refresh();if(!params.position)cal.showAtElement(params.button||params.displayArea||params.inputField,params.align);else cal.showAt(params.position[0],params.position[1]);return false;};return cal;};
// ** I18N

// Calendar EN language
// Author: Mihai Bazon, <mihai_bazon@yahoo.com>
// Encoding: any
// Distributed under the same terms as the calendar itself.

// For translators: please use UTF-8 if possible.  We strongly believe that
// Unicode is the answer to a real internationalized world.  Also please
// include your contact information in the header, as can be seen above.

// full day names
Calendar._DN = new Array
("Sunday",
 "Monday",
 "Tuesday",
 "Wednesday",
 "Thursday",
 "Friday",
 "Saturday",
 "Sunday");

// Please note that the following array of short day names (and the same goes
// for short month names, _SMN) isn't absolutely necessary.  We give it here
// for exemplification on how one can customize the short day names, but if
// they are simply the first N letters of the full name you can simply say:
//
//   Calendar._SDN_len = N; // short day name length
//   Calendar._SMN_len = N; // short month name length
//
// If N = 3 then this is not needed either since we assume a value of 3 if not
// present, to be compatible with translation files that were written before
// this feature.

// short day names
Calendar._SDN = new Array
("Sun",
 "Mon",
 "Tue",
 "Wed",
 "Thu",
 "Fri",
 "Sat",
 "Sun");

// First day of the week. "0" means display Sunday first, "1" means display
// Monday first, etc.
Calendar._FD = 0;

// full month names
Calendar._MN = new Array
("January",
 "February",
 "March",
 "April",
 "May",
 "June",
 "July",
 "August",
 "September",
 "October",
 "November",
 "December");

// short month names
Calendar._SMN = new Array
("Jan",
 "Feb",
 "Mar",
 "Apr",
 "May",
 "Jun",
 "Jul",
 "Aug",
 "Sep",
 "Oct",
 "Nov",
 "Dec");

// tooltips
Calendar._TT = {};
Calendar._TT["INFO"] = "About the calendar";

Calendar._TT["ABOUT"] =
"DHTML Date/Time Selector\n" +
"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-)
"For latest version visit: http://www.dynarch.com/projects/calendar/\n" +
"Distributed under GNU LGPL.  See http://gnu.org/licenses/lgpl.html for details." +
"\n\n" +
"Date selection:\n" +
"- Use the \xab, \xbb buttons to select year\n" +
"- Use the " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " buttons to select month\n" +
"- Hold mouse button on any of the above buttons for faster selection.";
Calendar._TT["ABOUT_TIME"] = "\n\n" +
"Time selection:\n" +
"- Click on any of the time parts to increase it\n" +
"- or Shift-click to decrease it\n" +
"- or click and drag for faster selection.";

Calendar._TT["PREV_YEAR"] = "Prev. year (hold for menu)";
Calendar._TT["PREV_MONTH"] = "Prev. month (hold for menu)";
Calendar._TT["GO_TODAY"] = "Go Today";
Calendar._TT["NEXT_MONTH"] = "Next month (hold for menu)";
Calendar._TT["NEXT_YEAR"] = "Next year (hold for menu)";
Calendar._TT["SEL_DATE"] = "Select date";
Calendar._TT["DRAG_TO_MOVE"] = "Drag to move";
Calendar._TT["PART_TODAY"] = " (today)";

// the following is to inform that "%s" is to be the first day of week
// %s will be replaced with the day name.
Calendar._TT["DAY_FIRST"] = "Display %s first";

// This may be locale-dependent.  It specifies the week-end days, as an array
// of comma-separated numbers.  The numbers are from 0 to 6: 0 means Sunday, 1
// means Monday, etc.
Calendar._TT["WEEKEND"] = "0,6";

Calendar._TT["CLOSE"] = "Close";
Calendar._TT["TODAY"] = "Today";
Calendar._TT["TIME_PART"] = "(Shift-)Click or drag to change value";

// date formats
Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d";
Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e";

Calendar._TT["WK"] = "wk";
Calendar._TT["TIME"] = "Time:";

/* /js/kigo.js */ /* UTF8 COOKIE: éà */

/* 
	Compatibility layer 
	1) PHP kigo class
	2) PHP libc
	
*/

var	kigo = {

	/*****************************************************************************************/
	/* KIGO */


	'CFG'			:	{},


	/*****************************************************************************************/
	/* TECH */

	'toString'		:	function(string)
	{
		if(string == null)
			return '';

		switch(typeof(string))
		{
			case 'string':
				return string;

			case 'number':
				return ''+string;

			case 'boolean':
				return string ? 'true' : 'false';

			case 'function':
				return '';

			case 'object':

				if(
					typeof(string['toString']) == 'function' &&
					typeof(string = string.toString()) == 'string'
				)
					return string;

				return '';

			case 'undefined':
			default:
				return '';
		}
	},

	'isset'			:	function(v)
	{
		return (typeof(v) == 'undefined' || v == null) ? false : true;
	},

	// 23/02/2010
	'is_function'	:	function(f)
	{
		return typeof(f) == 'function' ? true : false;
	},

	// 24/02/2010
	'is_null'		:	function(n)
	{
		return (typeof(n) == 'object' && n == null) ? true : false;
	},

	'is_array'		:	function(a)
	{
		return (
			a != null &&	
			typeof(a) == 'object' &&
			typeof(a['length']) == 'number' &&
			typeof(a['concat']) == 'function' &&
			typeof(a['join']) == 'function' &&
			typeof(a['pop']) == 'function' &&
			typeof(a['push']) == 'function' &&
			typeof(a['reverse']) == 'function' &&
			typeof(a['shift']) == 'function' &&
			typeof(a['slice']) == 'function' &&
			typeof(a['splice']) == 'function' &&
			typeof(a['sort']) == 'function' &&
			typeof(a['toString']) == 'function' &&
			typeof(a['unshift']) == 'function' &&
			typeof(a['valueOf']) == 'function'
		);
	},

	'in_array'		:	function(value, arr)	// [,strict=false]
	{
		if(!this.is_array(arr) || !arr.length)
			return false;

		if(arguments.length > 2 && arguments[2])
		{
			// strict
			for(var i = 0; i < arr.length; i++)
			{
				if(arr[i] === value)
					return true;
			}
		}
		else
		{
			for(var i = 0; i < arr.length; i++)
			{
				if(arr[i] == value)
					return true;
			}
		}

		return false;
	},

	'is_string'		:	function(s)
	{
		return typeof(s) == 'string';
	},

	'is_object'		:	function(o)
	{
		return typeof(o) == 'object' && o != null && !kigo.is_array(o);
	},

	'is_number'		:	function(n)
	{
		return typeof(n) == 'number';
	},

	'is_int'		:	function(i)
	{
		return typeof(i) == 'number' && ''+i == ''+this.intval(i);
	},

	'is_bool'		:	function(b)
	{
		return typeof(b) == 'boolean';
	},

	'intval'		:	function(value)
	{
		switch(typeof(value))
		{
			case 'number':
				if(isNaN(value = parseInt(Math.round(value), 10)))
					return 0;
				return value;

			case 'string':
				if(isNaN(value = parseInt(this.trim(value), 10)))
					return 0;
				return value;
	
			case 'boolean':
				return value ? 1 : 0;

			case 'object':	// Including null
			case 'function':
			default:
				return 0;
		}
	},

	'trim'			:	function(string)
	{
		if(!(string = this.toString(string)).length)
			return '';
		string = string.replace(new RegExp('^[\\s]+', 'g'), '');
		return string.replace(new RegExp('[\\s]+$', 'g'), '');
	},

	// 24/11/2009 - A couple of new ones
	'substr'		:	function(string, start)	// [, length]
	{
		var	length, total;

		if( (length = arguments.length > 2 ? this.intval(arguments[2]) : null) == 0 || !(total = (string = this.toString(string)).length))
			return '';

		if( (start = this.intval(start)) >= 0)
		{
			if(start >= total)
				return '';
		}
		else if((start += total) < 0)
			start = 0;

		if(length == null)
			return string.substr(start);

		if(length > 0)
			return string.substr(start, length);

		return string.substr(start, total - start + length);
	},


	'str_repeat'	:	function(text, multiplier)
	{
		var	ret = '';

		multiplier = Math.max(0, kigo.intval(multiplier));

		for(var i = 0; i < multiplier; i++)
			ret += text;

		return ret;
	},


	// 08/06/2010
	'strpos'		:	function(str, findme)	// [, offset]
	{
		// This is, currently, totally unoptimized!
		for(var i = (arguments.length > 2 ? arguments[2] : 0); i <= str.length - findme.length; i++)
		{
			if(this.substr(str, i, findme.length) == findme)
				return i;
		}

		return null;
	},

	'strlen'		:	function(str)
	{
		return kigo.toString(str).length;
	},

	// 02/08/2010
	'strtoupper'	:	function(str)
	{
		return this.toString(str).toUpperCase();
	},

	'strtolower'	:	function(str)
	{
		return this.toString(str).toLowerCase();
	},

/* TODO: explode and implode !
	// 02/08/2010
	'explode'		:	function(sep, str)	// [, limit]
	{

	},
*/

	'rawurlencode'	:	function(str)
	{
		return encodeURIComponent(str);
	},

	// 01/03/2010
	'array_merge'	:	function()	// [a1 [, a2 [, a3 [, ...]]]]
	{
		var	res = [];

		for(var i = 0; i < arguments.length; i++)
		{
			for(var j = 0; j < arguments[i].length; j++)
				res.push(arguments[i][j]);
		}

		return res;
	},

	// 26/04/2010
	'object_merge'	:	function()	// [o1 [, o2 [, o3 [, ...]]]]
	{
		var	res = {};

		for(var i = 0; i < arguments.length; i++)
		{
			(new kigoAssoc(arguments[i])).forEach(
				function(key, value)
				{
					res[key] = value;
				}
			);
		}

		return res;
	},

	// 24/02/2010
	'getScroll'		:	function()
	{
		return Math.max(document.body.scrollTop, document.documentElement.scrollTop);
	},

	'setScroll'		:	function(scroll)
	{
		document.body.scrollTop = scroll;
		document.documentElement.scrollTop = scroll;
	}
};



/* /js/kigoDate.js */ /* UTF8 COOKIE: éà */

/*
??/??/20??		Release #0
05/07/2010		Documented; Now throws exceptions on invalid dates.


Type	Returns				Method										Note

		kigoDate			kigoDate(day, month, year)					Creates an instance from day, month and year numeric values.
																		Throws exception on invalid values.

static	kigoDate			today()										Creates an instance holding current date (as provided by the browser)

static	kigoDate			createFromDate(date)						Creates an instance from native Date object.
																		Throws exception on invalid object.

static	kigoDate			createFromMysql(mysql)						Creates an instance from date string in MySQL format.
																		Throws exception on invalid format or date.

static	kigoDate			createFromCalendar(calendar)				Creates an instance from date string in calendar format.
																		Throws exception on invalid format or date.
																		OBSOLETED BY kigoDatePicker. DO NOT USE.

		kigoDate			clone()										Clones the instance.


		int					getDay()									Returns the day of month

		int					getMonth()									Returns the month

		int					getYear()									Returns the year


		string				mysql()										Returns the date as a mysql DATE string.

		string				display()									Returns the date in format suitable for calendar display.

		string				calendar()									Alias to display()
																		OBSOLETED BY kigoDatePicker. DO NOT USE.

		Date				date()										Returns the date as a native Date object.

		kigoDate			addYears(signed int years)					Returns new kigoDate instance.

		kigoDate			addMonths(signed int months)				Returns new kigoDate instance.

		kigoDate			addDays(signed int days)					Returns new kigoDate instance.

		kigoDate			firstMonthDay()								Returns new kigoDate instance with date set to the first month day.

		kigoDate			lastMonthDay()								Returns new kigoDate instance with date set to the last month day.

		signed int			daysDiff(kigoDate other)					Returns the difference, in number of days, between the given instance, and other instance
																		Returns < 0 if other < this; > 0 if other > this

		signed int			compare(kigoDate other)						Compares the given instance with other instance.
																		Returns -1 if other < this; 0 if other = this; 1 if other > this

static	kigoDate			min(date [, date [, date [, ... ] ] ])		Returns the smallest date (cloned). Only one date argument is mandatory

static	kigoDate			max(date [, date [, date [, ... ] ] ])		Returns the smallest date (cloned). Only one date argument is mandatory




// NOTE: Makes use of the Date object extended by "The DHTML Calendar"
// TODO: Get rid of obsolete methods ::display() and ::calendar().

*/

/***********************************************/
/* CONSTRUCTORS */

function	kigoDate(day, month, year)
{
	// 05/07/2010 - Validate the date and throw exception on error... 
	if(
		(this.day = parseInt(day, 10)) < 1 || this.day > 31 ||
		(this.month = parseInt(month, 10)) < 1 || this.month > 12 ||
		this.day < 1 || this.day > monthDays(this.month, this.year = parseInt(year, 10))
	)
		throw 'kigoDate::kigoDate(): invalid date';

	function	monthDays(month, year)
	{
		switch(month)
		{
			case 1: case 3: case 5: case 7: case 8: case 10: case 12:
				return 31;
			case 4: case 6: case 9: case 11:
				return 30;
			case 2:
				return ((year % 4 == 0) && ((!(year % 100 == 0)) || (year % 400 == 0))) ? 29 : 28;
			default:
				return 0;
		}
	}
}


kigoDate.today = function()
{
	return kigoDate.createFromDate(new Date());
}

kigoDate.createFromDate = function(date)
{
	if(date.constructor != Date.prototype.constructor)
		throw 'kigoDate::createFromDate(): invalid Date object';

	return new kigoDate(
		date.getDate(),
		date.getMonth()+1,
		date.getFullYear()
	);
}

kigoDate.createFromMysql = function(mysql)
{
	if(
		typeof(mysql) != 'string' ||
		mysql.length < 10 ||							// Tolerates mysql DATETIME string (that is, DATE followed by time)
		!mysql.match(/^[0-9]{4}-[0-9]{2}-[0-9]{2}/i)	// Rough format check, the constructor is doing a better one
	)
		throw 'kigoDate::createFromMysql(): invalid input';

	// 0123-56-89
	return new kigoDate(
		mysql.substr(8, 2),
		mysql.substr(5, 2),
		mysql.substr(0, 4)
	);
}

kigoDate.createFromCalendar = function(calendar)
{
	return kigoDate.createFromDate(Date.parseDate(calendar, '%a, %d %b %Y'));
}

kigoDate.prototype.clone = function()
{
	return new kigoDate(this.day, this.month, this.year);
}



/***********************************************/
/* FRIENDS */

kigoDate.isInstance = function(i)
{
	return kigo.is_object(i) && i.constructor === kigoDate;
}


/***********************************************/
/* HELPERS */

kigoDate.prototype.getDay = function()
{
	return this.day;
}

kigoDate.prototype.getMonth = function()
{
	return this.month;
}

kigoDate.prototype.getYear = function()
{
	return this.year;
}


/***********************************************/
/* FORMATTING */


kigoDate.prototype.mysql = function()
{
	function	pad(number, digits)
	{
		number = ''+number;
		while(number.length < digits)
			number = '0' + number;
		return number;
	}

	// Returns date string suitable for MySQL
	return pad(this.year, 4)+'-'+pad(this.month, 2)+'-'+pad(this.day, 2);
}


kigoDate.prototype.display = function()
{
	// Returns date string suitable for Kigo display (
	return this.date().print('%a, %d %b %Y');
}

// ALIAS
kigoDate.prototype.calendar = function()
{
	return this.display();
}

kigoDate.prototype.date = function()
{
	// Returns the native Date object instance
	//return Date.parseDate(this.mysql(), '%Y-%m-%d');
	var	d = Date.parseDate(this.mysql(), '%Y-%m-%d');
	d.setHours(0, 0, 0, 0);
	return d;
}


/***********************************************/
/* MANIPULATING */

/*

	All the methods below return a NEW object.
	They do NOT alter the original object

*/


kigoDate.prototype.addYears = function(years)
{
	/*
		Implementation compatible with MySQL's "+/- INTERVAL x YEAR",
		and therefore compatible with server-side kigoDate
	*/

	years = kigo.intval(years);

	// Straightforward, except when dealing with february...
	if(this.month != 2)
		return new kigoDate(this.day, this.month, this.year + years);

	var	year = this.year + years;

	return new kigoDate(Math.min(this.day, (new kigoDate(1, this.month, year)).date().getMonthDays()), this.month, year);
}

/*

This one gives unwanted results.
Ie: 
	2009-05-31 - 1 month = 2009-05-01
	2009-05-31 - 2 months = 2009-03-31

kigoDate.prototype.addMonths = function(months)
{
	var	d = this.date();

	d.setMonth(d.getMonth() + months);

	return kigoDate.createFromDate(d);
}
*/

kigoDate.prototype.addMonths = function(months)
{
	/*
		Implementation compatible with MySQL's "+/- INTERVAL x MONTH",
		and therefore compatible with server-side kigoDate
	*/

	var	month, year;

	months = kigo.intval(months);

	if( (month = this.month - 1 /* 0-11 for computations */ + months) >= 0)
	{
		year = this.year + Math.floor(month / 12);
		month = (month%12) + 1; 
	}
	else
	{
		year = this.year - 1 - Math.floor( (Math.abs(month)-1) / 12);
		month = 12 - (Math.abs(month)-1)%12;
	}

	return new kigoDate(Math.min(this.day, (new kigoDate(1, month, year)).date().getMonthDays()), month, year);
}

kigoDate.prototype.addDays = function(days)
{
	var	d = this.date();

	d.setDate(d.getDate() + kigo.intval(days));

	return kigoDate.createFromDate(d);

}

kigoDate.prototype.firstMonthDay = function()
{
	return new kigoDate(1, this.month, this.year);
}

kigoDate.prototype.lastMonthDay = function()
{
	return new kigoDate(this.date().getMonthDays(), this.month, this.year);
}


// < 0 if other < this; > 0 if other > this
kigoDate.prototype.daysDiff = function(other)
{
	var	current = this.date();
	var	other = other.date();

	return Math.round((other.getTime() - current.getTime()) / 86400000);	// 24 hours x 60 minutes x 60 seconds x 1000 milliseconds

	/*
	Why doesn't this work???

	// Avoid dealing with timezone problem by rounding the result...
	return Math.round(
		(
			Date.UTC(other.getYear(), other.getMonth(), other.getDay(), 12, 0, 0, 0) - 
			Date.UTC(this.year, this.month, this.day, 12, 0, 0, 0)
		) / 
		86400000 // 24 hours x 60 minutes x 60 seconds x 1000 milliseconds
	);
	*/
}

// -1 if other < this; 1 if other > this
kigoDate.prototype.compare = function(other)
{
	var	diff;

	if(
		(diff = other.getYear() - this.year) ||
		(diff = other.getMonth() - this.month) ||
		(diff = other.getDay() - this.day)
	)
		return diff;

	return 0;
}


kigoDate.min = function(date)
{
	if(!kigoDate.isInstance(date))
		throw 'kigoDate::min(): invalid date';

	var	current = date;

	for(var i = 1; i < arguments.length; i++)
	{
		if(!kigoDate.isInstance(arguments[i]))
			throw 'kigoDate::min(): invalid date';

		if(current.compare(arguments[i]) < 0)
			current = arguments[i];
	}

	return current.clone();
}

kigoDate.max = function(date)
{
	if(!kigoDate.isInstance(date))
		throw 'kigoDate::max(): invalid date';

	var	current = date;

	for(var i = 1; i < arguments.length; i++)
	{
		if(!kigoDate.isInstance(arguments[i]))
			throw 'kigoDate::max(): invalid date';

		if(current.compare(arguments[i]) > 0)
			current = arguments[i];
	}

	return current.clone();
}

/* /js/kigoSelect.js */ /* UTF8 COOKIE: éà */


/*

	OBSOLETED BY kigoSelect2
	All the new projects must use kigoSelect2

*/


function	kigoSelect(el)
{
	this.el = vkDom.el(el);
}


kigoSelect.prototype.element = function()
{
	return this.el;
}

// 02/12/2009 - For naming compatibility with kigoDom
kigoSelect.prototype.domNode = function()
{
	return this.el;
}

kigoSelect.prototype.reset = function()
{
	vkDom.clean(this.el);
/*
	for(var i = this.el.options.length; i >=0; i--)
		this.el.options[i] = null;

	this.el.options.length = 0;
*/
}


kigoSelect.prototype.addOption = function(value, text)	// [, class(es)]
{
	var	o = document.createElement('option');
	o.value = value;
	if(arguments.length == 3)
		o.className = arguments[2];
	o.appendChild(document.createTextNode(text));
	this.el.appendChild(o);

	return this.el.options.length - 1;
}


kigoSelect.prototype.insertOption = function(value, text)	// [, insertIndex]
{
	if(arguments.length == 2)
		insertIndex = 0;
	else if(arguments.length == 3)
		insertIndex = arguments[2];
	else
		throw 'Bad usage';

	if(insertIndex >= this.el.options.length)
		return this.addOption(value, text);
	
	var	o = document.createElement('option');
	o.value = value;
	o.appendChild(document.createTextNode(text));

	this.el.options[insertIndex].parentNode.insertBefore(o, this.el.options[insertIndex]);

	if(this.el.selectedIndex >= insertIndex)
		++this.el.selectedIndex;

	return insertIndex;
}

kigoSelect.prototype.addOptionsFromArray = function(arr)	// [, valueKey, textKey]
{
	if(arguments.length == 1)
	{
		var	tmp;
		
		for(i in arr)
		{
			switch(typeof(arr[i]))
			{
				case 'number':
				case 'string':
					this.addOption(i, arr[i]);
					break;
			}

		}
	}
	else if(arguments.length == 3)
	{
		var	valueKey = arguments[1];
		var	textKey = arguments[2];

		for(var i = 0; i < arr.length; i++)
			this.addOption(arr[i][valueKey], arr[i][textKey]);
	}
	else
		throw 'Bad usage';
}



kigoSelect.prototype.addGroup = function(group)
{
	this.el.appendChild(group.el);
}

kigoSelect.prototype.getIndex = function()
{
	return this.el.selectedIndex;
}

kigoSelect.prototype.setIndex = function(idx)
{
	return this.el.selectedIndex = idx;
}

kigoSelect.prototype.getValue = function()
{
	if(this.el.selectedIndex < 0)
		return null;
	
	return this.el.options[this.el.selectedIndex].value;
}

kigoSelect.prototype.getOption = function()
{
	if(this.el.selectedIndex < 0)
		return null;
	
	return this.el.options[this.el.selectedIndex];
}

kigoSelect.prototype.setValue = function(value)
{
//	kigoDebug.text('setValue('+value+')');

	if(this.el.selectedIndex < 0)
		return false;
	
	for(var i = 0; i < this.el.options.length; i++)
	{
		if(this.el.options[i].value == value)
		{
			this.el.selectedIndex = i;

			// Stupid IE6 fix
			if(vkDom.hasClass(document.body, 'ua-msie-6'))
				this.el.options[i].setAttribute('selected', true);

			return true;
		}
	}

	this.el.selectedIndex = 0;

	// Stupid IE6 fix
	if(vkDom.hasClass(document.body, 'ua-msie-6'))
		this.el.options[0].setAttribute('selected', true);

	return false;
}



function	kigoOptgroup(text)
{
	this.el = document.createElement('optgroup');
	this.el.label = text;
}

kigoOptgroup.prototype.addOption = function(value, text)	// [, class(es)]
{
	var	o = document.createElement('option');
	o.value = value;
	if(arguments.length == 3)
		o.className = arguments[2];
	o.appendChild(document.createTextNode(text));
	this.el.appendChild(o);
}


/* /js/kigoList.js */ /* UTF8 COOKIE: éà */

/*

02/12/2009		Release #0



Type	Returns				Method											Note

		kigoList			kigoList()										Creates an empty instance

		kigoList			kigoList(array)									Create an instance for an existing Array

static	kigoList			kigoList.createFromCSV(csv, separator)			Creates an instance from a Comma Separated Values string

		kigoList			empty()											Empties the list.

		int					add(value)										Returns the index of the added value. Note that the index is not constant.
																			Indexes are altered by move(), remove(), ...

		int	| null			insertBefore(value, idx)						Adds the value before index idx.
																			However, if idx is NULL, the value is added to the end (same behaviour as the add() method).
																			Returns the index for the inserted value, or NULL if the provided index was invalid 
																			and value could not be inserted.

		int					length()										Returns the number of elements

		bool				find(value [, strict=false])

		int | null			pos(value, [, strict=false])

		bool | null			isFirst(idx)									Returns null if the index is out of range.

		bool | null			isLast(idx)										Returns null if the index is out of range.

		mixed | null		get(idx)										Returns the value at index idx

		mixed | null		getFirst()										Returns the value at first index

		mixed | null		getLast()										Returns the value at last index

		int | null			move(idx, where)								Moves the value indexed by idx to index where.
																			Returns the new position or null if the move failed.
																			On success, All elements' indexes may be reassigned.

		mixed | null		remove(idx)										Returns the removed value, null if nonexistent.
																			On success, the specified index, idx, may be reassigned to another element.

		void				forEach(callback [, data])						Runs the callback for every element. 
																			The callback takes the following parameters:
																			callback(value, idx, list [, data])
																			The loop is done on a list clone, therefore changes
																			made to the list are not visible during the loop.

		array				array()											Returns the list as an Array object.

		string				CSV(separator)									Returns the list as a Comma Separated Values string, separated
																			by the mandatory argument 'separator'.
																			Makes sense only if list values are scalar values.

Possible extensions (only if really required):

		kigoList			sort(callback [, data])							Sorts the array using the callback() comparison function.
																			The callback received values of the two entries to compare, and must return negative, 
																			zero or positive values if the first entry is to be placed before, at same level, or after 
																			the second value. The optional data argument, if any, is also passed to the callback function.
																			A new instance is return, the original instance is unchanged.

*/




function	kigoList()	// [array]
{
	this.list = (arguments.length && kigo.is_array(arguments[0])) ? arguments[0] : [];
}

kigoList.createFromCSV = function(csv, separator)
{
	return new kigoList(
		(kigo.is_string(csv) && csv.length && kigo.is_string(separator)) ? csv.split(separator) : []
	);
}




/********************************************/
/* Manipulating */

// kigoList
kigoList.prototype.empty = function()
{
	this.list = [];
}

// int
kigoList.prototype.length = function()
{
	return this.list.length;
}

// bool
kigoList.prototype.find = function(value) // [,strict=false]
{
	return kigo.in_array(value, this.list, arguments.length > 1 && arguments[1]);
}

// int | null
kigoList.prototype.pos = function(value) // [,strict=false]
{
	if(arguments.length > 1 && arguments[1])
	{
		// strict
		for(var i = 0; i < this.list.length; i++)
		{
			if(this.list[i] === value)
				return i;
		}
	}
	else
	{
		// non-strict
		for(var i = 0; i < this.list.length; i++)
		{
			if(this.list[i] == value)
				return i;
		}
	}

	return null;
}


// bool | null
kigoList.prototype.isFirst = function(idx)
{
	return (idx >= 0 && idx < this.list.length) ? (idx ? false : true) : null;
}

// bool | null
kigoList.prototype.isLast = function(idx)
{
	return (idx >= 0 && idx < this.list.length) ? (idx == this.list.length - 1 ? true : false) : null;
}


// bool (private)
kigoList.prototype.exists = function(idx)
{
	return (kigo.is_int(idx) || kigo.is_string(idx)) && ''+kigo.intval(idx) == ''+idx && idx >= 0 && idx < this.list.length;
}


// mixed | null
kigoList.prototype.remove = function(idx)
{
	var	removed;

	if(!this.exists(idx))
		return null;

	removed = this.list[idx];

	for(var i = idx; i < this.list.length - 1; i++)
		this.list[i] = this.list[i+1];
	
	this.list.pop();

	return removed;
}

// idx
kigoList.prototype.add = function(value)
{
	return this.list.push(value) - 1;
}


// idx | null
kigoList.prototype.insertBefore = function(value, idx)
{
	if(idx == null)
		return this.add(value);

	if(!this.exists(idx))
		return null;

	for(i = this.list.length; i > idx; i--)
		this.list[i] = this.list[i-1];

	this.list[idx] = value;

	return idx;
}




// idx | null
kigoList.prototype.move = function(idx, where)
{
	if(
		!this.exists(idx) ||
		!this.exists(where)
	)
		return null;

	if(idx == where)
		return idx;

	var	i, tmp;

	if(where < idx)
	{
		tmp = this.list[idx];

		for(i = idx; i > where; i--)
			this.list[i] = this.list[i-1];

		this.list[where] = tmp;
	}
	else if(where > idx)
	{
		tmp = this.list[idx];

		for(i = idx; i < where; i++)
			this.list[i] = this.list[i+1];

		this.list[where] = tmp;
	}

	return where;
}

// mixed | null
kigoList.prototype.get = function(idx)
{
	if(!this.exists(idx))
		return null;

	return this.list[idx];
}

// mixed | null
kigoList.prototype.getFirst = function()
{
	return this.get(0);
}

// mixed | null
kigoList.prototype.getLast = function()
{
	return this.get(this.list.length - 1);
}


// void	
kigoList.prototype.forEach = function(callback) // [,data]
{
	// Work on a clone
	var	clone = this.list.slice(0);

	for(var i = 0; i < clone.length; i++)
		callback(clone[i], i, this, arguments[1]);
}




// kigoList
kigoList.prototype.sort = function(callback)	// [,data]
{
	// Work on a clone
	var	clone = this.list.slice(0);
	var	data = arguments.length > 1 ? arguments[1] : undefined;

	clone.sort(
		function(a, b)
		{
			return callback(a, b, data);
		}
	);

	return new kigoList(clone);
}



/********************************************/
/* Formatting */

kigoList.prototype.array = function()
{
	return this.list.slice(0);	// Return a clone
}

// This one makes sense only if values are scalar
kigoList.prototype.CSV = function(separator)
{
	return this.list.length ? this.list.join(separator) : '';
}

/* /js/kigoDom.js */ /* UTF8 COOKIE: éà */

/*

02/12/2009		Release #0


Type	Returns						Method					Note

		kigoDom						kigoDom(element)		Creates a kigoDom instance from a DOM element.
															Throws exception if invalid/inexistant element was provided.

		kigoDom						kigoDom(id)				Creates a kigoDom instance from a unique element id (string).
															Throws exception if invalid/inexistant id was provided. Therefore, use getById() if
															unsure whether the element exists.

		kigoDom						kigoDom(domInstance)	Creates a kigoDom instance from an existing kigoDom instance. This is a reference to (rather than a clone of) the existing instance.

static	kigoDom | null				create(tagName [, attributes=null [, styles=null [, events=null ] ] ])

															Creates a kigoDom instance holding Element of tagName type.
															Throws exception on failure (ie. bad tagName)

static	kigoDom						getBody()				Returns the document body.

static	kigoDom | null				getById(id)				Returns dom Element by unique id.

static	Array(kigoDom) | null		getByTagName(tag)		Returns an array of element found by tag name.

static	kigoDom | null				getByTagName(tag, idx)	Returns an idx-th element found by tag name, null if not found.

		kigoDom | null				getById(id)				Returns child dom Element by unique id

		Array(kigoDom) | null		getByTagName(tag)		Returns an array of child elements found by tag name

		kigoDom | null				getByTagName(tag, idx)	Returns an idx-th element child of the current element found by tag name, null if not found.


		Element						domNode()				Returns the DOM Element

		kigoDom						empty()					Empties the node and returns the reference to itself

		kigoDom						append(child [, child [, ... ] ])
		kigoDom						appendArray(children)

															Appends one or more children.
															kigoDom instances, DOM Elements, strings (tranformed to text nodes), and arrays holding any of these are accepted.

		kigoDom | null				parentNode()			Returns the parent node kigoDom instance, or null if there is no parent

		kigoDom						orphanize()				Removes the element from its parent node, if any.

		kigoDom						clone([deep=true])		Clones the node

		kigoDom						swap(other)				Swaps the node with 'other' node. Nodes may be in different dom trees, and may even not be in a node tree at all.
															The method also swaps instances - this becomes other, and other becomes this.


Possible extensions (only if really required):

TODO:

	PRIVATE isDomNode() method. Currently we're treating every object that is neither kigoDom instance, nor null, nor array in some places, as being a DOM node.


*/

//////////////////////////////////////////////////////////////////
// CONSTRUCTOR

function	kigoDom(el)
{
	if(kigoDom.isNode(el))
		this.node = el;
	else if(kigoDom.isInstance(el))
		this.node = el.domNode();
	else
	{
		if(typeof(el) == 'string')
			this.node = document.getElementById(el);
		else
			this.node = null;

		if(!this.node)
			throw 'kigoDom::kigoDom(): Invalid DOM node'+(kigo.is_string(el) ? '('+el+')' : '');
	}
}

//////////////////////////////////////////////////////////////////
// PRIVATE PROPERTIES & METHODS

kigoDom.__embryon__ = {};

kigoDom.isInstance = function(i)
{
	return kigo.is_object(i) && i.constructor === kigoDom;
}

kigoDom.isNode = function(n)
{
	// Check whether this is an html node - this is a quick & dirty check - TODO: write a better one
	return kigo.is_object(n) && typeof(n['tagName']) == 'string'/* && !n.hasOwnProperty('tagName')*/;
}

kigoDom.mapAttrName = function(name)
{
	switch(name.toLowerCase())
	{
		case 'defaultchecked':
			return 'defaultChecked';

		case 'class':
		case 'classname':
			return 'className';
		
		case 'colspan':
			return 'colSpan';

		case 'maxlength':
			return 'maxLength';

		case 'readonly':
			return 'readOnly';

		case 'rowspan':
			return 'rowSpan';

		default:
			return name;	// Such as written by the developer
	}
}




//////////////////////////////////////////////////////////////////
// STATIC METHODS

kigoDom.getBody = function()
{
	return new kigoDom(document.body);
}

kigoDom.getById = function(id)
{
	var	el = document.getElementById(id);

	if(el)
		return new kigoDom(el);

	return null;
}

kigoDom.getByTagName = function(tagName)	// [, idx]
{
	var	els = document.getElementsByTagName(tagName);

	if(arguments.length > 1)
	{
		// Return single element
		if(typeof(els[arguments[1]]) != 'undefined')
			return new kigoDom(els[arguments[1]]);

		return null;
	}
	else
	{
		// Return array
		var	arr = [];

		for(var i = 0; i < els.length; i++)
			arr[i] = new kigoDom(els[i]);

		return arr;
	}
}




// Returns the created element
kigoDom.create = function(tagName)	// [, attributes [, styles [, events ] ] ]
{
	if(typeof(tagName) != 'string')
		throw 'kigoDom::create(): Bad argument';

	// TODO: Check whether cloning node is faster that creating nodes in all browsers - possibly do a browser cbeck and choose the faster method
	// Meanwhile, use cloning as it is significantly faster on very slow browsers

	if(typeof(kigoDom.__embryon__[tagName = tagName.toLowerCase()]) == 'undefined')
	{
		try
		{
			kigoDom.__embryon__[tagName] = document.createElement(tagName);
		}
		catch(e)
		{
			throw 'Failed creating element: '+e;
		}
	}

	var el = kigoDom.__embryon__[tagName].cloneNode(false);
	var	attrName;

	// SETUP ATTRIBUTES
	if(arguments.length > 1 && kigo.is_object(arguments[1]))
	{
		for(name in arguments[1])
		{
			if(arguments[1].hasOwnProperty(name))
			{
				// Intercept a couple of properties that some browsers dislike setting with setAttribute(), or that need special handling (ie. form elements)

				switch(attrName = kigoDom.mapAttrName(name))	// Also, 'repair' frequently misstypes attribute names with mapAttrName()
				{
					case 'id':
						el.id = arguments[1][name];
						break;

					case 'className':
						el.className = arguments[1][name];
						break;

					case 'checked':
					case 'defaultChecked':

						if(el.tagName == 'INPUT')
						{
							if(el.type.toLowerCase() == 'checkbox')
							{
								if(attrName == 'checked')
									el.checked = arguments[1][name] ? true : false;

								// 23/06/2010 - Why weren't we doing this for checkboxes?
//								else
//									el.defaultChecked = arguments[1][name] ? true : false;

								// Always set defaultChecked
								el.defaultChecked = arguments[1][name] ? true : false;
							}
							else if(el.type.toLowerCase() == 'radio')
							{
								if(attrName == 'checked')
									el.checked = arguments[1][name] ? true : false;

								// Always set defaultChecked
								el.defaultChecked = arguments[1][name] ? true : false;
							}
							else
								el.setAttribute(attrName, arguments[1][name]);
						}
						else
							el.setAttribute(attrName, arguments[1][name]);

						break;						

					case 'value':

						if(
							el.tagName == 'INPUT' ||
							el.tagName == 'TEXTAREA'
						)
							el.value = arguments[1][name];
						else
							el.setAttribute(attrName, arguments[1][name]);
						break;

					case 'readOnly':

						if(
							el.tagName == 'INPUT' ||
							el.tagName == 'TEXTAREA'
						)
							el.readOnly = arguments[1][name] ? true : false;
						else
							el.setAttribute(attrName, arguments[1][name]);
						break;

						/*
						else if(el.tagName == 'TEXTAREA')
							el.value = arguments[1][name];
							//el.appendChild(document.createTextNode(arguments[1][name]));
						else
							el.setAttribute(attrName, arguments[1][name]);
						break;
						*/
	
/* Ooops, IE doesn't like this! - I guess that the value becomes available only if the input's "type" attribute was set *before*...

					case 'value':
						// If 'value' is a prototype property, prefer using obj.value = 'xx' rather that setAttribute.
						// Otherwise, use setAttribute()
						if(
							!el.hasOwnProperty(name) &&		// is prototype or doesn't exist
							typeof(el[name]) != 'undefined'	// ... does exist
						)
							el.value = arguments[1][name];
						else
							el.setAttribute(name, arguments[1][name]);
						break;
*/
					default:
						el.setAttribute(attrName, arguments[1][name]);
				}
			}
		}
	}

	// SETUP STYLES
	if(arguments.length > 2 && kigo.is_object(arguments[2]))
	{
		for(name in arguments[2])
		{
			if(arguments[2].hasOwnProperty(name))
			{
				// Intercept a couple of styles that browsers will refuse to handle by their proper names
				switch(name)
				{
					case 'cssFloat':
					case 'float':		// This is a handy (but invalid) shortcut

						el.style['cssFloat'] = arguments[2][name];

						// Stupid IE, again and again
						if(vkDom.hasClass(document.body, 'ua-msie'))
							el.style['styleFloat'] = arguments[2][name];

						break;

					default:
						el.style[name] = arguments[2][name];
				}
			}
		}
	}

	// SETUP EVENTS
	if(arguments.length > 3 && kigo.is_object(arguments[3]))
	{
		for(name in arguments[3])
		{
			if(arguments[3].hasOwnProperty(name) && name == name.toLowerCase())
				el[kigo.substr(name, 0, 2) == 'on' ? name : 'on'+name] = arguments[3][name];
		}
	}


	return new kigoDom(el);
}


//////////////////////////////////////////////////////////////////
// NON-STATIC METHODS

kigoDom.prototype.domNode = function()
{
	return this.node;
}


kigoDom.prototype.getById = function(id)
{
	var el = this.node.getElementById(id);

	if(el)
		return new kigoDom(el);

	return null;
}

kigoDom.prototype.getByTagName = function(tagName)	// [, idx]
{
	var	els = this.node.getElementsByTagName(tagName);

	if(arguments.length > 1)
	{
		// Return single element
		if(typeof(els[arguments[1]]) != 'undefined')
			return new kigoDom(els[arguments[1]]);

		return null;
	}
	else
	{
		// Return array
		var	arr = [];

		for(var i = 0; i < els.length; i++)
			arr[i] = new kigoDom(els[i]);

		return arr;
	}
}


kigoDom.prototype.empty = function()
{
	while(this.node.firstChild)
		this.node.removeChild(this.node.firstChild);
	return this;
}




kigoDom.prototype.append = function()	// child [, child [, child [, ...] ] ]
{
	return this.appendArray(arguments);
}


kigoDom.prototype.appendArray = function(kids)
{
	for(var i = 0; i < kids.length; i++)
	{
		switch(typeof(kids[i]))
		{
			// kigoDom or Dom instance
			case 'object':

				// kigoDom instance (the most frequent usage case)
				if(kigoDom.isInstance(kids[i]))
					this.node.appendChild(kids[i].domNode());
				else if(kids[i] != null)
				{
					if(kigo.is_array(kids[i]))
						this.appendArray(kids[i]);
					else
						this.node.appendChild(kids[i]);
				}
				// Silently skip null values

				break;

			// Text nodes
			case 'string':
			case 'number':
				this.node.appendChild(
					document.createTextNode(kids[i])
				);
				break;

			default:
				// Silently skip others
		}
	}

	return this;
}


kigoDom.prototype.parentNode = function()
{

	/*
		We cannot use the parentNode attribute to determine whether the node has a parent, because of a "yet another" stupid IE bug:

		http://www.omacronides.com/notes/090424-parentnode-ie-et-les-autres/

		Use IE's parentElement!
	*/

	if(
		!this.node.parentNode ||
		kigo.is_null(this.node.parentElement)	// IE specific
	)
		return null;

	return new kigoDom(this.node.parentNode);
}


kigoDom.prototype.orphanize = function()
{
	var p;

	if(p = this.parentNode())
		p.node.removeChild(this.node);

	return this;
}


kigoDom.prototype.clone = function()	// [deep=true]
{
	return new kigoDom(this.node.cloneNode(!arguments.length || arguments[0] ? true : false));
}

kigoDom.prototype.swap = function(other)
{
	var	tmp;

	if(!kigoDom.isInstance(other))
		other = new kigoDom(other);

	// Use self::parentNode() to ensure there is a parent, regardless of IE's bugs
	// Use replaceChild() to ensure the element is inserted at the right place

	if(this.parentNode())
	{
		if(other.parentNode())
		{
			// Both have a parent..
			tmp = kigoDom.create('span');

			other.node.parentNode.replaceChild(tmp, other.node);
			this.node.parentNode.replaceChild(other.node, this.node);
			tmp.parentNode.replaceChild(this.node, tmp);
		}
		else
			this.node.parentNode.replaceChild(other.node, this.node);
	}
	else if(other.parentNode())
		other.node.parentNode.replaceChild(this.node, other.node);


/*
	if(this.node.parentNode)
	//if(kigo.is_object(this.node.parentNode) && kigo.is_function(this.node.parentNode['replaceChild']))
	{
		if(other.node.parentNode)
		//if(kigo.is_object(other.node.parentNode) && kigo.is_function(other.node.parentNode['replaceChild']))
		{
			alert('CASE 1.A');
			// Both have parent..
			tmp = kigoDom.create('span');

			other.node.parentNode.replaceChild(tmp, other.node);
			this.node.parentNode.replaceChild(other.node, this.node);
			tmp.parentNode.replaceChild(this.node, tmp);
		}
		else
		{
			alert('CASE 1.B');
			this.node.parentNode.replaceChild(other.node, this.node);
		}
	}
	else if(other.node.parentNode)
	//else if(kigo.is_object(other.node.parentNode) && kigo.is_function(other.node.parentNode['replaceChild']))
	{
		alert('CASE 2');
		other.node.parentNode.replaceChild(this.node, other.node);
	}
	else
		alert('CASE 3');
*/


	// Finally, "swap" instances
	tmp = this.node;
	this.node = other.node;
	other.node = tmp;

	return this;
}



/* /js/kigoVal.js */ /* UTF8 COOKIE: éà */



var	kigoVal = {

	
	/**************************************************************************************************************/
	/* PUBLIC  */


	'CHR'			:	function(value, len)
	{
		return (value = kigo.trim(value)).length == len;
	},

	'CHRCONTENT'	:	function(value, pool, len)
	{
		return kigoVal.CHR((value = kigo.trim(value)), len) && kigoVal.STRCONTENT(value, pool);
	},

	'VCHR'			:	function(value, max) // [, min=0 ]
	{
		var	min = arguments.length < 3 ? 0 : arguments[2];
		var	len = (value = kigo.trim(value)).length;

		return len <= max && len >= min;
	},

	'VCHRCONTENT'	:	function(value, pool, max) // [, min=0 ] 
	{
		return kigoVal.VCHR((value = kigo.trim(value)), max, arguments.length < 3 ? 0 : arguments[3]) && kigoVal.STRCONTENT(value, pool);
	},



	'INT8'			:	function(value) // [, min [, max]]
	{
		return kigoVal.INTX(value, 0xFF, arguments.length > 1 ? arguments[1] : null, arguments.length > 2 ? arguments[2] : null);
	},

	'INT16'			:	function(value) // [, min [, max]]
	{
		return kigoVal.INTX(value, 0xFFFF, arguments.length > 1 ? arguments[1] : null, arguments.length > 2 ? arguments[2] : null);
	},

	'INT31'			:	function(value) // [, min [, max]]
	{
		return kigoVal.INTX(value, 0x7FFFFFFF, arguments.length > 1 ? arguments[1] : null, arguments.length > 2 ? arguments[2] : null);
	},


	'BOOL' 			: function(value)
	{
		if(	
			value === true ||
			value === 1 ||
			value === '1' 
		)
			value = true;
		else if(
			value === false ||
			value === 0 ||
			value === '0'
		)
			value = false;
		else
			return false;

		return true;
	},
	

	'EMAIL'			:	function(value) // [, mandatory=true ]
	{
		var	mandatory = arguments.length < 2 ? true : (arguments[1] ? true : false);
		var value = kigo.trim(value);
		if(
			!mandatory &&
			!value.length
		)
			return true;

		if(!kigoVal.VCHR(value, kigo.CFG.MISC.MAXLEN_EMAIL, 0))	// Limit to 200 characters
			return false;

		// http://atranchant.developpez.com/code/validation/index.php
		// Validation RFC1035 & RFC2822

		var atom   = '[-a-z0-9!#$%&\'*+\\/=?^_`{|}~]';		// caractères autorisés avant l'arobase
		var domain = '([a-z0-9]([-a-z0-9]*[a-z0-9]+)?)';	// caractères autorisés après l'arobase (nom de domaine)

		var regex = '^' + atom + '+' +						// Une ou plusieurs fois les caractères autorisés avant l'arobase
		'(\\.' + atom + '+)*' +								// Suivis par zéro point ou plus
															// séparés par des caractères autorisés avant l'arobase
		'@' +												// Suivis d'un arobase
		'(' + domain + '{1,63}\\.)+' +						// Suivis par 1 à 63 caractères autorisés pour le nom de domaine
															// séparés par des points
		domain + '{2,63}$';									// Suivi de 2 à 63 caractères autorisés pour le nom de domaine

		return (new RegExp(regex, 'i')).test(value) ? true : false;
	},
	
	'USERNAME'				:	function(value) 
	{
		return kigoVal.VCHRCONTENT(value, 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_', kigo.CFG.ACCOUNT.USERNAME_MAX_CHARS, kigo.CFG.ACCOUNT.USERNAME_MIN_CHARS);
	},
	
	'PASSWORD'				:	function(value) 
	{
		return kigoVal.VCHR(value, 100, kigo.CFG.ACCOUNT.PASSWORD_MIN_CHARS);
	},
	
	
	'HOUR'					:	function(value)  
	{
		return kigoVal.INT8(value, 0,23);
	},	
	
	'MINUTE'				:	function(value)  
	{
		return kigoVal.INT8(value, 0,59);
	},		
	
	'AMOUNT'				: 	function(value)	// [, allowNegative=true [, allowEmpty=true ] ]
	{
		var	allowNegative = arguments.length > 1 ? arguments[1] : true;
		var	allowEmpty = arguments.length > 2 ? arguments[2] : true;

		// - Remove the ' separator
		// - Replace ',' by '.'
		value = kigo.trim(value);		
		
		value = value.split('\'').join('');
		value = value.split(',').join('.');
		
		if(!kigoVal.STRCONTENT(value, '0123456789.' + (allowNegative ? '-' : '') ))		
			return false;
		var tmp = value.split('.');
		var s = tmp.length;

		if(s == 1)
		{
			// Only decimal part...
			var decimal = tmp[0];
			var float = null;
		}
		else if(s == 2)
		{
			var decimal = tmp[0];
			var float = tmp[1];
		}
		else
			return false;

		if (decimal.length && decimal.substring(0,1) == '-')
		{
			var negative = true;
			decimal = decimal.substr(1,decimal.length -1);
		}
		else 		
			var negative = false;

		// Okay, the "decimal" part may store up to 8 digits, while the "float" part may store up to 2 digits

		if(	decimal.length > 8 ||
			(float !== null && float.length > 2)
		)
			return false;
	
		return true;
	},

	'GMAPCOORD'			:	function(value) // [, mandatory=true ]
	{
		// [-]XXX.XXXXXXXXXXXXXXX
		var tmp = value.split('.');
		var s = tmp.length;
		
		if( s == 1)
		{
			// Only decimal part...
			decimal = tmp[0];
			float = null;
		}
		else if(s == 2)
		{
			decimal = tmp[0];
			float = tmp[1];

		}
		else
			return false;


		if( decimal.length && decimal.substring(0,1) == '-')
		{
			var negative = true;
			decimal = decimal.substr(1,decimal.length -1);
		}
		else
			var negative = false;

		if(!kigoVal.INT8(decimal, 0, 180))
			return false;
		
		if(float === null)
		{			
			return false;
		}

		// treat float as a string...
		if(!kigoVal.VCHRCONTENT(float, '0123456789', 20, 1))
			return false;

		return true;
		
	},
	
	'GMAPZOOM'			:	function(value) 
	{	
		return kigoVal.INT8(value, 0, 23);
	},
	
	'GANALYTICS'			:	function(value) // [, mandatory=true ]
	{
		var	mandatory = arguments.length < 2 ? true : (arguments[1] ? true : false);
		var value = kigo.trim(value);
		if(
				!mandatory &&
				!value.length
			)
				return true;

		if(!kigoVal.VCHR(value, kigo.CFG.WS.GOOGLE_ANALYTICS_MAX_LENGTH, kigo.CFG.WS.GOOGLE_ANALYTICS_MIN_LENGTH))
			return false;
						
		var googleCodeFilter = /^UA-[0-9]+-[0-9]+$/i;

		if(!value.match(googleCodeFilter))
			return false;
			
		return true;
	},

	'URL'			:	function(value) // [, mandatory=true ] 
	{	
		var	mandatory = arguments.length < 2 ? true : (arguments[1] ? true : false);
		var value = kigo.trim(value);
		var	https;

		if(
			!mandatory &&
			!value.length
		)
			return true;

		if(!kigoVal.VCHR(value, kigo.CFG.MISC.MAXLEN_URL, 0))	// Limit to 200 characters
			return false;
		
		if(value.substr(0, 7).toLowerCase() == 'http://')	
		{		
			https = false;
			value = value.substr(7,value.length-1);
		}
		else if(value.substr(0, 8).toLowerCase() == 'https://')
		{
			https = true;
			value = value.substr(8,value.length-1);
		}
		else
			https = false;

		if(!value.length)
		{
			if(mandatory)
				return false;
			return true;
		}

		// Okay, check if the rest looks like valid url

		var exp = /^[a-z0-9-]+(\.[a-z0-9-]+)+(:[0-9]+)?(\/.*)?$/i;
		
		if(!exp.test(value))
			return false;
	
		return true;
	},	

	'KIGO_DOMAIN'			:	function(value)
	{
		// Rules: a-z, 0-9, cannot start with a digit
		var exp = /^([a-z0-9]([-a-z0-9]*[a-z0-9]+)?)$/i;
	
		if(
			!kigoVal.VCHR(value, kigo.CFG.WS.CFG_KIGODOMAIN_MAXLEN, kigo.CFG.WS.CFG_KIGODOMAIN_MINLEN) ||
			!exp.test(value)
		)
			return false;
	
		return true;
	},

	'DOMAIN'			:	function(value)
	{
		// see php definition
		var rgxpDomain = "([a-z0-9]([-a-z0-9]*[a-z0-9]+)?)";
		var exp = new RegExp('^(' + rgxpDomain + '{1,63}\.)+' + rgxpDomain + '{2,63}$','i');
	
		if(
			!kigoVal.VCHR(value, kigo.CFG.WS.CFG_CUSTOMDOMAIN_MAXLEN, kigo.CFG.WS.CFG_CUSTOMDOMAIN_MINLEN) ||
			!exp.test(value)
		)
			return false;
	
		return true;
	},
	
	'REQKEY'			:	function(value)
	{
		return kigoVal.CHRCONTENT(value, '0123456789abcdef', 32);
	},
	
	/**************************************************************************************************************/
	/* PUBLIC / PRIVATE  */


	'STRCONTENT'	:	function(value, pool)
	{
		var len = (value = kigo.trim(value)).length;

		for(var i = 0; i < len; i++)
		{
			if(pool.indexOf(value.substr(i, 1)) == -1)
				return false;
		}

		return true;
	},


	'INTX'			:	function(value, Xmax, min, max)
	{
		if(!kigoVal.VCHRCONTENT(value, '0123456789', 99, 1))
			return false;

		min = (min == null) ? 0 : Math.min(Xmax, Math.max(0, min));
		max = (max == null) ? Xmax : Math.max(1, Math.min(Xmax, max));

		return (value = parseInt(kigo.trim(value), 10)) >= min && value <= max;
	}

};

/* SWFObject v2.1 <http://code.google.com/p/swfobject/>
	Copyright (c) 2007-2008 Geoff Stearns, Michael Williams, and Bobby van der Sluis
	This software is released under the MIT License <http://www.opensource.org/licenses/mit-license.php>
*/
var swfobject=function(){var b="undefined",Q="object",n="Shockwave Flash",p="ShockwaveFlash.ShockwaveFlash",P="application/x-shockwave-flash",m="SWFObjectExprInst",j=window,K=document,T=navigator,o=[],N=[],i=[],d=[],J,Z=null,M=null,l=null,e=false,A=false;var h=function(){var v=typeof K.getElementById!=b&&typeof K.getElementsByTagName!=b&&typeof K.createElement!=b,AC=[0,0,0],x=null;if(typeof T.plugins!=b&&typeof T.plugins[n]==Q){x=T.plugins[n].description;if(x&&!(typeof T.mimeTypes!=b&&T.mimeTypes[P]&&!T.mimeTypes[P].enabledPlugin)){x=x.replace(/^.*\s+(\S+\s+\S+$)/,"$1");AC[0]=parseInt(x.replace(/^(.*)\..*$/,"$1"),10);AC[1]=parseInt(x.replace(/^.*\.(.*)\s.*$/,"$1"),10);AC[2]=/r/.test(x)?parseInt(x.replace(/^.*r(.*)$/,"$1"),10):0}}else{if(typeof j.ActiveXObject!=b){var y=null,AB=false;try{y=new ActiveXObject(p+".7")}catch(t){try{y=new ActiveXObject(p+".6");AC=[6,0,21];y.AllowScriptAccess="always"}catch(t){if(AC[0]==6){AB=true}}if(!AB){try{y=new ActiveXObject(p)}catch(t){}}}if(!AB&&y){try{x=y.GetVariable("$version");if(x){x=x.split(" ")[1].split(",");AC=[parseInt(x[0],10),parseInt(x[1],10),parseInt(x[2],10)]}}catch(t){}}}}var AD=T.userAgent.toLowerCase(),r=T.platform.toLowerCase(),AA=/webkit/.test(AD)?parseFloat(AD.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):false,q=false,z=r?/win/.test(r):/win/.test(AD),w=r?/mac/.test(r):/mac/.test(AD);/*@cc_on q=true;@if(@_win32)z=true;@elif(@_mac)w=true;@end@*/return{w3cdom:v,pv:AC,webkit:AA,ie:q,win:z,mac:w}}();var L=function(){if(!h.w3cdom){return }f(H);if(h.ie&&h.win){try{K.write("<script id=__ie_ondomload defer=true src=//:><\/script>");J=C("__ie_ondomload");if(J){I(J,"onreadystatechange",S)}}catch(q){}}if(h.webkit&&typeof K.readyState!=b){Z=setInterval(function(){if(/loaded|complete/.test(K.readyState)){E()}},10)}if(typeof K.addEventListener!=b){K.addEventListener("DOMContentLoaded",E,null)}R(E)}();function S(){if(J.readyState=="complete"){J.parentNode.removeChild(J);E()}}function E(){if(e){return }if(h.ie&&h.win){var v=a("span");try{var u=K.getElementsByTagName("body")[0].appendChild(v);u.parentNode.removeChild(u)}catch(w){return }}e=true;if(Z){clearInterval(Z);Z=null}var q=o.length;for(var r=0;r<q;r++){o[r]()}}function f(q){if(e){q()}else{o[o.length]=q}}function R(r){if(typeof j.addEventListener!=b){j.addEventListener("load",r,false)}else{if(typeof K.addEventListener!=b){K.addEventListener("load",r,false)}else{if(typeof j.attachEvent!=b){I(j,"onload",r)}else{if(typeof j.onload=="function"){var q=j.onload;j.onload=function(){q();r()}}else{j.onload=r}}}}}function H(){var t=N.length;for(var q=0;q<t;q++){var u=N[q].id;if(h.pv[0]>0){var r=C(u);if(r){N[q].width=r.getAttribute("width")?r.getAttribute("width"):"0";N[q].height=r.getAttribute("height")?r.getAttribute("height"):"0";if(c(N[q].swfVersion)){if(h.webkit&&h.webkit<312){Y(r)}W(u,true)}else{if(N[q].expressInstall&&!A&&c("6.0.65")&&(h.win||h.mac)){k(N[q])}else{O(r)}}}}else{W(u,true)}}}function Y(t){var q=t.getElementsByTagName(Q)[0];if(q){var w=a("embed"),y=q.attributes;if(y){var v=y.length;for(var u=0;u<v;u++){if(y[u].nodeName=="DATA"){w.setAttribute("src",y[u].nodeValue)}else{w.setAttribute(y[u].nodeName,y[u].nodeValue)}}}var x=q.childNodes;if(x){var z=x.length;for(var r=0;r<z;r++){if(x[r].nodeType==1&&x[r].nodeName=="PARAM"){w.setAttribute(x[r].getAttribute("name"),x[r].getAttribute("value"))}}}t.parentNode.replaceChild(w,t)}}function k(w){A=true;var u=C(w.id);if(u){if(w.altContentId){var y=C(w.altContentId);if(y){M=y;l=w.altContentId}}else{M=G(u)}if(!(/%$/.test(w.width))&&parseInt(w.width,10)<310){w.width="310"}if(!(/%$/.test(w.height))&&parseInt(w.height,10)<137){w.height="137"}K.title=K.title.slice(0,47)+" - Flash Player Installation";var z=h.ie&&h.win?"ActiveX":"PlugIn",q=K.title,r="MMredirectURL="+j.location+"&MMplayerType="+z+"&MMdoctitle="+q,x=w.id;if(h.ie&&h.win&&u.readyState!=4){var t=a("div");x+="SWFObjectNew";t.setAttribute("id",x);u.parentNode.insertBefore(t,u);u.style.display="none";var v=function(){u.parentNode.removeChild(u)};I(j,"onload",v)}U({data:w.expressInstall,id:m,width:w.width,height:w.height},{flashvars:r},x)}}function O(t){if(h.ie&&h.win&&t.readyState!=4){var r=a("div");t.parentNode.insertBefore(r,t);r.parentNode.replaceChild(G(t),r);t.style.display="none";var q=function(){t.parentNode.removeChild(t)};I(j,"onload",q)}else{t.parentNode.replaceChild(G(t),t)}}function G(v){var u=a("div");if(h.win&&h.ie){u.innerHTML=v.innerHTML}else{var r=v.getElementsByTagName(Q)[0];if(r){var w=r.childNodes;if(w){var q=w.length;for(var t=0;t<q;t++){if(!(w[t].nodeType==1&&w[t].nodeName=="PARAM")&&!(w[t].nodeType==8)){u.appendChild(w[t].cloneNode(true))}}}}}return u}function U(AG,AE,t){var q,v=C(t);if(v){if(typeof AG.id==b){AG.id=t}if(h.ie&&h.win){var AF="";for(var AB in AG){if(AG[AB]!=Object.prototype[AB]){if(AB.toLowerCase()=="data"){AE.movie=AG[AB]}else{if(AB.toLowerCase()=="styleclass"){AF+=' class="'+AG[AB]+'"'}else{if(AB.toLowerCase()!="classid"){AF+=" "+AB+'="'+AG[AB]+'"'}}}}}var AD="";for(var AA in AE){if(AE[AA]!=Object.prototype[AA]){AD+='<param name="'+AA+'" value="'+AE[AA]+'" />'}}v.outerHTML='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"'+AF+">"+AD+"</object>";i[i.length]=AG.id;q=C(AG.id)}else{if(h.webkit&&h.webkit<312){var AC=a("embed");AC.setAttribute("type",P);for(var z in AG){if(AG[z]!=Object.prototype[z]){if(z.toLowerCase()=="data"){AC.setAttribute("src",AG[z])}else{if(z.toLowerCase()=="styleclass"){AC.setAttribute("class",AG[z])}else{if(z.toLowerCase()!="classid"){AC.setAttribute(z,AG[z])}}}}}for(var y in AE){if(AE[y]!=Object.prototype[y]){if(y.toLowerCase()!="movie"){AC.setAttribute(y,AE[y])}}}v.parentNode.replaceChild(AC,v);q=AC}else{var u=a(Q);u.setAttribute("type",P);for(var x in AG){if(AG[x]!=Object.prototype[x]){if(x.toLowerCase()=="styleclass"){u.setAttribute("class",AG[x])}else{if(x.toLowerCase()!="classid"){u.setAttribute(x,AG[x])}}}}for(var w in AE){if(AE[w]!=Object.prototype[w]&&w.toLowerCase()!="movie"){F(u,w,AE[w])}}v.parentNode.replaceChild(u,v);q=u}}}return q}function F(t,q,r){var u=a("param");u.setAttribute("name",q);u.setAttribute("value",r);t.appendChild(u)}function X(r){var q=C(r);if(q&&(q.nodeName=="OBJECT"||q.nodeName=="EMBED")){if(h.ie&&h.win){if(q.readyState==4){B(r)}else{j.attachEvent("onload",function(){B(r)})}}else{q.parentNode.removeChild(q)}}}function B(t){var r=C(t);if(r){for(var q in r){if(typeof r[q]=="function"){r[q]=null}}r.parentNode.removeChild(r)}}function C(t){var q=null;try{q=K.getElementById(t)}catch(r){}return q}function a(q){return K.createElement(q)}function I(t,q,r){t.attachEvent(q,r);d[d.length]=[t,q,r]}function c(t){var r=h.pv,q=t.split(".");q[0]=parseInt(q[0],10);q[1]=parseInt(q[1],10)||0;q[2]=parseInt(q[2],10)||0;return(r[0]>q[0]||(r[0]==q[0]&&r[1]>q[1])||(r[0]==q[0]&&r[1]==q[1]&&r[2]>=q[2]))?true:false}function V(v,r){if(h.ie&&h.mac){return }var u=K.getElementsByTagName("head")[0],t=a("style");t.setAttribute("type","text/css");t.setAttribute("media","screen");if(!(h.ie&&h.win)&&typeof K.createTextNode!=b){t.appendChild(K.createTextNode(v+" {"+r+"}"))}u.appendChild(t);if(h.ie&&h.win&&typeof K.styleSheets!=b&&K.styleSheets.length>0){var q=K.styleSheets[K.styleSheets.length-1];if(typeof q.addRule==Q){q.addRule(v,r)}}}function W(t,q){var r=q?"visible":"hidden";if(e&&C(t)){C(t).style.visibility=r}else{V("#"+t,"visibility:"+r)}}function g(s){var r=/[\\\"<>\.;]/;var q=r.exec(s)!=null;return q?encodeURIComponent(s):s}var D=function(){if(h.ie&&h.win){window.attachEvent("onunload",function(){var w=d.length;for(var v=0;v<w;v++){d[v][0].detachEvent(d[v][1],d[v][2])}var t=i.length;for(var u=0;u<t;u++){X(i[u])}for(var r in h){h[r]=null}h=null;for(var q in swfobject){swfobject[q]=null}swfobject=null})}}();return{registerObject:function(u,q,t){if(!h.w3cdom||!u||!q){return }var r={};r.id=u;r.swfVersion=q;r.expressInstall=t?t:false;N[N.length]=r;W(u,false)},getObjectById:function(v){var q=null;if(h.w3cdom){var t=C(v);if(t){var u=t.getElementsByTagName(Q)[0];if(!u||(u&&typeof t.SetVariable!=b)){q=t}else{if(typeof u.SetVariable!=b){q=u}}}}return q},embedSWF:function(x,AE,AB,AD,q,w,r,z,AC){if(!h.w3cdom||!x||!AE||!AB||!AD||!q){return }AB+="";AD+="";if(c(q)){W(AE,false);var AA={};if(AC&&typeof AC===Q){for(var v in AC){if(AC[v]!=Object.prototype[v]){AA[v]=AC[v]}}}AA.data=x;AA.width=AB;AA.height=AD;var y={};if(z&&typeof z===Q){for(var u in z){if(z[u]!=Object.prototype[u]){y[u]=z[u]}}}if(r&&typeof r===Q){for(var t in r){if(r[t]!=Object.prototype[t]){if(typeof y.flashvars!=b){y.flashvars+="&"+t+"="+r[t]}else{y.flashvars=t+"="+r[t]}}}}f(function(){U(AA,y,AE);if(AA.id==AE){W(AE,true)}})}else{if(w&&!A&&c("6.0.65")&&(h.win||h.mac)){A=true;W(AE,false);f(function(){var AF={};AF.id=AF.altContentId=AE;AF.width=AB;AF.height=AD;AF.expressInstall=w;k(AF)})}}},getFlashPlayerVersion:function(){return{major:h.pv[0],minor:h.pv[1],release:h.pv[2]}},hasFlashPlayerVersion:c,createSWF:function(t,r,q){if(h.w3cdom){return U(t,r,q)}else{return undefined}},removeSWF:function(q){if(h.w3cdom){X(q)}},createCSS:function(r,q){if(h.w3cdom){V(r,q)}},addDomLoadEvent:f,addLoadEvent:R,getQueryParamValue:function(v){var u=K.location.search||K.location.hash;if(v==null){return g(u)}if(u){var t=u.substring(1).split("&");for(var r=0;r<t.length;r++){if(t[r].substring(0,t[r].indexOf("="))==v){return g(t[r].substring((t[r].indexOf("=")+1)))}}}return""},expressInstallCallback:function(){if(A&&M){var q=C(m);if(q){q.parentNode.replaceChild(M,q);if(l){W(l,true);if(h.ie&&h.win){M.style.display="block"}}M=null;l=null;A=false}}}}}();
/* ws/fastSearch/static/js/embedSwf.js */ /* UTF8-Côôkie */

/*
These are used to obfuscate URL's google started indexing in a wrong way - it doesnt take the base path into account - resulting
in 404 errors being reported in Google Webmaster Tools, while the files do exist in different location.


24/11/2009 - Heavily extended for flash detection and install
*/


function	fsEmbedSwf(url, width, height, container, minver)	// [, id [, flashvars [, params ] ] ]
{
	var	attributes = { 'align' : 'middle' };
	var	params = {
		'play'				:	'true',
		'menu'				:	'false',
		'loop'				:	'true',
		'quality'			:	'high',
		'base'				:	'.',
		'scale'				:	'noscale',
		'salign'			:	'TL',
		'devicefont'		:	'false',
		'allowScriptAccess'	:	'sameDomain',
		'allowFullScreen'	:	'true',
		'wmode'				:	'window'
	};


	// Additional attributes
	if(arguments.length > 5 && arguments[5] != null)
		attributes['id'] = arguments[5];

	// Override params
	if(arguments.length > 7)
	{
		var p = arguments[7];

		for(prop in p)
		{
			if(
				typeof(prop) == 'string' &&
				p.hasOwnProperty(prop) &
				typeof(p[prop]) == 'string'
			)
				params[prop] = p[prop];
		}
	}


	function	installButton(popup)
	{
		var	a = document.createElement('a'), span = document.createElement('span');
		
		a.className = 'install';
		a.setAttribute('href', fsEmbedSwf.flashInstallURL);
		a.onclick = function() 
		{ 
			alert(fsEmbedSwf.flashInstallBrowserRestartText);
			window.open(fsEmbedSwf.flashInstallURL); 
			if(popup != undefined)
				popup.parentNode.removeChild(popup);

			return false; 
		};
		a.title = fsEmbedSwf.flashInstallButtonTitle;
		
		span.appendChild(document.createTextNode(fsEmbedSwf.flashInstallButtonText));
		a.appendChild(span);

		return a;
	}

	function	closePopupButton(popup)
	{
		var	a = document.createElement('a'), span = document.createElement('span');

		a.className = 'close';
		a.setAttribute('href', '#');
		a.onclick = function() { popup.parentNode.removeChild(popup); return false;};
		a.title = fsEmbedSwf.flashInstallPopupCloseButtonText;

		span.appendChild(document.createTextNode(fsEmbedSwf.flashInstallPopupCloseButtonText));
		a.appendChild(span);

		return a;
	}

	function	embedUpgrade(where, width, height)
	{
		swfobject.embedSWF(
			WS_ROOT+'swf/kigoFlashUpgrade.swf',
			where,
			width, height,
			'6.0.65',
			'',
			{},
			{
				'play'				:	'true',
				'menu'				:	'false',
				'loop'				:	'false',
				'quality'			:	'high',
				'scale'				:	'noscale',
				'base'				:	'/',
				'wmode'				:	'opaque',
				'allowScriptAccess'	:	'sameDomain',
				'allowFullScreen'	:	'true',
				'devicefont'		:	'false',
				'salign'			:	'TL',
				'flashvars'			:	'class=fsEmbedSwf'
			},
			{
				'align'				:	'middle'
			}
		);
	}



	function	fakeContainer()
	{
		// Give the container dimensions of the requested flash move, so that the layout is (hopefully) not impacted

		function	doIt()
		{
			if(container = vkDom.el(container))
			{
				vkDom.addClass(container, 'flash_missing_placeholder');
				// Force same dimensions as the flash movie
				container.style.display = 'block';
				container.style.width = width+'px';
				container.style.height = height+'px';
				container.appendChild(installButton());
			}
		}

		if(vkDom.el('container'))
			doIt();
		else
			vkDom.onLoad(doIt);
	}

	function	upgradeContainer()
	{
		embedUpgrade(container, width, height);
	}


	// Check whether we have the minimum version for easy flash player upgrade...
	if(!swfobject.hasFlashPlayerVersion('6.0.65'))
	{
		// Okay, create a fake container for this flash movie
		fakeContainer();

		// Warn once per session only...
		if(vkDom.getCookie('_FLASH_INSTALL_POPUP') != 'WARNED')
		{
			vkDom.setCookie('_FLASH_INSTALL_POPUP', 'WARNED');

			// Display message once for any number of flash movies
			vkDom.onLoad(
				function()
				{
					var	popup = document.createElement('div');

					popup.className = 'flash_install_popup';
					// The popup is always positioned in the middle of the screen, therefore we have to build everything before computing its size
					popup.style.display = 'block';
					popup.style.position = 'absolute';

						var	textDiv = document.createElement('div');
						textDiv.className = 'text';

							var	span = document.createElement('span');
							span.appendChild(document.createTextNode(fsEmbedSwf.flashInstallPopupText));

						textDiv.appendChild(span);

					popup.appendChild(textDiv);

						var	btnDiv = document.createElement('div');
						btnDiv.className = 'buttons';

						btnDiv.appendChild(installButton(popup));
						btnDiv.appendChild(closePopupButton(popup));

					popup.appendChild(btnDiv);


					document.body.appendChild(popup);
					// Okay, move to the center of the screen

					popup.style.left = (Math.max(document.documentElement.scrollLeft, document.body.scrollLeft) + ((document.documentElement.clientWidth-popup.clientWidth)>>1))+'px';
					popup.style.top = (Math.max(document.documentElement.scrollTop, document.body.scrollTop) + ((document.documentElement.clientHeight-popup.clientHeight)>>1))+'px';
				}
			);
		}

		return;
	}

	// Check whether we have the minimum version for the requested flash movie
	if(!swfobject.hasFlashPlayerVersion(minver))
	{
		/*
			Okay, the idea is to display popup only if we found no flash container big enough to hold the installer
		
			That is:

			- If this container is big enough, set the container to hold the updater
			- Otherwise, if there was already a container big enough, don't do anything except creating a fake container
			- Otherwise, wait till the dom is loaded to see if the popup is necessary
		*/


		if(
			false &&
			width >= fsEmbedSwf.flashUpgradeMovieWidth &&
			height >= fsEmbedSwf.flashUpgradeMovieHeight
		)
		{
			fsEmbedSwf.upgradeContainerOnPage = true;
			upgradeContainer();
		}
		else
		{
			// Always
			fakeContainer();

			if(!fsEmbedSwf.upgradeContainerOnPage)
			{
				vkDom.onLoad(
					function()
					{
						// Okay, check whether we displayed at least one fake upgrade container
						if(!fsEmbedSwf.upgradeContainerOnPage)
						{
							// We didn't - display a popup!
							// There is nothing to style

							var	popup = document.createElement('div');
							
							popup.className = 'flash_upgrade_popup';
			
							popup.style.width = fsEmbedSwf.flashUpgradeMovieWidth+'px';
							popup.style.height = fsEmbedSwf.flashUpgradeMovieHeight+'px';

							popup.style.display = 'block';
							popup.style.position = 'absolute';

								var	span = document.createElement('span');
								span.id = 'kigoFlashUpgrade_'+(new Date()).getTime()+Math.floor(Math.random()*999999999);
								popup.appendChild(span);


							document.body.appendChild(popup);
							// Okay, move to the center of the screen

							popup.style.left = (Math.max(document.documentElement.scrollLeft, document.body.scrollLeft) + ((document.documentElement.clientWidth-popup.clientWidth)>>1))+'px';
							popup.style.top = (Math.max(document.documentElement.scrollTop, document.body.scrollTop) + ((document.documentElement.clientHeight-popup.clientHeight)>>1))+'px';
							
							embedUpgrade(span.id, fsEmbedSwf.flashUpgradeMovieWidth, fsEmbedSwf.flashUpgradeMovieHeight);

							fsEmbedSwf.updatePopup = popup;
						}

					}
				);
			}
		}

		return;
	}

	// Okay, finally do embed the right flash movie

	// The original version
	swfobject.embedSWF(
		WS_ROOT+url+'.swf',
		container,
		width, height,
		minver,
		'',
		arguments.length > 6 ? arguments[6] : {},
		params,
		attributes
	);
}



// Config vars
fsEmbedSwf.flashInstallURL = 'http://get.adobe.com/fr/flashplayer/';
fsEmbedSwf.flashInstallButton = WS_ROOT+'img/Get_Adobe_Flash_Player.gif';
fsEmbedSwf.flashInstallButtonTitle = 'Get Adobe Flash Player';
fsEmbedSwf.flashInstallButtonText = 'Get Adobe Flash Player';

fsEmbedSwf.flashInstallPopupText = 'The Adobe Flash Player is required for correctly viewing this website, and some other websites such as Google\'s YouTube.';
fsEmbedSwf.flashInstallPopupCloseButtonText = 'close';
fsEmbedSwf.flashInstallBrowserRestartText = 'You may need to restart your browser after installing the Adobe Flash Player.';

/*
fsEmbedSwf.flashUpgradeSuccessText = 	'The Adobe Flash Player was successfully upgraded to the latest version.\n'+
										'\n'+
										'However, you need to restart your browser for the changes to take effect.',
*/

fsEmbedSwf.flashInstallButtonWidth = 112;
fsEmbedSwf.flashInstallButtonHeight = 33;

fsEmbedSwf.flashUpgradeMovieWidth = 310;
fsEmbedSwf.flashUpgradeMovieHeight = 137;


// State vars
fsEmbedSwf.upgradeContainerOnPage = false;
fsEmbedSwf.updatePopup = null;



// Static callbacks


fsEmbedSwf.flashInstallReady = function()
{
	// Nothing...
}

fsEmbedSwf.flashInstallFailed = function()
{
	fsEmbedSwf.updatePopup.parentNode.removeChild(fsEmbedSwf.updatePopup);
}

fsEmbedSwf.flashInstallTimedOut = fsEmbedSwf.flashInstallFailed;
fsEmbedSwf.flashInstallCanceled = fsEmbedSwf.flashInstallFailed;

fsEmbedSwf.flashInstallComplete = function()
{
	//alert(fsEmbedSwf.flashUpgradeSuccessText);
}















function	fsEmbedPPP(propId, type, code, width, height, container)
{
	fsEmbedSwf(
		'ppp/player/'+code, 
		width, height, 
		container, 
		_CFG_PPP_PLAYER_SWF_MINFLASHVERSION, 
		null, 
		{
			'images'			:	WS_ROOT+'ppp/imagelist/'+propId+'.xml',
			'baseimageurl'		:	WS_ROOT+'ppp/img',
			'params'			:	WS_ROOT+'ppp/params/'+type+'.xml',
			'width'				:	width,
			'height'			:	height
		}
	);
}


/* ws/fastSearch/static/js/debug_disable.js */

var	debug = new vkDebug();
debug.enable(false);
kigo.CFG = {"MISC":{"MAXLEN_EMAIL":200,"MAXLEN_URL":200}}; 
