//--------------------------------------------------------------

Object.extend(Array.prototype, {

	removeDuplicates: function () {
		for(i = 1; i < this.length; i++){
			if(this[i][0] == this[i-1][0]){
				this.splice(i,1);
			}
		}
	},

	empty: function () {
		for(i = 0; i <= this.length; i++)
			this.shift();
	}
});

//--------------------------------------------------------------

Object.extend(Date.prototype, {
    MONTH_NAMES:['gennaio','febbraio','marzo','aprile','maggio','giugno','luglio','agosto','settembre','ottobre','novembre','dicembre',
                          'gen','feb','mar','apr','mag','giu','lug','ago','set','ott','nov','dic'],
    DAY_NAMES:['domenica','lunedi','martedi','mercolei','giovedi','veenrdi','sabato','dom','lun','mar','mer','gio','ven','sab'],
    ACCEPTED_DATETIME_FORMATS: ["d/M/y","d-M-y","d.M.y","d MMM y",
                               "d/M/y H:m","d-M-y H:m","d.M.y H:m","d MMM y H:m",
                               "d/M/y H:m:s","d-M-y H:m:s","d.M.y H:m:s","d MMM y H:m:s"],
    ACCEPTED_DATE_FORMATS: ["d/M/y","d-M-y","d.M.y","d MMM y"],
	ACCEPTED_TIME_FORMATS: ["H:m","H:m:s","k:ma","k:m:sa","k:m a","k:m:s a"],
    
    __getInt:function(str,i,minlength,maxlength)
    {
    	for (var x=maxlength; x>=minlength; x--)
        {
    		var token=str.substring(i,i+x);
    		if (token.length < minlength) { return null; }
    		if (Validator.isInteger(token)) { return token; }
     	}
    	return null;
    },
    
    getDateFromFormat:function(val,format,defaultval)
    {
        if (defaultval==undefined) defaultval=null;

    	val=val+"";
    	format=format+"";

    	var i_val=0;
    	var i_format=0;
    	var c="";
    	var token="";
    	var token2="";
    	var x,y;
    	var now=new Date();
    	var year=now.getYear();
    	var month=now.getMonth()+1;
    	var date=1;
    	var hh=now.getHours();
    	var mm=now.getMinutes();
    	var ss=now.getSeconds();
    	var ampm="";

    	while (i_format < format.length) {
    		// Get next token from format string
    		c=format.charAt(i_format);
    		token="";
    		while ((format.charAt(i_format)==c) && (i_format < format.length)) {
    			token += format.charAt(i_format++);
    			}
    		// Extract contents of value based on format token
    		if (token=="yyyy" || token=="yy" || token=="y") {
    			if (token=="yyyy") { x=4;y=4; }
    			if (token=="yy")   { x=2;y=2; }
    			if (token=="y")    { x=2;y=4; }
    			year=this.__getInt(val,i_val,x,y);
    			if (year==null) { return defaultval; }
    			i_val += year.length;
    			if (year.length==2) {
    				if (year > 70) { year=1900+(year-0); }
    				else { year=2000+(year-0); }
    				}
    			}
    		else if (token=="MMM"||token=="NNN"){
    			month=0;
    			for (var i=0; i<this.MONTH_NAMES.length; i++) {
    				var month_name=this.MONTH_NAMES[i];
    				if (val.substring(i_val,i_val+month_name.length).toLowerCase()==month_name.toLowerCase()) {
    					if (token=="MMM"||(token=="NNN"&&i>11)) {
    						month=i+1;
    						if (month>12) { month -= 12; }
    						i_val += month_name.length;
    						break;
    						}
    					}
    				}
    			if ((month < 1)||(month>12)){return defaultval;}
    			}
    		else if (token=="EE"||token=="E"){
    			for (var i=0; i<this.DAY_NAMES.length; i++) {
    				var day_name=this.DAY_NAMES[i];
    				if (val.substring(i_val,i_val+day_name.length).toLowerCase()==day_name.toLowerCase()) {
    					i_val += day_name.length;
    					break;
    					}
    				}
    			}
    		else if (token=="MM"||token=="M") {
    			month=this.__getInt(val,i_val,token.length,2);
    			if(month==null||(month<1)||(month>12)){return defaultval;}
    			i_val+=month.length;}
    		else if (token=="dd"||token=="d") {
    			date=this.__getInt(val,i_val,token.length,2);
    			if(date==null||(date<1)||(date>31)){return defaultval;}
    			i_val+=date.length;}
    		else if (token=="hh"||token=="h") {
    			hh=this.__getInt(val,i_val,token.length,2);
    			if(hh==null||(hh<1)||(hh>12)){return defaultval;}
    			i_val+=hh.length;}
    		else if (token=="HH"||token=="H") {
    			hh=this.__getInt(val,i_val,token.length,2);
    			if(hh==null||(hh<0)||(hh>23)){return defaultval;}
    			i_val+=hh.length;}
    		else if (token=="KK"||token=="K") {
    			hh=this.__getInt(val,i_val,token.length,2);
    			if(hh==null||(hh<0)||(hh>11)){return defaultval;}
    			i_val+=hh.length;}
    		else if (token=="kk"||token=="k") {
    			hh=this.__getInt(val,i_val,token.length,2);
    			if(hh==null||(hh<1)||(hh>24)){return defaultval;}
    			i_val+=hh.length;hh--;}
    		else if (token=="mm"||token=="m") {
    			mm=this.__getInt(val,i_val,token.length,2);
    			if(mm==null||(mm<0)||(mm>59)){return defaultval;}
    			i_val+=mm.length;}
    		else if (token=="ss"||token=="s") {
    			ss=this.__getInt(val,i_val,token.length,2);
    			if(ss==null||(ss<0)||(ss>59)){return defaultval;}
    			i_val+=ss.length;}
    		else if (token=="a") {
    			if (val.substring(i_val,i_val+2).toLowerCase()=="am") {ampm="AM";}
    			else if (val.substring(i_val,i_val+2).toLowerCase()=="pm") {ampm="PM";}
    			else {return defaultval;}
    			i_val+=2;}
    		else {
    			if (val.substring(i_val,i_val+token.length)!=token) {return defaultval;}
    			else {i_val+=token.length;}
    			}
    		}
    	// If there are any trailing characters left in the value, it doesn't match
    	if (i_val != val.length) { return defaultval; }
    	// Is date valid for month?
    	if (month==2) {
    		// Check for leap year
    		if ( ( (year%4==0)&&(year%100 != 0) ) || (year%400==0) ) { // leap year
    			if (date > 29){ return defaultval; }
    			}
    		else { if (date > 28) { return defaultval; } }
    		}
    	if ((month==4)||(month==6)||(month==9)||(month==11)) {
    		if (date > 30) { return defaultval; }
    		}
    	// Correct hours value
    	if (hh<12 && ampm=="PM") { hh=hh-0+12; }
    	else if (hh>11 && ampm=="AM") { hh-=12; }
    	var newdate=new Date(year,month-1,date,hh,mm,ss);
    	return newdate;
    },
    
    parseDate:function(val,defaultval)
    {
        var d;
        if (defaultval==undefined) defaultval=null;
    	for (var i=0; i<this.ACCEPTED_DATETIME_FORMATS.length; i++)
        {
			d=this.getDateFromFormat(val,this.ACCEPTED_DATETIME_FORMATS[i],null);
			if (d!=null) return d;
    	}
    	return defaultval;
	},
	
	isDate:function(val,format)
    {
        if (format==undefined) format=this.ACCEPTED_DATETIME_FORMATS;
        else if (format.constructor==String) format=new Array(format);

        for (var i=0; i<format.length; i++)
        {
			d=this.getDateFromFormat(val,format[i]);
			if (d!=null) return true;
    	}
    	return false;
    },
    
	toFormattedString:function(format)
    {
        var LZ=function(x)
        {
            return (x<0||x>9?"":"0")+x;
        };
    
    	format=format+"";
    	var result="";
    	var i_format=0;
    	var c="";
    	var token="";
    	var y=this.getYear()+"";
    	var M=this.getMonth()+1;
    	var d=this.getDate();
    	var E=this.getDay();
    	var H=this.getHours();
    	var m=this.getMinutes();
    	var s=this.getSeconds();
    	var yyyy,yy,MMM,MM,dd,hh,h,mm,ss,ampm,HH,H,KK,K,kk,k;
    	// Convert real date parts into formatted versions
    	var value=new Object();
    	if (y.length < 4) {y=""+(y-0+1900);}
    	value["y"]=""+y;
    	value["yyyy"]=y;
    	value["yy"]=y.substring(2,4);
    	value["M"]=M;
    	value["MM"]=LZ(M);
    	value["MMM"]=this.MONTH_NAMES[M-1];
    	value["NNN"]=this.MONTH_NAMES[M+11];
    	value["d"]=d;
    	value["dd"]=LZ(d);
    	value["E"]=this.DAY_NAMES[E+7];
    	value["EE"]=this.DAY_NAMES[E];
    	value["H"]=H;
    	value["HH"]=LZ(H);
    	if (H==0){value["h"]=12;}
    	else if (H>12){value["h"]=H-12;}
    	else {value["h"]=H;}
    	value["hh"]=LZ(value["h"]);
    	if (H>11){value["K"]=H-12;} else {value["K"]=H;}
    	value["k"]=H+1;
    	value["KK"]=LZ(value["K"]);
    	value["kk"]=LZ(value["k"]);
    	if (H > 11) { value["a"]="PM"; }
    	else { value["a"]="AM"; }
    	value["m"]=m;
    	value["mm"]=LZ(m);
    	value["s"]=s;
    	value["ss"]=LZ(s);
    	while (i_format < format.length) {
    		c=format.charAt(i_format);
    		token="";
    		while ((format.charAt(i_format)==c) && (i_format < format.length)) {
    			token += format.charAt(i_format++);
    			}
    		if (value[token] != null) { result=result + value[token]; }
    		else { result=result + token; }
    		}
		return result;
	},

	setByTokens: function(day,month,year)
	{
		var leap = 0;
		if ((year % 4 == 0) || (year % 100 == 0) || (year % 400 == 0))
			leap = 1;
		if ((day <= 0) || (day > 31) || (month <= 0) || (month > 12) || (year <= 0))
			return false;
		if ((month == 2) && (leap == 1) && (day > 29))
			return false;
		if ((month == 2) && (leap != 1) && (day > 28))
			return false;
		if ( (day >= 31) && ((month == 1) || (month == 3) ||
			(month == 7) || (month == 8) ||
			(month == 10) || (month == 12)))
			return false;
		if ((day >= 30) && ((month == 4) || (month == 6) ||
			(month == 9) || (month == 11)))
			return false;
		this.setYear(year);
		this.setDate(day);
		this.setMonth(month-1);
		return true;
	},

	dateParsePatterns: [
		// ddmmyyyy
		{   re: /\d{8}/,
			handler: function(d,bits) {
				bits = String(bits);
				return d.setByTokens(
					parseInt(bits.substring(0,2), 10),
					parseInt(bits.substring(2,4), 10),
					parseInt(bits.substring(4,8))
				);
			}
		},
		// ddmmyy
		{   re: /\d{6}/,
			handler: function(d,bits) {
				bits = String(bits);
				return d.setByTokens(
					parseInt(bits.substring(0,2), 10),
					parseInt(bits.substring(2,4), 10),
					parseInt("20"+bits.substring(4,6))
				);
			}
		},
		// dd*mm*yyyy
		{   re: /(\d{1,2})[\.\s\\\/\-\:\|\_]{1,}(\d{1,2})[\.\s\\\/\-\:\|\_]{1,}(\d{4})/,
			handler: function(d,bits) {
				return d.setByTokens(
					parseInt(bits[1], 10),
					parseInt(bits[2], 10),
					parseInt(bits[3])
				);
			}
		},
		// dd*mm*yy
		{   re: /(\d{1,2})[\.\s\\\/\-\:\|\_]{1,}(\d{1,2})[\.\s\\\/\-\:\|\_]{1,}(\d{2})/,
			handler: function(d,bits) {
				return d.setByTokens(
					parseInt(bits[1], 10),
					parseInt(bits[2], 10),
					parseInt("20"+bits[3])
				);
			}
		}
	],

	guess: function(s) {
		var foundOnePattern = false;
	    for (var i = 0; i < this.dateParsePatterns.length; i++) {
	        var re = this.dateParsePatterns[i].re;
	        var handler = this.dateParsePatterns[i].handler;
	        var bits = re.exec(s);
	        if (bits) {
				foundOnePattern = handler(this,bits);
				break;
	        }
	    }
		return foundOnePattern;
	}

});


