Array.prototype.contains = function (elem) {
	for (var i=0; i<this.length; i++)
		if (this[i]==elem) return true;
	return false}

w = window;
d = document;

function object(id) {
	var obj = d.getElementById(id);
	// sadly, IE interprets this method as getElementByIdOrName
	return (obj && obj.id==id) ? obj : null;
}

function $(id) {
	return object(id);
}

// in beta version!!! doesn't create clones of attributes which are objects
function clone(obj) {
	var cObj = {};
	for (var i in obj) {
		cObj[i] = obj[i]}
	return cObj;
}

function getKey() {
	return Math.round(Math.random()*1000000);
}

function encodeDashes(str) {
	return str.replace(/-/g,'DASH');
}

function decodeDashes(str) {
	return str.replace(/DASH/g,'-');
}

function toTextOnly(html) {
	return html.replace(/<[^>]+>/g,' ').replace(/&nbsp;/g,' '); // remove tags & format nbsp's
}

function formatNumber(num,minDigits) {
	var numStr = num.toString();
	while (numStr.length<minDigits) numStr = '0' + numStr;
	return numStr;
}

function cancelBubble(e) { // e = event
	if (!e) e = window.event;
	e.cancelBubble = true;
	if (e.stopPropagation) e.stopPropagation();
}


//------------------------------- window geometry -------------------------------

// returns absolute x or y coordinate of an object relative to the window
function getAbsPos(obj,which) { // which : 'Left' : 'Top';
	var i = 0;
	while (obj) {
		i += obj['offset' + which];
		obj = obj.offsetParent}
	return i;
}

function getInnerWindowDimensions() {
	var de = d.documentElement, b = d.body;
	var width = (w.innerWidth) ? w.innerWidth : (de && de.clientWidth) ? de.clientWidth : b.clientWidth;
	var height = (w.innerHeight) ? w.innerHeight : (de && de.clientHeight) ? de.clientHeight : b.clientHeight;
	return {w: width, h: height};
}

// This should work all the time for WinIE and most of the time for other browsers
function getInnerWindowPosition() {
	var x = w.screenLeft, y = w.screenTop, outPos = getOuterWindowPosition();
	if (x==null || (x==outPos.x && y==outPos.y)) { // mozilla or safari
		var outDim = getOuterWindowDimensions();
		var inDim = getInnerWindowDimensions();
		x = outPos.x + ((outDim.w - inDim.w)/2);
		y = outPos.y - inDim.h + outDim.h}
	else if (outPos.y<-4) { // opera
		x = 0;
		y = 0 - outPos.y}
	return {x: x, y: y};
}

function getOuterWindowDimensions() {
	return {w: w.outerWidth, h: w.outerHeight};
}

function getOuterWindowPosition() {
	return {x: w.screenX, y: w.screenY};
}

// Get the absolute position of an object on the screen
function getPosition(obj) {
	var x, y, b = d.body, s = screen;
	if (obj && b.scrollLeft!=null) {
		x = getAbsPos(obj,"Left") - b.scrollLeft;
		y = getAbsPos(obj,"Top") - b.scrollTop;
		var iwPos = getInnerWindowPosition();
		if (iwPos.x!=null) {
			x += iwPos.x;
			y += iwPos.y}}
	return {x: x, y: y};
}


//------------------------------- frames -------------------------------

// resizes top & bottom frames to the size of object('mainTable')
function resizeFrame(fType) { // fType is frame type = "top" | "bottom"
	if (fType && w!=top) {
		var mT = object('mainTable'), p = parent;
		var fs = p.document.getElementById('ps_win_frameset');
		if (mT && fs) {
			p[fType+'FrameHeight'] = mT.offsetHeight;
			var tH = p.topFrameHeight, bH = p.bottomFrameHeight;
			if (tH>=0 && bH>=0) fs.rows = tH+',*,'+bH}}
}

// Function used to resize automatically a frame depending of the objects it contains
// oUsed : Array of id used to compute the new frame height
function resizeFrameByObjects(oUsed) {
	var fIndex = -1;

	// Get the index of the current frame in the framset
	for(var i=0; i < parent.frames.length; i++) {
		if(parent.frames[i] == window)
			fIndex = i;
	}

	if(fIndex >= 0) {
		// Get the current frame's size set in the framset
		var fSizes = parent.document.body.rows.split(',');

		// Compute the real frame size and set it in the array
		// representing the frames size
		if(oUsed && oUsed.length) {
			var size = 0;

			for(var i=0; i < oUsed.length; i++) {
				var object = document.getElementById(oUsed[i]);

				if(object) size += object.offsetHeight;
			}

			if(size > fSizes[fIndex]) fSizes[fIndex] = size;
		}

		// Set the new size in the framset
		var rows = '';
		for(var i=0; i < fSizes.length; i++) {
			if(i > 0 ) rows += ',';

			rows += fSizes[i];
		}

		parent.document.body.rows = rows;
	}
}


