/*
  termlib.js - JS-WebTerminal Object v1.07

  (c) Norbert Landsteiner 2003-2005
  mass:werk - media environments
  <http://www.masswerk.at>

  Creates [multiple] Terminal instances.

  Synopsis:

  myTerminal = new Terminal(<config object>);
  myTerminal.open();

  <config object> overrides any values of object `TerminalDefaults'.
  individual values of `id' must be supplied for multiple terminals.
  `handler' specifies a function to be called for input handling.
  (see `Terminal.prototype.termDefaultHandler()' and documentation.)

  globals defined in this library:
  	Terminal           (Terminal object)
    TerminalDefaults   (default configuration)
    termDefaultHandler (default command line handler)
    TermGlobals        (common vars and code for all instances)
    termKey            (named mappings for special keys)
    termDomKeyRef      (special key mapping for DOM constants)

  globals defined for fixing String methods, if missing
  (String.fromCharCode, String.prototype.charCodeAt):
    termString_keyref, termString_keycoderef, termString_makeKeyref

  required CSS classes for font definitions: ".term", ".termReverse".

  Compatibilty:
  Standard web browsers with a JavaScript implementation compliant to
  ECMA-262 2nd edition and support for the anonymous array and object
  constructs and the anonymous function construct in the form of
  "myfunc=function(x) {}" (c.f. ECMA-262 3rd edion for details).
  This comprises almost all current browsers but Konquerer (khtml) and
  versions of Apple Safari for Mac OS 10.0-10.28 (Safari 1.0) which
  lack support for keyboard events.

  License:
  This JavaScript-library is free for private and academic use.
  Please include a readable copyright statement and a backlink to
  <http://www.masswerk.at> in the web page.
  The library should always be accompanied by the 'readme.txt' and the
  sample HTML-documents.
  
  The term "private use" includes any personal or non-commercial use, which
  is not related to commercial activites, but excludes intranet, extranet
  and/or public net applications that are related to any kind of commercial
  or profit oriented activity.

  For commercial use see <http://www.masswerk.at> for contact information.
  
  Any changes should be commented and must be reflected in `Terminal.version'
  in the format: "Version.Subversion (compatibility)".

  Disclaimer:
  This software is distributed AS IS and in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. The entire risk as to
  the quality and performance of the product is borne by the user. No use of
  the product is authorized hereunder except under this disclaimer.

  ### The sections above must not be removed. ###
  
  version 1.01: added Terminal.prototype.resizeTo(x,y)
                added Terminal.conf.fontClass (=> configureable class name)
                Terminal.prototype.open() now checks for element conf.termDiv
                in advance and returns success.

  version 1.02: added support for <TAB> and Euro sign
                (Terminal.conf.printTab, Terminal.conf.printEuro)
                and a method to evaluate printable chars:
                Terminal.prototype.isPrintable(keycode)

  version 1.03: added global keyboard locking (TermGlobals.keylock)
                modified Terminal.prototype.redraw for speed (use of locals)

  version 1.04: modified the key handler to fix a bug with MSIE5/Mac
                fixed a bug in TermGlobals.setVisible with older MSIE-alike
                browsers without DOM support.

  version 1.05: added config flag historyUnique.
 
  version 1.06: fixed CTRl+ALT (Windows alt gr) isn't CTRL any more
                fixed double backspace bug for Safari;
                added TermGlobals.setDisplay for setting style.display props
                termlib.js now outputs lower case html (xhtml compatibility)

  version 1.07: added method rebuild() to rebuild with new color settings.

*/

var TerminalDefaults = {
	// dimensions
	cols:80,
	rows:24,
	// appearance
	x:100,
	y:100,
	termDiv:'termDiv',
	bgColor:'#181818',
	frameColor:'#555555',
	frameWidth:1,
	rowHeight:15,
	blinkDelay:500,
	// css class
	fontClass:'term',
	// initial cursor mode
	crsrBlinkMode:false,
	crsrBlockMode:true,
	// key mapping
	DELisBS:false,
	printTab:true,
	printEuro:true,
	catchCtrlH:true,
	closeOnESC:true,
	// prevent consecutive history doublets
	historyUnique:false,
	// optional id
	id:0,
	// strings
	ps:'>',
	greeting:'%+r Terminal ready. %-r',
	// handlers
	handler:termDefaultHandler,
	ctrlHandler:null,
	initHandler:null,
	exitHandler:null
}

var Terminal = function(conf) {
	if (typeof conf != 'object') conf=new Object();
	else {
		for (var i in TerminalDefaults) {
			if (typeof conf[i] == 'undefined') conf[i]=TerminalDefaults[i];
		}
	}
	this.conf=conf;
	this.version='1.07 (original)';
	this.isSafari= (navigator.userAgent.indexOf('Safari')>=0)? true:false;
	this.setInitValues();
}

Terminal.prototype.setInitValues=function() {
	this.id=this.conf.id;
	this.maxLines=this.conf.rows;
	this.maxCols=this.conf.cols;
	this.termDiv=this.conf.termDiv;
	this.crsrBlinkMode=this.conf.crsrBlinkMode;
	this.crsrBlockMode=this.conf.crsrBlockMode;
	this.blinkDelay=this.conf.blinkDelay;
	this.DELisBS=this.conf.DELisBS;
	this.printTab=this.conf.printTab;
	this.printEuro=this.conf.printEuro;
	this.catchCtrlH=this.conf.catchCtrlH;
	this.closeOnESC=this.conf.closeOnESC;
	this.historyUnique=this.conf.historyUnique;
	this.ps=this.conf.ps;
	this.closed=false;
	this.r;
	this.c;
	this.charBuf=new Array();
	this.styleBuf=new Array();
	this.scrollBuf=null;
	this.blinkBuffer=0;
	this.blinkTimer;
	this.cursoractive=false;
	this.lock=true;
	this.insert=false;
	this.charMode=false;
	this.rawMode=false;
	this.lineBuffer='';
	this.inputChar=0;
	this.lastLine='';
	this.guiCounter=0;
	this.history=new Array();
	this.histPtr=0;
	this.env=new Object();
	this.ns4ParentDoc=null;
	this.handler=this.conf.handler;
	this.ctrlHandler=this.conf.ctrlHandler;
	this.initHandler=this.conf.initHandler;
	this.exitHandler=this.conf.exitHandler;
}

function termDefaultHandler() {
	this.newLine();
	if (this.lineBuffer != '') {
		this.type('You typed: '+this.lineBuffer);
		this.newLine();
	}
	this.prompt();
}

Terminal.prototype.open=function() {
	if (this.termDivReady()) {
		if (!this.closed) this._makeTerm();
		this.init();
		return true;
	}
	else return false;
}