//--------------------------------------------------------------------------
/* DEPRECATED */
var Numbers = {

	max: function( v1,v2 ) {
		return (v2>v1)?v2:v1;  // se v1 o v2 sono undefined ritorna v1
	},

	min: function( v1,v2 ) {
		return (v2<v1)?v2:v1; // se v1 o v2 sono undefined ritorna v1
	},

	round: function(n,p) {
		if( p > 0 )
		{
			if( (n.toString().length - n.toString().lastIndexOf('.')) > (p + 1) )
			{
				var r = Math.pow( 10, p );
				return Math.round(n * r) / r;
			}
			return n;
		}
		return Math.round(n);
	},

	fromDecimalToHex: function(n) { 
		var s = n.toString(16).toUpperCase();
		return s.toString();
	} ,

	fromHexToDecimal: function(n) {
		return parseInt(n,16);
	}

};


//--------------------------------------------------------------------------
var Color = Class.create();
Object.extend(Color.prototype,{

	initialize: function()
	{
		switch(arguments.length)
		{
		case 1:
			this.fromHTMLstring(arguments[0]);
			break;
		case 3:
			this.fromRGBargs(arguments[0],
								arguments[1],
								arguments[2]);
			break;
		case 4:
			this.fromRGBAargs(arguments[0],
								arguments[1],
								arguments[2],
								arguments[3]);
			break;
		case 0:
		default:
			this.r=this.g=this.b=this.a=255;
			break;
		}
	},

	fromHTMLstring: function(s)
	{
		if( s.indexOf("#") != -1 )
			s = s.replace("#","");
		var hex = new String(s);
		this.r = parseInt(hex.substr(0,2),16);
		this.g = parseInt(hex.substr(2,2),16);
		this.b = parseInt(hex.substr(4,2),16);
		this.a = 255;
	},

	fromRGBargs: function( r, g, b ) {
		this.r = (r<0)?0:((r>255)?255:r);
		this.g = (g<0)?0:((g>255)?255:g);
		this.b = (b<0)?0:((b>255)?255:b);
		this.a = 255;
	},

	fromRGBint: function( i ) {
		this.r = Math.floor(i / 65536);
		i -= this.r * 65536;
		this.g = Math.floor(i / 256);
		i -= this.g * 256;
		this.b = i;
		this.a = 255;
	},

	fromRGBAargs: function( r, g, b, a ) {
		this.r = (r<0)?0:((r>255)?255:r);
		this.g = (g<0)?0:((g>255)?255:g);
		this.b = (b<0)?0:((b>255)?255:b);
		this.a = (a<0)?0:((a>255)?255:a);
	},

	fromRGBAint: function( i ) {
		this.r = Math.floor(i / 16777216);
		i -= this.r * 16777216;
		this.g = Math.floor(i / 65536);
		i -= this.g * 65536;
		this.b = Math.floor(i / 256);
		i -= this.b * 256;
		this.a = i;
	},

	fromBGRargs: function( b, g, r ) {
		this.r = (r<0)?0:((r>255)?255:r);
		this.g = (g<0)?0:((g>255)?255:g);
		this.b = (b<0)?0:((b>255)?255:b);
		this.a = 255;
	},

	fromBGRint: function( i ) {
		this.b = Math.floor(i / 65536);
		i -= this.b * 65536;
		this.g = Math.floor(i / 256);
		i -= this.g * 256;
		this.r = i;
		this.a = 255;
	},

	fromBGRAargs: function( b, g, r, a ) {
		this.r = (r<0)?0:((r>255)?255:r);
		this.g = (g<0)?0:((g>255)?255:g);
		this.b = (b<0)?0:((b>255)?255:b);
		this.a = (a<0)?0:((a>255)?255:a);
	},

	fromBGRAint: function( i ) {
		this.b = Math.floor(i / 16777216);
		i -= this.b * 16777216;
		this.g = Math.floor(i / 65536);
		i -= this.g * 65536;
		this.r = Math.floor(i / 256);
		i -= this.r * 256;
		this.a = i;
	},

	toHTMLstring: function() {
		var b = this.b.toString(16).toUpperCase();
		if( String(b).length < 2 ) b = "0" + b;
		var g = this.g.toString(16).toUpperCase();
		if( String(g).length < 2 ) g = "0" + g;
		var r = this.r.toString(16).toUpperCase();
		if( String(r).length < 2 ) r = "0" + r;
		return "#" + r + g + b;
	},

	toRGBint: function() {
		return 65536 * this.r + 256 * this.g + this.b;
	},

	toBGRint: function() {
		return 65536 * this.b + 256 * this.g + this.r;
	},

	toRGBAint: function() {
		return 16777216 * this.r + 65536 * this.g + 256 * this.b + this.a;
	},

	toBGRAint: function() {
		return 16777216 * this.b + 65536 * this.g + 256 * this.r + this.a;
	}

});