//------------------------------- popups -------------------------------

var INIT_POPUP_SIZE = {w: 150, h: 100};
var MAX_POPUP_SIZE = {w: 800, h: 600};

var g_pops = {}; // maps popup window names to window Objects

function isPopup() { // test if this window was opened using an 'openPopup' function
	if (w.name && /^popup_\w+/.test(w.name)) return true;
	try {
		var o = opener;
		return (o!=null && o.g_pops!=null && o.g_pops[w.name]!=null);
	} catch (e) {
		return false}
}

Popup = {

	resizeByDims : {
		w: 0,
		h: 0,
		isZero: function() {return (this.w==0 && this.h==0)}},

	/**
	 * A listener that expires once the popup has been correctly resized.
	 */
	resize : function() {
		try {resizePopup()}
		catch (e) {}
		if (this.resizeByDims.isZero()) return;
		setTimeout('Popup.resize()',50)}
}
/**
 * Resizes inner window to dimensions of first child element of BODY element.
 * @param {Object} args {minWidth,minHeight,maxWidth,maxHeight,overrideMax,overrideWidth}
 */
function resizePopup(args) {
	var de = d.documentElement;
	var getFirstChildElement = function(obj) {
		var cNs = obj.childNodes;
		var i = 0;
		while (cNs[i] && (!cNs[i].tagName || cNs[i].nodeName=="#comment")) i++;
		return cNs[i];}
	// get first child element dimensions
	var obj = getFirstChildElement(d.body);
	if (!obj) return;
	while (obj.tagName.toUpperCase()=='FORM') {
		obj = getFirstChildElement(obj);
		if (!obj) return;}
	var objDim = {w: obj.offsetWidth, h: obj.offsetHeight};
	// apply max dimensions
	if (!args || args.overrideMax!=true) {
		var maxW = (args && args.maxWidth) ? args.maxWidth : MAX_POPUP_SIZE.w;
		if (objDim.w>maxW) objDim.w = maxW;
		var maxH = (args && args.maxHeight) ? args.maxHeight : MAX_POPUP_SIZE.h;
		if (objDim.h>maxH) objDim.h = maxH;}
	// apply min dimensions
	if (args && args.minWidth && objDim.w<args.minWidth) objDim.w = args.minWidth;
	if (args && args.minHeight && objDim.h<args.minHeight) objDim.h = args.minHeight;
	// get inner window dimensions
	var inDim = getInnerWindowDimensions();
	// resize window
	var rbDim = {w: objDim.w - inDim.w, h: objDim.h - inDim.h};
	// override width changes if required
	if (args && args.overrideWidth==true) rbDim.w = 0;
	Popup.resizeByDims.w = rbDim.w;
	Popup.resizeByDims.h = rbDim.h;
	// check that complete surface of window will be visible
	var inPos = getInnerWindowPosition(), s = screen;
	var mbPos = {x: s.width - inPos.x - objDim.w, y: s.height - inPos.y - objDim.h - 40};
	try {
		if (mbPos.x<0 || mbPos.y<0) {
			mbPos.x = (mbPos.x>=0) ? 0 : mbPos.x-25;
			mbPos.y = (mbPos.y>=0) ? 0 : mbPos.y-25;
			w.moveBy(mbPos.x,mbPos.y)}}
	catch (e) {};
	w.resizeBy(rbDim.w,rbDim.h);
}

// Opens a popup window with default PS attributes & adds it to g_pops array
function openPopup(url,name,props) {
	if (!url) url = '';
	if (!name) name = 'popup_' + getKey();
	name = encodeDashes(name); // IE doesn't like dashes
	if (!props) props = 'scrollbars=1,resizable,width='+INIT_POPUP_SIZE.w+',height='+INIT_POPUP_SIZE.h;
	var n = w.open(url,name,props); // new window
	g_pops[name] = n;
	n.focus();
	return n;
}

// Opens a popup window and writes a message in it
function openPopupMessage(name,props,msg) {
	var n = openPopup(null,name,props);
	n.document.write(msg); // write content in popup
	return n;
}

// Opens a popup window positioned according to obj
function openPositionedPopup(url,name,obj) {
	var pos = getPosition(obj);
	var x = (pos.x!=null) ? pos.x : 0;
	var y = (pos.y!=null) ? pos.y + obj.offsetHeight + 6 : 0;
	return openPopup(url,name,'scrollbars=1,resizable,width='+INIT_POPUP_SIZE.w+',height='+INIT_POPUP_SIZE.h+',left='+x+',top='+y);
}