Terminal.prototype.close=function() {
	this.lock=true;
	this.cursorOff();
	if (this.exitHandler) this.exitHandler();
	TermGlobals.setVisible(this.termDiv,0);
	this.closed=true;
}

Terminal.prototype.init=function() {
	// wait for gui
	if (this.guiReady()) {
		this.guiCounter=0;
		// clean up at re-entry
		if (this.closed) {
			this.setInitValues();
		}
		this.clear();
		TermGlobals.setVisible(this.termDiv,1);
		TermGlobals.enableKeyboard(this);
		if (this.initHandler) {
			this.initHandler();
		}
		else {
			this.write(this.conf.greeting);
			this.newLine();
			this.prompt();
		}
	}
	else {
		this.guiCounter++;
		if (this.guiCounter>18000) {
			if (confirm('Terminal:\nYour browser hasn\'t responded for more than 2 minutes.\nRetry?')) this.guiCounter=0
			else return;
		};
		TermGlobals.termToInitialze=this;
		window.setTimeout('TermGlobals.termToInitialze.init()',200);
	}
}

Terminal.prototype.getRowArray=function(l,v) {
	var a=new Array();
	for (var i=0; i<l; i++) a[i]=v;
	return a;
}

Terminal.prototype.type=function(text,style) {
	for (var i=0; i<text.length; i++) {
		var ch=text.charCodeAt(i);
		if (!this.isPrintable(ch)) ch=94;
		this.charBuf[this.r][this.c]=ch;
		this.styleBuf[this.r][this.c]=(style)? style:0;
		var last_r=this.r;
		this._incCol();
		if (this.r!=last_r) this.redraw(last_r);
	}
	this.redraw(this.r)
}

Terminal.prototype.write=function(text,usemore) {
	// write to scroll buffer with markup
	// new line = '%n' prepare any strings or arrys first
	if (typeof text != 'object') {
		if (typeof text!='string') text=''+text;
		if (text.indexOf('\n')>=0) {
			var ta=text.split('\n');
			text=ta.join('%n');
		}
	}
	else {
		if (text.join) text=text.join('%n')
		else text=''+text;
	}
	this._sbInit(usemore);
	var chunks=text.split('%');
	var esc=(text.charAt(0)!='%');
	var style=0;
	for (var i=0; i<chunks.length; i++) {
		if (esc) {
			if (chunks[i].length>0) this._sbType(chunks[i],style)
			else if (i>0) this._sbType('%', style);
			esc=false;
		}
		else {
			var func=chunks[i].charAt(0);
			if ((chunks[i].length==0) && (i>0)) {
				this._sbType("%",style);
				esc=true;
			}
			else if (func=='n') {
				this._sbNewLine();
				if (chunks[i].length>1) this._sbType(chunks[i].substring(1),style);
			}
			else if (func=='+') {
				var opt=chunks[i].charAt(1);
				opt=opt.toLowerCase();
				if (opt=='p') style=0
				else if (opt=='r') style|=1
				else if (opt=='u') style|=2
				else if (opt=='i') style|=4
				else if (opt=='s') style|=8;
				if (chunks[i].length>2) this._sbType(chunks[i].substring(2),style);
			}
			else if (func=='-') {
				var opt=chunks[i].charAt(1);
				opt=opt.toLowerCase();
				if (opt=='p') style|=0
				else if (opt=='r') style&=~1
				else if (opt=='u') style&=~2
				else if (opt=='i') style&=~4
				else if (opt=='s') style&=~8;
				if (chunks[i].length>2) this._sbType(chunks[i].substring(2),style);
			}
			else if ((chunks[i].length>1) && (chunks[i].charAt(0)=='C') && (chunks[i].charAt(1)=='S')) {
				this.clear();
				this._sbInit();
				if (chunks[i].length>2) this._sbType(chunks[i].substring(2),style);
			}
			else {
				if (chunks[i].length>0) this._sbType(chunks[i],style);
			}
		}
	}
	this._sbOut();
}

Terminal.prototype._sbType=function(text,style) {
	// type to scroll buffer
	var sb=this.scrollBuf;
	for (var i=0; i<text.length; i++) {
		var ch=text.charCodeAt(i);
		if (!this.isPrintable(ch)) ch=94;
		sb.lines[sb.r][sb.c]=ch;
		sb.styles[sb.r][sb.c]=(style)? style:0;
		sb.c++;
		if (sb.c>=this.maxCols) this._sbNewLine();
	}
}

Terminal.prototype._sbNewLine=function() {
	var sb=this.scrollBuf;
	sb.r++;
	sb.c=0;
	sb.lines[sb.r]=this.getRowArray(this.conf.cols,0);
	sb.styles[sb.r]=this.getRowArray(this.conf.cols,0);
}


Terminal.prototype._sbInit=function(usemore) {
	var sb=this.scrollBuf=new Object();
	var sbl=sb.lines=new Array();
	var sbs=sb.styles=new Array();
	sb.more=usemore;
	sb.line=0;
	sb.status=0;
	sb.r=0;
	sb.c=this.c;
	sbl[0]=this.getRowArray(this.conf.cols,0);
	sbs[0]=this.getRowArray(this.conf.cols,0);
	for (var i=0; i<this.c; i++) {
		sbl[0][i]=this.charBuf[this.r][i];
		sbs[0][i]=this.styleBuf[this.r][i];
	}
}