//--------------------------------------------------------------------------
var Global =
{
	EXPLORER : ((/MSIE/).test(navigator.userAgent)),
	EXPLORER_NT : ((/MSIE/).test(navigator.userAgent))&&((/5\.0/).test(navigator.userAgent)),
	EXPLORER_XP : ((/MSIE/).test(navigator.userAgent))&&((/SV1/).test(navigator.userAgent)),
	FIREFOX : ((/Firefox/).test(navigator.userAgent)),
	SAFARI : ((/Safari/).test(navigator.userAgent)),
	CANVAS_SUPPORT : false,

	offx : ((this.EXPLORER_NT)?(-5):
			((this.EXPLORER_XP)?(-2):
			 ((this.EXPLORER)?(-3):
			  -1))),
	offy : ((this.EXPLORER_NT)?(-8):
			((this.EXPLORER_XP)?(-2):
			 ((this.EXPLORER)?(-6):
			  -3))),

	// return a contained frame document
	frameContent: function(element) {
		var obj = $(element);
		if(obj.contentDocument)
			return obj.contentDocument;
		else if(obj.contentWindow)
			return obj.contentWindow.document;
		else if(obj.document)
			return obj.document;
		else return null;
	},

	// open a popup
	openPopup: function(url, options) {

		options = (options) || {};

		this.url = url;
		this.name = options.name || "_blank";
		this.width = options.width || 640;
		this.height = options.height || 480;
		this.status = options.status || 0;
		this.scroll = options.scroll || 1;
		this.resize = options.resize || 0;
		this.normal = options.normal || 0;

		if (screen && screen.availWidth) {
			this.left = (screen.availWidth - this.width) / 2;
			this.top = (screen.availHeight - this.height) / 2;
		}
		else if (screen && screen.width) {
			this.left = (screen.width - this.width) / 2;
			this.top = (screen.height - this.height) / 2;
		}

		this.str = "resizable="+this.resize;
		this.str += ", scrollbars="+this.scroll;
		this.str += ", toolbar="+this.bar;
		this.str += ", status="+this.status;
		this.str += ", menubar="+this.bar;
		this.str += ", location="+this.bar;
		this.str += ", directories="+this.bar;

		if(!this.normal) {
			this.str += ", width="+this.width;
			this.str += ", height="+this.height;
			this.str += ", left="+Math.round(this.left);
			this.str += ", top="+Math.round(this.top);
		}

		var win = window.open( this.url, this.name, this.str );
		if (win) win.opener = window;

		return win;
	},

	// context menu disable
	disableContextMenu: function() {
		document.oncontextmenu = new Function("return false");
		if( document.layers ) {
			document.captureEvents( Event.MOUSEDOWN );
			document.onmousedown=function(e) {
				if ( document.layers||document.getElementById&&!document.all )
					if ( e.which==2||e.which==3 ) return false;
			};
		}
		else if( document.all && !document.getElementById )
			document.onmousedown=function() {
				if( event.button==2 ) return false;
			}
	}

};


