//*******************************************************************************
//* inc.main.js
//*******************************************************************************
//* LogBook 0.24.x - Copyright © Maxime MARCONATO / MaaaX (maxime@maaax.com).
//* 
//* Notice : This computer program is not a freeware. It is protected by
//* copyright laws and international treaties. Unauthorized reproduction or
//* distribution of this program, or any portion of it, may result in severe
//* civil and criminal penalties, and will be prosecuted to the maximum extent
//* possible under the law.
//*******************************************************************************

//*******************************************************************************
//* undefined
//*******************************************************************************
//* global 'undefined' object reference
//*==============================================================================
//* @public
//* @type [Undefined]
//*******************************************************************************
var undefined;

//*******************************************************************************
//* Object.prototype.hasOwnProperty
//*******************************************************************************
//* Determines whether or not the property was added to the object instance.
//* Returns false if the property is not present in the object, or was inherited
//* from the prototype. This abstraction is provided to enable hasOwnProperty for
//* Safari 1.3 and IE 5.0
//*==============================================================================
//* @public
//* @param p [String]
//* 	The property being testing
//* @return [Boolean]
//* 	Returns false if the property is not present in the object, or was
//* 	inherited from the prototype
//*******************************************************************************
if(!Object.prototype.hasOwnProperty)
{
	Object.prototype.hasOwnProperty = function(p)
	{
		try
		{
			if($Lu.isUndefined(this[p]))
				return false;
			var a = this.constructor.prototype;
			while(a)
			{
				if(a[p] == this[p])
					return false;
				a = a.prototype;
			}
			return true;
		}
		catch(X)
		{
			return false;
		}
	};
}

//*******************************************************************************
//* Function.prototype.call
//*******************************************************************************
//* Function call() method that is missing in IE 5.0
//*==============================================================================
//* @public
//* @param o [Object]
//* 	Object to call on
//* @param arguments [Any*]
//* 	Function parameters
//* @return [Any]
//* 	Depending of the function called
//*******************************************************************************
if(!Function.prototype.call)
{
	Function.prototype.call = function(o)
	{
		var a = [];
		for(var i = 1; i < arguments.length; i++)
			a[a.length] = 'arguments['+i+']';
		o._function_prototype_call_f = this;
		var r = eval('o._function_prototype_call_f('+ a.join(',')+')');
		delete o._function_prototype_call_f;
		return r;
	};
}

//*******************************************************************************
//* Function.prototype.apply
//*******************************************************************************
//* Function apply() method that is missing in IE 5.0
//*==============================================================================
//* @public
//* @param o [Object]
//* 	Object to call on
//* @param p [Array]
//* 	Function parameters
//* @return [Any]
//* 	Depending of the function called
//*******************************************************************************
if(!Function.prototype.apply)
{
	Function.prototype.apply = function(o, p)
	{
		o._function_prototype_apply_f = this;
		var a = [];
		if(p)
			for(var i = 0; i < p.length; i++)
				a[a.length] = 'p['+i+']';
		var r = eval('o._function_prototype_apply_f('+a.join(',')+')');
		delete o._function_prototype_apply_f;
		return r;
	};
}

//*******************************************************************************
//* Array.prototype.pop
//*******************************************************************************
//* Array pop() method that is missing in IE 5.0
//*==============================================================================
//* @public
//* @no_param
//* @return [Number]
//* 	Last array index
//*******************************************************************************
if(!Array.prototype.pop)
{
	Array.prototype.pop = function()
	{
		var l;
		if(this.length)
		{
			l = this[this.length - 1];
			this.length -= 1;
		}
		return l;
	};
}

//*******************************************************************************
//* Array.prototype.push
//*******************************************************************************
//* Array push() method that is missing in IE 5.0
//*==============================================================================
//* @public
//* @no_param
//* @return [Number]
//* 	Last array index
//*******************************************************************************
if(!Array.prototype.push)
{
	Array.prototype.push = function()
	{
		for(var i = 0; i < arguments.length; i++)
			this[this.length] = arguments[i];
		return this.length;
	};
}

//*******************************************************************************
//* Array.prototype.shift
//*******************************************************************************
//* Simulation of Array shift() method that is missing in IE 5.0
//*==============================================================================
//* @public
//* @no_param
//* @return [Number]
//* 	First array index
//*******************************************************************************
if(!Array.prototype.shift)
{
	Array.prototype.shift = function()
	{
		var f;
		if(this.length)
		{
			f = this[0];
			for(var i = 0; i < this.length - 1; i++)
				this[i] = this[i + 1];
			this.length -= 1;
		}
		return f;
	};
}

//*******************************************************************************
//* Array.prototype.unshift
//*******************************************************************************
//* Simulation of Array unshift() method that is missing in IE 5.0
//*==============================================================================
//* @public
//* @no_param
//* @return [Number]
//* 	Last array index
//*******************************************************************************
if(!Array.prototype.unshift)
{
	Array.prototype.unshift = function()
	{
		if(arguments.length)
		{
			var i, l = arguments.length;
			for(i = this.length + l - 1; i >= l; i--)
				this[i] = this[i - l];
			for(i = 0; i < l; i++)
				this[i] = arguments[i];
		}
		return this.length;
	};
}

//*******************************************************************************
//* Array.prototype.splice
//*******************************************************************************
// Array splice() method that is missing in IE 5.0
//*==============================================================================
//* @public
//* @param i [Number]
//* 	Index of the first element
//* @param n [Number]
//* 	Number of element to remove
//* @return [Array]
//* 	Array composed of removed elements
//*******************************************************************************
if(!Array.prototype.splice)
{
	Array.prototype.splice = function(i, n)
	{
		var e = [], r = [], j;
		for(j = 2; j < arguments.length; j++)
			e.push(arguments[j]);
		for(j = i; (j < i + n) && (j < this.length); j++)
			r.push(this[j]);
		for(j = i + n; j < this.length; j++)
			this[j - n] = this[j];
		this.length -= r.length;
		for(j = this.length + e.length - 1; j >= i + e.length; j--)
			this[j] = this[j - e.length];
		for(j = 0; j < e.length; j++)
			this[i + j] = e[j];
		return r;
	};
}

//*******************************************************************************
//* Array.prototype.indexOf
//*******************************************************************************
//* Array indexOf() method that appear in Firefox. See also :
//* http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:indexOf
//*==============================================================================
//* @public
//* @param s [Any]
//* 	Element to locate in the array
//* @param f [Any]
//* 	The index at which to begin the search
//* @return [Number]
//* 	The first index at which a given element can be found in the array, or -1
//* 	if it is not present
//*******************************************************************************
if(!Array.prototype.indexOf)
{
	Array.prototype.indexOf = function(s, f)
	{
		if(!f)
			f = 0;
		for(var i = f; i < this.length; i++)
			if(this[i] == s)
				return i;
		return -1;
	};
}

//*******************************************************************************
//* Array.prototype.insertBefore
//*******************************************************************************
//* Inserts the element into an array.
//* It influences the order in which the elements will be iterated in the
//* for...in cycle.
//*==============================================================================
//* @public
//* @param v [Any]
//* 	The value of the element to insert
//* @param i [Number]
//* 	Index of the element to be inserted before
//* @no_return
//*******************************************************************************
if(!Array.prototype.insertBefore)
{
	Array.prototype.insertBefore = function(v, i)
	{
		for(var j = this.length; j > i; j--)
			this[j] = this[j - 1];
		this[i] = v;
	};
}

//*******************************************************************************
//* Array.prototype.insertAfter
//*******************************************************************************
//* Inserts the element into an array. 
//* It influences the order in which the elements will be iterated in the
//* for...in cycle.
//*==============================================================================
//* @public
//* @param v [Any]
//* 	The value of the element to insert
//* @param i [Number]
//* 	Index of the element to be inserted after
//* @no_return
//*******************************************************************************
if(!Array.prototype.insertAfter)
{
	Array.prototype.insertAfter = function(v, i)
	{
		for(var j = this.length; j > i + 1; j--)
			this[j] = this[j - 1];
		this[i + 1] = v;
	};
}