Terminal.prototype._sbOut=function() {
	var sb=this.scrollBuf;
	var sbl=sb.lines;
	var sbs=sb.styles;
	var tcb=this.charBuf;
	var tsb=this.styleBuf;
	var ml=this.maxLines;
	var buflen=sbl.length;
	if (sb.more) {
		if (sb.status) {
			if (this.inputChar==TermGlobals.lcMoreKeyAbort) {
				this.r=ml-1;
				this.c=0;
				tcb[this.r]=this.getRowArray(this.maxLines,0);
				tsb[this.r]=this.getRowArray(this.maxLines,0);
				this.redraw(this.r);
				this.handler=sb.handler;
				this.charMode=false;
				this.inputChar=0;
				this.scrollBuf=null;
				this.prompt();
				return;
			}
			else if (this.inputChar==TermGlobals.lcMoreKeyContinue) {
				this.clear();
			}
			else {
				return;
			}
		}
		else {
			if (this.r>=ml-1) this.clear();
		}
	}
	if (this.r+buflen-sb.line<=ml) {
		for (var i=sb.line; i<buflen; i++) {
			var r=this.r+i-sb.line;
			tcb[r]=sbl[i];
			tsb[r]=sbs[i];
			this.redraw(r);
		}
		this.r+=sb.r-sb.line;
		this.c=sb.c;
		if (sb.more) {
			if (sb.status) this.handler=sb.handler;
			this.charMode=false;
			this.inputChar=0;
			this.scrollBuf=null;
			this.prompt();
			return;
		}
	}
	else if (sb.more) {
		ml--;
		if (sb.status==0) {
			sb.handler=this.handler;
			this.handler=this._sbOut;
			this.charMode=true;
			sb.status=1;
		}
		if (this.r) {
			var ofs=ml-this.r;
			for (var i=sb.line; i<ofs; i++) {
				var r=this.r+i-sb.line;
				tcb[r]=sbl[i];
				tsb[r]=sbs[i];
				this.redraw(r);
			}
		}
		else {
			var ofs=sb.line+ml;
			for (var i=sb.line; i<ofs; i++) {
				var r=this.r+i-sb.line;
				tcb[r]=sbl[i];
				tsb[r]=sbs[i];
				this.redraw(r);
			}
		}
		sb.line=ofs;
		this.r=ml;
		this.c=0;
		this.type(TermGlobals.lcMorePrompt1, TermGlobals.lcMorePromtp1Style);
		this.type(TermGlobals.lcMorePrompt2, TermGlobals.lcMorePrompt2Style);
		this.lock=false;
		return;
	}
	else if (buflen>=ml) {
		var ofs=buflen-ml;
		for (var i=0; i<ml; i++) {
			var r=ofs+i;
			tcb[i]=sbl[r];
			tsb[i]=sbs[r];
			this.redraw(i);
		}
		this.r=ml-1;
		this.c=sb.c;
	}
	else {
		var dr=ml-buflen;
		var ofs=this.r-dr;
		for (var i=0; i<dr; i++) {
			var r=ofs+i;
			for (var c=0; c<this.maxCols; c++) {
				tcb[i][c]=tcb[r][c];
				tsb[i][c]=tsb[r][c];
			}
			this.redraw(i);
		}
		for (var i=0; i<buflen; i++) {
			var r=dr+i;
			tcb[r]=sbl[i];
			tsb[r]=sbs[i];
			this.redraw(r);
		}
		this.r=ml-1;
		this.c=sb.c;
	}
	this.scrollBuf=null;
}

// basic console output

Terminal.prototype.typeAt=function(r,c,text,style) {
	var tr1=this.r;
	var tc1=this.c;
	this.cursorSet(r,c);
	for (var i=0; i<text.length; i++) {
		var ch=text.charCodeAt(i);
		if (!this.isPrintable(ch)) ch=94;
		this.charBuf[this.r][this.c]=ch;
		this.styleBuf[this.r][this.c]=(style)? style:0;
		var last_r=this.r;
		this._incCol();
		if (this.r!=last_r) this.redraw(last_r);
	}
	this.redraw(this.r);
	this.r=tr1;
	this.c=tc1;
}

Terminal.prototype.statusLine = function(text,style,offset) {
	var ch,r;
	style=((style) && (!isNaN(style)))? parseInt(style)&15:0;
	if ((offset) && (offset>0)) r=this.conf.rows-offset
	else r=this.conf.rows-1;
	for (var i=0; i<this.conf.cols; i++) {
		if (i<text.length) {
			ch=text.charCodeAt(i);
			if (!this.isPrintable(ch)) ch = 94;
		}
		else ch=0;
		this.charBuf[r][i]=ch;
		this.styleBuf[r][i]=style;
	}
	this.redraw(r);
}

Terminal.prototype.printRowFromString = function(r,text,style) {
	var ch;
	style=((style) && (!isNaN(style)))? parseInt(style)&15:0;
	if ((r>=0) && (r<this.maxLines)) {
		if (typeof text != 'string') text=''+text;
		for (var i=0; i<this.conf.cols; i++) {
			if (i<text.length) {
				ch=text.charCodeAt(i);
				if (!this.isPrintable(ch)) ch = 94;
			}
			else ch=0;
			this.charBuf[r][i]=ch;
			this.styleBuf[r][i]=style;
		}
		this.redraw(r);
	}
}

Terminal.prototype.setChar=function(ch,r,c,style) {
	this.charBuf[r][c]=ch;
	this.styleBuf[this.r][this.c]=(style)? style:0;
	this.redraw(r);
}

Terminal.prototype._charOut=function(ch, style) {
	this.charBuf[this.r][this.c]=ch;
	this.styleBuf[this.r][this.c]=(style)? style:0;
	this.redraw(this.r);
	this._incCol();
}

Terminal.prototype._incCol=function() {
	this.c++;
	if (this.c>=this.maxCols) {
		this.c=0;
		this._incRow();
	}
}

Terminal.prototype._incRow=function() {
	this.r++;
	if (this.r>=this.maxLines) {
		this._scrollLines(0,this.maxLines);
		this.r=this.maxLines-1;
	}
}

Terminal.prototype._scrollLines=function(start, end) {
	window.status='Scrolling lines ...';
	start++;
	for (var ri=start; ri<end; ri++) {
		var rt=ri-1;
		this.charBuf[rt]=this.charBuf[ri];
		this.styleBuf[rt]=this.styleBuf[ri];
	}
	// clear last line
	var rt=end-1;
	this.charBuf[rt]=this.getRowArray(this.conf.cols,0);
	this.styleBuf[rt]=this.getRowArray(this.conf.cols,0);
	this.redraw(rt);
	for (var r=end-1; r>=start; r--) this.redraw(r-1);
	window.status='';
}

Terminal.prototype.newLine=function() {
	this.c=0;
	this._incRow();
}

Terminal.prototype.clear=function() {
	window.status='Clearing display ...';
	this.cursorOff();
	this.insert=false;
	for (var ri=0; ri<this.maxLines; ri++) {
		this.charBuf[ri]=this.getRowArray(this.conf.cols,0);
		this.styleBuf[ri]=this.getRowArray(this.conf.cols,0);
		this.redraw(ri);
	}
	this.r=0;
	this.c=0;
	window.status='';
}

Terminal.prototype.reset=function() {
	if (this.lock) return;
	this.lock=true;
	this.rawMode=false;
	this.charMode=false;
	this.maxLines=this.conf.rows;
	this.maxCols=this.conf.cols;
	this.lastLine='';
	this.lineBuffer='';
	this.inputChar=0;
	this.clear();
}

Terminal.prototype.cursorSet=function(r,c) {
	var crsron=this.cursoractive;
	if (crsron) this.cursorOff();
	this.r=r%this.maxLines;
	this.c=c%this.maxCols;
	this._cursorReset(crsron);
}