//--------------------------------------------------------------------------
var Timer = {
  start: function () {
    this.internalTimer = new Date();
  },

  stop: function () {
    return parseInt((new Date()).valueOf()) -
			parseInt(this.internalTimer.valueOf());
  }
};

//--------------------------------------------------------------------------
var Mouse = {

	NO_BUTTON: -1,
	LEFT_BUTTON: 0,
	MIDDLE_BUTTON: 1,
	RIGHT_BUTTON: 2,

	NO_MODIFIER: -1,
	ALT_MODIFIER: 0,
	CTRL_MODIFIER: 1,
	SHIFT_MODIFIER: 2,

	// obtain the button identifier
	button: function(e) {
		if(Global.EXPLORER){
			switch(e.button){
				case 1: return this.LEFT_BUTTON;
				case 4: return this.MIDDLE_BUTTON;
				case 2: return this.RIGHT_BUTTON;
			}
		}
		else{
			if(e.button==0 && e.which==1)
				return this.LEFT_BUTTON;
			else if(e.button==1 && e.which==2)
				return this.MIDDLE_BUTTON;
			else if(e.button==2 && e.which==3)
				return this.RIGHT_BUTTON;
		}

		return this.NO_BUTTON;
	},

	// obtain the modifier pressed (if any)
	modifier: function(e) {
		if( e.shiftKey )	return this.SHIFT_MODIFIER;
		if( e.ctrlKey )		return this.CTRL_MODIFIER;
		if( e.altKey )		return this.ALT_MODIFIER;
		return this.NO_MODIFIER;
	},

	// get absolute mouse X
	absoluteX: function(event,obj) {
		var x = Event.pointerX(event);
		if (obj!=undefined)
			x += Position.realOffset(obj)[0];
		return parseInt(x);
	},

	// get absolute mouse Y
	absoluteY: function(event,obj) {
		var y = Event.pointerY(event);
		if (obj!=undefined)
			y += Position.realOffset(obj)[1];
		return parseInt(y);
	},

	// get relative mouse X
	relativeX: function(event,obj) {
		var x = Event.pointerX(event);
		var element = Event.element(event);
		if (obj!=undefined)
			x -= Position.cumulativeOffset(obj)[0];
		return parseInt(x);
	},

	// get relative mouse Y
	relativeY: function(event,obj) {
		var y = Event.pointerY(event);
		var element = Event.element(event);
		if (obj!=undefined)
			y -= Position.cumulativeOffset(obj)[1];
		return parseInt(y);
	}
};


//--------------------------------------------------------------------------
var Keyboard = {
	
	BACKSPACE: 8,
	TAB : 9,
	ENTER: 13,
	ESC: 27,
	PAGEUP: 33,
	PAGEDOWN: 34,
	END: 35,
	HOME: 36,
	LEFT: 37,
	UP: 38,
	RIGHT: 39,
	DOWN: 40,

	// get the current keycode
	keyCode: function(e) {
	    if (window.event)
			return window.event.keyCode;
	    else
			return e.which;
	},

	// get the current char
	keyChar: function(e) {
	    if (window.event)
			return String.fromCharCode(window.event.keyCode);
	    else
			return String.fromCharCode(e.which);
	},

	// is shift down ?
	shiftDown : function(e) {
		return (e.shiftKey) ? true : false;
	},

	// is ctrl down ?
	ctrlDown : function(e) {
		return (e.ctrlKey) ? true : false;
	},

	// is alt down down ?
	altDown : function(e) {
		return (e.altKey) ? true : false;
	},

	// used for filtering characters; to be used inside an onkeypress event
	filter : function(e, goodChars)
	{
		var key = 0;
		if (window.event)
			key = window.event.keyCode;
		else
			key = e.which;

		// check special characters
		if (key==0 ||
			key==Keyboard.ENTER ||
			key==Keyboard.TAB ||
			key==Keyboard.BACKSPACE) return true;

		// get character
		if (goodChars!=undefined)
		{
			var keychar = String.fromCharCode(key);
			if (goodChars.indexOf(keychar) != -1)
				return true;
		}
		else return true;

		return false;
	},

	// used for blocking characters; to be used inside an onkeypress event
	block : function(e, badChars)
	{
		var key = 0;
		if (window.event)
			key = window.event.keyCode;
		else
			key = e.which;

		// check special characters
		if (key==0 ||
			key==Keyboard.ENTER ||
			key==Keyboard.TAB ||
			key==Keyboard.BACKSPACE) return true;

		// get character
		if (badChars!=undefined)
		{
			var keychar = String.fromCharCode(key);
			if (badChars.indexOf(keychar) != -1)
				return false;
			return true;
		}
		else
			return false;
	},

	blockReturn: function (element,callback,e) {
		if(!e) e = window.event;
		if(e.keyCode == 13) { // return
			var element = $(el);
			eval ("element."+callback+"();");
			return false;
		}
		return true;
	},

	// bubble events
	bubbleEvent: function(e)
	{
	    if (document.layers)
	        return true;
	    else if (document.all)
	        e.returnValue = true;
		return true;
	},

	// cancels events
	cancelEvent: function(e)
	{
	    if (document.layers)
	        return false;
	    else if (document.all)
	        e.returnValue = false;
		return false;
	}
};