// Opens a popup window using MAX_POPUP_SIZE, with scrollbars & resizable
function openExternalPopup(url) {
	var props = 'scrollbars=1,resizable,width='+MAX_POPUP_SIZE.w+',height='+MAX_POPUP_SIZE.h;
	openPopup(url,null,props);
}

function resizeAndCenterPopup(W,H) {
	var s = screen;
	w.resizeTo(W,H);
	w.moveTo(s.width/2 - W/2, s.height/2 - H/2);
}

// Maps popup window names to response functions
PopupResponseFunctions = {

	map : {},

	set : function(winName,fResponse) {
		this.map[winName] = fResponse},

	call : function(winName) {
		this.map[winName](g_pops[winName].XML)}
}


//------------------------------- show/hide element/s -------------------------------

function hideGroup(grId) {
	toggleGroup('hide',gpId)}

function showGroup(grId) {
	toggleGroup('show',gpId)}

// Toggles 'display' property of 3 objects: o1, o2 & o3
// o1 is a block level element
// o2 & o3 are inline
function toggleGroup(cmd,gpId) { // cmd : 'show' | 'hide'
	var o1 = object(gpId),
			o2 = object(gpId+'_ex'),
			o3 = object(gpId+'_col'),
			s1 = '',
			s2 = 'none';
	if (cmd=='hide') {s1 = 'none'; s2 = ''}
	if (o1!=null) o1.style.display = s1;
	if (o2!=null) o2.style.display = s2;
	if (o3!=null) o3.style.display = s1;
	if (cmd=='show') adjustAllRows()}

function showTrs(gpId,gpParId) { // gpParId is the group parent id
	var gpParent = (gpParId) ? object(gpParId) : d;
	toggleTrs('show',gpId,gpParent)}

function hideTrs(gpId,gpParId) { // gpParId is the group parent id
	var gpParent = (gpParId) ? object(gpParId) : d;
	toggleTrs('hide',gpId,gpParent)}

function toggleTrs(showHide,gpId,gpParent) { // showHide : 'show' | 'hide'; gpParent is an obj that contains the TR elements
	if (!gpParent) gpParent = d;
	var trs = gpParent.getElementsByTagName('tr'),
			oE = object(gpId+'Expand'),
			oC = object(gpId+'Collapse'),
			isToHide = (showHide=='hide');
	for (var i=0; i<trs.length; i++) {
		if (trs[i].id.indexOf(gpId+'-')==0) trs[i].style.display = (isToHide) ? 'none' : ''}
	if (oE!=null) oE.style.display = (isToHide) ? '' : 'none';
	if (oC!=null) oC.style.display = (isToHide) ? 'none' : '';
	if (!isToHide) adjustAllRows();
}

function toggleAllTrs(showHide,gpPrefix,gpParent) {
	if (!gpParent) gpParent = d;
	var tO = gpParent.getElementsByTagName('tr'),
			gpId = null;
	for (var i=0; i<tO.length; i++) {
		if (tO[i].id.indexOf(gpPrefix)==0) {
			var trGpId = tO[i].id.split('-')[0];
			if (trGpId!=gpId) { // if this tr is not in the same group as the last tr
				gpId = trGpId;
				toggleTrs(showHide,gpId,gpParent)}}}}


// ----------------- Automatic resizing of TEXTAREA rows ----------------------------
// Adjusts the number of rows of a textarea object to fit the content

function adjustRows(obj) { // obj is a TEXTAREA object
	if (!obj) obj = this;
	var initRows = obj.rows;
	if (obj && obj.tagName=='TEXTAREA' && obj.clientHeight && obj.scrollHeight && obj.offsetHeight && obj.scrollHeight!=obj.offsetHeight && obj.rows) {
		// method supported by MSIE
		while (obj.scrollHeight<obj.clientHeight && obj.rows>1) obj.rows--;
		while (obj.scrollHeight>obj.clientHeight) obj.rows++;}
	else { // open standard method
		var text = obj.value.replace(/\t/g,'        '); // replace tabs
		var blocks = text.split('\n'); // split line returns
		var rows = 0;
		for (var i=0; i<blocks.length; i++) { // now calculate number of lines in each block of text
			rows += Math.ceil((blocks[i].length+1)/obj.cols)}
		obj.rows = rows}
	obj.scrollTop = 0;
	if (isPopup() && initRows!=obj.rows) resizePopup({overrideWidth:true});}