Terminal.prototype._cursorReset=function(crsron) {
	if (crsron) this.cursorOn()
	else {
		this.blinkBuffer=this.styleBuf[this.r][this.c];
	}
}

Terminal.prototype.cursorOn=function() {
	if (this.blinkTimer) clearTimeout(this.blinkTimer);
	this.blinkBuffer=this.styleBuf[this.r][this.c];
	this._cursorBlink();
	this.cursoractive=true;
}

Terminal.prototype.cursorOff=function() {
	if (this.blinkTimer) clearTimeout(this.blinkTimer);
	if (this.cursoractive) {
		this.styleBuf[this.r][this.c]=this.blinkBuffer;
		this.redraw(this.r);
		this.cursoractive=false;
	}
}

Terminal.prototype._cursorBlink=function() {
	if (this.blinkTimer) clearTimeout(this.blinkTimer);
	if (this == TermGlobals.activeTerm) {
		if (this.crsrBlockMode) {
			this.styleBuf[this.r][this.c]=(this.styleBuf[this.r][this.c]&1)?
				this.styleBuf[this.r][this.c]&254:this.styleBuf[this.r][this.c]|1;
		}
		else {
			this.styleBuf[this.r][this.c]=(this.styleBuf[this.r][this.c]&2)?
				this.styleBuf[this.r][this.c]&253:this.styleBuf[this.r][this.c]|2;
		}
		this.redraw(this.r);
	}
	if (this.crsrBlinkMode) this.blinkTimer=setTimeout('TermGlobals.activeTerm._cursorBlink()', this.blinkDelay);
}

Terminal.prototype.cursorLeft=function() {
	var crsron=this.cursoractive;
	if (crsron) this.cursorOff();
	var r=this.r;
	var c=this.c;
	if (c>0) c--
	else if (r>0) {
		c=this.maxCols-1;
		r--;
	}
	if (this.isPrintable(this.charBuf[r][c])) {
		this.r=r;
		this.c=c;
	}
	this.insert=true;
	this._cursorReset(crsron);
}

Terminal.prototype.cursorRight=function() {
	var crsron=this.cursoractive;
	if (crsron) this.cursorOff();
	var r=this.r;
	var c=this.c;
	if (c<this.maxCols-1) c++
	else if (r<this.maxLines-1) {
		c=0;
		r++;
	}
	if (!this.isPrintable(this.charBuf[r][c])) {
		this.insert=false;
	}
	if (this.isPrintable(this.charBuf[this.r][this.c])) {
		this.r=r;
		this.c=c;
	}
	this._cursorReset(crsron);
}

Terminal.prototype.backspace=function() {
	var crsron=this.cursoractive;
	if (crsron) this.cursorOff();
	var r=this.r;
	var c=this.c;
	if (c>0) c--
	else if (r>0) {
		c=this.maxCols-1;
		r--;
	};
	if (this.isPrintable(this.charBuf[r][c])) {
		this._scrollLeft(r, c);
		this.r=r;
		this.c=c;
	};	
	this._cursorReset(crsron);
}

Terminal.prototype.fwdDelete=function() {
	var crsron=this.cursoractive;
	if (crsron) this.cursorOff();
	if (this.isPrintable(this.charBuf[this.r][this.c])) {
		this._scrollLeft(this.r,this.c);
		if (!this.isPrintable(this.charBuf[this.r][this.c])) this.insert=false;
	}
	this._cursorReset(crsron);
}

Terminal.prototype.prompt=function() {
	this.lock=true;
	if (this.c>0) this.newLine();
	this.type(this.ps);
	this._charOut(1);
	this.lock=false;
	this.cursorOn();
}

Terminal.prototype._scrollLeft=function(r,c) {
	var rows=new Array();
	rows[0]=r;
	while (this.isPrintable(this.charBuf[r][c])) {
		var ri=r;
		var ci=c+1;
		if (ci==this.maxCols) {
			if (ri<this.maxLines-1) {
				ci=0;
				ri++;
				rows[rows.length]=ri;
			}
			else {
				break;
			}
		}
		this.charBuf[r][c]=this.charBuf[ri][ci];
		this.styleBuf[r][c]=this.styleBuf[ri][ci];
		c=ci;
		r=ri;
	}
	if (this.charBuf[r][c]!=0) this.charBuf[r][c]=0;
	for (var i=0; i<rows.length; i++) this.redraw(rows[i]);
}

Terminal.prototype._scrollRight=function(r,c) {
	var rows=new Array();
	var end=this._getLineEnd(r,c);
	var ri=end[0];
	var ci=end[1];
	if ((ci==this.maxCols-1) && (ri==this.maxLines-1)) {
		if (r==0) return;
		this._scrollLines(0,this.maxLines);
		this.r--;
		r--;
		ri--;
	}
	rows[r]=1;
	while (this.isPrintable(this.charBuf[ri][ci])) {
		var rt=ri;
		var ct=ci+1;
		if (ct==this.maxCols) {
			ct=0;
			rt++;
			rows[rt]=1;
		}
		this.charBuf[rt][ct]=this.charBuf[ri][ci];
		this.styleBuf[rt][ct]=this.styleBuf[ri][ci];
		if ((ri==r) && (ci==c)) break;
		ci--;
		if (ci<0) {
			ci=this.maxCols-1;
			ri--;
			rows[ri]=1;
		}
	}
	for (var i=r; i<this.maxLines; i++) {
		if (rows[i]) this.redraw(i);
	}
}

Terminal.prototype._getLineEnd=function(r,c) {
	if (!this.isPrintable(this.charBuf[r][c])) {
		c--;
		if (c<0) {
			if (r>0) {
				r--;
				c=this.maxCols-1;
			}
			else {
				c=0;
			}
		}
	}
	if (this.isPrintable(this.charBuf[r][c])) {
		while (true) {
			var ri=r;
			var ci=c+1;
			if (ci==this.maxCols) {
				if (ri<this.maxLines-1) {
					ri++;
					ci=0;
				}
				else {
					break;
				}
			}
			if (!this.isPrintable(this.charBuf[ri][ci])) break;
			c=ci;
			r=ri;
		}
	}
	return [r,c];
}

Terminal.prototype._getLineStart=function(r,c) {
	// not used by now, just in case anyone needs this ...
	var ci, ri;
	if (!this.isPrintable(this.charBuf[r][c])) {
		ci=c-1;
		ri=r;
		if (ci<0) {
			if (ri==0) return [0,0];
			ci=this.maxCols-1;
			ri--;
		}
		if (!this.isPrintable(this.charBuf[ri][ci])) return [r,c]
		else {
			r=ri;
			c=ci;
		}
	}
	while (true) {
		var ri=r;
		var ci=c-1;
		if (ci<0) {
			if (ri==0) break;
			ci=this.maxCols-1;
			ri--;
		}
		if (!this.isPrintable(this.charBuf[ri][ci])) break;;
		r=ri;
		c=ci;
	}
	return [r,c];
}