//--------------------------------------------------------------------------
var Page = {
  fill: function(object) {
	$H(object).each(function(property){
      if (property.key != undefined){
        var element = $(property.key);
		if (element) Page.Element.fill(element,property.value);
      }
	});
//  for( property in object ) {
//	  var element = $(property);
//	  if (element && object[property] != undefined) {
//	    Page.Element.fill(element,object[property]);
//	  }
//	}
  }
};

Page.Element = {
  fill: function(element,object) {
    var element = $(element);
    var method = element.tagName.toLowerCase();
    Page.Element.Fillers[method](element,object);
  }
};

Page.Element.Fillers = {
  body: function(element,data) {
	Page.Element.Fillers.innerHTML(element,data);
  },
  head: function(element,data) {
	Page.Element.Fillers.innerHTML(element,data);
  },
  title: function(element,data) {
	Page.Element.Fillers.innerText(element,data);
  },
  div: function(element,data) {
	Page.Element.Fillers.innerHTML(element,data);
  },
  span: function(element,data) {
	Page.Element.Fillers.innerHTML(element,data);
  },
  p: function(element,data) {
	Page.Element.Fillers.innerHTML(element,data);
  },
  table: function(element,data) {
	Page.Element.Fillers.innerHTML(element,data);
  },
  tr: function(element,data) {
	Page.Element.Fillers.innerHTML(element,data);
  },
  td: function(element,data) {
	Page.Element.Fillers.innerHTML(element,data);
  },
  img: function(element,data) {
	Page.Element.Fillers.inputImage(element,data);
  },
  button: function(element,data) {
	Page.Element.Fillers.innerHTML(element,data);
  },
  input: function(element,data) {
    switch (element.type.toLowerCase()) {
      case 'submit':
      case 'hidden':
      case 'password':
      case 'text':
        return Page.Element.Fillers.textarea(element,data);
      case 'checkbox':  
      case 'radio':
        return Page.Element.Fillers.inputSelector(element,data);
      case 'image':
        return Page.Element.Fillers.inputImage(element,data);
    }
    return false;
  },
  textarea: function(element,data) {
      element.value = data;
  },
  select: function(element,data) {
    Page.Element.Fillers[element.type == 'select-one' ? 
      'selectOne' : 'selectMany'](element,data);
  },
  selectOne: function(element,data) {
	for(var i=0; i<element.options.length; i++ ) {
	  var opt = element.options[i];
	  if( opt.value == data ) {
	    element.selectedIndex = i;
        break;
	  }
    }
  },
  selectMany: function(element,data) {
	for(var i=0; i<element.options.length; i++ ) {
	  var opt = element.options[i];
	  for(var j=0; j<data.length; j++ ) {
	    if( opt.value == data[j] ) {
	      opt.selected = true;
          break;
		}
	  }
    }
  },
  inputSelector: function(element,data) {
    element.checked = parseInt(data);
  },
  inputImage: function(element,data) {
	if( data != null )
	    element.src = data;
  },
  innerHTML: function(element,data) {
	element.innerHTML = data;
  }
};


//--------------------------------------------------------------------------
var Persistent = {

  expiredate : new Date(),
  hash : "3444fcaa04dcfe852f7f159617e0d725",

  initialize : function(hash,days) {
	  this.hash = hash;
	  this.expiredate.setTime(this.expiredate.getTime() + (days * 24 * 3600 * 1000));
  },

  loadObject : function(key,def) {
	var o = this.load(key,null);
	if (o != null) {
		eval("o=("+o+")");
		return o;
	}
	else
		return def;
  },

  saveObject : function(key,object) {
	this.save(key,JSON.stringify(object));
  },

  load : function(key,def) {
	var ckstring=String(document.cookie);
	var ndx = ckstring.indexOf(this.hash+"_"+key + "=");
	if (ndx == -1) return def;
    ndx = ckstring.indexOf("=", ndx) + 1; // first character
    var edx = ckstring.indexOf(";", ndx);
    if (edx == -1) edx = ckstring.length; // last character
    return unescape(ckstring.substring(ndx, edx));
  },

  save : function(key,val) {
	document.cookie = this.hash + "_" + key + "=" + escape(val) +
		((this.expiredate == null) ? ";" : ";expires=" + this.expiredate.toGMTString());
  },

  remove : function(key) {
    if (this.load(key,null))
		document.cookie = this.hash + "_" + key + "=" + ";expires=Thu, 01-Jan-70 00:00:01 GMT";
  }

};