// Gets the number of cols of the 1st text area & applies it to the others
function initTextAreaObjs() {
	var tAs = d.getElementsByTagName('TEXTAREA');
	var cols = 0;
	for (var i=0; i<tAs.length; i++) {
		// remove class that refers to width
		if (/(^| )wide( |$)/.test(tAs[i].className)) {
			tAs[i].className = tAs[i].className.replace(/wide ?/g,'');
			tAs[i].style.width = '100%'}
		// set min width of 200px
		if (tAs[i].style.display=='' && tAs[i].clientWidth && tAs[i].clientWidth<200) {
			tAs[i].style.width='200px'}
		// set cols according to first qualifying text area width
		if (cols==0 && tAs[i].style.display=='' && tAs[i].clientWidth) {
			var initialWidth = tAs[i].clientWidth;
			tAs[i].style.width = '';
			tAs[i].cols = 1;
			while (tAs[i].clientWidth < initialWidth) tAs[i].cols++;
			if (tAs[i].cols>1) tAs[i].cols--;
			cols = tAs[i].cols}
		else if (cols>0) {
			tAs[i].style.width = '';
			tAs[i].cols = cols}
		// adjust rows
		if (tAs[i].style.display=='') adjustRows(tAs[i]);}}

function adjustAllRows() {
	var tAs = d.getElementsByTagName('TEXTAREA');
	for (var i=0; i<tAs.length; i++) adjustRows(tAs(i))}


// ----------------- Automatic resizing of Text Inputs' size ----------------------------

function autoTextInputSize(minSize) {
	var osInput = d.getElementsByTagName('INPUT');
	for (var i=0; i<osInput.length; i++) {
		if (osInput[i].type=='text' && osInput[i].value!='') {
			var chars = osInput[i].value.length * 1.2;
			if (chars>minSize && chars>osInput[i].size) osInput[i].size = chars;}}
	setTimeout('autoTextInputSize('+minSize+')',500)}


// ----------------- drop down menus ----------------------------

DDMenus = {

	DELAY : 1000, // in milliseconds
	map : {}, // maps Menu instances by id

	Menu : function(id) { // private object
		this.obj = object(id+'Menu'); // HTML DIV element
		this.timeoutId = -1;
		DDMenus.map[id] = this}, // add this to map

	show : function(obj,id,hOffset,vOffset) { // previously showMenu
		// hide all menu objs
		this.hideAll();
		// create new menu instance
		var m = new this.Menu(id);
		// show menu
		if (m.obj) {
			var mos = m.obj.style;
			mos.left = (getAbsPos(obj,'Left') + hOffset) + 'px';
			mos.top = (getAbsPos(obj,'Top') + obj.offsetHeight + vOffset) + 'px';
			mos.visibility = 'visible'}},

	hideAll : function() {
		for (var i in this.map) {
			this.stopTimer(i);
			this.hide(i)}},

	startTimer : function(id) { // previously startMenuTimer
		this.map[id].timeoutId = setTimeout('DDMenus.hide("'+id+'")', this.DELAY)},

	stopTimer : function(id) { // previously stopMenuTimer
		var m = this.map[id];
		w.clearTimeout(m.timeoutId);
		m.timeoutId = -1},

	hide : function(id) { // private
		var mo = this.map[id].obj;
		if (mo) mo.style.visibility = 'hidden'}
}


// ----------------------- cookies ---------------------------------------

Cookies = {
	set : function(id,value) {
		var date = new Date();
		date.setTime(date.getTime() + (100*365*24*60*60*1000));
		d.cookie = id + '=' + value + '; path=' + location.pathname + '; expires=' + date.toGMTString()},
	get : function(id) {
		var c = d.cookie;
		if (c) {
			(new RegExp(id+"=([^;]+)")).test(c);
			return RegExp.$1}},
	del : function(id) {
		if (this.get(id)) {
			var date = new Date();
			date.setTime(date.getTime() - (24*60*60*1000));
			d.cookie = id + '=; path=' + location.pathname + '; expires=' + (new Date()).toGMTString()}}
}


// ----------------------- A log display opened in a popup window -----------------------
g_blogWin = null;

function blog(str) {
	try {
		if (!g_blogWin || !g_blogWin.document) {
			g_blogWin = window.open('','psw_blog');
			g_blogWin.document.write('<HTML><HEAD></HEAD><BODY></BODY></HTML>')}
		var now = new Date();
		g_blogWin.document.body.innerHTML += '<P style="font: 12px monospace; white-space: nowrap">'
		+ formatNumber(now.getHours(),2) + ':'
		+ formatNumber(now.getMinutes(),2) + ':'
		+ formatNumber(now.getSeconds(),2) + ':'
		+ formatNumber(now.getMilliseconds(),3) + ' '
		+ str.replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/\n/g,'<BR>').replace(/\t/g,'&nbsp;&nbsp;&nbsp;&nbsp;').replace(/ /g,'&nbsp;')
		+ '</P>'}
	catch (e) {
				alert(str)}}