Terminal.prototype._getLine=function() {
	var end=this._getLineEnd(this.r,this.c);
	var r=end[0];
	var c=end[1];
	var line=new Array();
	while (this.isPrintable(this.charBuf[r][c])) {
		line[line.length]=String.fromCharCode(this.charBuf[r][c]);
		if (c>0) c--
		else if (r>0) {
			c=this.maxCols-1;
			r--;
		}
		else break;
	}
	line.reverse();
	return line.join('');
}

Terminal.prototype._clearLine=function() {
	var end=this._getLineEnd(this.r,this.c);
	var r=end[0];
	var c=end[1];
	var line='';
	while (this.isPrintable(this.charBuf[r][c])) {
		this.charBuf[r][c]=0;
		if (c>0) {
			c--;
		}
		else if (r>0) {
			this.redraw(r);
			c=this.maxCols-1;
			r--;
		}
		else break;
	}
	if (r!=end[0]) this.redraw(r);
	c++;
	this.cursorSet(r,c);
	this.insert=false;
}

Terminal.prototype.isPrintable=function(ch, unicodePage1only) {
	if ((unicodePage1only) && (ch>255)) {
		return ((ch==termKey.EURO) && (this.printEuro))? true:false;
	}
	return (
		((ch>=32) && (ch!=termKey.DEL)) ||
		((this.printTab) && (ch==termKey.TAB))
	);
}

// keyboard focus

Terminal.prototype.focus=function() {
	TermGlobals.activeTerm=this;
}

// global store and functions

var TermGlobals={
	termToInitialze:null,
	activeTerm:null,
	kbdEnabled:false,
	keylock:false,
	lcMorePrompt1: ' -- MORE -- ',
	lcMorePromtp1Style: 1,
	lcMorePrompt2: ' (Type: space to continue, \'q\' to quit)',
	lcMorePrompt2Style: 0,
	lcMoreKeyAbort: 113,
	lcMoreKeyContinue: 32
};

// keybard focus

TermGlobals.setFocus=function(termref) {
	TermGlobals.activeTerm=termref;
}

// text related

TermGlobals.normalize=function(n,m) {
	var s=''+n;
	while (s.length<m) s='0'+s;
	return s;
}

TermGlobals.fillLeft=function(t,n) {
	if (typeof t != 'string') t=''+t;
	while (t.length<n) t=' '+t;
	return t;
}

TermGlobals.center=function(t,l) {
	var s='';
	for (var i=t.length; i<l; i+=2) s+=' ';
	return s+t;
}

TermGlobals.stringReplace=function(s1,s2,t) {
	var l1=s1.length;
	var l2=s2.length;
	var ofs=t.indexOf(s1);
	while (ofs>=0) {
		t=t.substring(0,ofs)+s2+t.substring(ofs+l1);
		ofs=t.indexOf(s1,ofs+l2);
	}
	return t;
}

// keyboard

var termKey= {
	// special key codes
	'NUL': 0x00,
	'SOH': 0x01,
	'STX': 0x02,
	'ETX': 0x03,
	'EOT': 0x04,
	'ENQ': 0x05,
	'ACK': 0x06,
	'BEL': 0x07,
	'BS': 0x08,
	'HT': 0x09,
	'TAB': 0x09,
	'LF': 0x0A,
	'VT': 0x0B,
	'FF': 0x0C,
	'CR': 0x0D,
	'SO': 0x0E,
	'SI': 0x0F,
	'DLE': 0x10,
	'DC1': 0x11,
	'DC2': 0x12,
	'DC3': 0x13,
	'DC4': 0x14,
	'NAK': 0x15,
	'SYN': 0x16,
	'ETB': 0x17,
	'CAN': 0x18,
	'EM': 0x19,
	'SUB': 0x1A,
	'ESC': 0x1B,
	'IS4': 0x1C,
	'IS3': 0x1D,
	'IS2': 0x1E,
	'IS1': 0x1F,
	'DEL': 0x7F,
	// other specials
	'EURO': 0x20AC,
	// cursor mapping
	'LEFT': 0x1C,
	'RIGHT': 0x1D,
	'UP': 0x1E,
	'DOWN': 0x1F
};

var termDomKeyRef = {
	DOM_VK_LEFT: termKey.LEFT,
	DOM_VK_RIGHT: termKey.RIGHT,
	DOM_VK_UP: termKey.UP,
	DOM_VK_DOWN: termKey.DOWN,
	DOM_VK_BACK_SPACE: termKey.BS,
	DOM_VK_RETURN: termKey.CR,
	DOM_VK_ENTER: termKey.CR,
	DOM_VK_ESCAPE: termKey.ESC,
	DOM_VK_DELETE: termKey.DEL,
	DOM_VK_TAB: termKey.TAB
};

TermGlobals.enableKeyboard=function(term) {
	if (!this.kbdEnabled) {
		if (document.addEventListener) document.addEventListener("keypress", this.keyHandler, true)
		else {
			if ((self.Event) && (self.Event.KEYPRESS)) document.captureEvents(Event.KEYPRESS);
			document.onkeypress = this.keyHandler;
		}
		window.document.onkeydown=this.keyFix;
		this.kbdEnabled=true;
	}
	this.activeTerm=term;
}

TermGlobals.keyFix=function(e) {
	var term=TermGlobals.activeTerm;
	if ((TermGlobals.keylock) || (term.lock)) return true;
	if (window.event) {
		var ch=window.event.keyCode;
		if  (!e) e=window.event;
		if (e.DOM_VK_UP) {
			for (var i in termDomKeyRef) {
				if ((e[i]) && (ch == e[i])) {
					this.keyHandler({which:termDomKeyRef[i],_remapped:true});
					if (e.preventDefault) e.preventDefault();
					if (e.stopPropagation) e.stopPropagation();
					e.cancleBubble=true;
					return false;
				}
			}
			e.cancleBubble=false;
			return true;
		}
		else {
			// no DOM support
			if ((ch==8) && (!term.isSafari)) TermGlobals.keyHandler({which:termKey.BS,_remapped:true})
			else if (ch==9) TermGlobals.keyHandler({which:termKey.TAB,_remapped:true})
			else if (ch==37) TermGlobals.keyHandler({which:termKey.LEFT,_remapped:true})
			else if (ch==39) TermGlobals.keyHandler({which:termKey.RIGHT,_remapped:true})
			else if (ch==38) TermGlobals.keyHandler({which:termKey.UP,_remapped:true})
			else if (ch==40) TermGlobals.keyHandler({which:termKey.DOWN,_remapped:true})
			else if (ch==127) TermGlobals.keyHandler({which:termKey.DEL,_remapped:true})
			else if ((ch>=57373) && (ch<=57376)) {
				if (ch==57373) TermGlobals.keyHandler({which:termKey.UP,_remapped:true})
				else if (ch==57374) TermGlobals.keyHandler({which:termKey.DOWN,_remapped:true})
				else if (ch==57375) TermGlobals.keyHandler({which:termKey.LEFT,_remapped:true})
				else if (ch==57376) TermGlobals.keyHandler({which:termKey.RIGHT,_remapped:true});
			}
			else {
				e.cancleBubble=false;
				return true;
			}
			if (e.preventDefault) e.preventDefault();
			if (e.stopPropagation) e.stopPropagation();
			e.cancleBubble=true;
			return false;
		}
	}
}