//--------------------------------------------------------------------------
var Validator = {

  isNull : function(val) {
    return(val==null);
  },

  isUndefined : function(val) {
    return(val==undefined || val=="undefined");
  },

  isBlank : function(val) {
    if (val==null) return true;
    for (var i=0;i<val.length;i++)
      if ((val.charAt(i)!=' ')&&(val.charAt(i)!="\t")&&
			(val.charAt(i)!="\n")&&(val.charAt(i)!="\r"))
        return false;
    return true;
  },

  isDigit : function(val) {
    if (val.length>1) return false;
	return (/\d{1}/).test(val);
  },

  isInteger : function(val) {
	return (/^\d+$/).test(val);
  },
	
  isFloat : function(val) {
	if ( (/[-+]?[0-9]*\.?[0-9]+/).test(val) ) return true;
	else return (/[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?/).test(val);
  },

  isHex : function(val) {
	return (/\b0[xX][0-9a-fA-F]+\b/).test(val);
  },

  isDate : function(val) {
    var d=new Date();
    return d.isDate(val,d.ACCEPTED_DATE_FORMATS);
  },

  isTime : function(val) {
    var d=new Date();
    return d.isDate(val,d.ACCEPTED_TIME_FORMATS);
  },

  isDateTime : function(val) {
    var d=new Date();
    return d.isDate(val);
  },
	
  isEmail : function(val) {
    return (/(^[a-z]([a-z_\.]*)@([a-z_\.]*)([.][a-z]{3})$)|(^[a-z]([a-z_\.]*)@([a-z_\.]*)(\.[a-z]{3})(\.[a-z]{2})*$)/i).test(val);
  },

  isIpAddress : function(val) {
    return (/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/).test(val);
  },

  isShorterThan : function(val,size) {
	return String(val).length <= size;
  },
  
  isEqualThan : function(val,size) {
	return String(val).length == size;
  }

};


//--------------------------------------------------------------------------
var JSON = {
	message: '',

    stringify: function (arg) {
        var c, i, l, s = '', v;
        switch (typeof arg) {
        case 'object':
            if (arg) {
                if (arg instanceof Array) {
                    for (i = 0; i < arg.length; ++i) {
                        v = this.stringify(arg[i]);
                        if (s) {
                            s += ',';
                        }
                        s += v;
                    }
                    return '[' + s + ']';
                } else if (typeof arg.toString != 'undefined') {
                    for (i in arg) {
                        v = arg[i];
                        if (typeof v != 'undefined' && typeof v != 'function') {
                            v = this.stringify(v);
                            if (s) {
                                s += ',';
                            }
                            s += this.stringify(i) + ':' + v;
                        }
                    }
                    return '{' + s + '}';
                }
            }
            return 'null';
        case 'number':
            return isFinite(arg) ? String(arg) : 'null';
        case 'string':
            l = arg.length;
            s = '"';
            for (i = 0; i < l; i += 1) {
                c = arg.charAt(i);
                if (c >= ' ') {
                    if (c == '\\' || c == '"') {
                        s += '\\';
                    }
                    s += c;
                } else {
                    switch (c) {
						case '\b':
                            s += '\\b';
                            break;
                        case '\f':
                            s += '\\f';
                            break;
                        case '\n':
                            s += '\\n';
                            break;
                        case '\r':
                            s += '\\r';
                            break;
                        case '\t':
                            s += '\\t';
                            break;
                        default:
                            c = c.charCodeAt();
                            s += '\\u00' + Math.floor(c / 16).toString(16) +
                                (c % 16).toString(16);
                    }
                }
            }
            return s + '"';
        case 'boolean':
            return String(arg);
        default:
            return 'null';
        }
    },
    parse: function (text) {
        var at = 0;
        var ch = ' ';

        function error(m) {
            throw {
                name: 'JSONError',
                message: m,
                at: at - 1,
                text: text
            };
        }

        function next() {
            ch = text.charAt(at);
            at += 1;
            return ch;
        }

        function white() {
            while (ch !== '' && ch <= ' ') {
                next();
            }
        }

        function str() {
            var i, s = '', t, u;

            if (ch == '"') {
outer:          while (next()) {
                    if (ch == '"') {
                        next();
                        return s;
                    } else if (ch == '\\') {
                        switch (next()) {
                        case 'b':
                            s += '\b';
                            break;
                        case 'f':
                            s += '\f';
                            break;
                        case 'n':
                            s += '\n';
                            break;
                        case 'r':
                            s += '\r';
                            break;
                        case 't':
                            s += '\t';
                            break;
                        case 'u':
                            u = 0;
                            for (i = 0; i < 4; i += 1) {
                                t = parseInt(next(), 16);
                                if (!isFinite(t)) {
                                    break outer;
                                }
                                u = u * 16 + t;
                            }
                            s += String.fromCharCode(u);
                            break;
                        default:
                            s += ch;
                        }
                    } else {
                        s += ch;
                    }
                }
            }
            error("Bad string");
        }

        function arr() {
            var a = [];

            if (ch == '[') {
                next();
                white();
                if (ch == ']') {
                    next();
                    return a;
                }
                while (ch) {
                    a.push(val());
                    white();
                    if (ch == ']') {
                        next();
                        return a;
                    } else if (ch != ',') {
                        break;
                    }
                    next();
                    white();
                }
            }
            error("Bad array");
        }

        function obj() {
            var k, o = {};

            if (ch == '{') {
                next();
                white();
                if (ch == '}') {
                    next();
                    return o;
                }
                while (ch) {
                    k = str();
                    white();
                    if (ch != ':') {
                        break;
                    }
                    next();
                    o[k] = val();
                    white();
                    if (ch == '}') {
                        next();
                        return o;
                    } else if (ch != ',') {
                        break;
                    }
                    next();
                    white();
                }
            }
            error("Bad object");
        }

        function num() {
            var n = '', v;
            if (ch == '-') {
                n = '-';
                next();
            }
            while (ch >= '0' && ch <= '9') {
                n += ch;
                next();
            }
            if (ch == '.') {
                n += '.';
                while (next() && ch >= '0' && ch <= '9') {
                    n += ch;
                }
            }
            if (ch == 'e' || ch == 'E') {
                n += 'e';
                next();
                if (ch == '-' || ch == '+') {
                    n += ch;
                    next();
                }
                while (ch >= '0' && ch <= '9') {
                    n += ch;
                    next();
                }
            }
            v = +n;
            if (!isFinite(v)) {
                error("Bad number");
            } else {
                return v;
            }
        }

        function word() {
            switch (ch) {
                case 't':
                    if (next() == 'r' && next() == 'u' && next() == 'e') {
                        next();
                        return true;
                    }
                    break;
                case 'f':
                    if (next() == 'a' && next() == 'l' && next() == 's' &&
                            next() == 'e') {
                        next();
                        return false;
                    }
                    break;
                case 'n':
                    if (next() == 'u' && next() == 'l' && next() == 'l') {
                        next();
                        return null;
                    }
                    break;
            }
            error("Syntax error");
        }

        function val() {
            white();
            switch (ch) {
                case '{':
                    return obj();
                case '[':
                    return arr();
                case '"':
                    return str();
                case '-':
                    return num();
                default:
                    return ch >= '0' && ch <= '9' ? num() : word();
            }
        }

        return val();
    }
};


//--------------------------------------------------------------------------
var MD5 = {

	hexcase : 0,	// hex output format. 0 - lowercase; 1 - uppercase
	b64pad : "",	// base-64 pad character. "=" for strict RFC compliance
	chrsz : 8,		// bits per input character. 8 - ASCII; 16 - Unicode


	// These are the functions you'll usually want to call
	// They take string arguments and return either hex or base-64 encoded strings
	hex : function(s) {
		return this.binl2hex(this.core_md5(this.str2binl(s), s.length * this.chrsz));
	},

	b64 : function(s) {
		return this.binl2b64(this.core_md5(this.str2binl(s), s.length * this.chrsz));
	},

	hex_hmac : function(key, data) {
		return this.binl2hex(this.core_hmac_md5(key, data));
	},

	b64_hmac : function(key, data) {
		return this.binl2b64(this.core_hmac_md5(key, data));
	},

	// internal 
	// Calculate the MD5 of an array of little-endian words, and a bit length
	core_md5 : function(x, len)
	{
	  x[len >> 5] |= 0x80 << ((len) % 32);
	  x[(((len + 64) >>> 9) << 4) + 14] = len;
	  var a =  1732584193;
	  var b = -271733879;
	  var c = -1732584194;
	  var d =  271733878;
	  for(var i = 0; i < x.length; i += 16)
	  {
		var olda = a;
		var oldb = b;
		var oldc = c;
		var oldd = d;

		a = this.md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
		d = this.md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
		c = this.md5_ff(c, d, a, b, x[i+ 2], 17,  606105819);
		b = this.md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
		a = this.md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
		d = this.md5_ff(d, a, b, c, x[i+ 5], 12,  1200080426);
		c = this.md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
		b = this.md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
		a = this.md5_ff(a, b, c, d, x[i+ 8], 7 ,  1770035416);
		d = this.md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
		c = this.md5_ff(c, d, a, b, x[i+10], 17, -42063);
		b = this.md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
		a = this.md5_ff(a, b, c, d, x[i+12], 7 ,  1804603682);
		d = this.md5_ff(d, a, b, c, x[i+13], 12, -40341101);
		c = this.md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
		b = this.md5_ff(b, c, d, a, x[i+15], 22,  1236535329);

		a = this.md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
		d = this.md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
		c = this.md5_gg(c, d, a, b, x[i+11], 14,  643717713);
		b = this.md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
		a = this.md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
		d = this.md5_gg(d, a, b, c, x[i+10], 9 ,  38016083);
		c = this.md5_gg(c, d, a, b, x[i+15], 14, -660478335);
		b = this.md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
		a = this.md5_gg(a, b, c, d, x[i+ 9], 5 ,  568446438);
		d = this.md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
		c = this.md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
		b = this.md5_gg(b, c, d, a, x[i+ 8], 20,  1163531501);
		a = this.md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
		d = this.md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
		c = this.md5_gg(c, d, a, b, x[i+ 7], 14,  1735328473);
		b = this.md5_gg(b, c, d, a, x[i+12], 20, -1926607734);

		a = this.md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
		d = this.md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
		c = this.md5_hh(c, d, a, b, x[i+11], 16,  1839030562);
		b = this.md5_hh(b, c, d, a, x[i+14], 23, -35309556);
		a = this.md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
		d = this.md5_hh(d, a, b, c, x[i+ 4], 11,  1272893353);
		c = this.md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
		b = this.md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
		a = this.md5_hh(a, b, c, d, x[i+13], 4 ,  681279174);
		d = this.md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
		c = this.md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
		b = this.md5_hh(b, c, d, a, x[i+ 6], 23,  76029189);
		a = this.md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
		d = this.md5_hh(d, a, b, c, x[i+12], 11, -421815835);
		c = this.md5_hh(c, d, a, b, x[i+15], 16,  530742520);
		b = this.md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);

		a = this.md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
		d = this.md5_ii(d, a, b, c, x[i+ 7], 10,  1126891415);
		c = this.md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
		b = this.md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
		a = this.md5_ii(a, b, c, d, x[i+12], 6 ,  1700485571);
		d = this.md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
		c = this.md5_ii(c, d, a, b, x[i+10], 15, -1051523);
		b = this.md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
		a = this.md5_ii(a, b, c, d, x[i+ 8], 6 ,  1873313359);
		d = this.md5_ii(d, a, b, c, x[i+15], 10, -30611744);
		c = this.md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
		b = this.md5_ii(b, c, d, a, x[i+13], 21,  1309151649);
		a = this.md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
		d = this.md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
		c = this.md5_ii(c, d, a, b, x[i+ 2], 15,  718787259);
		b = this.md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);

		a = this.safe_add(a, olda);
		b = this.safe_add(b, oldb);
		c = this.safe_add(c, oldc);
		d = this.safe_add(d, oldd);
	  }
	  return Array(a, b, c, d);
	},

	// These functions implement the four basic operations the algorithm uses.
	md5_cmn : function(q, a, b, x, s, t) {
	  return this.safe_add(this.bit_rol(this.safe_add(this.safe_add(a, q), this.safe_add(x, t)), s),b);
	},
	md5_ff : function(a, b, c, d, x, s, t) {
	  return this.md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
	},
	md5_gg : function(a, b, c, d, x, s, t) {
	  return this.md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
	},
	md5_hh : function(a, b, c, d, x, s, t) {
	  return this.md5_cmn(b ^ c ^ d, a, b, x, s, t);
	},
	md5_ii : function(a, b, c, d, x, s, t) {
	  return this.md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
	},

	// Calculate the HMAC-MD5, of a key and some data
	core_hmac_md5 : function(key, data)
	{
	  var bkey = this.str2binl(key);
	  if(bkey.length > 16) bkey = this.core_md5(bkey, key.length * this.chrsz);
	  var ipad = Array(16), opad = Array(16);
	  for(var i = 0; i < 16; i++) {
		ipad[i] = bkey[i] ^ 0x36363636;
		opad[i] = bkey[i] ^ 0x5C5C5C5C;
	  }
	  var hash = this.core_md5(ipad.concat(this.str2binl(data)), 512 + data.length * this.chrsz);
	  return this.core_md5(opad.concat(hash), 512 + 128);
	},

	// Add integers, wrapping at 2^32. This uses 16-bit operations internally
	// to work around bugs in some JS interpreters.
	safe_add : function(x, y) {
	  var lsw = (x & 0xFFFF) + (y & 0xFFFF);
	  var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
	  return (msw << 16) | (lsw & 0xFFFF);
	},

	// Bitwise rotate a 32-bit number to the left.
	bit_rol : function(num, cnt) {
	  return (num << cnt) | (num >>> (32 - cnt));
	},

	// Convert a string to an array of little-endian words
	// If chrsz is ASCII, characters >255 have their hi-byte silently ignored.
	str2binl : function(str) {
	  var bin = Array();
	  var mask = (1 << this.chrsz) - 1;
	  for(var i = 0; i < str.length * this.chrsz; i += this.chrsz)
		bin[i>>5] |= (str.charCodeAt(i / this.chrsz) & mask) << (i%32);
	  return bin;
	},

	// Convert an array of little-endian words to a string
	binl2str : function(bin) {
	  var str = "";
	  var mask = (1 << this.chrsz) - 1;
	  for(var i = 0; i < bin.length * 32; i += this.chrsz)
		str += String.fromCharCode((bin[i>>5] >>> (i % 32)) & mask);
	  return str;
	},

	// Convert an array of little-endian words to a hex string.
	binl2hex : function(binarray) {
	  var hex_tab = this.hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
	  var str = "";
	  for(var i = 0; i < binarray.length * 4; i++) {
		str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) +
			   hex_tab.charAt((binarray[i>>2] >> ((i%4)*8  )) & 0xF);
	  }
	  return str;
	},

	// Convert an array of little-endian words to a base-64 string
	binl2b64 : function(binarray)
	{
	  var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
	  var str = "";
	  for(var i = 0; i < binarray.length * 4; i += 3) {
		var triplet = (((binarray[i   >> 2] >> 8 * ( i   %4)) & 0xFF) << 16)
					| (((binarray[i+1 >> 2] >> 8 * ((i+1)%4)) & 0xFF) << 8 )
					|  ((binarray[i+2 >> 2] >> 8 * ((i+2)%4)) & 0xFF);
		for(var j = 0; j < 4; j++) {
		  if(i * 8 + j * 6 > binarray.length * 32) str += this.b64pad;
		  else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F);
		}
	  }
	  return str;
	},

	// Perform a simple self-test to see if the VM is working
	test : function() {
		alert( this.hex("abc") == "900150983cd24fb0d6963f7d28e17f72" );
	}
};