//*******************************************************************************
//* String.prototype.isStyle
//*******************************************************************************
//* Determines if it's a CSS style definition
//*==============================================================================
//* @public
//* @no_param
//* @return [Boolean]
//* 	True if the string is a CSS style definition
//*******************************************************************************
if(!String.prototype.isStyle)
{
	String.prototype.isStyle = function()
	{
		return (/^([a-z\-_]{1}[a-z0-9\-_]{2,}\s*:[a-z0-9\s\-_=,\.:#%\(\)\/']+;?)+$/i.test(this));
	};
}

//*******************************************************************************
//* String.prototype.isClass
//*******************************************************************************
//* Determines if the string is a CSS class name
//*==============================================================================
//* @public
//* @no_param
//* @return [Boolean]
//* 	True if the string is a CSS class name
//*******************************************************************************
if(!String.prototype.isClass)
{
	String.prototype.isClass = function()
	{
		return (/^[a-z_]{1}[a-z0-9\-_]*$/i.test(this));
	};
}

//*******************************************************************************
//* String.prototype.contains
//*******************************************************************************
//* Determines if a string contains a text
//*==============================================================================
//* @public
//* @param arguments [String*]
//* 	One or more string can be passed in argument.
//* 	i.e.: myString.contains('a', 'b', 'c', ...)
//* @return [Boolean]
//* 	True if the string contains the text
//*******************************************************************************
if(!String.prototype.contains)
{
	String.prototype.contains = function()
	{
		for(var i = 0; i < arguments.length; i++)
			if(this.indexOf(arguments[i]) > -1)
				return true;
		return false;
	};
}

//*******************************************************************************
//* String.prototype.equals
//*******************************************************************************
//* Determines if a string equals a text
//*==============================================================================
//* @public

//* @param arguments [String*]
//* 	One or more string can be passed in argument.
//* 	i.e.: myString.equals('a', 'b', 'c', ...)
//* @return [Boolean]
//* 	True if the string equals the text
//*******************************************************************************
if(!String.prototype.equals)
{
	String.prototype.equals = function()
	{
		for(var i = 0; i < arguments.length; i++)
			if(this == arguments[i])
				return true;
		return false;
	};
}

//*******************************************************************************
//* String.prototype.startsWith
//*******************************************************************************
//* Determines if the string starts with a text
//*==============================================================================
//* @public
//* @param arguments [String*]
//* 	One or more string can be passed in argument.
//* 	i.e.: myString.startsWith('a', 'b', 'c', ...)
//* @return [Boolean]
//* 	True if the string starts with the text
//*******************************************************************************
if(!String.prototype.startsWith)
{
	String.prototype.startsWith = function()
	{
		for(var i = 0; i < arguments.length; i++)
			if(this.substr(0, arguments[i].length) == arguments[i])
				return true;
		return false;
	};
}

//*******************************************************************************
//* String.prototype.endsWith
//*******************************************************************************
//* Determines if the string ends with a text
//*==============================================================================
//* @public
//* @param arguments [String*]
//* 	One or more string can be passed in argument.
//* 	i.e.: myString.endsWith('a', 'b', 'c', ...)
//* @return [Boolean]
//* 	True if the string ends with the text
//*******************************************************************************
if(!String.prototype.endsWith)
{
	String.prototype.endsWith = function()
	{
		for(var i = 0; i < arguments.length; i++)
			if(this.substr(this.length - arguments[i].length, arguments[i].length) == arguments[i])
				return true;
		return false;
	};
}

//*******************************************************************************
//* String.prototype.remove
//*******************************************************************************
//* Removes a part of the string
//*==============================================================================
//* @public
//* @param s [Number]
//* 	Start of the part to remove
//* @param l [Number]
//* 	Length of the part to remove
//* @return [String]
//* 	Result String
//*******************************************************************************
if(!String.prototype.remove)
{
	String.prototype.remove = function(s, l)
	{
		var r = '';
		if(s > 0)
			r = this.substring(0, s);
		if((s + l) < this.length)
			r += this.substring(s + l, this.length);
		return r;
	};
}

//*******************************************************************************
//* String.prototype.trim
//*******************************************************************************
//* Trim a String. Removes white spaces at start and at end of a string.
//*==============================================================================
//* @public
//* @no_param
//* @return [String]
//* 	Result String
//*******************************************************************************
if(!String.prototype.trim)
{
	String.prototype.trim = function()
	{
		return this.replace(/^\s*|\s*$/g, '');
	};
}

//*******************************************************************************
//* String.prototype.lTrim
//*******************************************************************************
//* Left trim a string. Removes white spaces at start of a string.
//*==============================================================================
//* @public
//* @no_param
//* @return [String]
//* 	Result String
//*******************************************************************************
if(!String.prototype.lTrim)
{
	String.prototype.lTrim = function()
	{
		return this.replace(/^\s*/g, '');
	};
}

//*******************************************************************************
//* String.prototype.rTrim
//*******************************************************************************
//* Right trim a string. Removes white spaces at end of a string.
//*==============================================================================
//* @public
//* @no_param
//* @return [String]
//* 	Result String
//*******************************************************************************
if(!String.prototype.rTrim)
{
	String.prototype.rTrim = function()
	{
		return this.replace(/\s*$/g, '');
	};
}

//*******************************************************************************
//* String.prototype.replaceNewLineChars
//*******************************************************************************
//* Replaces any all new line chars '\r\n' and '\n' by a replacement string
//*==============================================================================
//* @public
//* @param r [String]
//* 	Replacement string. Default: '' (empty string)
//* @return [String]
//* 	Result String
//*******************************************************************************
if(!String.prototype.replaceNewLineChars)
{
	String.prototype.replaceNewLineChars = function(r)
	{
		return this.replace(/\r?\n/g, ''+r);
	};
}

//*******************************************************************************
//* LOGBOOK
//*******************************************************************************
//* The LOGBOOK global namespace object
//*==============================================================================
//* @public
//* @type [Object]
//*******************************************************************************
var LOGBOOK = function()
{
	if(window.onerror)
		window.onerror = function()
		{
			return true;
		};
	return {};
}, $L = LOGBOOK;

//*******************************************************************************
//* LOGBOOK.env
//*******************************************************************************
//* LOGBOOK.env is used to keep track of what is known about the LogBook library
//* and the browsing environment
//*==============================================================================
//* @public
//* @type [Object]
//*******************************************************************************
var $Le = LOGBOOK.env = function()
{
	return {
		//*******************************************************************************
		//* LOGBOOK.env.undefined
		//*******************************************************************************
		//* 'undefined' object reference
		//*==============================================================================
		//* @public
		//* @type [undefined]
		//*******************************************************************************
		undefined: undefined,
	
		//*******************************************************************************
		//* LOGBOOK.env.modules
		//*******************************************************************************
		//* Keeps the version info for all LogBook modules that have reported themselves
		//*==============================================================================
		//* @public
		//* @type [Objects Array]
		//*******************************************************************************
// TODO:
//		modules: [],
	
		//*******************************************************************************
		//* LOGBOOK.env.listeners
		//*******************************************************************************
		//* Lists functions that should be executed every time a LogBook module reports
		//* itself
		//*==============================================================================
		//* @public
		//* @type [Functions Array]
		//*******************************************************************************
// TODO:
//		listeners: [],
	
		//*******************************************************************************
		//* LOGBOOK.env.ua
		//*******************************************************************************
		//* Stores a version number for the user agent (layout engine or web browser),
		//* 0 otherwise.
		//* The value is presented as a float so that it can easily be used for boolean
		//* evaluation as well as for looking for a particular range of versions. Because
		//* of this, some of the granularity of the version info may be lost
		//* (e.g., Gecko 1.9.1.13' reports 1.9).
		//*==============================================================================
		//* @public
		//* @type [Object]
		//*******************************************************************************
		ua: function()
		{
			var ua = 	
			{
				//*******************************************************************************
				//* LOGBOOK.env.ua.ie
				//*******************************************************************************
				//* Keeps the Internet Explorer version number or 0.
				//* Internet Explorer is a web browser that use the Trident layout engine since
				//* v4.0 but the version of Trident was not visible before Internet Explorer 8.0
				//* Example: 5.5
				//*==============================================================================
				//* @public
				//* @type [Number]
				//*******************************************************************************
				ie: 0,
	
				//*******************************************************************************
				//* LOGBOOK.env.ua.gk
				//*******************************************************************************
				//* Keeps the Gecko version number or 0.
				//* Will evaluate to 1 if Gecko is detected but the revision could not be found,
				//* oher browsers will be 0.
				//* Gecko is a layout engine used by Firefox, Mozilla, SeaMonkey, Netscape,
				//* Camino and other web browsers.
				//* Example: 1.8
				//* Netscape 6.01	:	''		--> Reports 1
				//* Netscape 7.0	:	'rv:1.0.1'	--> Reports 1
				//* Firefox 1.0.0.4	:	'rv:1.7.8'	--> Reports 1.7
				//* Firefox 1.5.0.9	:	'rv:1.8.0.9'	--> Reports 1.8
				//* Firefox 2.0.0.3	:	'rv:1.8.1.3'	--> Reports 1.8
				//* Firefox 3 alpha	:	'rv:1.9a4'	--> Reports 1.9
				//* Firefox 3.5.13	:	'rv:1.9.1.13'	--> Reports 1.9
				//*==============================================================================
				//* @public
				//* @type [Number]
				//*******************************************************************************
				gk: 0,
	
				//*******************************************************************************
				//* LOGBOOK.env.ua.wk
				//*******************************************************************************
				//* Keeps the WebKit version number or 0.
				//* KHTML browsers that are not WebKit browsers (like Conqueror 4.0 and less)
				//* will evaluate to 1, other browsers 0.
				//* WebKit is a layout engine used by Safari, Chrome, Conqueror (v4.1 and more),
				//* OmniWeb and some other web browsers.
				//* Example: 418.9
				//* Safari 1.3.2 (312.6)	: 312.8.1	--> Reports 312.8
				//* Safari 2.0.2		: 416		--> hasOwnProperty introduced
				//* Safari 2.0.4		: 418		--> preventDefault fixed
				//* Safari 2.0.4 (419.3)	: 418.9.1	--> One version of Safari may run
				//*                                                 different versions of webkit
				//* Safari 2.0.4 (419.3)	: 419		--> Safari 2.0
				//* Webkit 212 nightly		: 522+		--> Safari 3.0 (with native SVG)
				//* Safari 5.0.2		: 533		--> Safari 5.0
				//* http://developer.apple.com/internet/safari/uamatrix.html
				//*==============================================================================
				//* @public
				//* @type [Number]
				//*******************************************************************************
				wk: 0,
	
				//*******************************************************************************
				//* LOGBOOK.env.ua.op
				//*******************************************************************************
				//* Keeps the Opera version number or 0.
				//* Opera is a web browser that used the Elektra layout engine from v4 to v6 and
				//* the Presto layout engine from v7 and more.
				//* Example: 9.2
				//*==============================================================================
				//* @public
				//* @type [Number]
				//*******************************************************************************
				op: 0
			};
			{
				var u = navigator.userAgent, m;

				// Look for WebKit
				if(/KHTML/i.test(u))	// Modern KHTML browsers should qualify as Safari X-Grade
					ua.wk = 1;
				m = u.match(/WebKit\/([^\s]*)/i); // Modern WebKit browsers are at least X-Grade
				if(m && m[1])
					ua.wk = parseFloat(m[1]);
	
				if(ua.wk == 0)
				{
					// Look for Opera
					m = u.match(/Opera[\s\/]([^\s]*)/i);
					if(m && m[1])
					{
						ua.op = 1; // Opera detected, look for revision
						m = u.match(/Version\/([^\s\)]*)/i);
						if(m && m[1])
							ua.op = parseFloat(m[1]);
					}
		
					if(ua.op == 0)
					{
						// Look for Internet Explorer
						m = u.match(/MSIE\s([^;]*)/i);
						if(m && m[1])
							ua.ie = parseFloat(m[1]);

						if(ua.ie == 0)
						{
							// Look for Gecko
							m = u.match(/Gecko\/([^\s]*)/i);
							if(m)
							{
								ua.gk = 1; // Gecko detected, look for revision
								m = u.match(/rv:([^\s\)]*)/i);
								if(m && m[1])
									ua.gk = parseFloat(m[1]);
							}
						}
					}
				}
				return ua;
			}
		}(),
	
		//*******************************************************************************
		//* LOGBOOK.env.os
		//*******************************************************************************
		//* Stores a flag 'true' for the operating system , 'false' otherwise.
		//*==============================================================================
		//* @public
		//* @type [Object]
		//*******************************************************************************
		os: function()
		{
			var o =
			{
				//*******************************************************************************
				//* LOGBOOK.env.os.wn
				//*******************************************************************************
				//* Flag 'true' for Windows or 'false'.
				//*==============================================================================
				//* @public
				//* @type [Boolean]
				//*******************************************************************************
				wn: false,
	
				//*******************************************************************************
				//* LOGBOOK.env.os.mc
				//*******************************************************************************
				//* Flag 'true' for Mac OS, Mac OS X (not IOS) or 'false'.
				//*==============================================================================
				//* @public
				//* @type [Boolean]
				//*******************************************************************************
				mc: false,
	
				//*******************************************************************************
				//* LOGBOOK.env.os.ux
				//*******************************************************************************
				//* Flag 'true' for Unix like (except Mac OS X, iOS and Android) or 'false'.
				//*==============================================================================
				//* @public
				//* @type [Boolean]
				//*******************************************************************************
				ux: false,
	
				//*******************************************************************************
				//* LOGBOOK.env.os.io
				//*******************************************************************************
				//* Flag 'true' for IOS like (iPhone, iPod, iPad) or 'false'.
				//*==============================================================================
				//* @public
				//* @type [Boolean]
				//*******************************************************************************
				io: false,
	
				//*******************************************************************************
				//* LOGBOOK.env.os.an
				//*******************************************************************************
				//* Flag 'true' for Android like or 'false'.
				//*==============================================================================
				//* @public
				//* @type [Boolean]
				//*******************************************************************************
				an: false
			};
			{
				var u = navigator.userAgent;
				// IOS
				if(/ios|cpu os|cpu iphone os|iphone|ipod|ipad/i.test(u))
					o.io = true;
				// Android
				else if(/android/i.test(u))
					o.an = true;
				// Windows
				else if(/windows|win[0-9]+/i.test(u))
					o.wn = true;
				// Mac
				else if(/darwin|apple|mac/i.test(u))
					o.mc = true;
				// Unix
				else if(/bsd|linux|sunos|irix|unix/i.test(u))
					o.ux = true;
				return o;
			}
		}()
	};
}();

//*******************************************************************************
//* LOGBOOK.utl
//*******************************************************************************
//* LOGBOOK.utl is used to store some common utility functions
//*==============================================================================
//* @public
//* @type [Object]
//*******************************************************************************
var $Lu = LOGBOOK.utl = function()
{
	return {
		//*******************************************************************************
		//* LOGBOOK.utl.isArray
		//*******************************************************************************
		//* Determines whether or not the provided object is an array.
		//* Testing typeof/instanceof/constructor of arrays across frame boundaries isn't
		//* possible in Safari unless you have a reference to the other frame to test
		//* against its Array prototype. To handle this case, we test well-known array
		//* properties instead.
		//*==============================================================================
		//* @public
		//* @param o [Any]
		//* 	The object being testing
		//* @return [Boolean]
		//*******************************************************************************
		isArray: function(o)
		{ 
			if(o)
			   return $Lu.isNumber(o.length) && $Lu.isFunction(o.splice) && !$Lu.hasOwnProperty(o.length);
			return false;
		},

		//*******************************************************************************
		//* LOGBOOK.utl.isBoolean
		//*******************************************************************************
		//* Determines whether or not the provided object is a boolean
		//*==============================================================================
		//* @public
		//* @param o [Any]
		//* 	The object being testing
		//* @return [Boolean]
		//*******************************************************************************
		isBoolean: function(o)
		{
			return typeof o === 'boolean';
		},

		//*******************************************************************************
		//* LOGBOOK.utl.isFunction
		//*******************************************************************************
		//* Determines whether or not the provided object is a function
		//*==============================================================================
		//* @public
		//* @param o [Any]
		//* 	The object being testing
		//* @return [Boolean]
		//*******************************************************************************
		isFunction: function(o)
		{
			return typeof o === 'function';
		},

		//*******************************************************************************
		//* LOGBOOK.utl.isNull
		//*******************************************************************************
		//* Determines whether or not the provided object is null
		//*==============================================================================
		//* @public
		//* @param o [Any]
		//* 	The object being testing
		//* @return [Boolean]
		//*******************************************************************************
		isNull: function(o)
		{
			return o === null;
		},

		//*******************************************************************************
		//* LOGBOOK.utl.isNumber
		//*******************************************************************************
		//* Determines whether or not the provided object is a legal number
		//*==============================================================================
		//* @public
		//* @param o [Any]
		//* 	The object being testing
		//* @return [Boolean]
		//*******************************************************************************
		isNumber: function(o)
		{
			return typeof o === 'number' && isFinite(o);
		},

		//*******************************************************************************
		//* LOGBOOK.utl.isObject
		//*******************************************************************************
		//* Determines whether or not the provided object is of type object or function
		//*==============================================================================
		//* @public
		//* @param o [Any]
		//* 	The object being testing
		//* @return [Boolean]
		//*******************************************************************************
		isObject: function(o)
		{
			return(o && (typeof o === 'object' || $Lu.isFunction(o))) || false;
		},

		//*******************************************************************************
		//* LOGBOOK.utl.isString
		//*******************************************************************************
		//* Determines whether or not the provided object is a string
		//*==============================================================================
		//* @public
		//* @param o [Any]
		//* 	The object being testing
		//* @return [Boolean]
		//*******************************************************************************
		isString: function(o)
		{
			return typeof o === 'string';
		},

		//*******************************************************************************
		//* LOGBOOK.utl.isUndefined
		//*******************************************************************************
		//* Determines whether or not the provided object is undefined
		//*==============================================================================
		//* @public
		//* @param o [Any]
		//* 	The object being testing
		//* @return [Boolean]
		//*******************************************************************************
		isUndefined: function(o)
		{
			return typeof o === 'undefined';
		},

		//*******************************************************************************
		//* LOGBOOK.utl.isValue
		//*******************************************************************************
		//* Detects a legitimate non-null value.
		//* Returns false for null/undefined/NaN, true for other values, including 0/false/''
		//*==============================================================================
		//* @public
		//* @param o [Any]
		//* 	The object being testing
		//* @return [Boolean]
		//* 	True if it is not null/undefined/NaN || false
		//*******************************************************************************
		isValue: function(o)
		{	// return (o || o === false || o === 0 || o === ''); // Infinity fails
			return ($Lu.isObject(o) || $Lu.isString(o) || $Lu.isNumber(o) || $Lu.isBoolean(o));
		},

		//*******************************************************************************
		//* LOGBOOK.utl.write
		//*******************************************************************************
		//* Write a string in the document (must be used to avoid active content
		//* activation when adding Flash animations and Java applets in the document)
		//*==============================================================================
		//* @public
		//* @param t [Any]
		//* 	The string or object.toString() value to write in document
		//* @no_return
		//*******************************************************************************
		write: function(t)
		{
			document.write(''+t);
		},

		//*******************************************************************************
		//* LOGBOOK.utl.namespace
		//*******************************************************************************
		//* Returns the namespace specified and creates it if it doesn't exist
		//*==============================================================================
		//* @public
		//* @param arguments [String*]
		//* 	Arguments 1-n namespaces to create 
		//* @return [Object]
		//* 	A reference to the last namespace object created
		//*******************************************************************************
// TODO:
//		namespace: function()
//		{
//			var a = arguments, o = null, i, j, d;
//			for (i = 0; i < a.length; i = i + 1)
//			{
//				d = a[i].split('.'); o = LOGBOOK;
//				for (j = (d[0] == 'LOGBOOK') ? 1 : 0; j < d.length; j++)
//				{
//					o[d[j]] = o[d[j]] || {};
//					o = o[d[j]];
//				}
//			}
//			return o;
//		},

		//*******************************************************************************
		//* LOGBOOK.utl.log
		//*******************************************************************************
		//* Log some text
		//*==============================================================================
		//* @public
		//* @param m [String]
		//* 	The message to log
		//* @param c [String, optional]
		//* 	The log category for the message. Default categories are 'info', 'warn',
		//* 	'error' and 'time'.
		//* 	Custom categories can be used as well.
		//* @param s [String, optional]
		//* 	The source of the the message
		//* @return [Boolean]
		//* 	True if the log operation was successful.
		//*******************************************************************************
// TODO:
//		log: function(m, c, s)
//		{
//			alert('TODO: LOGBOOK.utl.log');
//			/*
//			if ($Lw && $Lw.log)
//				return $Lw.log(m, c, s);
//			*/
//			return false;
//		},

		//*******************************************************************************
		//* LOGBOOK.utl.register
		//*******************************************************************************
		//* Registers a module with the LogBook object
		//*==============================================================================
		//* @public
		//* @param n [String]
		//* 	The name of the module
		//* @param c [Function]
		//* 	A reference to the main class in the module
		//* @param i [Object]
		//* 	Info object for the module (version, authors, etc.)
		//*******************************************************************************
// TODO:
//		register: function(n, c, i)
//		{
//			if(!c)
//				$Lu.log('main class is undefined for module '+n, 'warn');
//
//			// Stores the module data
//			var m = $Le.modules, l = $Le.listeners;
//			if(!m[n])
//				m[n] = {n: '', c: function(){}, i: {}};
//			var o = m[n];
//			o.n = n || '';
//			o.c = c || function(){};
//			o.i = i || {};
//
//			// fire the module load listeners
//			for(var j = 0; j < l.length; j++)
//				l[j](o);
//		},

		//*******************************************************************************
		//* LOGBOOK.utl._fixEnum
		//*******************************************************************************
		//* IE will not enumerate native functions in a derived object even if the
		//* function was overridden.  This is a workaround for specific functions 
		//* we care about on the Object prototype. 
		//*==============================================================================
		//* @private
		//* @param r [Function]
		//* 	The object to receive the augmentation
		//* @param s [Function]
		//* 	The object that supplies the properties to augment
		//* @no_return
		//*******************************************************************************
// TODO:
//		_fixEnum: function(r, s)
//		{
//			if($Le.ua.ie)
//			{
//				var add = ['toString', 'valueOf'];
//				for(var i = 0; i < add.length; i = i + 1)
//				{
//					var fname = add[i], f = s[fname];
//					if($Lu.isFunction(f) && f != Object.prototype[fname])
//						r[fname] = f;
//				}
//			}
//		},

		//*******************************************************************************
		//* LOGBOOK.utl.extend
		//*******************************************************************************
		//* Extends one class with another. Gives ability to access properties and
		//* methods of the superclass having the same names as in subclass.
		//* 
		//* Should be used as follows:
		//* 
		//* // Define SuperClass and its methods
		//* LOGBOOK.SuperClass = function(args){...};
		//* LOGBOOK.SuperClass.prototype.init = function(args){...};
		//* 
		//* // Define SubClass and its methods
		//* LOGBOOK.SubClass = function(args)
		//* {
		//* 	...
		//* 	// Call constructor of superclass
		//* 	LOGBOOK.SubClass.superConstructor.call(this, args);
		//* 	...
		//* };
		//* 
		//* // Extend SuperClass
		//* LOGBOOK.utl.extend(LOGBOOK.SubClass, LOGBOOK.SuperClass);
		//* LOGBOOK.SubClass.prototype.init = function(args)
		//* {
		//* 	...
		//* 	// Call method of superclass
		//* 	LOGBOOK.SubClass.superClass.init.call(this, args);
		//* 	...
		//* };
		//*==============================================================================
		//* @public
		//* @param c [Function]
		//* 	Child class, inheriting class
		//* @param s [Function]
		//* 	Super class, class from which to inherit
		//* @param v [Object, optional]
		//* 	Override, additional properties/methods to add to the child class
		//* 	prototype. These will override the matching items obtained from the
		//* 	superclass if present.
		//* @no_return
		//*******************************************************************************
//		TODO:
//		extend: function(c, s, v)
//		{
//			var i = function(){};
//			i.prototype = s.prototype;
//			c.prototype = new i();
//			c.prototype.constructor = c;
//			c.superConstructor = s;
//			c.superClass = s.prototype;
//			if(s.prototype.constructor == Object.prototype.constructor)
//				s.prototype.constructor = s;
//			if(o)
//			{
//				for(var i in v)
//					c.prototype[i] = v[i];
//				$Lu._fixEnum(c.prototype, v);
//			}
//		},

		//*******************************************************************************
		//* LOGBOOK.utl.augment
		//*******************************************************************************
		//* Applies all properties in the super class to the child class if the child
		//* class does not have these properties yet. Optionally, some methods/properties
		//* can be specified. This option will overwrite the property if child class has
		//* it already. If true is passed as the third parameter, all properties will be
		//* applied and will overwrite properties in the receiver.
		//*==============================================================================
		//* @public
		//* @param c [Function]
		//* 	Child class, receives the augmentation
		//* @param s [Function]
		//* 	Super class, supplies the properties to augment
		//* @param arguments [String*|Boolean, optional]
		//* 	Override, arguments zero or more properties methods to augment the
		//* 	receiver with. If none specified, everything in the supplier will be
		//* 	used unless it would overwrite an existing property in the receiver.
		//* 	If true is specified as the third parameter, all properties will be
		//* 	applied and will overwrite an existing property in the receiver.
		//*******************************************************************************
// 		TODO:
//		augment: function(r, s)
//		{
//			var a = arguments, i, p, v = a[2];
//			if(v && v !== true)
//				// only absorb the specified properties
//				for(i = 2; i < a.length; i++)
//					c[a[i]] = s[a[i]];
//			else
//			{	// take everything, overwriting only if the third parameter is true
//				for(p in s)
//					if(v || !c[p])
//						c[p] = s[p];
//				$Lu._fixEnum(c, s);
//			}
//		},

		//*******************************************************************************
		//* LOGBOOK.utl._uids
		//*******************************************************************************
		//* Object that keeps auto-generated unique Ids counters
		//*==============================================================================
		//* @private
		//* @type [Object]
		//*******************************************************************************
		_uids: {},

		//*******************************************************************************
		//* LOGBOOK.utl.uid
		//*******************************************************************************
		//* Generates an unique ID with the prefix.
		//*==============================================================================
		//* @public
		//* @param e [Object]
		//* 	The element to create the id for
		//* @return [String]
		//* 	The resulting id of the element
		//*******************************************************************************
		uid: function(p)
		{
			p += '';
			if(!_uids[p])
				_uids[p] = 0;
			r = '_LOGBOOK_utl_uids_'+(p!=''?p+'_':'')+_uids[p];
			_uids[p]++;
			return r;
		},
	
		//*******************************************************************************
		//* LOGBOOK.utl.decToHex
		//*******************************************************************************
		//* Convert a decimal number to hexadecimal number
		//*==============================================================================
		//* @public
		//* @param d [Number]
		// *	Decimal number to convert
		//* @return [String]
		//* 	Hexadecimal number
		//*******************************************************************************
		decToHex: function(d)
		{
			return d.toString(16);
		},

		//*******************************************************************************
		//* LOGBOOK.utl.Utils.hexToDec
		//*******************************************************************************
		//* Convert a hexadecimal number to decimal number
		//*==============================================================================
		//* @public
		//* @param h [String]
		//* 	Hexadecimal number to convert
		//* @return [Number]
		//* 	Decimal number
		//*******************************************************************************
		hexToDec: function(h)
		{ 
			return parseInt(''+h, 16); 
		}
	};
}();

//*******************************************************************************
//* LOGBOOK.utl.dom
//*******************************************************************************
//* LOGBOOK.utl.dom is used to store some DOM related utility functions
//*==============================================================================
//* @public
//* @type [Object]
//*******************************************************************************
var $Lud = LOGBOOK.utl.dom = function()
{
	// Workarround 'windows.Node' that is missing in IE
	if(!window.Node)
	{
		window.Node =
		{
			ELEMENT_NODE:					1,
			ATTRIBUTE_NODE:					2,
			TEXT_NODE:						3,
			CDATA_SECTION_NODE:				4,
			ENTITY_REFERENCE_NODE:			5,
			ENTITY_NODE:					6,
			PROCESSING_INSTRUCTION_NODE:	7,
			COMMENT_NODE:					8,
			DOCUMENT_NODE:					9,
			DOCUMENT_TYPE_NODE:				10,
			DOCUMENT_FRAGMENT_NODE:			11,
			NOTATION_NODE:					12
		};
	}
	return {
		//*******************************************************************************
		//* LOGBOOK.utl.dom.minZIndex
		//*******************************************************************************
		//* Minimum usable zIndex.
		//*==============================================================================
		//* @public
		//* @type [Number]
		//*******************************************************************************
		minZIndex: -1000000,

		//*******************************************************************************
		//* LOGBOOK.utl.dom.maxZIndex
		//*******************************************************************************
		//* Maximum usable zIndex.
		//*==============================================================================
		//* @public
		//* @type [Number]
		//*******************************************************************************
		maxZIndex: 1000000,

		//*******************************************************************************
		//* LOGBOOK.utl.dom._scrollbarWidth
		//*******************************************************************************
		//* Width of the vertcal scrollbar.
		//*==============================================================================
		//* @private
		//* @type [Number]
		//*******************************************************************************
		_scrollbarWidth: 0,

		//*******************************************************************************
		//* LOGBOOK.utl.dom._scrollbarHeight
		//*******************************************************************************
		//* Height of the horizontal scrollbar
		//*==============================================================================
		//* @private
		//* @type [Number]
		//*******************************************************************************
		_scrollbarHeight: 0,

		//*******************************************************************************
		//* LOGBOOK.utl.dom._init
		//*******************************************************************************
		//* Runned automatically when DOM is ready.
		//* Find the min and max usable zIndex.
		//* Find the vertical scrollbar's width and the horizontal scrollbar's height.
		//*==============================================================================
		//* @private
		//* @param e [Event]
		//* @no_return
		//*******************************************************************************
		_init: function(e)
		{
			// Try to fix document direction
			$Lud._fixDirection();

			// Try to fix images (fix IE5.5 and IE6 bug with transparent PNG files)
			$Lud._fixImage();
/*
			// Save scrollbars position and hide all elements
			var	s0 = $Lud.getScrollXYWH();
				l = [],
				n = b.firstChild;
			while(n)
			{
				if(n.nodeType == Node.ELEMENT_NODE)
				{
					l[l.length] = {e: n, d: n.style && n.style.display ? n.style.display : ''};
					n.style.display = 'none';
				}
				n = n.nextSibling;
			}

			// Create the test div
			var n = $Lud.createElement('div');
			n.style.id = '_LOGBOOK_utl_dom_init_div';
			n.style.position = 'absolute';
			n.style.margin = '0';
			n.style.padding = '0';
			n.style.left = '0';
			n.style.top = '0';
			n.style.width = '100px';
			n.style.height = '100px';
			n.style.zIndex = '0';
			n.style.backgroundColor = '#FFFFFF';
			b.appendChild(n);

			// Find the minimum and maximum zIndex
			var minZ = 0, varZ = 1000000000;
			while(varZ >= 1)
			{
				try
				{
					n.style.zIndex = ''+(minZ - varZ);
				}
				catch(X)
				{
				}
				if(''+n.style.zIndex != ''+(minZ - varZ))
					varZ /= 10;
				else
					minZ -= varZ;
			}
			var maxZ = 0;
			varZ = 1000000000;
			while(varZ >= 1)
			{
				try
				{
					n.style.zIndex = ''+(maxZ + varZ);
				}
				catch(X)
				{
				}
				if(''+n.style.zIndex != ''+(maxZ + varZ))
					varZ /= 10;
				else
					maxZ += varZ;
			}
			$Lud.minZIndex = minZ;
			$Lud.maxZIndex = maxZ;

			// Find the vertical scrollbar's width and the horizontal scrollbar's height
			n.style.width = '0';
			n.style.height = '0';
			n.style.zIndex = '0';
			$Lud.setScrollXY(0, 0);
			var c = $Lud.getClientWH();
			n.style.width = (c.w+100)+'px';
			n.style.height = (c.h+100)+'px';
			$Lud.setScrollXY(c.w+1000, c.h+1000);
			var s1 = $Lud.getScrollXY();
			$Lud._scrollbarWidth = s1.x-100;
			$Lud._scrollbarHeight = s1.y-100;

			// Destroy the test div
			$Lud.destroyElement(n);

			// Show all elements and restore scrollbars position
			for(i = 0; i < l.length; i++)
				l[i].e.style.display = l[i].d;
			$Lud.setScrollXY(dir == 'rtl' ? s0.w : 0, 0);
			var f = function(n)
			{
				while(n)
				{
					if(n.style && n.style.overflow && (n.style.overflow == 'scroll' || n.style.overflow == 'auto'))
						$Lud.setScrollXY(dir == 'rtl' ? $Lud.getScrollWH(n).w : 0, 0, n);
					if(n.firstChild)
						f(n.firstChild);
					n = n.nextSibling;
				}
			};
			if(b.firstChild)
				f(b.firstChild);
			if(window.location.hash != '')
				window.location.replace(window.location.hash);
			else
				$Lud.setScrollY(s0.y);
*/
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom._fixDirection
		//*******************************************************************************
		//* Fixes document direction
		//*==============================================================================
		//* @no_param
		//* @no_return
		//*******************************************************************************
		_fixDirection: function()
		{
			// Fix document direction
			var d = document,
				h = d.getElementsByTagName('html')[0],
				b = d.getElementsByTagName('body')[0],
				ta = b.firstChild;
			while(ta && ta.nodeType == Node.TEXT_NODE)
				if(ta.nodeValue.match(/^\s*$/))
					ta = ta.nextSibling;
				else
					break;
			if(ta && ta.tagName && ta.tagName.toLowerCase() == 'table' && ta.dir.match(/^ltr|rtl$/))
				var dir = $Lud.getDir(ta);
			else
			{
				var dir = $Lud.getDir();
				ta = null;
			}
			var w = window,
				d = document,
				h = d.getElementsByTagName('html')[0],
				b = d.getElementsByTagName('body')[0];
				ta = b.firstChild;
			while(ta && ta.nodeType == Node.TEXT_NODE)
				if(ta.nodeValue.match(/^\s*$/))
					ta = ta.nextSibling;
				else
					break;
			if(ta && ta.tagName && ta.tagName.toLowerCase() == 'table' && ta.dir.match(/^ltr|rtl$/))
				var dir = $Lud.getDir(ta);
			else
			{
				var dir = $Lud.getDir();
				ta = null;
			}
			h.dir = 'ltr';
			b.style.padding = '';
			b.style.margin = '';
			$Lud.removeAttribute(b, 'dir');
			d.dir = 'ltr';
			if(ta == null)
			{
				ta = $Lud.createElement('table');
				ta.cellPadding = '0';
				ta.cellSpacing = '0';
				ta.border = '0';
				ta.style.width = '100%';
				ta.dir = dir;
				if(b.firstChild)
					b.insertBefore(ta, b.firstChild);
				else
					b.appendChild(ta);
				var tb = $Lud.createElement('tbody');
				ta.appendChild(tb);
				var tr = $Lud.createElement('tr');
				tb.appendChild(tr);
				var td = $Lud.createElement('td');
				tr.appendChild(td);
				var dv = $Lud.createElement('div');
				td.appendChild(dv);
				var n = b.firstChild;
				while(n)
				{
					s = n.nextSibling;
					if(n !== ta)
						dv.appendChild(n);
					n = s;
				}
			}
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom._fixOpacity
		//*******************************************************************************
		//* Fixes opacity styles to complie with some browsers
		//*==============================================================================
		//* @private
		//* @param e [HTMLElement, optional]
		//* @no_return
		//*******************************************************************************
		_fixOpacity: function(e)
		{
			if(e)
			{
				$Lud.getStyle(e, 'opacity');
			}
			else
			{
			}
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom._fixImage
		//*******************************************************************************
		//* Fixes images to work arround IE 5.5 and IE 6 bug with PNG files
		//*==============================================================================
		//* @private
		//* @param e [HTMLElement, optional]
		//* @no_return
		//*******************************************************************************
		_fixImage: function(e)
		{
			if($Le.ua.ie >= 5.5 && $Le.ua.ie < 7)
			{
				if(e)
				{
					if(!e.src || e.src == '')
						e.src = 'public/media/pictures/blank.gif';
					if(e['_LOGBOOK_utl_dom__fixImage_fixed'] != 'true')
					{
						e.onpropertychange = null;
						$Lud.setStyle(e, 'opacity', '');
						$Lud.setAttribute(e, '_LOGBOOK_utl_dom__fixImage_src', e.src);
						$Lud.setAttribute(e, '_LOGBOOK_utl_dom__fixImage_timer', null);
						e.runtimeStyle.filter = 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\''+e.src+'\',sizingMethod=\'scale\')';
						e.src = 'public/media/pictures/blank.gif';
						var f = function()
						{
							if(event.propertyName == 'src')
							{
								clearTimeout(e['_LOGBOOK_utl_dom__fixImage_timer']);
								$Lud.setAttribute(e, '_LOGBOOK_utl_dom__fixImage_fixed', 'false');
								$Lud._fixImage(e);
							}
						};
						e.oncontextmenu = function()
						{
							e.onpropertychange = null;
							e.src = $Lud.getAttribute(e, '_LOGBOOK_utl_dom__fixImage_src');
							e.runtimeStyle.filter = '';
							$Lud.setAttribute(e, '_LOGBOOK_utl_dom__fixImage_fixed', 'false');
							$Lud.setAttribute(e, '_LOGBOOK_utl_dom__fixImage_timer', setTimeout(function(){$Lud._fixImage(e);}, 5000));
							e.onpropertychange = f;
						};
						$Lud.setAttribute(e, '_LOGBOOK_utl_dom__fixImage_fixed', 'true');
						e.onpropertychange = f;
					}
				}
				else
				{
					for(var i = 0; i < document.images.length; i++)
						$Lud._fixImage(document.images[i]);
				}
			}
			else
			{
				for(var i = 0; i< document.images.length; i++)
					$Lud.setStyle(document.images[i], 'opacity', '');
			}
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.getNamespace
		//*******************************************************************************
		//* Return the namespace of the document
		//*==============================================================================
		//* @public
		//* @param d [HTMLDocument, optional]
		//* 	HTML document
		//* @return [String]
		//* 	The document namespace
		//*******************************************************************************
		getNamespace: function(d)
		{
			d = d || document;
			var n = null, h = d.getElementsByTagName('html');
			if(h && h[0] && h[0].attributes['xmlns'] && h[0].attributes['xmlns'].value && h[0].attributes['xmlns'].value != '')
				n = h[0].attributes['xmlns'].value;
			return n;
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.createElement
		//*******************************************************************************
		//* Create an element of a certain type.
		//* Optionally, if the second argument is passed, it will appendChild() the
		//* newly created element to its parent.
		//*==============================================================================
		//* @public
		//* @param t [String]
		//* 	The tag name of the new HTML element
		//* @param p [HTMLElement, optional]
		//* 	Parent of the new element
		//* @param d [HTMLDocument, optional]
		//* 	Document of the new element
		//* @return [HTMLElement]
		//* 	Reference to the new element
		//*******************************************************************************
		createElement: function(t, p, d)
		{
			var e = null;
			d = d || document;
			if(d.createElementNS)
				// Try to use the document namespace; IE won't normally get here unless microsoft fix the DOM2 implementation
				e = d.createElementNS($Lud.getNamespace(d), t);
			else
				e = d.createElement(t);
			if(/^img$/i.test(e.tagName))
				$Lud._fixImage(e);
			if(p && p.appendChild)
				p.appendChild(e);
			return e;
		},
		
		//*******************************************************************************
		//* LOGBOOK.utl.dom.getElementById
		//*******************************************************************************
		//* Return a HTML element by its Id
		//*==============================================================================
		//* @public
		//* @param e [HTMLElement|String]
		//* 	HTML element, id of the HTML element
		//* @param d [HTMLDocument, optional]
		//* 	Document of the element
		//* @return [HTMLElement]
		//* 	Reference to the HTML element or null
		//*******************************************************************************
		getElementById: function(e, d)
		{
			if(!e || e.tagName || e.item)
				return e;
			var r;
			d = d || document;
			// DOM2 Method
			if(d.getElementById)
			{
				r = d.getElementById(e);
				if($Lu.isObject(r))
					return r;
			}
			// IE4 DOM Method
			if(d.all)
			{
				r = d.all[e];
				if($Lu.isObject(r))
					return r;
			}
			// DOM0 Method
			if(d[e])
			{
				r = d[e];
				if($Lu.isObject(r))
					return r;
			}
			return null;
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.destroyElement
		//*******************************************************************************
		//* Destroy the given element (remove it from the DOM tree).
		//*==============================================================================
		//* @public
		//* @param e [HTMLElement]
		//* 	HTML element
		//* @no_return
		//*******************************************************************************
		destroyElement: function(e)
		{
			if(e && e.tagName && e.parentNode)
			{
				e.parentNode.removeChild(e);
				for(var i = $Lud._attributesToDestroyOnUnload.length - 1; i >= 0; i--)
				{
					var j = $Lud._attributesToDestroyOnUnload[i];
					if(j[0] === e)
					{
						j[0][j[1]] = null;
						j[0] = null;
					}
				}
				e = null;
			}
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom._attributesToDestroyOnUnload
		//*******************************************************************************
		//* Attributes that will be destroyed automatically on unload.
		//*==============================================================================
		//* @private
		//* @type [Array]
		//*******************************************************************************
		_attributesToDestroyOnUnload: [],
		
		//*******************************************************************************
		//* LOGBOOK.utl.dom.setAttribute
		//*******************************************************************************
		//* Create or set the value to an attribute of a HTML Element.
		//*==============================================================================
		//* @public
		//* @param e [HTMLElement]
		//* 	HTML element
		//* @param a [String]
		//* 	Attribute to set
		//* @param v [Any]
		//* 	Attribute value
		//* @no_return
		//*******************************************************************************
		setAttribute: function(e, a, v)
		{
			if($Lu.isUndefined(e[a]))
				$Lud._attributesToDestroyOnUnload.push([e, a]);
			if(e.setAttributeNS)
				e.setAttributeNS($Lud.getNamespace($Lud.getDocument(e)), a, v);
			else if(e.setAttribute)
				e.setAttribute(a, v);
			else
				e[a] = v;
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.hasAttribute
		//*******************************************************************************
		//* Indicate if a HTML element has the specified attribute
		//*==============================================================================
		//* @public
		//* @param e [HTMLElement]
		//* 	HTML element
		//* @param a [String]
		//* 	Attribute to return
		//* @return [Boolean]
		//* 	True if the element has the attribute
		//*******************************************************************************
		hasAttribute: function(e, a)
		{
			if(e.hasAttributeNS)
				return e.hasAttributeNS($Lud.getNamespace($Lud.getDocument(e)), a);
			if(e.hasAttribute)
				return e.hasAttribute(a);
			return e[a] ? true : false;
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.getAttribute
		//*******************************************************************************
		//* Return an attribute of a HTML element
		//*==============================================================================
		//* @public
		//* @param e [HTMLElement]
		//* 	HTML element
		//* @param a [String]
		//* 	Attribute to return
		//* @return [Any]
		//* 	The attribute of the element
		//*******************************************************************************
		getAttribute: function(e, a)
		{
			if(e.getAttributeNS)
				return e.getAttributeNS($Lud.getNamespace($Lud.getDocument(e)), a);
			if(e.getAttribute)
				return e.getAttribute(a);
			return e[a] ? e[a] : null;
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.removeAttribute
		//*******************************************************************************
		//* Remove one attribute of a HTML element
		//*==============================================================================
		//* @public
		//* @param e [HTMLElement]
		//* 	HTML element
		//* @param a [String]
		//* 	Attribute to remove
		//* @no_return
		//*******************************************************************************
		removeAttribute: function(e, a)
		{
			if(!$Lud.hasAttribute(e, a))
				return;
			if(e.removeAttributeNS)
				e.removeAttributeNS($Lud.getNamespace($Lud.getDocument(e)), a);
			else if(e.removeAttribute)
				e.removeAttribute(a);
			else
				e[a] = undefined;
		},
		
		//*******************************************************************************
		//* LOGBOOK.utl.dom.getTextElement
		//*******************************************************************************
		//* In some cases, some browsers will return a text node inside the actual HTML
		//* element that was targeted by an event.
		//* This normalize the return value for $Lue.getTarget and $Lue.getRelatedTarget
		//*==============================================================================
		//* @public
		//* @param n [Node]
		//* 	Node to resolve
		//* @return [HTMLElement]
		//* 	The normized HTML element or null
		//*******************************************************************************
		getTextElement: function(n)
		{
			if(n && n.nodeType && n.nodeType == Node.TEXT_NODE && n.parentNode)
				return n.parentNode;
			else if(n && n.tagName)
				return n;
			return null;
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.getElementText
		//*******************************************************************************
		//* Function that concatenate and return all children texts in a HTML Element.
		//*==============================================================================
		//* @public
		//* @param e [HTMLElement]
		//* 	HTML element
		//* @return [String]
		//* 	Concatenated children texts
		//*******************************************************************************
		getElementText: function(e)
		{
			var f = function(e, t)
			{
				if(!(/^script|style$/i.test(e.tagName)))
				{
					if(e.nodeType == Node.TEXT_NODE)
					{
						var d = e.data.replace(/^[ \t\r\n]*|[ \t\r\n]$/, '');
						if(d != '')
							t.push(d);
						return t;
					}
					else
					{
						var c = e.firstChild;
						while(c)
						{
							t = f(c, t);
							c = c.nextSibling;
						}
					}
				}
				return t;
			}, t = f(e, []);
			return t.join(' ');
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.getDocument
		//*******************************************************************************
		//* Return the parent HTML document of a HTML element
		//*==============================================================================
		//* @public
		//* @param e [HTMLElement]
		//* 	HTML element
		//* @return	[HTMLDocument]
		//* 	HTML document of the element
		//*******************************************************************************
		getDocument: function(e)
		{
			return e.ownerDocument || e.document || null;
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom._fixParentWindow
		//*******************************************************************************
		//* Fix parentWindow attribute of a Window element
		//*==============================================================================
		//* @private
		//* @param w [Window]
		//* 	Window element
		//* @no_return
		//*******************************************************************************
		_fixParentWindow: function(w)
		{
			w.document.parentWindow = w; 
			for(var i = 0; i < w.frames.length ; i++)
				$Lud._fixParentWindow(w.frames[i]);
		},

		//*******************************************************************************
		//* MxAjax.Utils.getWindow
		//*******************************************************************************
		//* Return the parent Window element of a HTML element or a HTML document
		//*==============================================================================
		//* @public
		//* @param e [HTMLElement|HTMLDocument]
		//* 	HTML element or HTML document
		//* @return [Window]
		//* 	Parent HTML Window element
		//*******************************************************************************
		getWindow: function(e)
		{
			e = e || document;
			if(!e.nodeType || e.nodeType == Node.DOCUMENT_NODE)
			{
				// Safari bug fix
				if(!e.parentWindow && !e.defaultView)
					$Lud._fixParentWindow(window.top);
				return e.parentWindow || e.defaultView;
			}
			return $Lud.getWindow($Lud.getDocument(e));
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.getDir
		//*******************************************************************************
		//* Returns the direction of a HTML element or a HTML document.
		//* Without parameter, returns the direction of the document.
		//*==============================================================================
		//* @public
		//* @param e [HTMLElement|HTMLDocument, optional]
		//* 	HTML element or HTML document
		//* @param r [Boolean]
		//* 	Recurse parents, default true
		//* @return [String]
		//* 	The element direction 'ltr' or 'rtl'
		//*******************************************************************************
		getDir: function(e, r)
		{
			e = e || document;
			r = r || true;
			var d = '';
			while(d == '')
			{
				if(e.dir && e.dir.match(/^ltr|rtl$/))
					d = e.dir;
				else
				{
					e = e.parentNode;
					if(!e || !r)
						d = 'ltr';
				}
			}
			return d;
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom._convertedStyles
		//*******************************************************************************
		//* Cache that keep styles already converted.
		//*==============================================================================
		//* @private
		//* @type [Array]
		//*******************************************************************************
		_convertedStyles: {},

		//*******************************************************************************
		//* LOGBOOK.utl.dom._convertStyle
		//*******************************************************************************
		//* Convert a CSS style (with hiphens) in a Javascript style (without hiphens)
		//*==============================================================================
		//* @private
		//* @param p [String]
		//* 	Property (with hiphens)
		//* @return [String]
		//* 	Converted property (without hiphens)
		//*******************************************************************************
		_convertStyle: function(p)
		{
			p = (''+p).toLowerCase();
			if(!$Lud._convertedStyles[p])
			{
				var n = p;
				while(/(-[a-z])/i.exec(n))
					n = n.replace(RegExp.$1, RegExp.$1.substr(1).toUpperCase());
				$Lud._convertedStyles[p] = n;
			}
			return $Lud._convertedStyles[p];
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.getComputedStyle
		//*******************************************************************************
		//* Get current computed style
		//*==============================================================================
		//* @public
		//* @param e [HTMLElement]
		//* 	HTML element
		//* @param p [String]
		//* 	Property
		//* @return [String]
		//* 	The property value or null
		//*******************************************************************************
		getComputedStyle: function()
		{
			if($Le.ua.ie)
			{ // IE method
				return function(e, p)
				{
					p = $Lud._convertStyle(p);
					if(p == 'opacity')
					{
							var o = 100, m = (''+e.style.filter).match(/alpha\s*\([^\)]*opacity\s*\=\s*([0-9]{1,3})[^\)]*\)/i);
							if(m && m[1])
								o = parseInt(m[1]);
							return ''+(o / 100);
					}
					if(p == 'float')
						p = 'styleFloat';
					var s = e.style[p] || e.currentStyle ? e.currentStyle[p] : null;
					if(p == 'cursor' && (''+s).toLowerCase() == 'hand')
						s = 'pointer';
					return s;
				};
			}
			else if(document.defaultView && document.defaultView.getComputedStyle)
			{ // W3C DOM method
				return function(e, p)
				{
					p = $Lud._convertStyle(p);
					if(p == 'opacity')
						return e.style['opacity'] || e.style['MozOpacity'] || e.style['KhtmlOpacity'] || '1';
					if(p == 'float')
						p = 'cssFloat';
					try
					{
						return e.style[p] || $Lud.getDocument(e).defaultView.getComputedStyle(e, '').getPropertyValue(p) || null;
					}
					catch(X)
					{
						return null;
					}
				};
			}
			else
			{ // Default method
				return function(e, p)
				{
					p = $Lud._convertStyle(p);
					if(p == 'opacity')
						return e.style['opacity'] || e.style['MozOpacity'] || e.style['KhtmlOpacity'] || '1';
					if(p == 'float')
						p = 'cssFloat';
					return e.style[p] || null;
				};
			}
		}(),

		//*******************************************************************************
		//* LOGBOOK.utl.dom.getStyle
		//*******************************************************************************
		//* Get current style
		//*==============================================================================
		//* @public
		//* @param e [HTMLElement]
		//* 	HTML element
		//* @param p [String]
		//* 	Property
		//* @return [String]
		//* 	The property value or null
		//*******************************************************************************
		getStyle: function()
		{
			if($Le.ua.ie)
			{ // IE method
				return function(e, p)
				{
					p = $Lud._convertStyle(p);
					if(p == 'opacity')
					{
							var o = 100, m = (''+e.style.filter).match(/alpha\s*\([^\)]*opacity\s*\=\s*([0-9]{1,3})[^\)]*\)/i);
							if(m && m[1])
								o = parseInt(m[1]);
							return ''+(o / 100);
					}
					if(p == 'float')
						p = 'styleFloat';
					var s = e.style[p] || null;
					if(p == 'cursor' && (''+s).toLowerCase() == 'hand')
						s = 'pointer';
					return s;
				};
			}
			else
			{ // Default method
				return function(e, p)
				{
					p = $Lud._convertStyle(p);
					if(p == 'opacity')
						return e.style['opacity'] || e.style['MozOpacity'] || e.style['KhtmlOpacity'] || '1';
					if(p == 'float')
						p = 'cssFloat';
					return e.style[p] || null;
				};
			}
		}(),

		//*******************************************************************************
		//* LOGBOOK.utl.dom.setStyle
		//*******************************************************************************
		//* Set current style
		//*==============================================================================
		//* @public
		//* @param e [HTMLElement]
		//* 	HTML element
		//* @param p [String]
		//* 	Property
		//* @param v [String]
		//* 	Value
		//* @no_return
		//*******************************************************************************
		setStyle: function()
		{
			if($Le.ua.ie)
			{ // IE DOM method
				return function(e, p, v)
				{
					p = $Lud._convertStyle(p);
					if(p == 'opacity')
					{
						// Can't set images opacity since $Lud._fixImage method is applyed
						if(/^img$/i.test(e.tagName))
							v = '';
						if(v == '')
						{
							try
							{
								e.style.filter = (''+e.style.filter).replace(/alpha\s*\([^\)]*opacity\s*[:=]\s*[0-9]+[^\)]*\)/i, '');
							}
							catch(X)
							{
							}
						}
						else
						{
							try
							{
								var m = /((alpha\s*\([^\)]*opacity\s*[:=]\s*)[0-9]+([^\)]*\)))/i.exec(''+e.style.filter);
								if(!RegExp.$1)
									e.style.filter += (e.style.filter != '' ? ' ' : '')+'alpha(opacity='+parseInt(v * 100)+')';
								else
									e.style.filter = (''+e.style.filter).replace(RegExp.$1, ''+RegExp.$2+parseInt(v * 100)+RegExp.$3);
							}
							catch(X)
							{
							}
						}
						try
						{
							// Bugfix IE when the node have no width and/or no height
							if(!e.currentStyle || !e.currentStyle.hasLayout)
								e.style.zoom = 1; // when no layout or cant tell
						}
						catch(X)
						{
						}
					}
					else
					{
						if(p == 'float')
							p = 'styleFloat';
						else if(p == 'clip' && v == '')
						{
							v = 'rect(auto, auto, auto, auto)';
						}
						try
						{
							e.style[p] = v;
						}
						catch(X)
						{
						}
						if(p == 'cursor' && v == 'pointer' && e.style[p] != v)
						{
							try
							{
								e.style[p] = 'hand';
							}
							catch(X)
							{
							}
						}
					}
				};
			}
			else
			{ // Default method
				return function(e, p, v)
				{
					p = $Lud._convertStyle(p);
					// Bug fix Opera that reset scollbars in RTL pages
					var s = $Lud.getScrollXY();
					if(p == 'opacity')
					{
						// Can't set images opacity since $Lud._fixImage method is applyed
						if(/^img$/i.test(e.tagName))
							v = '';
						try
						{
							e.style['opacity'] = v;
						}
						catch(X)
						{
						}
						if(e.style['MozOpacity'])
						{
							try
							{
								e.style['MozOpacity'] = v;
							}
							catch(X)
							{
							}
						}
						if(e.style['KhtmlOpacity'])
						{
							try
							{
								e.style['KhtmlOpacity'] = v;
							}
							catch(X)
							{
							}
						}
					}
					else
					{
						if(p == 'float')
							p = 'cssFloat';
						else if(p == 'clip' && v == '')
							v = 'rect(auto, auto, auto, auto)';
						try
						{
							e.style[p] = v;
						}
						catch(X)
						{
						}
					}
					// Bug fix Opera that reset scollbars in RTL pages
					$Lud.setScrollXY(s.x, s.y)
				};
			}
		}(),

		//*******************************************************************************
		//* LOGBOOK.utl.dom._cacheClassRegExp
		//*******************************************************************************
		//* Cache for classes regular expressions
		//*==============================================================================
		//* @private
		//* @type [Object]
		//*******************************************************************************
		_cacheClassRegExp: {},

		//*******************************************************************************
		//* LOGBOOK.utl.dom._getClassRegExp
		//*******************************************************************************
		//* Return a regular expression for a certain class
		//*==============================================================================
		//* @public
		//* @param c [String]
		//* 	The classname
		//* @return [RegExp]
		//* 	The regular expression
		//*******************************************************************************
		_getClassRegExp: function(c)
		{
			if(!$Lud._cacheClassRegExp[c])
				$Lud._cacheClassRegExp[c] = new RegExp('(?:^|\\s+)'+ c+'(?:\\s+|$)');
			return $Lud._cacheClassRegExp[c];
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.addClass
		//*******************************************************************************
		//* Appends a certain CSS class to the given element.
		//*==============================================================================
		//* @public
		//* @param e [HTMLElement]
		//* 	HTML element.
		//* @param c [String]
		//* 	The class to append
		//* @no_return
		//*******************************************************************************
		addClass: function(e, c)
		{
			if($Lud.hasClass(e, c))
				return;
			e.className = [e.className, c].join(' ').trim();
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.hasClass
		//*******************************************************************************
		//* Return true if the given element has a certain CSS class.
		//*==============================================================================
		//* @public
		//* @param e [HTMLElement]
		//* 	HTML element.
		//* @param c [String]
		//* 	The class to check.
		//* @return [Boolean]
		//* 	True if the element have the class
		//*******************************************************************************
		hasClass: function(e, c)
		{
			return $Lud._getClassRegExp(c).test(e.className)
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.removeClass
		//*******************************************************************************
		//* Remove a certain CSS class from the given element.
		//*==============================================================================
		//* @public
		//* @param e [HTMLElement]
		//* 	HTML element.
		//* @param c [String]
		//* 	The class to remove.
		//* @no_return
		//*******************************************************************************
		removeClass: function(e, c)
		{
			if(!$Lud.hasClass(e, c))
				return;
			e.className = e.className.replace($Lud._getClassRegExp(c), ' ');
			if($Lud.hasClass(e, c))	// in case of multiple adjacent
				$Lud.removeClass(e, c);
			e.className = e.className.trim(); // remove any trailing spaces
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.replaceClass
		//*******************************************************************************
		//* Pelace a certain CSS class from the given element by an other.
		//*==============================================================================
		//* @public
		//* @param e [HTMLElement]
		//* 	HTML element.
		//* @param o [String]
		//* 	The old class to remove.
		//* @param n [String]
		//* 	The new class to add.
		//* @no_return
		//*******************************************************************************
		replaceClass: function(e, o, n)
		{
			if(!n || o === n)	// avoid infinite loop
				return;
			if(!$Lud.hasClass(e, o))
			{
				$Lud.addClass(e, n); // just add it if nothing to replace
				return;
			}
			e.className = e.className.replace( $Lud._getClassRegExp(o), ' '+n+' ');
			if($Lud.hasClass(e, o))	// in case of multiple adjacent
				$Lud.replaceClass(e, o, n);
			e.className = e.className.trim(); // remove any trailing spaces
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.getScreenW
		//*******************************************************************************
		//* Returns the current horizontal size of the screen
		//*==============================================================================
		//* @public
		//* @param w [Window, optional]
		//* 	Window
		//* @return [Number]
		//* 	Current horizontal size
		//*******************************************************************************
		getScreenW: function(w)
		{
			return $Lud.getScreenWH(w).w;
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.getScreenH
		//*******************************************************************************
		//* Returns the current vertical size of the screen
		//*==============================================================================
		//* @public
		//* @param w [Window, optional]
		//* 	Window
		//* @return [Number]
		//* 	Current horizontal size
		//*******************************************************************************
		getScreenH: function(w)
		{
			return $Lud.getScreenWH(w).h;
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.getScreenWH
		//*******************************************************************************
		//* Returns the horizontal and vertical size of the screen
		//*==============================================================================
		//* @public
		//* @param w [Window, optional]
		//* 	Window
		//* @return [Array]
		//* 	Current horizontal and vertical size
		//*******************************************************************************
		getScreenWH: function(w)
		{
			w = w || window;
			return {w: w.screen.availWidth || w.screen.width || 1024, h: w.screen.availHeight || w.screen.height || 768};
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.getOriginX
		//*******************************************************************************
		//* Returns the horizontal origin for a HTML element or a HTML document
		//*==============================================================================
		//* @public
		//* @param e [HTMLElement|HTMLDocument, optional]
		//* 	HTML element or HTML document
		//* @return [Number]
		//* 	Current horizontal origin
		//*******************************************************************************
		getOriginX: function()
		{
			if($Le.ua.ie >= 5.5)
				return function(e)
				{
					e = e || document;
					if($Lud.getDir(e) == 'rtl')
					{
						if($Le.ua.ie && $Le.ua.ie < 7 && e.body && (e.body.scrollWidth || e.body.scrollWidth === 0) && (e.body.clientWidth || e.body.clientWidth === 0))
							return e.body.scrollWidth - e.body.clientWidth;
						if(e.documentElement && (e.documentElement.scrollWidth || e.documentElement.scrollWidth === 0) && (e.documentElement.clientWidth || e.documentElement.clientWidth === 0))
							return e.documentElement.scrollWidth - e.documentElement.clientWidth;
						if((e.scrollWidth || e.scrollWidth === 0) && (e.clientWidth || e.clientWidth === 0))
							return e.scrollWidth - e.clientWidth;
					}
					return 0;
				};
			return function(e)
			{
				return 0;
			};
		}(),

		//*******************************************************************************
		//* LOGBOOK.utl.dom.getOriginY
		//*******************************************************************************
		//* Returns the vertical origin for a HTML element or a HTML document
		//*==============================================================================
		//* @public
		//* @param e [HTMLElement|HTMLDocument, optional]
		//* 	HTML element or HTML document
		//* @return [Number]
		//* 	Current horizontal origin
		//*******************************************************************************
		getOriginY: function(e)
		{
			return 0;
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.getOriginXY
		//*******************************************************************************
		//* Returns the horizontal and vertical origin for a HTML element or a HTML
		//* document
		//*==============================================================================
		//* @public
		//* @param e [HTMLElement|HTMLDocument, optional]
		//* 	HTML element or HTML document
		//* @return [Array]
		//* 	Current horizontal and vertical origin
		//*******************************************************************************
		getOriginXY: function(e)
		{
			return {x: $Lud.getOriginX(e), y: $Lud.getOriginY(e)};
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.getScrollX
		//*******************************************************************************
		//* Returns the horizontal scroll position for a HTML Element
		//* Without parameter, returns the document horizontal scroll position
		//*==============================================================================
		//* @public
		//* @param e [HTMLElement, optional]
		//* 	HTML element
		//* @return [Number]
		//* 	Current horizontal scroll position
		//*******************************************************************************
		getScrollX: function(e)
		{
			e = e || document, w = $Lud.getWindow(e);
			if((!e.nodeType || e.nodeType == Node.DOCUMENT_NODE) && w.pageXOffset)
				return w.pageXOffset;
			if($Le.ua.ie && $Le.ua.ie < 7 && e.body && e.body.scrollLeft)
				return e.body.scrollLeft;
			if(e.documentElement && e.documentElement.scrollLeft)
				return e.documentElement.scrollLeft;
			if(e.scrollLeft)
				return e.scrollLeft;
			return 0;
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.getScrollY
		//*******************************************************************************
		//* Returns the vertical scroll position for a HTML Element
		//* Without parameter, returns the document vertical scroll position
		//*==============================================================================
		//* @public
		//* @param e [HTMLElement, optional]
		//* 	HTML element
		//* @return [Number]
		//* 	Current vertical scroll position
		//*******************************************************************************
		getScrollY: function(e)
		{
			e = e || document, w = $Lud.getWindow(e);
			if((!e.nodeType || e.nodeType == Node.DOCUMENT_NODE) && w.pageYOffset)
				return w.pageYOffset;
			if($Le.ua.ie && $Le.ua.ie < 7 && e.body && e.body.scrollTop)
				return e.body.scrollTop;
			if(e.documentElement && e.documentElement.scrollTop)
				return e.documentElement.scrollTop;
			if(e.scrollTop)
				return e.scrollTop;
			return 0;
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.getScrollXY
		//*******************************************************************************
		//* Returns the horizontal and vertical scroll position for a HTML Element
		//* Without parameter, returns the document horizontal and vertical scroll position
		//*==============================================================================
		//* @public
		//* @param e [HTMLElement, optional]
		//* 	HTML element
		//* @return [Number]
		//* 	Current horizontal and vertical scroll position
		//*******************************************************************************
		getScrollXY: function(e)
		{
			return {x: $Lud.getScrollX(e), y: $Lud.getScrollY(e)};
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.getScrollW
		//*******************************************************************************
		//* Returns the horizontal scroll size for a HTML Element
		//* Without parameter, returns the document horizontal scroll size
		//*==============================================================================
		//* @public
		//* @param e [HTMLElement, optional]
		//* 	HTML element
		//* @return [Number]
		//* 	Current horizontal scroll size
		//*******************************************************************************
		getScrollW: function(e)
		{
			e = e || document;
			if($Le.ua.ie && $Le.ua.ie < 7 && e.body && e.body.scrollWidth)
				return e.body.scrollWidth;
			if(e.documentElement && e.documentElement.scrollWidth)
				return e.documentElement.scrollWidth;
			if(e.scrollWidth)
				return e.scrollWidth;
			return 0;
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.getScrollH
		//*******************************************************************************
		//* Returns the vertical scroll size for a HTML Element
		//* Without parameter, returns the document vertical scroll size
		//*==============================================================================
		//* @public
		//* @param e [HTMLElement, optional]
		//* 	HTML element
		//* @return [Number]
		//* 	Current vertical scroll size
		//*******************************************************************************
		getScrollH: function(e)
		{
			e = e || document;
			if($Le.ua.ie && $Le.ua.ie < 7 && e.body && e.body.scrollHeight)
				return e.body.scrollHeight;
			if(e.documentElement && e.documentElement.scrollHeight)
				return e.documentElement.scrollHeight;
			if(e.scrollHeight)
				return e.scrollHeight;
			return 0;
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.getScrollWH
		//*******************************************************************************
		//* Returns the horizontal and vertical scroll size for a HTML Element
		//* Without parameter, returns the document horizontal and vertical scroll size
		//*==============================================================================
		//* @public
		//* @param e [HTMLElement, optional]
		//* 	HTML element
		//* @return [Number]
		//* 	Current horizontal and vertical scroll size
		//*******************************************************************************
		getScrollWH: function(e)
		{
			return {w: $Lud.getScrollW(e), h: $Lud.getScrollH(e)};
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.getScrollXYWH
		//*******************************************************************************
		//* Returns the horizontal and vertical scroll position and horizontal and
		//* vertical scroll size for a HTML Element
		//* Without parameter, returns the document horizontal and vertical scroll position
		//* and horizontal and vertical scroll size
		//*==============================================================================
		//* @public
		//* @param e [HTMLElement, optional]
		//* 	HTML element
		//* @return [Number]
		//* 	Current horizontal and vertical scroll position and current horizontal
		//* 	and vertical scroll size
		//*******************************************************************************
		getScrollXYWH: function(e)
		{
			return {x: $Lud.getScrollX(e), y: $Lud.getScrollY(e), w: $Lud.getScrollW(e), h: $Lud.getScrollH(e)};
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.setScrollX
		//*******************************************************************************
		//* Sets the current horizontal scroll position for a HTML Element
		//* Without parameter, sets the document horizontal scroll position
		//*==============================================================================
		//* @public
		//* @param x [Number]
		//* 	New horizontal scroll position
		//* @param e [HTMLElement, optional]
		//* 	HTML element
		//* @no_return
		//*******************************************************************************
		setScrollX: function(x, e)
		{
			e = e || document;
			x = 0 + parseInt(x);
			try
			{
				if(e.body && (e.body.scrollLeft || e.body.scrollLeft === 0))
					e.body.scrollLeft = x;
			}
			catch(X)
			{
			}
			try
			{
				if(e.documentElement && (e.documentElement.scrollLeft || e.documentElement.scrollLeft === 0))
					e.documentElement.scrollLeft = x;
			}
			catch(X)
			{
			}
			try
			{
				if(e.scrollLeft || e.scrollLeft === 0)
					e.scrollLeft = x;
			}
			catch(X)
			{
			}
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.setScrollY
		//*******************************************************************************
		//* Sets the current vertical scroll position for a HTML Element
		//* Without parameter, sets the document vertical scroll position
		//*==============================================================================
		//* @public
		//* @param y [Number]
		//* 	New vertical scroll position
		//* @param e [HTMLElement, optional]
		//* 	HTML element
		//* @no_return
		//*******************************************************************************
		setScrollY: function(y, e)
		{
			e = e || document;
			y = 0 + parseInt(y);
			try
			{
				if(e.body && (e.body.scrollTop || e.body.scrollTop === 0))
					e.body.scrollTop = y;
			}
			catch(X)
			{
			}
			try
			{
				if(e.documentElement && (e.documentElement.scrollTop || e.documentElement.scrollTop === 0))
					e.documentElement.scrollTop = y;
			}
			catch(X)
			{
			}
			try
			{
				if(e.scrollTop || e.scrollTop === 0)
					e.scrollTop = y;
			}
			catch(X)
			{
			}
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.setScrollXY
		//*******************************************************************************
		//* Returns the horizontal and vertical scroll position a HTML Element
		//* Without parameter, sets the document horizontal and vertical scroll position
		//*==============================================================================
		//* @public
		//* @param x [Number]
		//* 	New horizontal scroll position
		//* @param y [Number]
		//* 	New vertical scroll position
		//* @param e [HTMLElement, optional]
		//* 	HTML element
		//* @no_return
		//*******************************************************************************
		setScrollXY: function(x, y, e)
		{
			$Lud.setScrollX(x, e);
			$Lud.setScrollY(y, e);
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.getOffsetX
		//*******************************************************************************
		//* Returns the current horizontal position of a HTML element relatively to its
		//* offset parent
		//*==============================================================================
		//* @public
		//* @param e [HTMLElement]
		//* 	HTML element
		//* @return [String]
		//* 	Current horizontal position
		//*******************************************************************************
		getOffsetX: function(e)
		{
			return e.offsetLeft;
		},
		
		//*******************************************************************************
		//* LOGBOOK.utl.dom.getOffsetY
		//*******************************************************************************
		//* Returns the current vertical position of a HTML element relatively to its
		//* offset parent
		//*==============================================================================
		//* @public
		//* @param e [HTMLElement]
		//* 	HTML element
		//* @return [String]
		//* 	Current vertical position
		//*******************************************************************************
		getOffsetY: function(e)
		{
			return e.offsetTop;
		},
		
		//*******************************************************************************
		//* LOGBOOK.utl.dom.getOffsetXY
		//*******************************************************************************
		//* Returns the current horizontal and vertical position of a HTML
		//* element relatively to its offset parent
		//*==============================================================================
		//* @public
		//* @param e [HTMLElement]
		//* 	HTML element
		//* @return [Number Array]
		//* 	Current horizontal and vertical position
		//*******************************************************************************
		getOffsetXY: function(e)
		{
			return {x: $Lud.getOffsetX(e), y: $Lud.getOffsetY(e)};
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.getDocumentX
		//*******************************************************************************
		//* Returns the current horizontal position of a HTML element in the document
		//*==============================================================================
		//* @public
		//* @param e [HTMLElement]
		//* 	HTML element
		//* @return [String]
		//* 	Current horizontal position
		//*******************************************************************************
		getDocumentX: function(e)
		{
			if((e.parentNode === null || e.offsetParent === null || $Lud.getStyle(e, 'display') == 'none') && e != document.body)
				return false;

			// IE
			if(e.getBoundingClientRect)
				return e.getBoundingClientRect().left + $Lud.getScrollX($Lud.getDocument(e));

			// Others browsers
			var x = e.offsetLeft;
			p = e.offsetParent;

			// Webkit: if e is absolute or any parent is absolute, subtract body offsets
			var a = $Lud.getStyle(e, 'position') == 'absolute';
			if(p != e)
				while(p)
				{
					x += p.offsetLeft;
					if($Le.ua.wk && !a &&  $Lud.getStyle(p, 'position') == 'absolute')
						a = true; // we need to offset if any parent is absolutely positioned
					p = p.offsetParent;
				}
			if($Le.ua.wk && a)
				// Webkit doubles in this case
				x -= $Lud.getDocument(e).body.offsetLeft;
			p = e.parentNode;
			// Account for any scrolled ancestors
			while(p.tagName && !(/^body|html$/i.test(p.tagName))) 
			{
				// work around opera inline/table scrollLeft/Top bug
				if((''+$Lud.getComputedStyle(p, 'display')).search(/^inline|table-row.*$/i))
					x -= $Lud.getScrollX(p);
				p = p.parentNode; 
			}
			return x;
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.getDocumentY
		//*******************************************************************************
		//* Returns the current vertical position of a HTML element in the document
		//*==============================================================================
		//* @public
		//* @param e [HTMLElement]
		//* 	HTML element
		//* @return [String]
		//* 	Current vertical position
		//*******************************************************************************
		getDocumentY: function(e)
		{
			if((e.parentNode === null || e.offsetParent === null || $Lud.getStyle(e, 'display') == 'none') && e != document.body)
				return false;

			if(e.getBoundingClientRect)
				// IE
				return e.getBoundingClientRect().top + $Lud.getScrollY($Lud.getDocument(e));

			// Others browsers
			var y = e.offsetTop;
			p = e.offsetParent;

			// Webkit: if e is absolute or any parent is absolute, subtract body offsets
			var a = $Lud.getStyle(e, 'position') == 'absolute';
			if(p != e)
				while(p)
				{
					y += p.offsetTop;
					if($Le.ua.wk && !a &&  $Lud.getStyle(p, 'position') == 'absolute')
						a = true; // we need to offset if any parent is absolutely positioned
					p = p.offsetParent;
				}
			if($Le.ua.wk && a)
				// Webkit doubles in this case
				y -= $Lud.getDocument(e).body.offsetTop;
			p = e.parentNode;
			
			// account for any scrolled ancestors
			while(p.tagName && !(/^body|html$/i.test(p.tagName))) 
			{
				// work around opera inline/table scrollLeft/Top bug
				if((''+$Lud.getComputedStyle(p, 'display')).search(/^inline|table-row.*$/i))
					y -= $Lud.getScrollY(p);
				p = p.parentNode; 
			}
			return y;
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.getDocumentXY
		//*******************************************************************************
		//* Returns the current horizontal and vertical position of a HTML element
		//* in the document
		//*==============================================================================
		//* @public
		//* @param e [HTMLElement]
		//* 	HTML element
		//* @return [Number Array]
		//* 	Current horizontal and vertical position
		//*******************************************************************************
		getDocumentXY: function(e)
		{
			return {x: $Lud.getDocumentX(e), y: $Lud.getDocumentY(e)};
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.getElementClientX
		//*******************************************************************************
		//* Gets the current horizontal position of a HTML element in the client
		//*==============================================================================
		//* @public
		//* @param e [HTMLElement]
		//* 	HTML element
		//* @return [Number]
		//* 	Current horizontal position
		//*******************************************************************************
		getClientX: function(e)
		{
			if((e.parentNode === null || e.offsetParent === null || $Lud.getStyle(e, 'display') == 'none') && e != document.body)
				return false;
			return $Lud.getDocumentX(e) - $Lud.getScrollX(e ? $Lud.getDocument(e) : null);
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.getClientY
		//*******************************************************************************
		//* Gets the current vertical position of a HTML element in the client
		//*==============================================================================
		//* @public
		//* @param e [HTMLElement]
		//* 	HTML element
		//* @return [Number]
		//* 	Current vertical position
		//*******************************************************************************
		getClientY: function(e)
		{
			if((e.parentNode === null || e.offsetParent === null || $Lud.getStyle(e, 'display') == 'none') && e != document.body)
				return false;
			return $Lud.getDocumentY(e) - $Lud.getScrollY(e ? $Lud.getDocument(e) : null);
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.getClientXY
		//*******************************************************************************
		//* Returns the horizontal and vertical position for a HTML element in the client
		//*==============================================================================
		//* @public
		//* @param e [HTMLElement]
		//* 	HTML element
		//* @return [Array]
		//* 	Current horizontal and vertical position
		//*******************************************************************************
		getClientXY: function(e)
		{
			return {x: $Lud.getClientX(e), y: $Lud.getClientY(e)};
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.getClientW
		//*******************************************************************************
		//* Returns the current horizontal size of the client
		//*==============================================================================
		//* @public
		//* @param d [HTMLDocument, optional]
		//* 	HTML document
		//* @return [Number]
		//* 	Current horizontal size
		//*******************************************************************************
		getClientW: function(d)
		{
			d = d || document;
			var w = $Lud.getWindow(d);
			if(w.innerWidth || w.innerWidth === 0)
				return w.innerWidth;
			if($Le.ua.ie && $Le.ua.ie < 7 && d.body && (d.body.clientWidth || d.body.clientWidth === 0))
				return d.body.clientWidth;
			if(d.documentElement && d.documentElement.clientWidth)
				return d.documentElement.clientWidth;
			return 0;
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.getClientH
		//*******************************************************************************
		//* Returns the current vertical size of the client
		//*==============================================================================
		//* @public
		//* @param d [HTMLDocument, optional]
		//* 	HTML document
		//* @return [Number]
		//* 	Current vertical size
		//*******************************************************************************
		getClientH: function(d)
		{
			d = d || document;
			var w = $Lud.getWindow(d);
			if(w.innerHeight || w.innerHeight === 0)
				return w.innerHeight;
			if($Le.ua.ie && $Le.ua.ie < 7 && d.body && (d.body.clientHeight || d.body.clientHeight === 0))
				return d.body.clientHeight;
			if(d.documentElement && d.documentElement.clientHeight)
				return d.documentElement.clientHeight;
			return 0;
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.getClientWH
		//*******************************************************************************
		//* Returns the current horizontal and vertical size of the client
		//*==============================================================================
		//* @public
		//* @param d [HTMLDocument, optional]
		//* 	HTML document
		//* @return [Number Array]
		//* 	Current horizontal and vertical size
		//*******************************************************************************
		getClientWH: function(d)
		{
			return {w: $Lud.getClientW(d), h: $Lud.getClientH(d)};
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.getDocumentW
		//*******************************************************************************
		//* Returns the current horizontal size of the document
		//*==============================================================================
		//* @public
		//* @param d [HTMLDocument, optional]
		//* 	HTML document
		//* @return [Number]
		//* 	Current horizontal size
		//*******************************************************************************
		getDocumentW: function(d)
		{
			return Math.max($Lud.getScrollW(d), $Lud.getClientW(d));
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.getDocumentH
		//*******************************************************************************
		//* Returns the current vertical size of the document
		//*==============================================================================
		//* @public
		//* @param d [HTMLDocument, optional]
		//* 	HTML document
		//* @return [Number]
		//* 	Current vertical size
		//*******************************************************************************
		getDocumentH: function(d)
		{
			return Math.max($Lud.getScrollH(d), $Lud.getClientH(d));
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.getDocumentWH
		//*******************************************************************************
		//* Returns the current horizontal and vertical size of a the document
		//*==============================================================================
		//* @public
		//* @param d [HTMLDocument, optional]
		//* 	HTML document
		//* @return [Number Array]
		//* 	Current horizontal and vertical size
		//*******************************************************************************
		getDocumentWH: function(d)
		{
			return {w: $Lud.getDocumentW(d), h: $Lud.getDocumentH(d)};
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.getElementW
		//*******************************************************************************
		//* Returns the current horizontal size of a HTML element
		//*==============================================================================
		//* @public
		//* @param e [HTMLElement]
		//* 	HTML element
		//* @return [Number]
		//* 	Current horizontal size
		//*******************************************************************************
		getElementW: function(e)
		{
			return e.offsetWidth;
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.getElementH
		//*******************************************************************************
		//* Returns the current vertical size of a HTML element
		//*==============================================================================
		//* @public
		//* @param e [HTMLElement]
		//* 	HTML element
		//* @return [Number]
		//* 	Current vertical size
		//*******************************************************************************
		getElementH: function(e)
		{
			return e.offsetHeight;
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.getElementWH
		//*******************************************************************************
		//* Returns the current horizontal and vertical size of a HTML element
		//*==============================================================================
		//* @public
		//* @param e [HTMLElement]
		//* 	HTML element
		//* @return [Number Array]
		//* 	Current horizontal and vertical size
		//*******************************************************************************
		getElementWH: function(e)
		{
			return {w: $Lud.getElementW(e), h: $Lud.getElementH(e)};
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.setElementW
		//*******************************************************************************
		//* Set the horizontal size of a HTML element
		//*==============================================================================
		//* @public
		//* @param e [HTMLElement]
		//* 	HTML element
		//* @param w [Number]
		//* 	New horizontal size, must be greater than 0
		//* @param r [Boolean]
		//* 	Flag indicating that is a second try
		//* @no_return
		//*******************************************************************************
		setElementW: function(e, w, r)
		{
			w = 0 + w;
			// Bug fix for some old browser as ns7
			if(w < 1)
				w = 1;
			try
			{
				e.style.width = w+'px';
			}
			catch(X)
			{
			}
			if(!r)
			{
				var d = e.offsetWidth;
				if(w != d)
					$Lud.setElementW(e, 2 * w - d, true);
			}		
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.setElementH
		//*******************************************************************************
		//* Set the vertical size of a HTML element
		//*==============================================================================
		//* @public
		//* @param e [HTMLElement]
		//* 	HTML element
		//* @param h [Number]
		//* 	New vertical size
		//* @param r [Boolean]
		//* 	Flag indicating that is a second try
		//* @no_return
		//*******************************************************************************
		setElementH: function(e, h, r)
		{
			h = 0 + h;
			// Bug fix for some old browser as ns7
			if(h < 1)
				h = 1;
			try
			{
				e.style.height = h+'px';
			}
			catch(X)
			{
			}
			if(!r)
			{
				var d = e.offsetHeight;
				if(h != d)
					$Lud.setElementH(e, 2 * h - d, true);
			}		
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.setElementWH
		//*******************************************************************************
		//* Set the horizontal and vertical size of a HTML element
		//*==============================================================================
		//* @public
		//* @param e [HTMLElement]
		//* 	HTML element
		//* @param w [Number]
		//* 	New horizontal size
		//* @param h [Number]
		//* 	New vertical size
		//* @no_return
		//*******************************************************************************
		setElementWH: function(e, w, h)
		{
			$Lud.setElementW(e, w);
			$Lud.setElementH(e, h);
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.setDocumentX
		//*******************************************************************************
		//* Set the horizontal position of a HTML element in the document
		//*==============================================================================
		//* @public
		//* @param e [HTMLElement]
		//* 	HTML element
		//* @param x [Number]
		//* 	New horizontal position
		//* @param r [Boolean]
		//* 	Flag indicating that is a second try
		//* @no_return
		//*******************************************************************************
		setDocumentX: function(e, x, r)
		{
			x = 0 + x;
			var s = $Lud.getStyle(e, 'position');
			if(!s || s == '' || s == 'static')	// default to relative
			{
				$Lud.setStyle(e, 'position', 'relative');
				s = 'relative';
			}

			// assuming pixels; if not we will have to retry
			var p = $Lud.getDocumentX(e), d = parseInt($Lud.getStyle(e, 'left'), 10);
			if(!$Lu.isNumber(d))	// in case of 'auto'
				d = s == 'relative' ? 0 : e.offsetLeft;
			try
			{
				e.style.left = (x - p + d)+'px';
			}
			catch(X)
			{
			}
			if(!r)
			{
				p = $Lud.getDocumentX(e);
				if(p != x)
					$Lud.setDocumentX(e, x, true);
			}
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.setDocumentY
		//*******************************************************************************
		//* Set the vertical position of a HTML element in the document
		//*==============================================================================
		//* @public
		//* @param e [HTMLElement]
		//* 	HTML element
		//* @param x [Number]
		//* 	New vertical position
		//* @param r [Boolean]
		//* 	Flag indicating that is a second try
		//* @no_return
		//*******************************************************************************
		setDocumentY: function(e, y, r)
		{
			y = 0 + y;
			var s = $Lud.getStyle(e, 'position');
			if(!s || s == '' || s == 'static')	// default to relative
			{
				$Lud.setStyle(e, 'position', 'relative');
				s = 'relative';
			}

			// assuming pixels; if not we will have to retry
			var p = $Lud.getDocumentY(e), d = parseInt($Lud.getStyle(e, 'top'), 10);
			if(!$Lu.isNumber(d))	// in case of 'auto'
				d = s == 'relative' ? 0 : e.offsetTop;
			try
			{
				e.style.top = (y - p + d)+'px';
			}
			catch(X)
			{
			}
			if(!r)
			{
				p = $Lud.getDocumentY(e);
				if(p != y)
					$Lud.setDocumentY(e, y, true);
			}
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.setDocumentXY
		//*******************************************************************************
		//* Set the horizontal and vertical position of a HTML element in the document
		//*==============================================================================
		//* @public
		//* @param e [HTMLElement]
		//* 	HTML element
		//* @param x [Number]
		//* 	New horizontal position
		//* @param y [Number]
		//* 	New vertical position
		//* @no_return
		//*******************************************************************************
		setDocumentXY: function(e, x, y)
		{
			$Lud.setDocumentX(e, x);
			$Lud.setDocumentY(e, y);
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.setClientX
		//*******************************************************************************
		//* Set the horizontal position of a HTML element in the client
		//*==============================================================================
		//* @public
		//* @param e [HTMLElement]
		//* 	HTML element
		//* @param x [Number]
		//* 	New horizontal position
		//* @param r [Boolean]
		//* 	Flag indicating that is a second try
		//* @no_return
		//*******************************************************************************
		setClientX: function(e, x, r)
		{
			x = 0 + x;
			var s = $Lud.getStyle(e, 'position');
			if(!s || s == '' || s == 'static')	// default to relative
			{
				$Lud.setStyle(e, 'position', 'relative');
				s = 'relative';
			}

			// assuming pixels; if not we will have to retry
			var p = $Lud.getClientX(e), s = $Lud.getScrollX(e), d = parseInt($Lud.getStyle(e, 'left'), 10);
			if(!$Lu.isNumber(d))	// in case of 'auto'
				d = s == 'relative' ? 0 : e.offsetLeft;
			try
			{
				e.style.left = (x - p + d + s)+'px';
			}
			catch(X)
			{
			}
			if(!r)
			{
				p = $Lud.getClientX(e);
				if(p != x)
					$Lud.setClientX(e, x, true);
			}
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.setDocumentY
		//*******************************************************************************
		//* Set the vertical position of a HTML element in the client
		//*==============================================================================
		//* @public
		//* @param e [HTMLElement]
		//* 	HTML element
		//* @param y [Number]
		//* 	New vertical position
		//* @param r [Boolean]
		//* 	Flag indicating that is a second try
		//* @no_return
		//*******************************************************************************
		setClientY: function(e, y, r)
		{
			y = 0 + y;
			var s = $Lud.getStyle(e, 'position');
			if(!s || s == '' || s == 'static')	// default to relative
			{
				$Lud.setStyle(e, 'position', 'relative');
				s = 'relative';
			}

			// assuming pixels; if not we will have to retry
			var p = $Lud.getClientY(e), s = $Lud.getScrollY(e), d = parseInt($Lud.getStyle(e, 'top'), 10);
			if(!$Lu.isNumber(d))	// in case of 'auto'
				d = s == 'relative' ? 0 : e.offsetTop;
			try
			{
				e.style.top = (y - p + d + s)+'px';
			}
			catch(X)
			{
			}
			if(!r)
			{
				p = $Lud.getClientY(e);
				if(p != y)
					$Lud.setClientY(e, y, true);
			}
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.setClientXY
		//*******************************************************************************
		//* Set the horizontal and vertical position of a HTML element in the client
		//*==============================================================================
		//* @public
		//* @param e [HTMLElement]
		//* 	HTML element
		//* @param x [Number]
		//* 	New horizontal position
		//* @param y [Number]
		//* 	New vertical position
		//* @no_return
		//*******************************************************************************
		setClientXY: function(e, x, y)
		{
			$Lud.setClientX(e, x);
			$Lud.setClientY(e, y);
		}
	};
}();
$ = $Lud.getElementById;


/*
//*******************************************************************************
//* LOGBOOK.utl.dom.flw
//*******************************************************************************
//* LOGBOOK.utl.dom.flw is used to manage follow functions
//*==============================================================================
//* @public
//* @type [Object]
//*******************************************************************************
var $Ludf = LOGBOOK.utl.dom.flw = function()
{
	return {
		//*******************************************************************************
		//* LOGBOOK.utl.dom.flw.T_SCROLL
		//* LOGBOOK.utl.dom.flw..T_SCREEN
		//* LOGBOOK.utl.dom.flw..T_MOUSE
		//*******************************************************************************
		//* Type of follower item
		//*==============================================================================
		//* @public
		//* @type [Number]
		//*******************************************************************************
		T_SCROLL:	0,
		T_SCREEN:	1,
		T_MOUSE:	2,

		//*******************************************************************************
		//* LOGBOOK.utl.dom.flw..C_NONE
		//* LOGBOOK.utl.dom.flw..C_X
		//* LOGBOOK.utl.dom.flw..C_Y
		//*******************************************************************************
		//* Contraint of follower item
		//*==============================================================================
		//* @public
		//* @type [Number]
		//*******************************************************************************
		C_NONE:	0,
		C_X:	1,
		C_Y:	2,

		//*******************************************************************************
		//* LOGBOOK.utl.dom.flw..O_NONE
		//* LOGBOOK.utl.dom.flw..O_HIDE
		//* LOGBOOK.utl.dom.flw..O_SHOW
		//*******************************************************************************
		//* Overflow action when a follower item is out of the client zone
		//*==============================================================================
		//* @public
		//* @type [Number]
		//*******************************************************************************
		O_NONE:	0,
		O_HIDE:	1,
		O_SHOW:	2,

		//*******************************************************************************
		//* LOGBOOK.utl.dom.flw..D_AUTO
		//* LOGBOOK.utl.dom.flw..D_LTR
		//* LOGBOOK.utl.dom.flw..D_RTL
		//*******************************************************************************
		//* Direction of follower item
		//*==============================================================================
		//* @public
		//* @type [Number]
		//*******************************************************************************
		D_AUTO:	0,
		D_LTR:	1,
		D_RTL:	2,

		//*******************************************************************************
		//* LOGBOOK.utl.dom.flw._items
		//*******************************************************************************
		//* List of follower items that follow the scroll, the screen or the mouse
		//* {
		//* 	id :
		//* 	{
		//* 		e [HTMLElement]
		//* 			HTML element
		//* 		t [Number]
		//* 			Type of follower item, can be
		//* 				LOGBOOK.utl.dom.flw.T_SCROLL
		//* 				LOGBOOK.utl.dom.flw.T_SCREEN
		//* 				LOGBOOK.utl.dom.flw.T_MOUSE
		//* 
		//* 		fa [Function]
		//* 			Add function
		//* 		fu [Function]
		//* 			Update function
		//* 		fr [Function]
		//* 			Remove function
		//* 		fp [Any]
		//* 			Function parameter
		//* 
		//* 		os [String]
		//* 			Original style
		//* 
		//* 		ox [Number]
		//* 			Original horizontal position
		//* 		oy [Number]
		//* 			Original vertical position
		//* 		ow [String]
		//* 			Original horizontal size
		//* 		oh [String]
		//* 			Original vertical size
		//* 
		//* 		s [Number, optional]
		//* 			Stickiness of the follower.
		//* 			Must be 0.01 < s <= 1 (default)
		//* 		c [Number, optional]
		//* 			Constraint of the follower, can be
		//* 				LOGBOOK.utl.dom.C_NONE (default)
		//* 				LOGBOOK.utl.dom.C_X
		//* 				LOGBOOK.utl.dom.C_Y
		//* 		o [Number, optional]
		//* 			Overflow action for the follower, can be
		//* 				LOGBOOK.utl.dom.O_NONE (default)
		//* 				LOGBOOK.utl.dom.O_HIDE
		//* 				LOGBOOK.utl.dom.O_SHOW
		//* 		d [Number, optional]
		//* 			Direction of the follower, can be
		//* 				LOGBOOK.utl.dom.D_AUTO (default)
		//* 				LOGBOOK.utl.dom.D_LTR
		//* 				LOGBOOK.utl.dom.D_RTL
		//* 
		//* 		dx [Number, optional]
		//* 			Horizontal position offset, default 0
		//* 		dy [Number, optional]
		//* 			Vertical position offset, default 0
		//* 
		//* 		mix [Number|Null, optional]
		//* 			Minimum x position, default null
		//* 		max [Number|Null, optional]
		//* 			Maximum x position, default null
		//* 		miy [Number|Null, optional]
		//* 			Minimum y position, default null
		//* 		may [Number|Null, optional]
		//* 			Maximum y position, default null
		//* 
		//* 		rx [Number]
		//* 			Result horizontal position
		//* 		ry [Number]
		//* 			Result vertical position
		//* 		rw [Number]
		//* 			Result horizontal size
		//* 		rh [Number]
		//* 			Result vertical size
		//* 
		//* 		vx [Number]
		//* 			Visible horizontal position
		//* 		vy [Number]
		//* 			Visible vertical position
		//* 		vw [Number]
		//* 			Visible horizontal size
		//* 		vh [Number]
		//* 			Visible vertical size
		//* 	},
		//* 	...
		//* }
		//*==============================================================================
		//* @private
		//* @type [Object]
		//*******************************************************************************
		_items: {},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.flw._index
		//*******************************************************************************
		//* Next index
		//*==============================================================================
		//* @private
		//* @type [Number]
		//*******************************************************************************
		_index: 0,

		//*******************************************************************************
		//* LOGBOOK.utl.dom.flw._interval
		//*******************************************************************************
		//* Interval between two callback function call
		//*==============================================================================
		//* @private
		//* @type [Number]
		//*******************************************************************************
		_interval: 33,	// 30 frames per second (~1000/30)

		//*******************************************************************************
		//* LOGBOOK.utl.dom.flw._clientWH
		//*******************************************************************************
		//* Client size cache
		//*==============================================================================
		//* @private
		//* @type [Object]
		//*******************************************************************************
		_clientWH: {w: null, h: null},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.flw._scrollXY
		//*******************************************************************************
		//* Scroll position cache
		//*==============================================================================
		//* @private
		//* @type [Object]
		//*******************************************************************************
		_scrollXY: {x: null, y: null},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.flw._documentWH
		//*******************************************************************************
		//* Document size cache
		//*==============================================================================
		//* @private
		//* @type [Object]
		//*******************************************************************************
		_documentWH: {w: null, h: null},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.flw._mouseState
		//*******************************************************************************
		//* Mouse init state flag.
		//* The value is 2 when LOGBOOK.utl.dom._mouseXY is ready.
		//*==============================================================================
		//* @private
		//* @type [Number]
		//*******************************************************************************
		_mouseState: 0,

		//*******************************************************************************
		//* LOGBOOK.utl.dom.flw._mouseXY
		//*******************************************************************************
		//* Mouse position cache
		//*==============================================================================
		//* @private
		//* @type [Object]
		//*******************************************************************************
		_mouseXY: {x: null, y: null},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.flw._mouseScrollXY
		//*******************************************************************************
		//* Mouse Scroll position cache
		//*==============================================================================
		//* @private
		//* @type [Object]
		//*******************************************************************************
		_mouseScrollXY: {x: null, y: null},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.flw._enabled
		//*******************************************************************************
		//* Flag that indicates if the follow functions are enabled or disabled
		//*==============================================================================
		//* @private
		//* @type [Boolean]
		//*******************************************************************************
		_enabled: true,

		//*******************************************************************************
		//* LOGBOOK.utl.dom.flw._init
		//*******************************************************************************
		//* Runned automatically when DOM is ready.
		//*==============================================================================
		//* @private
		//* @param e [Event]
		//* @no_return
		//*******************************************************************************
		_init: function(e)
		{
			// Init follow functions
			$Ludf._clientWH = {w: null, h: null};
			$Ludf._scrollXY = {x: null, y: null};
			$Ludf._mouseState = 0;
			$Ludf._mouseXY = {x: null, y: null};
			$Ludf._mouseScrollXY = {x: null, y: null};
			$Ludf._documentWH = {w: null, h: null};
			$Lue.addListener(document, 'mousemove', $Ludf._mouseHandler);
			if (document.createEvent && document.dispatchEvent)
			{ // Send an initial event for some browsers (IE send it automatically)
				e = document.createEvent('MouseEvents');
				e.initMouseEvent('mousemove', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
				document.dispatchEvent(e);
			}
			$Ludf._timeHandler();
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.flw.enable
		//*******************************************************************************
		//* Enable all followers
		//*==============================================================================
		//* @public
		//* @no_param
		//* @no_return
		//*******************************************************************************
		enable: function()
		{
			$Ludf._enabled = true;
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.flw.disable
		//*******************************************************************************
		//* Disable all followers
		//*==============================================================================
		//* @public
		//* @no_param
		//* @no_return
		//*******************************************************************************
		disable: function()
		{
			$Ludf._enabled = false;
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.flw._fnAdd
		//*******************************************************************************
		//* Default function called when a new follower item is added
		//*==============================================================================
		//* @private
		//* @param i [Object]
		//* 	the follower item
		//* @no_return
		//*******************************************************************************
		_fnAdd: function(i)
		{
			if (!i)
				return;
			var c = $Lud.createElement('div');
			c.id = i.e.id+'_container';
			i.e.parentNode.insertBefore(c, i.e);
			$Lud.setStyle(c, 'position', 'absolute');
			$Lud.setStyle(c, 'margin', '0');
			$Lud.setStyle(c, 'padding', '0');
			$Lud.setStyle(c, 'overflow', 'hidden');
			$Lud.setStyle(c, 'border', '0');
			$Lud.setDocumentXY(c, i.ox, i.oy);
			$Lud.setElementWH(c, i.ow, i.oh);
			c.appendChild(i.e);
			$Lud.setStyle(i.e, 'position', 'relative');
			$Lud.setDocumentXY(i.e, i.ox, i.oy);
			$Lud.setElementWH(i.e, i.ow, i.oh);
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.flw._fnUpdate
		//*******************************************************************************
		//* Default function called when a follower item is updated
		//*==============================================================================
		//* @private
		//* @param i [Object]
		//* 	the follower item
		//* @no_return
		//*******************************************************************************
		_fnUpdate: function(i)
		{
			if (!i)
				return;
			var c = i.e.parentNode,
				rx = parseInt(i.rx),
				ry = parseInt(i.ry),
				rw = parseInt(i.rw),
				rh = parseInt(i.rh),
				vx = parseInt(i.vx),
				vy = parseInt(i.vy),
				vw = parseInt(i.vw),
				vh = parseInt(i.vh);
			
			if (vw == 0 || vh == 0)
			{
				$Lud.setStyle(c, 'display', 'none');
				$Lud.setDocumentXY(c, 0, -1000);
				$Lud.setElementWH(c, vw, vh);
			}
			else
			{
				$Lud.setStyle(c, 'display', 'block');
				$Lud.setDocumentXY(c, vx, vy);
				$Lud.setElementWH(c, vw, vh);
			}
			$Lud.setDocumentXY(i.e, rx, ry);
			$Lud.setElementWH(i.e, rw, rh);
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.flw._fnRemove
		//*******************************************************************************
		//* Default function called when a follower item is removed
		//*==============================================================================
		//* @private
		//* @param i [Object]
		//* 	the follower item
		//* @no_return
		//*******************************************************************************
		_fnRemove: function(i)
		{
			if (!i)
				return;
			var c = i.e.parentNode;
			c.parentNode.insertBefore(i.e, c);
			c.parentNode.removeChild(c);
			i.e.style = i.os;
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.flw._update
		//*******************************************************************************
		//* Update a follower
		//*==============================================================================
		//* @private
		//* @param i [Object]
		//* 	the follower item
		//* @no_return
		//*******************************************************************************
		_update: function(i)
		{
			if (!i)
				return;
			var s = $Ludf._scrollXY,
				m = $Ludf._mouseXY,
				c = $Ludf._clientWH;
				d = $Ludf._documentWH;

			// Move item if it's out of client zone
			if (i.o == $Ludf.O_SHOW)
			{
				if (i.d == $Ludf.D_RTL && i.rx < s.x)
					i.rx = s.x;
				if (i.rx + i.rw > s.x + c.w)
					i.rx = s.x + c.w - i.rw;
				if (i.d != $Ludf.D_RTL && i.rx < s.x)
					i.rx = s.x;
				if (i.ry + i.rh > s.y + c.h)
					i.ry = s.y + c.h - i.rh;
				if (i.ry < s.y)
					i.ry = s.y;
			}

			// Check it's in a valid zone
			if (i.max !== null && i.rx + i.rw > i.max)
				i.rx = i.max - i.rw;
			if (i.mix !== null && i.rx < i.mix)
				i.rx = i.mix;
			if (i.may !== null && i.ry + i.rh > i.may)
				i.ry = i.may - i.rh;
			if (i.miy !== null && i.ry < i.miy)
				i.ry = i.miy;

			// Check for overflow
			if (i.o == $Ludf.O_HIDE)
			{
				var dx = d.h > c.h ? $Lud._scrollbarWidth : 0,
					dy = d.w > c.w ? $Lud._scrollbarHeight : 0;
				if (i.rx < s.x)
				{
					i.vx = s.x;
					i.vw = (i.rx + i.rw < s.x ? 0 : i.rw + i.rx - s.x);
				}
				else if (i.rx > s.x + c.w - dx)
				{
					i.vx = s.x + c.w - dx;
					i.vw = 0;
				}
				else if (i.rx + i.rw > s.x + c.w - dx)
				{
					i.vx = i.rx;
					i.vw =  s.x + c.w - i.rx - dx;
				}
				else
				{
					i.vx = i.rx;
					i.vw = i.rw;
				}
				if (i.ry < s.y)
				{
					i.vy = s.y;
					i.vh = (i.ry + i.rh < s.y ? 0 : i.rh + i.ry - s.y);
				}
				else if (i.ry > s.y + c.h - dy)
				{
					i.vy = s.y + c.h - dy;
					i.vh = 0;
				}

				else if (i.ry + i.rh > s.y + c.h - dy)
				{
					i.vy = i.ry;
					i.vh =  s.y + c.h - i.ry - dy;
				}
				else
				{
					i.vy = i.ry;
					i.vh = i.rh;
				}
			}
			else
			{
				i.vx = i.rx;
				i.vy = i.ry;
				i.vw = i.rw;
				i.vh = i.rh;
			}

			return i;	//__FIXME__
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.flw.removeItem
		//*******************************************************************************
		//* Remove a follower item
		//*==============================================================================
		//* @public
		//* @param e [HTMLElement]
		//* 	HTML element to remove
		//* @return [Boolean]
		//* 	Return true if the follow item was removed successfully
		//*******************************************************************************
		removeItem: function(e)
		{
			// Check parameters
			if (!e || !e.id)
				return false;
			var id = e.id;
			if (!$Ludf._items[id])
				return false;

			// Restore the follower item position
			var i = $Ludf._items[id];
			i.rx = i.vx = i.ox;
			i.ry = i.vy = i.oy;
			i.rw = i.vw = i.ow;
			i.rh = i.vh = i.oh;
			try
			{
				if (i.fr)
					i.fr(i, i.fp);
				else
					$Ludf._fnRemove(i);
			}
			catch (X)
			{
			}

			// Remove the follower
			var t = {};
			for (var j in $Ludf._items)
				if (j != id)
					t[j] = $Ludf._items[j];
			$Ludf._items = t;
			return true;
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.flw.addItem
		//*******************************************************************************
		//* Add a follower item
		//*==============================================================================
		//* @public
		//* @param e [HTMLElement]
		//* 	HTML element to add
		//* @param t [Number]
		//* 	Type of follower item, can be :
		//* 		- LOGBOOK.utl.dom.flw.T_SCROLL
		//* 		- LOGBOOK.utl.dom.flw.T_SCREEN
		//* 		- LOGBOOK.utl.dom.flw.T_MOUSE
		//* 
		//* @param fa [Function, optional]
		//* 	Add function
		//* @param fu [Function, optional]
		//* 	Update function
		//* @param fr [Function, optional]
		//* 	Remove function
		//* @param fp [Any, optional]
		//* 	Function parameter
		//* 
		//* @param s [Number, optional]
		//* 	Stickiness (0 < s <= 1), default is 1
		//* @param c [Number, optional]
		//* 	Constraint of the follower item, can be :
		//* 		- LOGBOOK.utl.dom.flw.C_NONE (default)
		//* 		- LOGBOOK.utl.dom.flw.C_X
		//* 		- LOGBOOK.utl.dom.flw.C_Y
		//* @param o [Number, optional]
		//* 	Overflow action, can be
		//* 		- LOGBOOK.utl.dom.flw.O_NONE (default)
		//* 		- LOGBOOK.utl.dom.flw.O_HIDE
		//* 		- LOGBOOK.utl.dom.flw.O_SHOW
		//* @param d [Number, optional]
		//* 	Direction of the followerer item, can be :
		//* 		- LOGBOOK.utl.dom.D_AUTO (default)
		//* 		- LOGBOOK.utl.dom.D_LTR
		//* 		- LOGBOOK.utl.dom.D_RTL
		//* 
		//* @param dx [Number, optional]
		//* 	Horizontal position offset, default 0
		//* @param dy [Number, optional]
		//* 	Vertical position offset, default 0
		//* 
		//* @param mix [Number, optional]
		//* 	Minimum x position, default null
		//* @param max [Number, optional]
		//* 	Maximum x position, default null
		//* @param miy [Number, optional]
		//* 	Minimum y position, default null
		//* @param may [Number, optional]
		//* 	Maximum y position, default null
		//* 
		//* @return [Boolean]
		//* 	True if sucess
		//*******************************************************************************
		addItem: function(e, t, fa, fu, fr, fp, s, c, o, d, dx, dy, mix, max, miy, may)
		{
			// Check parameters
			if (!e || !e.parentNode)
				return false;
			if (t !== $Ludf.T_SCROLL && t !== $Ludf.T_SCREEN && t !== $Ludf.T_MOUSE)
				return false;
			fa = fa || null;
			fu = fu || null;
			fr = fr || null;
			fp = fp || null;
			if ((fa && !$Lu.isFunction(fa)) || (fu && !$Lu.isFunction(fu)) || (fr && !$Lu.isFunction(fr)))
				return false;
			if ((fa && (!fu || !fr)) || (fu && (!fa || !fr)) || (fr && (!fa || !fu)))
				return false;
			s = $Lu.isNumber(s) && s > 0 && s <= 1 ? s : 1;
			c = c === $Ludf.C_NONE || c === $Ludf.C_X || c === $Ludf.C_Y ? c : $Ludf.C_NONE;
			o = o === $Ludf.O_NONE || o === $Ludf.O_HIDE || o === $Ludf.O_SHOW ? o : $Ludf.O_NONE;
			d = d === $Ludf.D_AUTO || d === $Ludf.D_LTR || d === $Ludf.D_RTL ? d : $Ludf.D_AUTO;
			if (d == $Ludf.D_AUTO)
				d = $Lud.getDir(e) == 'rtl' ? $Ludf.D_RTL : $Ludf.D_LTR;
			dx = $Lu.isNumber(dx) ? parseInt(dx) : 0;
			dy = $Lu.isNumber(dy) ? parseInt(dy) : 0;
			mix = $Lu.isNumber(mix) ? parseInt(mix) : null;
			max = $Lu.isNumber(max) ? parseInt(max) : null;
			if (!e.id || e.id === '')
				e.id = 'Logbook_util_dom_flw_item'+$Ludf._index++;
			var	id = e.id;
			if ($Ludf._items[id])
				$Ludf.removeItem(e);
			var os = e.style,
				ps = $Lud.getDocumentXY(e),
				sz = $Lud.getElementWH(e);
			if (mix !== null && max !== null)
			{
				if (mix > max)
				{
					var z = max;
					max = mix;
					mix = z;
				}
				if (max < mix + sz.w)
					max = mix + sz.w;
			}
			miy = $Lu.isNumber(miy) ? parseInt(miy) : null;
			may = $Lu.isNumber(may) ? parseInt(may) : null;
			if (miy !== null && may !== null)
			{
				if (miy > may)
				{
					var z = may;
					may = miy;
					miy = z;
				}
				if (may < miy + sz.h)
					may = miy + sz.h;
			}

			// Add the follow item
			$Ludf._items[id] = {e: e, t: t,
				fa: fa, fu: fu, fr: fr, fp: fp,
				os: os,
				ox: ps.x, oy: ps.y, ow: sz.w, oh: sz.h,
				s: s, c: c, o: o, d: d,
				dx: dx, dy: dy,
				mix: mix, max: max, miy: miy, may: may,
				rx: ps.x, ry: ps.y, rw: sz.w, rh: sz.h,
				vx: ps.x, vy: ps.y, vw: sz.w, vh: sz.h};
			var	c = $Ludf._clientWH, s = $Ludf._scrollXY, m = $Ludf._mouseXY, i = $Ludf._items[id];	// __FIXME__
			switch (i.t)
			{
				case $Ludf.T_SCROLL:
					if (i.c != $Ludf.C_X)
						i.rx = i.ox + s.x + i.dx;
					else
						i.rx = i.ox;
					if (i.c != $Ludf.C_Y)
						i.ry = i.oy + s.y + i.dy;
					else
						i.ry = i.oy;
					i.rw = i.ow;
					i.rh = i.oh;
					break;
				case $Ludf.T_SCREEN:
					if (i.c != $Ludf.C_X && ((i.d == $Ludf.D_RTL && s.x + c.w < i.ox + i.ow) || (i.d == $Ludf.D_LTR && s.x > i.ox)))
					{
						if (i.d == $Ludf.D_RTL)
							i.rx = s.x + c.w - i.ow + i.dx;
						else
							i.rx = s.x + i.dx;
					}
					else
						i.rx = i.ox;
					if (i.c != $Ludf.C_Y && s.y > i.oy)
						i.ry = s.y + i.dy;
					else
						i.ry = i.oy;
					i.rw = i.ow;
					i.rh = i.oh;
					break;
				case $Ludf.T_MOUSE:
					break;
				default:
					i.rx = i.ox;
					i.ry = i.oy;
					i.rw = i.ow;
					i.rh = i.oh;
			}
			i.vx = i.rx;
			i.vy = i.ry;
			i.vw = i.rw;
			i.vh = i.rh;

			// Save the follow item
			$Ludf._update(i);
			$Ludf._items[id] = i;
			try
			{
				if (i.fa)
					i.fa(i, i.fp);
				else
					$Ludf._fnAdd(i);
			}
			catch (X)
			{
			}

			return true;
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.flw._timeHandler
		//*******************************************************************************
		//* Internally called
		//*==============================================================================
		//* @private
		//* @no_param
		//* @no_return
		//*******************************************************************************
		_timeHandler: function()
		{
			var c = $Ludf._clientWH = $Lud.getClientWH(),
				s = $Ludf._scrollXY = $Lud.getScrollXY(),
				m = $Ludf._mouseXY,
				ms = $Ludf._mouseScrollXY,
				d = $Ludf._documentWH = $Lud.getDocumentWH();
			for (var id in $Ludf._items)
			{
				var	i = $Ludf._items[id], g = {rx: i.rx, ry: i.ry, rw: i.rw, rh: i.rh, vx: i.vx, vy: i.vy, vw: i.vw, vh: i.vh};
				
				switch (i.t)
				{
					case $Ludf.T_SCROLL:
						if (i.c != $Ludf.C_X)
						{
							var d = i.ox + s.x + i.dx - i.rx;
							if ((d <= -1 || d >= 1) && i.s < 1)
								i.rx += d * i.s;
							else
								i.rx = i.ox + s.x + i.dx;
						}
						else
							i.rx = i.ox;
						if (i.c != $Ludf.C_Y)
						{
							var d = i.oy + s.y + i.dy - i.ry;
							if ((d <= -1 || d >= 1) && i.s < 1)
								i.ry += d * i.s;
							else
								i.ry = i.oy + s.y + i.dy;
						}
						else
							i.ry = i.oy;
						i.rw = i.ow;
						i.rh = i.oh;
						break;
					case $Ludf.T_SCREEN:
						if (i.c != $Ludf.C_X)
						{
							if (i.d == $Ludf.D_RTL)
							{
								var e = s.x + c.w < i.ox + i.ow ? s.x + c.w - i.ow : i.ox, d = e + i.dx - i.rx;
								if ((d <= -1 || d >= 1) && i.s < 1)
									i.rx += d * i.s;
								else
									i.rx = e + i.dx;
							}
							else
							{
								var e = s.x > i.ox ? s.x : i.ox, d = e + i.dx - i.rx;
								if ((d <= -1 || d >= 1) && i.s < 1)
									i.rx += d * i.s;
								else
									i.rx = e + i.dx;
							}
						}
						else
							i.rx = i.ox;
						if (i.c != $Ludf.C_Y)
						{
							var e = s.y > i.oy ? s.y : i.oy, d = e + i.dy - i.ry;
							if ((d <= -1 || d >= 1) && i.s < 1)
								i.ry += d * i.s;
							else
								i.ry = e + i.dy;
						}
						else
							i.ry = i.oy;
						i.rw = i.ow;
						i.rh = i.oh;
						break;
					case $Ludf.T_MOUSE:
						m.x = $Ludf._mouseXY.x = m.x + s.x - ms.x;
						m.y = $Ludf._mouseXY.y = m.y + s.y - ms.y;
						ms = $Ludf._mouseScrollXY = s;
						if (i.c != $Ludf.C_X && $Ludf._mouseState == 2)
						{
							if (i.d == $Ludf.D_RTL)
							{
								var d = m.x - i.ow - i.dx - i.rx;
								if ((d <= -1 || d >= 1) && i.s < 1)
									i.rx += d * i.s;
								else
									i.rx = m.x - i.ow - i.dx;
							}
							else
							{
								var d = m.x + i.dx - i.rx;
								if ((d <= -1 || d >= 1) && i.s < 1)
									i.rx += d * i.s;
								else
									i.rx = m.x + i.dx;
							}
						}
						else
							i.rx = i.ox;
						if (i.c != $Ludf.C_Y && $Ludf._mouseState == 2)
						{
							var d = m.y + i.dy - i.ry;
							if ((d <= -1 || d >= 1) && i.s < 1)
								i.ry += d * i.s;
							else
								i.ry = m.y + i.dy;
						}
						else
							i.ry = i.oy;
						break;
					default:
						i.rx = i.ox;
						i.ry = i.oy;
						i.rw = i.ow;
						i.rh = i.oh;
				}

				// Save the follower and call its callback function
				$Ludf._update(i);
				$Ludf._items[id] = i;
				try
				{
					if ($Ludf._enabled
					&& (i.rx != g.rx || i.ry != g.ry || i.rw != g.rw || i.rh != g.rh
					|| i.vx != g.vx || i.vy != g.vy || i.vw != g.vw || i.vh != g.vh))
					{
						if (i.fu)
							i.fu(i, i.fp);
						else
							$Ludf._fnUpdate(i);
					}
				}
				catch (X)
				{
				}
			}
			setTimeout(function(){$Ludf._timeHandler();}, $Ludf._interval);
		},

		//*******************************************************************************
		//* LOGBOOK.utl.dom.flw._mouseHandler
		//*******************************************************************************
		//* Internally called
		//*==============================================================================
		//* @private
		//* @param e [Event]
		//* @no_return
		//*******************************************************************************
		_mouseHandler: function(e)
		{
			$Lud._mouseScrollXY = $Lud.getScrollXY();
			switch ($Ludf._mouseState)
			{
				case 0:
					$Ludf._mouseXY = $Lue.getDocumentXY(e);
					$Ludf._mouseState = 1;
					break;
				case 1:
					var p = $Lue.getDocumentXY(e);
					if ($Ludf._mouseXY.x != p.x || $Ludf._mouseXY.y != p.y)
					{
						var m = $Ludf._mouseXY = p;
						$Ludf._mouseState = 2;
						for (id in $Lud._items)
							if ($Ludf._items[id].t == $Lud.T_MOUSE)
							{
								var i = $Lud._followers[id];
								if (i.c != $Ludf.C_X)
								{
									if (i.d == $Ludf.D_RTL)
										i.rx = m.x - i.ow - i.dx;
									else
										i.rx = m.x + i.dx;
								}
								else
									i.rx = i.ox;
								if (i.c != $Ludf.C_Y)
									i.ry = m.y + i.dy;
								else
									i.ry = i.oy;
								$Ludf._items[id] = i;
								$Ludf._update(i);
								try
								{
									if ($Ludf._enabled)
									{
										if (i.fu)
											i.fu(i, i.fp);
										else
											$Ludf._fnUpdate(i);
									}
								}
								catch (X)
								{
								}
							}
					}
					break;
				case 2:
					$Ludf._mouseXY = $Lue.getDocumentXY(e);
					break;
			}
		}
	};
}();
*/


//*******************************************************************************
//* LOGBOOK.cls
//*******************************************************************************
//* LOGBOOK.cls is used to store some classes
//*==============================================================================
//* @public
//* @type [Object]
//*******************************************************************************
var $Lc = LOGBOOK.cls = function()
{
	return {};
}();

//*******************************************************************************
//* LOGBOOK.cls.CustomEvent
//*******************************************************************************
//* The CustomEvent class lets you define events for your application
//* that can be subscribed to by one or more independent component.
//*==============================================================================
//* @public
//* @param t [String]
//* 	The type of event, which is passed to the callback when the event fires
//* @param s [Object]
//* 	The context the event will fire from. 'this' will refer to this object in
//* 	the callback. Default value: the window object. The listener can override
//* 	this.
//* @param m [boolean]
//* 	Pass true to prevent the event from writing to the debug system
//* @param g [int]
//* 	The signature that the custom event subscriber will receive. Can be :
//* 		- LOGBOOK.cls.CustomEvent.LIST (default)
//* 		- LOGBOOK.cls.CustomEvent.FLAT
//* @no_return
//*******************************************************************************
$Lc.CustomEvent = function(t, s, m, g)
{
	//*******************************************************************************
	//* LOGBOOK.cls.CustomEvent.type
	//*******************************************************************************
	//* The type of event, which is passed to the callback when
	//* The type of event, returned to subscribers when the event fires
	//*==============================================================================
	//* @public
	//* @type [String]
	//*******************************************************************************
	this.type = t;

	//*******************************************************************************
	//* LOGBOOK.cls.CustomEvent.scope
	//*******************************************************************************
	//* The scope the the event will fire from by default. Defaults to the window obj
	//*==============================================================================
	//* @public
	//* @type [Object]
	//*******************************************************************************
	this.scope = s || window;

	//*******************************************************************************
	//* LOGBOOK.cls.CustomEvent.silent
	//*******************************************************************************
	//* By default all custom events are logged in the debug build, set silent
	//* to true to disable debug output for this event.
	//*==============================================================================
	//* @public
	//* @type [Boolean]
	//*******************************************************************************
	this.silent = m ? true : false;

	//*******************************************************************************
	//* LOGBOOK.cls.CustomEvent.signature
	//*******************************************************************************
	//* Custom events support two styles of arguments provided to the event subscribers.
	//* - LOGBOOK.cls.CustomEvent.LIST:
	//* 	- param1:	event name
	//* 	- param2:	array of arguments sent to fire
	//* 	- param3:	(optional) a custom object supplied by the subscriber
	//* - LOGBOOK.cls.CustomEvent.FLAT:
	//* 	- param1:	the first argument passed to fire.  If you need to pass
	//*-				multiple parameters, use and array or object literal
	//* 	- param2:	(optional) a custom object supplied by the subscriber
	//*==============================================================================
	//* @public
	//* @type [Number]
	//*******************************************************************************
	this.signature = (g == $Lc.CustomEvent.FLAT) ? $Lc.CustomEvent.FLAT : $Lc.CustomEvent.LIST;

	//*******************************************************************************
	//* LOGBOOK.cls.CustomEvent.subscribers
	//*******************************************************************************
	//* The subscribers to this event
	//*==============================================================================
	//* @public
	//* @type [Array]
	//*******************************************************************************
	this.subscribers = [];

	var _onSubscribeType = '_LOGBOOK_cls_CustomEvent_onSubscribe';

	// Only add subscribe events for events that are not generated by CustomEvent
	if(t !== _onSubscribeType)
	{
		//*******************************************************************************
		//* LOGBOOK.cls.CustomEvent.subscribeEvent
		//*******************************************************************************
		//* Custom events provide a custom event that fires whenever there is
		//* a new subscriber to the event.  This provides an opportunity to
		//* handle the case where there is a non-repeating event that has
		//* already fired has a new subscriber.
		//*==============================================================================
		//* @public
		//* @type [LOGBOOK.cls.CustomEvent]
		//*******************************************************************************
		this.subscribeEvent = new LOGBOOK.cls.CustomEvent(_onSubscribeType, this, true);
	} 
};

//*******************************************************************************
//* LOGBOOK.cls.CustomEvent.LIST
//*******************************************************************************
//* Subscriber listener signature constant.  The LIST type returns three
//* parameters: the event type, the array of args passed to fire, and
//* the optional custom object
//*==============================================================================
//* @public
//* @type [Number]
//*******************************************************************************
$Lc.CustomEvent.LIST = 0;

//*******************************************************************************
//* LOGBOOK.cls.CustomEvent.FLAT
//*******************************************************************************
//* Subscriber listener signature constant.  The FLAT type returns two
//* parameters: the first argument passed to fire and the optional 
//* custom object
//*==============================================================================
//* @public
//* @type [Number]
//*******************************************************************************
$Lc.CustomEvent.FLAT = 1;

//*******************************************************************************
//* LOGBOOK.cls.CustomEvent.prototype
//*******************************************************************************
//* CustomEvent prototype
//*==============================================================================
//* @public
//* @type [Object]
//*******************************************************************************
$Lc.CustomEvent.prototype =
{
	//*******************************************************************************
	//* LOGBOOK.cls.CustomEvent.prototype.subscribe
	//*******************************************************************************
	//* Subscribes the caller to this event
	//*==============================================================================
	//* @public
	//* @param f [Function]
	//* 	The function to execute
	//* @param o [Object]
	//* 	An object to be passed along when the event fires
	//* @param s [Boolean|Object]
	//* 	If true, the obj passed in becomes the execution scope of the listener.
	//* 	If an object, that object becomes the the execution scope.
	//* @no_return
	//*******************************************************************************
	subscribe: function(f, o, s)
	{
		if(!f)
			throw new Error('Invalid callback for subscriber to \''+this.type+'\'');
		if(this.subscribeEvent)
			this.subscribeEvent.fire(f, o, s);
		this.subscribers.push(new $Lc.EventSubscriber(f, o, s));
	},

	//*******************************************************************************
	//* LOGBOOK.cls.CustomEvent.prototype.unsubscribe
	//*******************************************************************************
	//* Unsubscribes subscribers.
	//*==============================================================================
	//* @public
	//* @param f [Function]
	//* 	The subscribed function to remove, if not supplied all will be removed
	//* @param o [Object]
	//* 	The custom object passed to subscribe. This is optional, but if supplied
	//* 	will be used to disambiguate multiple listeners that are the same (i.e.:
	//* 	you subscribe many object using a function that lives on the prototype)
	//* @return [Boolean]
	//* 	True if the subscriber was found and detached.
	//*******************************************************************************
	unsubscribe: function(f, o)
	{
		if(!f)
			return this.unsubscribeAll();
		var r = false;
		for(var i = 0, l = this.subscribers.length; i < l; i++)
		{
			var s = this.subscribers[i];
			if(s && s.contains(f, o))
			{
				this._delete(i);
				r = true;
			}
		}
		return r;
	},

	//*******************************************************************************
	//* LOGBOOK.cls.CustomEvent.prototype.fire
	//*******************************************************************************
	//* Notifies the subscribers.  The callback functions will be executed
	//* from the scope specified when the event was created, and with the 
	//* following parameters:
	//* - The type of event
	//* - All of the arguments fire() was executed with as an array
	//* - The custom object (if any) that was passed into the subscribe() method
	//*==============================================================================
	//* @public
	//* @param arguments [Object*]
	//* 	An arbitrary set of parameters to pass to the handler.
	//* @return [Boolean]
	//* 	False if one of the subscribers returned false, true otherwise
	//*******************************************************************************
	fire: function()
	{
		var l = this.subscribers.length;
		if(!l && this.silent)
			return true;
		var a = [], r = true, i, b = false;
		for(i = 0; i < arguments.length; i++)
			a.push(arguments[i]);
		var n = a.length;
		for(i = 0; i < l; i++)
		{
			var s = this.subscribers[i];
			if(!s)
				b = true;
			else
			{
				var c = s.getScope(this.scope);
				if(this.signature == $Lc.CustomEvent.FLAT)
				{
					var p = null;
					if(a.length > 0)
						p = a[0];
					r = s.fn.call(c, p, s.obj);
				}
				else
					r = s.fn.call(c, this.type, a, s.obj);
				if(false === r)
					return false;
			}
		}
		
		if(b)
		{
			var m = [], t = this.subscribers;
			for(i = 0, l = t.length; i < l; i++)
			{
				s = t[i];
				m.push(t[i]);
			}
			this.subscribers = m;
		}
		return true;
	},

	//*******************************************************************************
	//* LOGBOOK.cls.CustomEvent.prototype.unsubscribeAll
	//*******************************************************************************
	//* Removes all listeners
	//*==============================================================================
	//* @public
	//* @no_param
	//* @return [Number]
	//* 	The number of listeners unsubscribed
	//*******************************************************************************
	unsubscribeAll: function()
	{
		for(var i = 0, l = this.subscribers.length; i < l; i++)
			this._delete(l - 1 - i);
		this.subscribers = [];
		return i;
	},

	//*******************************************************************************
	//* LOGBOOK.cls.CustomEvent.prototype._delete
	//*******************************************************************************
	//* 
	//*==============================================================================
	//* @private
	//* @param i [Number]
	//* @no_return
	//*******************************************************************************
	_delete: function(i)
	{
		var s = this.subscribers[i];
		if(s)
		{
			delete s.fn;
			delete s.obj;
		}
		this.subscribers[i] = null;
	},
	
	//*******************************************************************************
	//* LOGBOOK.cls.CustomEvent.prototype.toString
	//*******************************************************************************
	//* 
	//*==============================================================================
	//* @public
	//* @no_param
	//* @return [String]
	//*******************************************************************************
	toString: function()
	{
		return 'CustomEvent: '+'\''+this.type+'\', scope: '+this.scope;
	}
};

//*******************************************************************************
//* LOGBOOK.cls.EventSubscriber
//*******************************************************************************
//* Stores the subscriber information to be used when the event fires.
//*==============================================================================
//* @public
//* @param f [Function]
//* 	The function to execute
//* @param o [Object]
//* 	An object to be passed along when the event fires
//* @param v [Boolean]
//* 	'override', If true, the obj passed in becomes the execution
//* @no_return
//*******************************************************************************
$Lc.EventSubscriber = function(f, o, v)
{
	//*******************************************************************************
	//* LOGBOOK.cls.EventSubscriber.fn
	//*******************************************************************************
	//* The callback that will be execute when the event fires
	//*==============================================================================
	//* @public
	//* @type [Function]
	//*******************************************************************************
	this.fn = f;

	//*******************************************************************************
	//* LOGBOOK.cls.EventSubscriber.obj
	//*******************************************************************************
	//* An optional custom object that will passed to the callback when the event fires
	//*==============================================================================
	//* @public
	//* @type [Object]
	//*******************************************************************************
	this.obj = $Lu.isUndefined(o) ? null : o;

	//*******************************************************************************
	//* LOGBOOK.cls.EventSubscriber.override
	//*******************************************************************************
	//* The default execution scope for the event listener is defined when the
	//* event is created (usually the object which contains the event).
	//* By setting override to true, the execution scope becomes the custom
	//* object passed in by the subscriber.  If override is an object, that 
	//* object becomes the scope.
	//*==============================================================================
	//* @public
	//* @type [Boolean|Object]
	//*******************************************************************************
	this.override = v;

};

//*******************************************************************************
//* LOGBOOK.cls.EventSubscriber.prototype
//*******************************************************************************
//* EventSubscriber prototype
//*==============================================================================
//* @public
//* @type [Object]
//*******************************************************************************
$Lc.EventSubscriber.prototype =
{
	//*******************************************************************************
	//* LOGBOOK.cls.EventSubscriber.prototype.getScope
	//*******************************************************************************
	//* Returns the execution scope for this listener.  If override was set to true
	//* the custom obj will be the scope.  If override is an object, that is the
	//* scope, otherwise the default scope will be used.
	//*==============================================================================
	//* @public
	//* @param s [Object]
	//* 	The default scope to use if this listener does not override it.
	//* @return [Object]
	//* 	Execution scope
	//*******************************************************************************
	getScope: function(s)
	{
		if(this.override)
		{
			if(this.override === true)
				return this.obj;
			return this.override;
		}
		return s;
	},
	
	//*******************************************************************************
	//* LOGBOOK.cls.EventSubscriber.prototype.contains
	//*******************************************************************************
	//* Returns true if the fn and obj match this objects properties.
	//* Used by the unsubscribe method to match the right subscriber.
	//*==============================================================================
	//* @public
	//* @param f [Function]
	//* 	The function to execute
	//* @param o [Object]
	//* 	An object to be passed along when the event fires
	//* @return [Boolean]
	//* 	True if the supplied arguments match this subscriber's signature.
	//*******************************************************************************
	contains: function(f, o)
	{
		if(o)
			return (this.fn == f && this.obj == o);
		return (this.fn == f);
	},

	//*******************************************************************************
	//* LOGBOOK.cls.EventSubscriber.prototype.toString
	//*******************************************************************************
	//* 
	//*==============================================================================
	//* @public
	//* @no_param
	//* @return [String]
	//*******************************************************************************
	toString: function()
	{
		return 'EventSubscriber { obj: '+this.obj+', override: '+(this.override||'no')+' }';
	}
};

/*
//*******************************************************************************
//* LOGBOOK.itf
//*******************************************************************************
//* LOGBOOK.itf is used to store some interfaces designed to be used with
//* LOGBOOK.utl.augment()
//*==============================================================================
//* @public
//* @type [Object]
//*******************************************************************************
var $Li = LOGBOOK.itf = function()
{
	return {};
}();

//*******************************************************************************
//* LOGBOOK.itf.EventProvider
//*******************************************************************************
//* EventProvider is designed to be used with LOGBOOK.utl.augment() to wrap
//* CustomEvents in an interface that allows events to be subscribed to and fired
//* by name. This makes it possible for implementing code to subscribe to an
//* event that either has not been created yet, or will not be created at all.
//*==============================================================================
//* @public
//* @no_param
//* @no_return
//*******************************************************************************
$Li.EventProvider = function(){};

//*******************************************************************************
//* LOGBOOK.itf.EventProvider.prototype
//*******************************************************************************
//* EventProvider prototype
//*==============================================================================
//* @public
//* @type [Object]
//*******************************************************************************
$Li.EventProvider.prototype =
{
	//*******************************************************************************
	//* LOGBOOK.itf.EventProvider.prototype._events
	//*******************************************************************************
	//* Private storage of custom events
	//*==============================================================================
	//* @private
	//* @type [Object]
	//*******************************************************************************
	_events: null,
	
	//*******************************************************************************
	//* LOGBOOK.itf.EventProvider.prototype._subscribers
	//*******************************************************************************
	//* Private storage of custom events subscribers
	//*==============================================================================
	//* @private
	//* @type [Object]
	//*******************************************************************************
	_subscribers: null,
	
	//*******************************************************************************
	//* LOGBOOK.itf.EventProvider.prototype.subscribe
	//*******************************************************************************
	//* Subscribe to a CustomEvent by event type
	//*==============================================================================
	//* @public
	//* @param t [String]
	//* 	The type, or name of the event
	//* @param f [Function]
	//* 	The function to exectute when the event fires
	//* @param o [Object]
	//* 	An object to be passed along when the event fires
	//* @param v [Boolean]
	//* 	If true, the obj passed in becomes the execution scope of the listener
	//* @no_return
	//*******************************************************************************
	subscribe: function(t, f, o, v)
	{
		this._events = this._events || {};
		var c = this._events[t];
		if(c)
			c.subscribe(f, o, v);
		else
		{
			this._subscribers = this._subscribers || {};
			var s = this._subscribers;
			if(!s[t])
				s[t] = [];
			s[t].push({fn: f, obj: o, override: v});
		}
	},
	
	//*******************************************************************************
	//* LOGBOOK.itf.EventProvider.prototype.unsubscribe
	//*******************************************************************************
	//* Unsubscribes one or more listeners the from the specified event
	//*==============================================================================
	//* @public
	//* @param t [String]
	//* 	The type, or name of the event. If the type is not specified, it will
	//* 	attempt to remove the listener from all hosted events.
	//* @param f [Function, optional]
	//* 	The subscribed function to unsubscribe, if not supplied, all subscribers
	//* 	will be removed
	//* @param o [Object, optional]
	//* 	The custom object passed to subscribe. This is optional, but if supplied
	//* 	will be used to disambiguate multiple listeners that are the same (i.e:
	//* 	you subscribe many object using a function that lives on the prototype)
	//* @return [Boolean]
	//* 	True if the subscriber was found and detached
	//*******************************************************************************
	unsubscribe: function(t, f, o)
	{
		var e = this._events = this._events || {};;
		if(t)
		{
			var c = e[t];
			if(c)
				return c.unsubscribe(f, o);
		}
		else
		{
			for(var i in e)
			{
				var r = true;
				if($Lu.hasOwnProperty(e, i))
					r = e[i].unsubscribe(f, o) && r;
			}
			return r;
		}
		return false;
	},
	
	//*******************************************************************************
	//* LOGBOOK.itf.EventProvider.prototype.unsubscribeAll
	//*******************************************************************************
	//* Removes all listeners from the specified event. If the event type is not
	//* specified, all listeners from all hosted custom events will be removed.
	//*==============================================================================
	//* @public
	//* @param t [String, optional]
	//* 	The type, or name of the event
	//* @return [Boolean]
	//* 	True if the subscriber was found and detached
	//*******************************************************************************
	unsubscribeAll: function(t)
	{
		return this.unsubscribe(t);
	},
	
	//*******************************************************************************
	//* LOGBOOK.itf.EventProvider.prototype.unsubscribeAll
	//*******************************************************************************
	//* Creates a new custom event of the specified type. If a custom event by that
	//* name already exists, it will not be re-created. In either case the custom
	//* event is returned. 
	//*==============================================================================
	//* @public
	//* @param t [String]
	//* 	The type, or name of the event
	//* @param c [Object, optional]
	//* 	Optional config params. Valid properties are:
	//* 	{
	//* 		scope:
	//* 			defines the default execution scope. If not defined the default
	//* 			scope will be this instance.
	//* 		silent:
	//* 			if true, the custom event will not generate log messages. This is
	//* 			false by default.
	//* 		onSubscribeCallback:
	//* 			specifies a callback to execute when the event has a new subscriber.
	//* 			This will fire immediately for each queued subscriber if any exist
	//* 			prior to the creation of the event.
	//* 	}
	//* @return [CustomEvent]
	//* 	The custom event
	//*******************************************************************************
	createEvent: function(t, c)
	{
		var e = this._events = this._events || {};;
		var o = c || {};
		if(!e[t])
		{
			var s  = o.scope || this;
			var m = (o.silent);
			var d = new $Lc.CustomEvent(t, s, m, $Lc.CustomEvent.FLAT);
			e[t] = ce;
			if(o.onSubscribeCallback)
				d.subscribeEvent.subscribe(o.onSubscribeCallback);
			this._subscribers = this._subscribers || {};
			var q = this._subscribers[t];
			if(q)
				for(var i = 0; i < q.length; i++)
					d.subscribe(q[i].fn, q[i].obj, q[i].override);
		}
		return e[t];
	},
	
	//*******************************************************************************
	//* LOGBOOK.itf.EventProvider.prototype.fireEvent
	//*******************************************************************************
	//* Fire a custom event by name.  The callback functions will be executed from
	//* the scope specified when the event was created, and with the following
	//* parameters:
	//* 	- The first argument fire() was executed with
	//* 	- The custom object (if any) that was passed into the subscribe() method
	//* If the custom event has not been explicitly created, it will be created now
	//* with the default config, scoped to the host object
	//*==============================================================================
	//* @public
	//* @param t [String]
	//* 	The type, or name of the event
	//* @param arguments [Object*]
	//* 	An arbitrary set of parameters to pass to the handler.
	//* @return [Boolean]
	//* 	The return value from CustomEvent.fire
	//*******************************************************************************
	fireEvent: function(t)
	{
		this._events = this._events || {};
		var c = this._events[t];
		if(!c)
			return null;
		var a = [];
		for(var i = 1; i < arguments.length; i++)
			a.push(arguments[i]);
		return c.fire.apply(c, a);
	},
	
	//*******************************************************************************
	//* LOGBOOK.itf.EventProvider.prototype.hasEvent
	//*******************************************************************************
	//* Returns true if the custom event of the provided type has been created with
	//* createEvent.
	//*==============================================================================
	//* @public
	//* @param t [String]
	//* 	The type, or name of the event
	//* @return [Boolean]
	//* 	True if the custom event of the provided type has been created with
	//* 	createEvent.
	//*******************************************************************************
	hasEvent: function(t)
	{
		if(this._events && this._events[t])
				return true;
		return false;
	}
};

//*******************************************************************************
//* LOGBOOK.itf.KeyListener
//*******************************************************************************
//* KeyListener is a utility that provides an easy interface for listening for
//* keydown/keyup events fired against DOM elements.
//*==============================================================================
//* @public
//* @param n [HTMLElement|String]
//* 	The element or element ID to which the key event should be attached
//* @param k [Object]
//* 	The object literal representing the key(s) to detect. Possible attributes
//* 	are shift(Boolean), alt(Boolean), ctrl(Boolean) and keys(either an Number
//* 	or an array of Numbers representing keycodes).
//* @param h [Function|Object]
//* 	The CustomEvent handler to fire when the key event is detected or an
//* 	object literal representing the handler. 
//* @param e [String, optional]
//* 	The event (keydown or keyup) to listen for. Defaults automatically to
//* 	keydown.
//* @no_return
//*==============================================================================
//* @knownissue	the 'keypress' event is completely broken in Safari 2.x and below
//* 			the workaround is use 'keydown' for key listening. However, if it
//* 			is desired to prevent the default behavior of the keystroke, that
//* 			can only be done on the 'keypress' event. This makes key handling
//* 			quite ugly.
//* @knownissue	'keydown' is also broken in Safari 2.x and below for the ESC key.
//* 			There currently is no workaround other than choosing another key
//* 			to listen for.
//*******************************************************************************
$Li.KeyListener = function(n, k, h, e)
{
	//*******************************************************************************
	//* LOGBOOK.itf.KeyListener._keyEvent
	//*******************************************************************************
	//* The CustomEvent fired internally when a key is pressed
	//*==============================================================================
	//* @private
	//* @type [CustomEvent]
	//*******************************************************************************
	var _keyEvent = new $Lc.CustomEvent('keyPressed');
	
	//*******************************************************************************
	//* LOGBOOK.itf.KeyListener._enabledEvent
	//*******************************************************************************
	//* The CustomEvent fired when the KeyListener is enabled via the enable() 
	//*==============================================================================
	//* @private
	//* @type [CustomEvent]
	//*******************************************************************************
	var _enabledEvent = new $Lc.CustomEvent('enabled');

	//*******************************************************************************
	//* LOGBOOK.itf.KeyListener._disabledEvent
	//*******************************************************************************
	//* The CustomEvent fired when the KeyListener is disabled via the disable()
	//* function
	//*==============================================================================
	//* @private
	//* @type [CustomEvent]
	//*******************************************************************************
	var _disabledEvent = new $Lc.CustomEvent('disabled');

	//*******************************************************************************
	//* LOGBOOK.itf.KeyListener._enabled
	//*******************************************************************************
	//* Boolean indicating the enabled/disabled state of the KeyListener
	//*==============================================================================
	//* @private
	//* @type [Boolean]
	//*******************************************************************************
	var _enabled = false;

	//*******************************************************************************
	//* LOGBOOK.itf.KeyListener._handleKeyPress
	//*******************************************************************************
	//* Handles the key event when a key is pressed.
	//*==============================================================================
	//* @private
	//* @param e [Event]
	//* 	The keypress event
	//* @param o [Object]
	//* 	The event scope object
	//* @no_return
	//*******************************************************************************
	var _handleKeyPress = function(e, o)
	{
		if(!k.shift)
			k.shift = false;
		if(!k.alt)
			k.alt = false;
		if(!k.ctrl)
			k.ctrl = false;
		// check held down modifying keys first
		if(e.shiftKey == k.shift && e.altKey == k.alt && e.ctrlKey  == k.ctrl)
		{ // if we pass this, all modifiers match
			var d;
			if(k.keys instanceof Array)
			{
				for(var i = 0; i < k.keys.length; i++)
				{
					d = k.keys[i];
					if(d == e.charCode)
					{
						_keyEvent.fire(e.charCode, e);
						break;
					}
					else if(d == e.keyCode)
					{
						_keyEvent.fire(e.keyCode, e);
						break;
					}
				}
			}
			else
			{
				d = k.keys;
				if(d == e.charCode)
					_keyEvent.fire(e.charCode, e);
				else if(d == e.keyCode)
					_keyEvent.fire(e.keyCode, e);
			}
		}
	};

	if(!e)
		e = $Li.KeyListener.KEYDOWN;
	if(typeof n == 'string')
		n = $Lud.getElementById(n);
	if(typeof h == 'function')
		_keyEvent.subscribe(h);
	else
		_keyEvent.subscribe(h.fn, h.scope, h.correctScope);

	//*******************************************************************************
	//* LOGBOOK.itf.KeyListener.enable
	//*******************************************************************************
	//* Enables the KeyListener by attaching the DOM event listeners to the target
	//* DOM element
	//*==============================================================================
	//* @public
	//* @no_param
	//* @no_return
	//*******************************************************************************
	this.enable = function()
	{
		if(!_enabled)
		{
			$Lue.addListener(n, e, _handleKeyPress);
			_enabledEvent.fire(k);
		}
		_enabled = true;
	};
	
	//*******************************************************************************
	//* LOGBOOK.itf.KeyListener.disable
	//*******************************************************************************
	//* Disables the KeyListener by removing the DOM event listeners from the target
	//* DOM element
	//*==============================================================================
	//* @public
	//* @no_param
	//* @no_return
	//*******************************************************************************
	this.disable = function()
	{
		if(_enabled)
		{
			$Lue.removeListener(n, e, _handleKeyPress);
			_disabledEvent.fire(k);
		}
		_enabled = false;
	};
};

//*******************************************************************************
//* LOGBOOK.itf.KeyListener.KEYDOWN
//*******************************************************************************
//* Constant representing the DOM 'keydown' event.
//*==============================================================================
//* @public
//* @type [String]
//*******************************************************************************
$Li.KeyListener.KEYDOWN = 'keydown';

//*******************************************************************************
//* LOGBOOK.itf.KeyListener.KEYDOWN
//*******************************************************************************
//* Constant representing the DOM 'keyup' event.
//*==============================================================================
//* @public
//* @type [String]
//*******************************************************************************
$Li.KeyListener.KEYUP = 'keyup';
*/





//*******************************************************************************
//* LOGBOOK.utl.evt
//*******************************************************************************
//* LOGBOOK.utl.evt is used to store some event related utility functions
//*==============================================================================
//* @public
//* @type [Object]
//*******************************************************************************
var $Lue = LOGBOOK.utl.evt = function()
{

	//*******************************************************************************
	//* _domReady
	//*******************************************************************************
	//* True when the document is initially usable
	//*==============================================================================
	//* @private
	//* @type [Boolean]
	//*******************************************************************************
	var _domReady = false;

	//*******************************************************************************
	//* _loadComplete
	//*******************************************************************************
	//* True after the onload event has fired
	//*==============================================================================
	//* @private
	//* @type [Boolean]
	//*******************************************************************************
	var _loadComplete = false;

	//*******************************************************************************
	//* _listeners
	//*******************************************************************************
	//* Cache of wrapped listeners
	//*==============================================================================
	//* @private
	//* @type [Array]
	//*******************************************************************************
	var _listeners = [];

	//*******************************************************************************
	//* _unloadListeners
	//*******************************************************************************
	//* User-defined unload function that will be fired before all events are
	//* detached
	//*==============================================================================
	//* @private
	//* @type [Array]
	//*******************************************************************************
	var _unloadListeners = [];

	//*******************************************************************************
	//* _legacyEvents
	//*******************************************************************************
	//* Cache of DOM0 event handlers to work around issues with DOM2 events in Safari
	//*==============================================================================
	//* @private
	//* @type [Array]
	//*******************************************************************************
	var _legacyEvents = [];

	//*******************************************************************************
	//* _legacyHandlers
	//*******************************************************************************
	//* Listener stack for DOM0 events
	//*==============================================================================
	//* @private
	//* @type [Array]
	//*******************************************************************************
	var _legacyHandlers = [];

	//*******************************************************************************
	//* _legacyMap
	//*******************************************************************************
	//* Lookup table for legacy events
	//*==============================================================================
	//* @private
	//* @type [Array]
	//*******************************************************************************
	var _legacyMap = [];

	//*******************************************************************************
	//* _retryCount
	//*******************************************************************************
	//* The number of times to poll after window.onload. This number is increased if
	//* additional late-bound handlers are requested after the page load.
	//*==============================================================================
	//* @private
	//* @type [Number]
	//*******************************************************************************
	var _retryCount = 0;

	//*******************************************************************************
	//* _onAvailableListeners
	//*******************************************************************************
	//* onAvailable listeners
	//*==============================================================================
	//* @private
	//* @type [Array]
	//*******************************************************************************
	var _onAvailableListeners = [];
/*
	//*******************************************************************************
	//* _wkKeymap
	//*******************************************************************************
	//* Normalized keycodes for webkit/safari
	//*==============================================================================
	//* @private
	//* @type [Object]
	//*******************************************************************************
	var _wkKeymap =
	{
		63232: 38, // up
		63233: 40, // down
		63234: 37, // left
		63235: 39  // right
	};
*/

	//*******************************************************************************
	//* _locked
	//*******************************************************************************
	//* 
	//*==============================================================================
	//* @private
	//* @type [Boolean]
	//*******************************************************************************
	var _locked = false;

	return {
		//*******************************************************************************
		//* LOGBOOK.utl.evt.POLL_RETRYS
		//*******************************************************************************
		//* The number of times we should look for elements that are not in the DOM at
		//* the time the event is requested after the document has been loaded.
		//* The default is 4000 x 10 ms, so it will poll for 40 seconds or until all
		//* outstanding handlers are bound (whichever comes first).
		//*==============================================================================
		//* @public
		//* @type [Number]
		//*******************************************************************************
		POLL_RETRYS: 4000,
		
		//*******************************************************************************
		//* LOGBOOK.utl.evt.POLL_INTERVAL
		//*******************************************************************************
		//* The poll interval in milliseconds
		//*==============================================================================
		//* @public
		//* @type [Number]
		//*******************************************************************************
		POLL_INTERVAL: 10,

		//*******************************************************************************
		//* LOGBOOK.utl.evt.EL
		//*******************************************************************************
		//* Element to bind, int constant
		//*==============================================================================
		//* @public
		//* @type [Number]
		//*******************************************************************************
		EL: 0,
		
		//*******************************************************************************
		//* LOGBOOK.utl.evt.TYPE
		//*******************************************************************************
		//* Type of event, int constant
		//*==============================================================================
		//* @public
		//* @type [Number]
		//*******************************************************************************
		TYPE: 1,
		
		//*******************************************************************************
		//* LOGBOOK.utl.evt.FN
		//*******************************************************************************
		//* Function to execute, int constant
		//*==============================================================================
		//* @public
		//* @type [Number]
		//*******************************************************************************
		FN: 2,
		
		//*******************************************************************************
		//* LOGBOOK.utl.evt.WFN
		//*******************************************************************************
		//* Function wrapped for scope correction and cleanup, int constant
		//*==============================================================================
		//* @public
		//* @type [Number]
		//*******************************************************************************
		WFN: 3,
		
		//*******************************************************************************
		//* LOGBOOK.utl.evt.OBJ
		//*******************************************************************************
		//* Object passed in by the user that will be returned as a parameter to the
		//* callback, int constant
		//*==============================================================================
		//* @public
		//* @type [Number]
		//*******************************************************************************
		OBJ: 3,
		
		//*******************************************************************************
		//* LOGBOOK.utl.evt.ADJ_SCOPE
		//*******************************************************************************
		//* Adjusted scope, either the element we are registering the event on or the
		//* custom object passed in by the listener, int constant.
		//*==============================================================================
		//* @public
		//* @type [Number]
		//*******************************************************************************
		ADJ_SCOPE: 4,

		//*******************************************************************************
		//* LOGBOOK.utl.evt.lastError
		//*******************************************************************************
		//* addListener/removeListener can throw errors in unexpected scenarios. These
		//* errors are suppressed, the method returns false, and this property is set.
		//*==============================================================================
		//* @public
		//* @type [Error]
		//*******************************************************************************
		lastError: null,

		//*******************************************************************************
		//* LOGBOOK.utl.evt._interval
		//*******************************************************************************
		//* Poll handle
		//*==============================================================================
		//* @private
		//* @type [Object]
		//*******************************************************************************
		_interval: null,

		//*******************************************************************************
		//* LOGBOOK.utl.evt._startInterval
		//*******************************************************************************
		//* Starts poll
		//*==============================================================================
		//* @private
		//* @no_param
		//* @no_return
		//*******************************************************************************
		_startInterval: function()
		{
			if(!$Lue._interval)
			{
				var t = $Lue;
				var c = function()
				{
					t._tryPreloadAttach();
				};
				$Lue._interval = setInterval(c, $Lue.POLL_INTERVAL);
			}
		},

		//*******************************************************************************
		//* LOGBOOK.utl.evt.onAvailable
		//*******************************************************************************
		//* Executes the supplied callback when the item with the supplied
		//* id is found.  This is meant to be used to execute behavior as
		//* soon as possible as the page loads.  If you use this after the
		//* initial page load it will poll for a fixed time for the element.
		//* The number of times it will poll and the frequency are
		//* configurable.  By default it will poll for 10 seconds.
		//* The callback is executed with a single parameter:
		//* the custom object parameter, if provided.
		//*==============================================================================
		//* @public
		//* @param i [String]
		//* 	The id of the element to look for.
		//* @param f [Function]
		//* 	What to execute when the element is found.
		//* @param o [Object]
		//* 	An optional object to be passed back as a parameter to f.
		//* @param v [Boolean|Object]
		//* 	'Ovverride', if set to true, f will execute in the scope of o, if set to
		//* 	an object it will execute in the scope of that object
		//* @no_return
		//*******************************************************************************
		onAvailable: function(i, f, o, v)
		{
			_onAvailableListeners.push({id: i, fn: f, obj: o, override: v, checkReady: false});
			_retryCount = $Lue.POLL_RETRYS;
			$Lue._startInterval();
		},

		//*******************************************************************************
		//* LOGBOOK.utl.evt.onDomReady
		//*******************************************************************************
		//* Executes the supplied callback when the DOM is first usable. This will
		//* execute immediately if called after the domReady event has fired.
		//* The callback is a CustomEvent, so the signature is:
		//* 	{type [String], arguments [Array], custom object [Object]}
		//* For domReady events, there are no fire argments, so the signature is:
		//* 	{'DOMReady', [], o}
		//*==============================================================================
		//* @public
		//* @param f [Function]
		//* 	What to execute when the element is found.
		//* @param o [Object, optional]
		//* 	An optional object to be passed back as a parameter to f.
		//* @param s [Boolean|Object]
		//* 	If set to true, f will execute in the scope of o, if set to an object it
		//* 	will execute in the scope of that object
		//* @no_return
		//*******************************************************************************
		onDomReady: function(f, o, v)
		{
			if(_domReady)
			{
				setTimeout(function()
				{
					var s = window;
					if(v)
					{
						if(v === true)
							s = o;
						else
							s = v;
					}
					f.call(s, 'DOMReady', [], o);
				}, 0);
			}
			else
				$Lue._domReadyEvent.subscribe(f, o, v);
		},

		//*******************************************************************************
		//* LOGBOOK.utl.evt.onContentReady
		//*******************************************************************************
		//* Works the same way as onAvailable, but additionally checks the state of
		//* sibling elements to determine if the content of the available element is safe
		//* to modify. The callback is executed with a single parameter: the custom
		//* object parameter, if provided.
		//*==============================================================================
		//* @public
		//* @param i [String]
		//* 	The id of the element to look for.
		//* @param f [Function]
		//* 	What to execute when the element is ready.
		//* @param o [Object, optional]
		//* 	An optional object to be passed back as a parameter to f.
		//* @param v [Boolean|Object]
		//* 	If set to true, f will execute in the scope of o. If an object, f will
		//* 	exectute in the scope of that object
		//* @no_return
		//*******************************************************************************
		onContentReady: function(i, f, o, v)
		{
			_onAvailableListeners.push({id: i, fn: f, obj: o, override: v, checkReady: true});
			_retryCount = $Lue.POLL_RETRYS;
			$Lue._startInterval();
		},

		//*******************************************************************************
		//* LOGBOOK.utl.evt._domReadyEvent
		//*******************************************************************************
		//* Custom event the fires when the dom is initially usable
		//*==============================================================================
		//* @private
		//* @type [LOGBOOK.cls.CustomEvent]
		//*******************************************************************************
		_domReadyEvent: new LOGBOOK.cls.CustomEvent('DOMReady', $Lue),

		//*******************************************************************************
		//* LOGBOOK.utl.evt._simpleAdd
		//*******************************************************************************
		//* Adds a DOM event directly without the caching, cleanup, scope adj, etc.
		//*==============================================================================
		//* @private
		//* @param e [HTMLElement]
		//* 	The element to bind the handler to
		//* @param t [String]
		//* 	The type of event handler
		//* @param f [Function]
		//* 	The callback to invoke
		//* @param c [Boolean]
		//* 	Capture or bubble phase
		//* @no_return
		//*******************************************************************************
		_simpleAdd: function()
		{
			if(window.addEventListener)
			{
				return function(e, t, f, c)
				{
					e.addEventListener(t, f, (c));
				};
			}
			else if(window.attachEvent)
			{
				return function(e, t, f, c)
				{
					e.attachEvent('on'+t, f);
				};
			}
			else
			{
				return function(e, t, f, c)
				{
				};
			}
		}(),

		//*******************************************************************************
		//* LOGBOOK.utl.evt._simpleRemove
		//*******************************************************************************
		//* Basic remove listener
		//*==============================================================================
		//* @private
		//* @param e [HTMLElement]
		//* 	The element to bind the handler to
		//* @param t [String]
		//* 	The type of event handler
		//* @param f [Function]
		//* 	The callback to invoke
		//* @param c [Boolean]
		//* 	Capture or bubble phase
		//* @no_return
		//*******************************************************************************
		_simpleRemove: function()
		{
			if(window.removeEventListener)
			{
				return function(e, t, f, c)
				{
					e.removeEventListener(t, f, (c));
				};
			}
			else if(window.detachEvent)
			{
				return function(e, t, f, c)
				{
					e.detachEvent('on'+t, f);
				};
			}
			else
			{
				return function(e, t, f, c)
				{
				};
			}
		}(),

		//*******************************************************************************
		//* LOGBOOK.utl.evt.getEvent
		//*******************************************************************************
		//* Finds the event in the window object, the caller's arguments, or in the
		//* arguments of another method in the callstack. This is executed automatically
		//* for events registered through the event manager, so the implementer should
		//* not normally need to execute this function at all.
		//*==============================================================================
		//* @public
		//* @param e [Event]
		//* 	The event parameter from the handler
		//* @return [Event]
		//* 	The event 
		//*******************************************************************************
		getEvent: function(e)
		{
			e = e || window.event;
			if(!e)
			{
				var c = $Lue.getEvent.caller;
				while(c)
				{
					e = c.arguments[0];
					if(e && e.constructor == Event)
						break;
					c = c.caller;
				}
			}
			return e;
		},

		//*******************************************************************************
		//* LOGBOOK.utl.evt.getTarget
		//*******************************************************************************
		//* Returns the event's target element. Safari sometimes provides a text node,
		//* and this is automatically resolved to the text node's parent so that it
		//* behaves like other browsers.
		//*==============================================================================
		//* @public
		//* @param e [Event]
		//* 	The event
		//* @return [HTMLElement]
		//* 	The event's target
		//*******************************************************************************
		getTarget: function(e)
		{
			e = $Lue.getEvent(e);
			var t = e.target || e.srcElement;
			return $Lud.getTextElement(t);
		},

		//*******************************************************************************
		//* LOGBOOK.utl.evt.getRelatedTarget
		//*******************************************************************************
		//* Returns the event's related target 
		//*==============================================================================
		//* @public
		//* @param e [Event]
		//* 	The event
		//* @return [HTMLElement]
		//* 	The event's related target
		//*******************************************************************************
		getRelatedTarget: function(e)
		{
			e = $Lue.getEvent(e);
			var t = e.relatedTarget;
			if(!t)
			{
				if(e.type == 'mouseout')
					t = e.toElement;
				else if(e.type == 'mouseover')
					t = e.fromElement;
			}
			return $Lud.getTextElement(t);
		},

		//*******************************************************************************
		//* LOGBOOK.utl.evt.getTime
		//*******************************************************************************
		//* Returns the time of the event. If the time is not included, the event is
		//* modified using the current time.
		//*==============================================================================
		//* @public
		//* @param e [Event]
		//* 	The event
		//* @return [Date]
		//* 	The time of the event
		//*******************************************************************************
		getTime: function(e)
		{
			e = $Lue.getEvent(e);
			if(!e.time)
			{
				var t = new Date().getTime();
				try
				{
					e.time = t;
				}
				catch(X)
				{ 
					$Lue.lastError = X;
					return t;
				}
			}
			return e.time;
		},

		//*******************************************************************************
		//* LOGBOOK.utl.evt.getDocumentX
		//*******************************************************************************
		//* Returns horizontal x mouse position in document during the event.
		//*==============================================================================
		//* @public
		//* @param e [Event]
		//* 	The event
		//* @return [Number]
		//* 	Horizontal x mouse position during the event
		//*******************************************************************************
		getDocumentX: function(e)
		{
			e = $Lue.getEvent(e);
			var p = e.pageX, c = e.clientX;
			if(!p && p !==0)
				r = c + $Lud.getScrollX();
			else
				r = p;
			return r;
		},

		//*******************************************************************************
		//* LOGBOOK.utl.evt.getDocumentY
		//*******************************************************************************
		//* Returns vertical y mouse position in document during the event.
		//*==============================================================================
		//* @public
		//* @param e [Event]
		//* 	The event
		//* @return [Number]
		//* 	Vertical y mouse position during the event
		//*******************************************************************************
		getDocumentY: function(e)
		{
			e = $Lue.getEvent(e);
			var p = e.pageY, c = e.clientY;
			if(!p && p !==0)
				r = c + $Lud.getScrollY();
			else
				r = p;
			return r;
		},
		
		//*******************************************************************************
		//* LOGBOOK.utl.evt.getDocumentXY
		//*******************************************************************************
		//* Returns horizontal and vertical [x, y} mouse position in document during the
		//* event.
		//*==============================================================================
		//* @public
		//* @param e [Event]
		//* 	The event
		//* @return [Number Array]
		//* 	Horizontal and vertical [x, y} mouse position during the event
		//*******************************************************************************
		getDocumentXY: function(e)
		{
			return {x: $Lue.getDocumentX(e), y: $Lue.getDocumentY(e)};
		},

		//*******************************************************************************
		//* LOGBOOK.utl.evt.getClientX
		//*******************************************************************************
		//* Returns horizontal x mouse position in client during the event.
		//*==============================================================================
		//* @public
		//* @param e [Event]
		//* 	The event
		//* @return [Number]
		//* 	Horizontal x mouse position during the event
		//*******************************************************************************
		getClientX: function(e)
		{
			e = $Lue.getEvent(e);
			var p = e.pageX, c = e.clientX;
			if(!c && c !==0)
				r = p - $Lud.getScrollX();
			else
				r = c;
			// Ajust IE mouse position
			if($Le.ua.ie)
			{
				if($Lud.getDir() == 'rtl')
					r -= 15;
				else
					r -= 2;
			}
			return r;
		},

		//*******************************************************************************
		//* LOGBOOK.utl.evt.getClientY
		//*******************************************************************************
		//* Returns vertical y mouse position in client during the event.
		//*==============================================================================
		//* @public
		//* @param e [Event]
		//* 	The event
		//* @return [Number]
		//* 	Vertical y mouse position during the event
		//*******************************************************************************
		getClientY: function(e)
		{
			e = $Lue.getEvent(e);
			var p = e.pageY, c = e.clientY;
			if(!c && c !==0)
				r = p - $Lud.getScrollY();
			else
				r = c;
			// Ajust IE mouse position
			if($Le.ua.ie)
				r -= 2;
			return r;
		},
		
		//*******************************************************************************
		//* LOGBOOK.utl.evt.getClientXY
		//*******************************************************************************
		//* Returns horizontal and vertical [x, y} mouse position in client during the
		//* event.
		//*==============================================================================
		//* @public
		//* @param e [Event]
		//* 	The event
		//* @return [Number Array]
		//* 	Horizontal and vertical [x, y} mouse position during the event
		//*******************************************************************************
		getClientXY: function(e)
		{
			return {x: $Lue.getClientX(e), y: $Lue.getClientY(e)};
		},

		//*******************************************************************************
		//* LOGBOOK.utl.evt.getCharCode
		//*******************************************************************************
		//* Returns the charcode for an event
		//*==============================================================================
		//* @public
		//* @param e [Event]
		//* 	The event
		//* @return [Number]
		//* 	The event's charCode
		//*******************************************************************************
		getCharCode: function(e)
		{
			e = $Lue.getEvent(e);
			var c = e.keyCode || e.charCode || 0;
			if($Le.ua.wk && (c in _wkKeymap))
				c = _wkKeymap[c];
			return c;
		},

		//*******************************************************************************
		//* LOGBOOK.utl.evt.stopEvent
		//*******************************************************************************
		//* Convenience method for stopPropagation + preventDefault
		//*==============================================================================
		//* @public
		//* @param e [Event]
		//* 	The event
		//* @no_return
		//*******************************************************************************
		stopEvent: function(e)
		{
			$Lue.stopPropagation(e);
			$Lue.preventDefault(e);
		},
		
		//*******************************************************************************
		//* LOGBOOK.utl.evt.stopPropagation
		//*******************************************************************************
		//* Stops event propagation
		//*==============================================================================
		//* @public
		//* @param e [Event]
		//* 	The event
		//* @no_return
		//*******************************************************************************
		stopPropagation: function(e)
		{
			if(e.stopPropagation)
				e.stopPropagation();
			else
				e.cancelBubble = true;
		},
		
		//*******************************************************************************
		//* LOGBOOK.utl.evt.preventDefault
		//*******************************************************************************
		//* Prevents the default behavior of the event
		//*==============================================================================
		//* @public
		//* @param e [Event]
		//* 	The event
		//* @no_return
		//*******************************************************************************
		preventDefault: function(e)
		{
			if(e.preventDefault)
				e.preventDefault();
			else
				e.returnValue = false;
		},

		//*******************************************************************************
		//* LOGBOOK.utl.evt._isValidCollection
		//*******************************************************************************
		//* We want to be able to use getElementsByTagName as a collection to attach a
		//* group of events to. Unfortunately, different browsers return different types
		//* of collections. This function tests to determine if the object is array-like.
		//* It will also fail if the object is an array, but is empty.
		//*==============================================================================
		//* @private
		//* @param o [Object]
		//* 	The object to test
		//* @return [Boolean]
		//* 	True if the object is array-like and populated
		//*******************************************************************************
		_isValidCollection: function(o)
		{
			try
			{
				return (o						// o is something
						&& o.length				// o is indexed
						&& typeof o != 'string'	// o is not a string
						&& !o.tagName			// o is not an HTML element
						&& !o.alert				// o is not a window
						&& typeof o[0] != 'undefined');
			}
			catch(X)
			{
				return false;
			}
		},

		//*******************************************************************************
		//* LOGBOOK.utl.evt.addListener
		//*******************************************************************************
		//* Appends an event handler
		//*==============================================================================
		//* @public
		//* @param e [String|HTMLElement|Array|NodeList]
		//* 	An id, an element reference, or a collection of ids and/or elements to
		//* 	assign the listener to.
		//* @param t [String]
		//* 	The type of event to append
		//* @param f [Function]
		//* 	The method the event invokes
		//* @param o [Object]
		//* 	An arbitrary object that will be passed as a parameter to the handler
		//* @param v [Boolean|Object]
		//* 	'ovverride', If true, the obj passed in becomes the execution scope of
		//* 	the listener. If an object, this object becomes the execution scope
		//* @return [Boolean]
		//* 	True if the action was successful or defered, false if one or more of the
		//* 	elements could not have the listener attached, or if the operation throws
		//* 	an exception
		//*******************************************************************************
		addListener: function(e, t, f, o, v)
		{
			if(!f || !f.call)
				// throw new TypeError(t+' addListener call failed, callback undefined');
				return false;

			// The e argument can be an array of elements or element ids.
			if($Lue._isValidCollection(e))
			{
				var r = true;
				for(var i = 0, l = e.length; i < l; i++)
					r = $Lue.addListener(e[i], t, f, o, v) && r;
				return r;
			}
			else if($Lu.isString(e))
			{
				// If the e argument is a string, we assume it is actually the id of the element.
				var g = $Lud.getElementById(e);
				// If the page is loaded we convert e to the actual element, otherwise we defer attaching the event until onload event fires
				if(g)
					e = g;
				else
				{
					$Lue.onAvailable(e, function(){$Lue.addListener(e, t, f, o, v);});
					return true;
				}
			}

			// Element should be an html element or an array if we get here.
			if(!e)
				return false;

			// We need to make sure we fire registered unload events prior to automatically unhooking them.
			// So we hang on to these instead of attaching them to the window and fire the handles explicitly during our one unload event.
			if(t == 'unload' && o !== $Lue)
			{
				_unloadListeners[_unloadListeners.length] = [e, t, f, o, v];
				return true;
			}

			// If the user chooses to override the scope, we use the custom object passed in,
			// otherwise the executing scope will be the HTML element that the event is registered on
			var s = e;
			if(v)
			{
				if(v === true)
					s = o;
				else
					s = v;
			}

			// Wrap the function so we can return the o object when the event fires
			var w = function(p)
			{
				return f.call(s, $Lue.getEvent(p), o);
			};

			var a = [e, t, f, w, s];
			var i = _listeners.length;
			// cache the listener so we can try to automatically unload
			_listeners[i] = a;

			if($Lue._useLegacyEvent(e, t))
			{
				var i = $Lue._getLegacyIndex(e, t);
			
				// Add a new dom0 wrapper if one is not detected for this element
				if(i == -1 || _legacyEvents[i][$Lue.EL] != e)
				{
					i = _legacyEvents.length;
					_legacyMap[e.id+t] = i;
			
					// cache the signature for the DOM0 event, and
					// include the existing handler for the event, if any
					_legacyEvents[i] = [e, t, e['on'+t]];
					_legacyHandlers[i] = [];

					e['on'+t] = function(p)
					{
						$Lue._fireLegacyEvent($Lue.getEvent(p), i);
					};
				}
			
				// add a reference to the wrapped listener to our custom stack of events
				_legacyHandlers[i].push(a);
			}
			else
			{
				try
				{
					$Lue._simpleAdd(e, t, w, false);
				}
				catch(X)
				{
					$Lue.lastError = X;
					$Lue.removeListener(e, t, f);
					return false;
				}
			}
			return true;
		},

		//*******************************************************************************
		//* LOGBOOK.utl.evt.removeListener
		//*******************************************************************************
		//* Removes an event listener
		//*==============================================================================
		//* @public
		//* @param e [String|HTMLElement|Array|NodeList]
		//* 	An id, an element reference, or a collection of ids and/or elements to
		//* 	remove the listener from.
		//* @param t [String]
		//* 	The type of event to remove.
		//* @param f [Function]
		//* 	The method the event invokes. If f is undefined, then all event handlers
		//* 	for the type of event are removed.
		//* @return [Boolean]
		//* 	True if the unbind was successful, false otherwise.
		//*******************************************************************************
		removeListener: function(e, t, f)
		{
			var i, l;
			// The e argument can be a string
			if($Lu.isString(e))
				e = $Lud.getElementById(e);
			else if($Lue._isValidCollection(e))
			{ // The e argument can be an array of elements or element ids.
				var r = true;
				for(i = 0, l = e.length; i < l; i++)
					r = $Lue.removeListener(e[i], t, f) && r;
				return r;
			}
			if(!f || !f.call)
				return $Lue.purgeElement(e, false, t);
			if(t == 'unload')
			{
				for(i = 0, l = _unloadListeners.l; i < l; i++)
				{
					var j = _unloadListeners[i];
					if(j && j[$Lue.EL] == e && j[$Lue.TYPE] == t && j[$Lue.FN] == f)
					{
						_unloadListeners[i] = null;
						return true;
					}
				}
				return false;
			}
			var c = null;
			// The index is a hidden parameter; needed to remove it from the method signature
			// because it was tempting users to try and take advantage of it, which is not possible.
			var i = arguments[3];
			if(typeof i == 'undefined')
				i = $Lue._getCacheIndex(e, t, f);
			if(i >= 0)
				c = _listeners[i];
			if(!e || !c)
				return false;
			if($Lue._useLegacyEvent(e, t))
			{
				var j = $Lue._getLegacyIndex(e, t);
				var a = _legacyHandlers[j];
				if(a)
				{
					for(i = 0, l = a.length; i < l; i++)
					{
						k = a[i];
						if(k && k[$Lue.EL] == e && k[$Lue.TYPE] == t && k[$Lue.FN] == f)
						{
							a[i]=null;
							break;
						}
					}
				}
			}
			else
			{
				try
				{
					$Lue._simpleRemove(e, t, c[$Lue.WFN], false);
				}
				catch(X)
				{
					$Lue.lastError = X;
					return false;
				}
			}
			
			// removed the wrapped handler
			delete _listeners[i][$Lue.WFN];
			delete _listeners[i][$Lue.FN];
			_listeners[i] = null;
			return true;
		},

		//*******************************************************************************
		//* LOGBOOK.utl.evt._uid
		//*******************************************************************************
		//* Generates an unique ID for the element if it does not already have one.
		//*==============================================================================
		//* @public
		//* @param e [Object]
		//* 	The element to create the id for
		//* @return [String]
		//* 	The resulting id of the element
		//*******************************************************************************
		_uid: function(e)
		{
			var r = e.id;
			if(!r)
				e.id = r = $Lu.uid('evt');
			return r;
		},

		//*******************************************************************************
		//* LOGBOOK.utl.evt._getCacheIndex
		//*******************************************************************************
		//* Locating the saved event handler data by function ref
		//*==============================================================================
		//* @public
		//* @param e [Object]
		//* 	The element
		//* @param t [String]
		//* 	The type of event
		//* @param f [Function]
		//* 	The method of the event
		//* @return [Object]
		//* 	The cached event
		//*******************************************************************************
		_getCacheIndex: function(e, t, f)
		{
			for(var i = 0, l = listeners.length; i < l; i++)
			{
				var a = listeners[i];
				if(a && a[$Lue.FN] == f && a[$Lue.EL] == e && a[$Lue.TYPE] == t)
					return i;
			}
			return -1;
		},

		//*******************************************************************************
		//* LOGBOOK.utl.evt._fireLegacyEvent
		//*******************************************************************************
		//* When using legacy events, the handler is routed to this object so we can fire
		//* our custom listener stack.
		//*==============================================================================
		//* @private
		//* @param e [String|HTMLElement|Array|NodeList]
		//* @param i [Number]
		//* @return [Boolean]
		//*******************************************************************************
		_fireLegacyEvent: function(e, i)
		{
			var r = true, h = _legacyHandlers[i], j, s, u;
			for(var k = 0, l = h.length; k < l; k++)
			{
				j = h[k];
				if(j && j[$Lue.WFN])
				{
					s = j[$Lue.ADJ_SCOPE];
					u = j[$Lue.WFN].call(s, e);
					r = r && u;
				}
			}

			// Fire the original handler if we replaced one. We fire this after the other events
			// to keep stopPropagation/preventDefault that happened in the DOM0 handler from
			// touching our DOM2 substitute
			v = _legacyEvents[i];
			if(e && e[2])
				e[2](v);

			return r;
		},
		
		//*******************************************************************************
		//* LOGBOOK.utl.evt._getLegacyIndex
		//*******************************************************************************
		//* Returns the legacy event index that matches the supplied signature
		//*==============================================================================
		//* @private
		//* @param e [String|HTMLElement|Array|NodeList]
		//* @param t [String]
		//* @return [?]
		//*******************************************************************************
		_getLegacyIndex: function(e, t)
		{
			var k = $Lue._uid(e)+y;
			if(typeof _legacyMap[k] == 'undefined')
				return -1;
			return _legacyMap[k];
		},
		
		//*******************************************************************************
		//* LOGBOOK.utl.evt._useLegacyEvent
		//*******************************************************************************
		//* Logic that determines when we should automatically use legacy events instead
		//* of DOM2 events. Currently this is limited to old Safari browsers with a
		//* broken preventDefault
		//*==============================================================================
		//* @private
		//* @param e [String|HTMLElement|Array|NodeList]
		//* @param t [String]
		//* @return [Boolean]
		//*******************************************************************************
		_useLegacyEvent: function(e, t)
		{
			var wk = $Le.ua.wk;
			if(wk && (t == 'click' || t == 'dblclick'))
			{
				var v = parseInt(wk, 10);
				if(!isNaN(v) && v < 418)
					return true;
			}
			return false;
		},

		//*******************************************************************************
		//* LOGBOOK.utl.evt._ready
		//*******************************************************************************
		//* Fires the DOMReady event listeners the first time the document is usable.
		//*==============================================================================
		//* @private
		//* @param e [Event]
		//* @no_return
		//*******************************************************************************
		_ready: function(e)
		{
			if(!_domReady)
			{
				// Init Dom
				$Lud._init(e);

				// Init Followers
//				$Ludf._init(e);

				_domReady = true;
				$Lue._domReadyEvent.fire();
				// Remove the DOMContentLoaded for Firefox and Opera
				$Lue._simpleRemove(document, 'DOMContentLoaded', $Lue._ready);
			}
		},

		//*******************************************************************************
		//* LOGBOOK.utl.evt._load
		//*******************************************************************************
		//* Hook up any deferred listeners
		//*==============================================================================
		//* @private
		//* @param e [Event]
		//* @no_return
		//*******************************************************************************
		_load: function(e)
		{	
			if(!_loadComplete)
			{
				_loadComplete = true;

				// Just in case DOMReady did not go off for some reason
				$Lue._ready();

				// Available elements may not have been detected before the window load event fires.
				// Try to find them now so that the user is more likely to get the onAvailable notifications
				// before the window load notification
				$Lue._tryPreloadAttach();
			}
		},

		//*******************************************************************************
		//* LOGBOOK.utl.evt._unload
		//*******************************************************************************
		//* Removes all listeners registered. Called automatically during the unload
		//* event.
		//*==============================================================================
		//* @private
		//* @param e [Event]
		//* @no_return
		//*******************************************************************************
		_unload: function(e)
		{
			var i, j, k, l, m;
			for(i = 0, k = _unloadListeners.length; i < k; i++)
			{
				l = _unloadListeners[i];
				if(l)
				{
					var s = window;
					if(l[$Lue.ADJ_SCOPE])
					{
						if(l[$Lue.ADJ_SCOPE] === true)
							s = l[$Lue.OBJ];
						else
							s = l[$Lue.ADJ_SCOPE];
					}
					l[$Lue.FN].call(s, $Lue.getEvent(e), l[$Lue.OBJ]);
					_unloadListeners[i] = null;
					l = null;
					s = null;
				}
			}
			_unloadListeners = null;
			if(_listeners && _listeners.length > 0)
			{
				j = _listeners.length;
				while(j)
				{
					m = j - 1;
					l = _listeners[k];
					if(l)
						$Lue.removeListener(l[$Lue.EL], l[$Lue.TYPE], l[$Lue.FN], m);
					j = j - 1;
				}
				l = null;
			}
			for(i = 0, k = _legacyEvents.length; i < k; i++)
			{
				// dereference the element
				_legacyEvents[i][0] = null;
				// delete the array item
				_legacyEvents[i] = null;
			}
			_legacyEvents = null;
			// Remove custom attributes
			for(i = $Lud._attributesToDestroyOnUnload.length - 1; i >= 0; i--)
			{
				var j = $Lud._attributesToDestroyOnUnload[i];
				j[0][j[1]] = null;
				j[0] = null;
			}
			$Lue._simpleRemove(window, 'unload', $Lue._unload);
		},

		//*******************************************************************************
		//* LOGBOOK.utl.evt._tryPreloadAttach
		//*******************************************************************************
		//* Polling function that runs before the onload event fires, attempting to
		//* attach to DOM Nodes as soon as they are available
		//*==============================================================================
		//* @private
		//* @no_param
		//* @no_return
		//*******************************************************************************
		_tryPreloadAttach: function()
		{
			if(_locked)
				return false;
			// Hold off if _domReady has not fired to protect against the IE operation aborted issue
			if($Le.ua.ie > 0 && !_domReady)
			{
				$Lue._startInterval();
				return false;
			}
			_locked = true;

			// keep trying until after the page is loaded. We need to check the page load state prior to trying
			// to bind the elements so that we can be certain all elements have been tested appropriately
			var t = !_loadComplete, n = [], i, l, t, e, f = function(e, o)
			{
				var s = e;
				if(o.override)
				{
					if(o.override === true)
						s = o.obj;
					else
						s = o.override;
				}
				o.fn.call(s, o.obj);
			};
			if(!t)
				t = (_retryCount > 0);

			// onAvailable
			for(i = 0, l = _onAvailableListeners.length; i < l; i++)
			{
				t = _onAvailableListeners[i];
				if(t && !t.checkReady)
				{
					e = $Lud.getElementById(t.id);
					if(e)
					{
						f(e, t);
						_onAvailableListeners[i] = null;
					}
					else
						n.push(t);
				}
			}

			// onContentReady
			for(i = 0, l = _onAvailableListeners.length; i < l; i++)
			{
				t = _onAvailableListeners[i];
				if(t && t.checkReady)
				{
					e = $Lud.getElementById(t.id);
					if(e)
					{
						// The element is available, but not necessarily ready
						if(_loadComplete || e.nextSibling)
						{
							f(e, t);
							_onAvailableListeners[i] = null;
						}
					}
					else
						n.push(t);
				}
			}
			_retryCount = (n.length === 0) ? 0 : _retryCount - 1;
			if(t)
				// we may need to strip the nulled out items here
				$Lue._startInterval();
			else
			{
				clearInterval($Lue._interval);
				$Lue._interval = null;
			}

			_locked = false;
			return true;
		},

		//*******************************************************************************
		//* LOGBOOK.utl.evt.getListeners
		//*******************************************************************************
		//* Returns all listeners attached to the given element via addListener.
		//* Optionally, you can specify a specific type of event to return.
		//*==============================================================================
		//* @public
		//* @param e [HTMLElement]
		//* 	The element to inspect
		//* @param t [String, optional]
		//* 	Type of listener to return. If left out, all listeners will be returned
		//* @return [Object]
		//* 	The listener. Contains the following fields:
		//* 	{
		//* 		type [String]
		//* 			The type of event
		//* 		fn [Function]
		//* 			The callback supplied to addListener
		//* 		obj [Object]
		//* 			The custom object supplied to addListener
		//* 		adjust [Boolean]
		//* 			Whether or not to adjust the default scope
		//* 		index [Number]
		//* 			Its position in the Event util listener cache
		//* 	}
		//*******************************************************************************
		getListeners: function(e, t)
		{
			var r = [], s;
			if(!t)
				s = [_listeners, _unloadListeners];
			else if(t == 'unload')
				s = [_unloadListeners];
			else
				s = [_listeners];

			for(var j = 0; j < s.length; j++)
			{
				var a = s[j];
				if(a && a.length > 0)
				{
					for(var i=0 , n = a.length; i < n ; i++)
					{
						var l = a[i];
						if(l  && l[$Lue.EL] === el && (!t || t === l[$Lue.TYPE]))
							r.push({type: l[$Lue.TYPE], fn: l[$Lue.FN], obj: l[$Lue.OBJ], adjust: l[$Lue.ADJ_SCOPE], index: i});
					}
				}
			}
			return (r.length) ? r : null;
		},

		//*******************************************************************************
		//* LOGBOOK.utl.evt.purgeElement
		//*******************************************************************************
		//* Removes all listeners attached to the given element via addListener.
		//* Optionally, the node's children can also be purged.
		//* Optionally, you can specify a specific type of event to remove.
		//*==============================================================================
		//* @public
		//* @param e [HTMLElement]
		//* 	The element to purge
		//* @param r [Boolean]
		//* 	Recursively purge this element's children as well. Use with caution.
		//* @param t [String, optional]
		//* 	Type of listener to purge. If left out, all listeners will be removed
		//* @no_return
		//*******************************************************************************
		purgeElement: function(e, r, t)
		{
			var a = $Lue.getListeners(e, t);
			if(a)
			{
				for(var i = 0, l = a.length; i < l ; i++)
				{
					var m = a[i];
					// can't use the index on the changing collection
					$Lue.removeListener(e, m.type, m.fn, m.index);
				}
			}
			
			if(r && e && e.childNodes)
			{
				for(i = 0, l = e.childNodes.length; i < l ; i++)
					$Lue.purgeElement(e.childNodes[i], r, t);
			}
		}
	};
}();

if($Le.ua.ie)
{
	// IE: Process onAvailable/onContentReady items when the DOM is ready.
	$Lue.onDomReady($Lue._tryPreloadAttach, $Lue, true);
	$Lu.write('<s'+'cript id="_LOGBOOK_utl_event_defer" defer="true" src="//:"></s'+'cript>');
	e = document.getElementById('_LOGBOOK_utl_event_defer');
	if(e)
	{
		e.onreadystatechange = function()
		{
			if(this.readyState === 'complete')
			{
				this.parentNode.removeChild(this);
				$Lue._ready();
			}
		};
	}
	e = null;
}
else if($Le.ua.wk)
{
	// Safari: the document's readyState in Safari currently will
	// change to loaded/complete before images are loaded.
	$Lue._documentReadyWatcher = setInterval(function()
	{
		var r = document.readyState;
		if(r == 'loaded' || r == 'complete')
		{
			clearInterval($Lue._documentReadyWatcher);
			$Lue._documentReadyWatcher = null;
			$Lue._ready();
		}
	}, $Lue._POLL_INTERVAL); 
}
else
	$Lue._simpleAdd(document, 'DOMContentLoaded', $Lue._ready);
$Lue._simpleAdd(window, 'load', $Lue._load);
$Lue._simpleAdd(window, 'unload', $Lue._unload);
$Lue._tryPreloadAttach();