TermGlobals.keyHandler=function(e) {
	var term=TermGlobals.activeTerm;
	if ((TermGlobals.keylock) || (term.lock)) return true;
	if ((window.event) && (window.event.preventDefault)) window.event.preventDefault()
	else if ((e) && (e.preventDefault)) e.preventDefault();
	if ((window.event) && (window.event.stopPropagation)) window.event.stopPropagation()
	else if ((e) && (e.stopPropagation)) e.stopPropagation();
	var ch;
	var ctrl=false;
	var shft=false;
	var remapped=false;
	if (e) {
		ch=e.which;
		ctrl=(((e.ctrlKey) && (e.altKey)) || (e.modifiers==2));
		shft=((e.shiftKey) || (e.modifiers==4));
		if (e._remapped) {
			remapped=true;
			if (window.event) {
				//ctrl=((ctrl) || (window.event.ctrlKey));
				ctrl=((ctrl) || ((window.event.ctrlKey) && (!window.event.altKey)));
				shft=((shft) || (window.event.shiftKey));
			}
		}
	}
	else if (window.event) {
		ch=window.event.keyCode;
		//ctrl=(window.event.ctrlKey);
		ctrl=((window.event.ctrlKey) && (!window.event.altKey)); // allow alt gr == ctrl alts
		shft=(window.event.shiftKey);
	}
	else {
		return true;
	}
	if ((ch=='') && (remapped==false)) {
		// map specials
		if (e==null) e=window.event;
		if ((e.charCode==0) && (e.keyCode)) {
			if (e.DOM_VK_UP) {
				for (var i in termDomKeyRef) {
					if ((e[i]) && (e.keyCode == e[i])) {
						ch=termDomKeyRef[i];
						break;
					}
				}
			}
			else {
				// NS4
				if (e.keyCode==28) ch=termKey.LEFT
				else if (e.keyCode==29) ch=termKey.RIGHT
				else if (e.keyCode==30) ch=termKey.UP
				else if (e.keyCode==31) ch=termKey.DOWN
				// Mozilla alike but no DOM support
				else if (e.keyCode==37) ch=termKey.LEFT
				else if (e.keyCode==39) ch=termKey.RIGHT
				else if (e.keyCode==38) ch=termKey.UP
				else if (e.keyCode==40) ch=termKey.DOWN
				// just to have the TAB mapping here too
				else if (e.keyCode==9) ch=termKey.TAB;
			}
		}
	}
	// key actions
	if (term.charMode) {
		term.insert=false;
		term.inputChar=ch;
		term.lineBuffer='';
		term.handler();
		if ((ch<=32) && (window.event)) window.event.cancleBubble=true;
		return false;
	}
	if (!ctrl) {
		// special keys
		if (ch==termKey.CR) {
			term.lock=true;
			term.cursorOff();
			term.insert=false;
			if (term.rawMode) {
				term.lineBuffer=term.lastLine;
			}
			else {
				term.lineBuffer=term._getLine();
				if (
				    (term.lineBuffer!='') && ((!term.historyUnique) ||
				    (term.history.length==0) ||
				    (term.lineBuffer!=term.history[term.history.length-1]))
				   ) {
					term.history[term.history.length]=term.lineBuffer;
				}
				term.histPtr=term.history.length;
			}
			term.lastLine='';
			term.inputChar=0;
			term.handler();
			if (window.event) window.event.cancleBubble=true;
			return false;
		}
		else if (ch==termKey.ESC) {
			if (term.conf.closeOnESC) term.close();
			if (window.event) window.event.cancleBubble=true;
			return false;
		}
		if ((ch<32) && (term.rawMode)) {
			if (window.event) window.event.cancleBubble=true;
			return false;
		}
		else {
			if (ch==termKey.LEFT) {
				term.cursorLeft();
				if (window.event) window.event.cancleBubble=true;
				return false;
			}
			else if (ch==termKey.RIGHT) {
				term.cursorRight();
				if (window.event) window.event.cancleBubble=true;
				return false;
			}
			else if (ch==termKey.UP) {
				term.cursorOff();
				if (term.histPtr==term.history.length) term.lastLine=term._getLine();
				term._clearLine();
				if ((term.history.length) && (term.histPtr>=0)) {
					if (term.histPtr>0) term.histPtr--;
					term.type(term.history[term.histPtr]);
				}
				else if (term.lastLine) term.type(term.lastLine);
				term.cursorOn();
				if (window.event) window.event.cancleBubble=true;
				return false;
			}
			else if (ch==termKey.DOWN) {
				term.cursorOff();
				if (term.histPtr==term.history.length) term.lastLine=term._getLine();
				term._clearLine();
				if ((term.history.length) && (term.histPtr<=term.history.length)) {
					if (term.histPtr<term.history.length) term.histPtr++;
					if (term.histPtr<term.history.length) term.type(term.history[term.histPtr])
					else if (term.lastLine) term.type(term.lastLine);
				}
				else if (term.lastLine) term.type(term.lastLine);
				term.cursorOn();
				if (window.event) window.event.cancleBubble=true;
				return false;
			}
			else if (ch==termKey.BS) {
				term.backspace();
				if (window.event) window.event.cancleBubble=true;
				return false;
			}
			else if (ch==termKey.DEL) {
				if (term.DELisBS) term.backspace()
				else term.fwdDelete();
				if (window.event) window.event.cancleBubble=true;
				return false;
			}
		}
	}
	if (term.rawMode) {
		if (term.isPrintable(ch)) {
			term.lastLine+=String.fromCharCode(ch);
		}
		if ((ch==32) && (window.event)) window.event.cancleBubble=true
		else if ((window.opera) && (window.event)) window.event.cancleBubble=true;
		return false;
	}
	else {
		if ((term.conf.catchCtrlH) && ((ch==termKey.BS) || ((ctrl) && (ch==72)))) {
			// catch ^H
			term.backspace();
			if (window.event) window.event.cancleBubble=true;
			return false;
		}
		else if ((term.ctrlHandler) && ((ch<32) || ((ctrl) && (term.isPrintable(ch,true))))) {
			if (((ch>=65) && (ch<=96)) || (ch==63)) {
				// remap canonical
				if (ch==63) ch=31
				else ch-=64;
			}
			term.inputChar=ch;
			term.ctrlHandler();
			if (window.event) window.event.cancleBubble=true;
			return false;
		}
		else if ((ctrl) || (!term.isPrintable(ch,true))) {
			if (window.event) window.event.cancleBubble=true;
			return false;
		}
		else if (term.isPrintable(ch,true)) {
			if (term.blinkTimer) clearTimeout(term.blinkTimer);
			if (term.insert) {
				term.cursorOff();
				term._scrollRight(term.r,term.c);
			}
			term._charOut(ch);
			term.cursorOn();
			if ((ch==32) && (window.event)) window.event.cancleBubble=true
			else if ((window.opera) && (window.event)) window.event.cancleBubble=true;
			return false;
		}
	}
	return true;
}