//--------------------------------------------------------------------------
var Base64 = {

	encode: function( dStr ) {
		var decStr = new String( dStr );
		var base64s = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
		var bits, dual, i = 0, encOut = new String('');
		while(decStr.length >= i + 3){
			bits = (decStr.charCodeAt(i++) & 0xff) <<16 | (decStr.charCodeAt(i++) & 0xff) <<8  | decStr.charCodeAt(i++) & 0xff;
			encOut += base64s.charAt((bits & 0x00fc0000) >>18) + base64s.charAt((bits & 0x0003f000) >>12) + base64s.charAt((bits & 0x00000fc0) >> 6) + base64s.charAt((bits & 0x0000003f));
		}
		if(decStr.length -i > 0 && decStr.length -i < 3){
			dual = Boolean(decStr.length -i -1);
			bits = ((decStr.charCodeAt(i++) & 0xff) <<16) | (dual ? (decStr.charCodeAt(i) & 0xff) <<8 : 0);
			encOut += base64s.charAt((bits & 0x00fc0000) >>18) + base64s.charAt((bits & 0x0003f000) >>12) + (dual ? base64s.charAt((bits & 0x00000fc0) >>6) : '=') + '=';
		}
		return encOut;
	},

	decode: function( eStr ) {
		var encStr = new String( eStr );
		var base64s = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
		var bits, decOut = new String(""), i = 0;
		for(; i<encStr.length; i += 4){
			bits = (base64s.indexOf(encStr.charAt(i)) & 0xff) <<18 | (base64s.indexOf(encStr.charAt(i +1)) & 0xff) <<12 | (base64s.indexOf(encStr.charAt(i +2)) & 0xff) << 6 | base64s.indexOf(encStr.charAt(i +3)) & 0xff;
			decOut += String.fromCharCode( (bits & 0xff0000) >>16, (bits & 0xff00) >>8, bits & 0xff);
		}
		if(encStr.charCodeAt(i -2) == 61)			return decOut.substring(0, decOut.length -2);
		else if(encStr.charCodeAt(i -1) == 61)		return decOut.substring(0, decOut.length -1);
		else return decOut;
	}

};


//--------------------------------------------------------------------------
var UUID = {

	generate: function() {
		return [4, 2, 2, 2, 6].map(function(length) {
			return $R(0, length, true).map(function() {
				return (Math.random() * 256).toString(16);
			}).join('');
		}).join('-');
	}

};


//--------------------------------------------------------------------------
var Debug = {
	persistent: false,

	print: function()
	{
		var debugText = (this.persistent) ? Persistent.load("__debugoutput","") : "";
		
		for(var i=0; i<arguments.length; i++)
			debugText += arguments[i] + "\n";

		if (this.persistent)
			Persistent.save("__debugoutput", debugText);
		else
			Persistent.remove("__debugoutput");

		alert(debugText);
	}

};