// term gui

TermGlobals.hasSubDivs=false;
TermGlobals.hasLayers=false;
TermGlobals.termStringStart='';
TermGlobals.termStringEnd='';

TermGlobals.termSpecials=new Array();
TermGlobals.termSpecials[0]='&nbsp;';
TermGlobals.termSpecials[1]='&nbsp;';
TermGlobals.termSpecials[9]='&nbsp;';
TermGlobals.termSpecials[32]='&nbsp;';
TermGlobals.termSpecials[34]='&quot;';
TermGlobals.termSpecials[38]='&amp;';
TermGlobals.termSpecials[60]='&lt;';
TermGlobals.termSpecials[62]='&gt;';
TermGlobals.termSpecials[127]='&loz;';
TermGlobals.termSpecials[0x20AC]='&euro;';

TermGlobals.termStyles=new Array(1,2,4,8);
TermGlobals.termStyleOpen=new Array();
TermGlobals.termStyleClose=new Array();
TermGlobals.termStyleOpen[1]='<span class="termReverse">';
TermGlobals.termStyleClose[1]='<\/span>';
TermGlobals.termStyleOpen[2]='<u>';
TermGlobals.termStyleClose[2]='<\/u>';
TermGlobals.termStyleOpen[4]='<i>';
TermGlobals.termStyleClose[4]='<\/i>';
TermGlobals.termStyleOpen[8]='<strike>';
TermGlobals.termStyleClose[8]='<\/strike>';

Terminal.prototype._makeTerm=function(rebuild) {
	window.status='Building terminal ...';
	TermGlobals.hasLayers=(document.layers)? true:false;
	TermGlobals.hasSubDivs=(navigator.userAgent.indexOf('Gecko')<0);
	var divPrefix=this.termDiv+'_r';
	var s='';
	s+='<table border="0" cellspacing="0" cellpadding="'+this.conf.frameWidth+'">\n';
	s+='<tr><td bgcolor="'+this.conf.frameColor+'"><table border="0" cellspacing="0" cellpadding="2"><tr><td  bgcolor="'+this.conf.bgColor+'"><table border="0" cellspacing="0" cellpadding="0">\n';
	var rstr='';
	for (var c=0; c<this.conf.cols; c++) rstr+='&nbsp;';
	for (var r=0; r<this.conf.rows; r++) {
		var termid=((TermGlobals.hasLayers) || (TermGlobals.hasSubDivs))? '' : ' id="'+divPrefix+r+'"';
		s+='<tr><td nowrap height="'+this.conf.rowHeight+'"'+termid+' class="'+this.conf.fontClass+'">'+rstr+'<\/td><\/tr>\n';
	}
	s+='<\/table><\/td><\/tr>\n';
	s+='<\/table><\/td><\/tr>\n';
	s+='<\/table>\n';
	var termOffset=2+this.conf.frameWidth;
	if (TermGlobals.hasLayers) {
		for (var r=0; r<this.conf.rows; r++) {
			s+='<layer name="'+divPrefix+r+'" top="'+(termOffset+r*this.conf.rowHeight)+'" left="'+termOffset+'" class="'+this.conf.fontClass+'"><\/layer>\n';
		}
		this.ns4ParentDoc=document.layers[this.termDiv].document;
		TermGlobals.termStringStart='<table border="0" cellspacing="0" cellpadding="0"><tr><td nowrap height="'+this.conf.rowHeight+'" class="'+this.conf.fontClass+'">';
		TermGlobals.termStringEnd='<\/td><\/tr><\/table>';
	}
	else if (TermGlobals.hasSubDivs) {
		for (var r=0; r<this.conf.rows; r++) {
			s+='<div id="'+divPrefix+r+'" style="position:absolute; top:'+(termOffset+r*this.conf.rowHeight)+'px; left: '+termOffset+'px;" class="'+this.conf.fontClass+'"><\/div>\n';
		}
		TermGlobals.termStringStart='<table border="0" cellspacing="0" cellpadding="0"><tr><td nowrap height="'+this.conf.rowHeight+'" class="'+this.conf.fontClass+'">';
		TermGlobals.termStringEnd='<\/td><\/tr><\/table>';
	}
	TermGlobals.writeElement(this.termDiv,s);
	if (!rebuild) {
		TermGlobals.setElementXY(this.termDiv,this.conf.x,this.conf.y);
		TermGlobals.setVisible(this.termDiv,1);
	}
	window.status='';
}

Terminal.prototype.rebuild=function() {
	// check for bounds and array lengths
	var rl=this.conf.rows;
	var cl=this.conf.cols;
	for (var r=0; r<rl; r++) {
		var cbr=this.charBuf[r];
		if (!cbr) {
			this.charBuf[r]=this.getRowArray(cl,0);
			this.styleBuf[r]=this.getRowArray(cl,0);
		}
		else if (cbr.length<cl) {
			for (var c=cbr.length; c<cl; c++) {
				this.charBuf[r][c]=0;
				this.styleBuf[r][c]=0;
			}
		}
	}
	var resetcrsr=false;
	if (this.r>=rl) {
		r=rl-1;
		resetcrsr=true;
	}
	if (this.c>=cl) {
		c=cl-1;
		resetcrsr=true;
	}
	if ((resetcrsr) && (this.cursoractive)) this.cursorOn();
	// and actually rebuild
	this._makeTerm(true);
	for (var r=0; r<rl; r++) {
		this.redraw(r);
	}
}

Terminal.prototype.moveTo=function(x,y) {
	TermGlobals.setElementXY(this.termDiv,x,y);
}

Terminal.prototype.resizeTo=function(x,y) {
	if (this.termDivReady()) {
		x=parseInt(x,10);
		y=parseInt(y,10);
		if ((isNaN(x)) || (isNaN(y)) || (x<4) || (y<2)) return false;
		this.maxCols=this.conf.cols=x;
		this.maxLines=this.conf.rows=y;
		this._makeTerm();
		this.clear();
		return true;
	}
	else return false;
}

Terminal.prototype.redraw=function(r) {
	var s=TermGlobals.termStringStart;
	var curStyle=0;
	var tstls=TermGlobals.termStyles;
	var tscls=TermGlobals.termStyleClose;
	var tsopn=TermGlobals.termStyleOpen;
	var tspcl=TermGlobals.termSpecials;
	var t_cb=this.charBuf;
	var t_sb=this.styleBuf;
	for (var i=0; i<this.conf.cols; i++) {
		var c=t_cb[r][i];
		var cs=t_sb[r][i];
		if (cs!=curStyle) {
			if (curStyle) {
				for (var k=tstls.length-1; k>=0; k--) {
					var st=tstls[k];
					if (curStyle&st) s+=tscls[st];
				}
			}
			curStyle=cs;
			for (var k=0; k<tstls.length; k++) {
				var st=tstls[k];
				if (curStyle&st) s+=tsopn[st];
			}
		}
		s+= (tspcl[c])? tspcl[c] : String.fromCharCode(c);
	}
	if (curStyle>0) {
		for (var k=tstls.length-1; k>=0; k--) {
			var st=tstls[k];
			if (curStyle&st) s+=tscls[st];
		}
	}
	s+=TermGlobals.termStringEnd;
	TermGlobals.writeElement(this.termDiv+'_r'+r,s,this.ns4ParentDoc);
}

Terminal.prototype.guiReady=function() {
	ready=true;
	if (TermGlobals.guiElementsReady(this.termDiv, self.document)) {
		for (var r=0; r<this.conf.rows; r++) {
			if (TermGlobals.guiElementsReady(this.termDiv+'_r'+r,this.ns4ParentDoc)==false) {
				ready=false;
				break;
			}
		}
	}
	else ready=false;
	return ready;
}

Terminal.prototype.termDivReady=function() {
	if (document.layers) {
		return (document.layers[this.termDiv])? true:false;
	}
	else if (document.getElementById) {
		return (document.getElementById(this.termDiv))? true:false;
	}
	else if (document.all) {
		return (document.all[this.termDiv])? true:false;
	}
	else {
		return false;
	}
}

Terminal.prototype.getDimensions=function() {
	var w=0;
	var h=0;
	var d=this.termDiv;
	if (document.layers) {
		if (document.layers[d]) {
			w=document.layers[d].clip.right;
			h=document.layers[d].clip.bottom;
		}
	}
	else if (document.getElementById) {
		var obj=document.getElementById(d);
		if ((obj) && (obj.firstChild)) {
			w=parseInt(obj.firstChild.offsetWidth,10);
			h=parseInt(obj.firstChild.offsetHeight,10);
        }
		else if ((obj) && (obj.children) && (obj.children[0])) {
			w=parseInt(obj.children[0].offsetWidth,10);
			h=parseInt(obj.children[0].offsetHeight,10);
        }
	}
	else if (document.all) {
		var obj=document.all[d];
		if ((obj) && (obj.children) && (obj.children[0])) {
			w=parseInt(obj.children[0].offsetWidth,10);
			h=parseInt(obj.children[0].offsetHeight,10);
        }
	}
	return { width: w, height: h };
}

// basic dynamics

TermGlobals.writeElement=function(e,t,d) {
	if (document.layers) {
		var doc=(d)? d : self.document;
		doc.layers[e].document.open();
		doc.layers[e].document.write(t);
		doc.layers[e].document.close();
	}
	else if (document.getElementById) {
		var obj=document.getElementById(e);
		obj.innerHTML=t;
	}
	else if (document.all) {
		document.all[e].innerHTML=t;
	}
}

TermGlobals.setElementXY=function(d,x,y) {
	if (document.layers) {
		document.layers[d].moveTo(x,y);
	}
	else if (document.getElementById) {
		var obj=document.getElementById(d);
		obj.style.left=x+'px';
		obj.style.top=y+'px';
	}
	else if (document.all) {
		document.all[d].style.left=x+'px';
		document.all[d].style.top=y+'px';
	}
}

TermGlobals.setVisible=function(d,v) {
	if (document.layers) {
		document.layers[d].visibility= (v)? 'show':'hide';
	}
	else if (document.getElementById) {
		var obj=document.getElementById(d);
		obj.style.visibility= (v)? 'visible':'hidden';
	}
	else if (document.all) {
		document.all[d].style.visibility= (v)? 'visible':'hidden';
	}
}

TermGlobals.setDisplay=function(d,v) {
	if (document.getElementById) {
		var obj=document.getElementById(d);
		obj.style.display=v;
	}
	else if (document.all) {
		document.all[d].style.display=v;
	}
}

TermGlobals.guiElementsReady=function(e,d) {
	if (document.layers) {
		var doc=(d)? d : self.document;
		return ((doc) && (doc.layers[e]))? true:false;
	}
	else if (document.getElementById) {
		return (document.getElementById(e))? true:false;
	}
	else if (document.all) {
		return (document.all[e])? true:false;
	}
	else return false;
}


// constructor mods (ie4 fix)

var termString_keyref;
var termString_keycoderef;

function termString_makeKeyref() {
	termString_keyref= new Array();
	termString_keycoderef= new Array();
	var hex= new Array('A','B','C','D','E','F');
	for (var i=0; i<=15; i++) {
		var high=(i<10)? i:hex[i-10];
		for (var k=0; k<=15; k++) {
			var low=(k<10)? k:hex[k-10];
			var cc=i*16+k;
			if (cc>=32) {
				var cs=unescape("%"+high+low);
				termString_keyref[cc]=cs;
				termString_keycoderef[cs]=cc;
			}
		}
	}
}

if (!String.fromCharCode) {
	termString_makeKeyref();
	String.fromCharCode=function(cc) {
		return (cc!=null)? termString_keyref[cc] : '';
	};
}
if (!String.prototype.charCodeAt) {
	if (!termString_keycoderef) termString_makeKeyref();
	String.prototype.charCodeAt=function(n) {
		cs=this.charAt(n);
		return (termString_keycoderef[cs])? termString_keycoderef[cs] : 0;
	};
}

// eof