// stclib.js

var gsCSSBrow = "";
var gsCSSVers = "";
var gbCurrentHome = "F";

var Xoffset=-60;    // modify these values to ...
var Yoffset= 20;    // change the linkPop position.

var gsPopStyle = (document.all),yyy = -1000;
// var old,gsPopStyle,iex = (document.all),yyy = -1000;

var ns4 = document.layers;
var ns6 = document.getElementById&&!document.all;
var ie4 = document.all;
var ie = document.all;

var BrowserDetect = 
{
    init: function () 
    {
	this.browser = this.searchString(this.dataBrowser) || "An unknown browser";
	this.version = this.searchVersion(navigator.userAgent)
		|| this.searchVersion(navigator.appVersion)
		|| "an unknown version";
	this.OS = this.searchString(this.dataOS) || "an unknown OS";
    },
    searchString: function (data) 
    {
	for (var i=0;i<data.length;i++)	
	{
		var dataString = data[i].string;
		var dataProp = data[i].prop;
		this.versionSearchString = data[i].versionSearch || data[i].identity;
		if (dataString) 
		{
			if (dataString.indexOf(data[i].subString) != -1)
				return data[i].identity;
		}
		else if (dataProp)
			return data[i].identity;
	}
    },
    searchVersion: function (dataString) 
    {
	    var index = dataString.indexOf(this.versionSearchString);
	    if (index == -1) return;
	    return parseFloat(dataString.substring(index+this.versionSearchString.length+1));
    },
    dataBrowser: [
	    {
		    string: navigator.userAgent,
		    subString: "Chrome",
		    identity: "Chrome"
	    },
	    { 	string: navigator.userAgent,
		    subString: "OmniWeb",
		    versionSearch: "OmniWeb/",
		    identity: "OmniWeb"
	    },
	    {
		    string: navigator.vendor,
		    subString: "Apple",
		    identity: "Safari",
		    versionSearch: "Version"
	    },
	    {
		    prop: window.opera,
		    identity: "Opera"
	    },
	    {
		    string: navigator.vendor,
		    subString: "iCab",
		    identity: "iCab"
	    },
	    {
		    string: navigator.vendor,
		    subString: "KDE",
		    identity: "Konqueror"
	    },
	    {
		    string: navigator.userAgent,
		    subString: "Firefox",
		    identity: "Firefox"
	    },
	    {
		    string: navigator.vendor,
		    subString: "Camino",
		    identity: "Camino"
	    },
	    {		// for newer Netscapes (6+)
		    string: navigator.userAgent,
		    subString: "Netscape",
		    identity: "Netscape"
	    },
	    {
		    string: navigator.userAgent,
		    subString: "MSIE",
		    identity: "Explorer",
		    versionSearch: "MSIE"
	    },
	    {
		    string: navigator.userAgent,
		    subString: "Gecko",
		    identity: "Mozilla",
		    versionSearch: "rv"
	    },
	    { 		// for older Netscapes (4-)
		    string: navigator.userAgent,
		    subString: "Mozilla",
		    identity: "Netscape",
		    versionSearch: "Mozilla"
	    }
    ],
    dataOS : [
	    {
		    string: navigator.platform,
		    subString: "Win",
		    identity: "Windows"
	    },
	    {
		    string: navigator.platform,
		    subString: "Mac",
		    identity: "Mac"
	    },
	    {
		       string: navigator.userAgent,
		       subString: "iPhone",
		       identity: "iPhone/iPod"
	},
	    {
		    string: navigator.platform,
		    subString: "Linux",
		    identity: "Linux"
	    }
    ]

};

//Pop up information box II (Mike McGrath (mike_mcgrath@lineone.net,  http://website.lineone.net/~mike_mcgrath))
//Permission granted to Dynamicdrive.com to include script in archive
//For this and 100's more DHTML scripts, visit http://dynamicdrive.com

function initBody()
{
    document.write ('<div id="divPop">');
    document.write ('&nbsp;');
    document.write ('</div> <!-- divPop -->');

    if (ns4)
    {
	gsPopStyle = document.divPop
    }
    else if (ns6)
    {
	gsPopStyle = document.getElementById("divPop").style
    }
    else if (ie4)
    {
	gsPopStyle = document.all.divPop.style
    }

    if (ns4)
    {
	document.captureEvents(Event.MOUSEMOVE);
    }
    else
    {
	gsPopStyle = document.getElementById("divPop").style
	gsPopStyle.visibility = "visible"
	gsPopStyle.display = "none"
    }

    document.onmousemove = get_mouse;

}

function get_mouse(e)
{
    var x = (ns4||ns6)?e.pageX:event.x+document.body.scrollLeft;
    gsPopStyle.left = x+Xoffset;
    var y = (ns4||ns6)?e.pageY:event.y+document.body.scrollTop;
    gsPopStyle.top = y + yyy;
}

// POP-UP MESSAGES: 
// linkPopIn - Link to URL on same site
// linkPopOut - Link to URL on another site (opening new window)
// linkPopLeft - Show message Left justified
// linkPopRight - Show message Right justified
// linkPopOff - Turn off any of these Pop-ups
// linkPopSort - For Sortable headers

function linkPopIn(sMsg,sBg)
{
    var sContent;

    if ((sBg == '') || (sBg == undefined))
    {
	sBg = "#FFFFCC";
    }
    sContent=" <TABLE Border=1 BorderColor=#808080 CellPadding=3 CellSpacing=0 "+ "BgColor="+sBg+"><TD Align=Center Class=PopUp> "+sMsg+"</TD></TABLE>";
    yyy=Yoffset;
     if(ns4){gsPopStyle.document.write(sContent);gsPopStyle.document.close();gsPopStyle.visibility="visible"}
    if(ns6){document.getElementById("divPop").innerHTML=sContent;gsPopStyle.display=''}
    if(ie4){document.all("divPop").innerHTML=sContent;gsPopStyle.display=''}
}

function linkPopOut(sMsg)
{
    var sContent=" <TABLE Border=1 BorderColor=black CellPadding=2 CellSpacing=0 "+ "BgColor=#FFFFCC><TD Align=Center Class=PopUp><B>OPEN NEW WINDOW</B><BR>to<BR>"+sMsg+"</TD></TABLE>";
    yyy=Yoffset;

     if(ns4){gsPopStyle.document.write(sContent);gsPopStyle.document.close();gsPopStyle.visibility="visible"}
    if(ns6){document.getElementById("divPop").innerHTML=sContent;gsPopStyle.display=''}
    if(ie4){document.all("divPop").innerHTML=sContent;gsPopStyle.display=''}
}

function linkPopLeft(sMsg)
{
    var sContent=" <TABLE Border=1 BorderColor=black CellPadding=2 CellSpacing=0 "+ "BgColor=#FFFFCC><TD Align=Left Class=PopUp>"+sMsg+"</TD></TABLE>";
    yyy=Yoffset;

     if(ns4){gsPopStyle.document.write(sContent);gsPopStyle.document.close();gsPopStyle.visibility="visible"}
    if(ns6){document.getElementById("divPop").innerHTML=sContent;gsPopStyle.display=''}
    if(ie4){document.all("divPop").innerHTML=sContent;gsPopStyle.display=''}
}

function linkPopRight(sMsg)
{
    var sContent=" <TABLE Border=1 BorderColor=black CellPadding=2 CellSpacing=0 "+ "BgColor=#FFFFCC><TD Align=Right Class=PopUp>"+sMsg+"</TD></TABLE>";
    yyy=Yoffset;

     if(ns4){gsPopStyle.document.write(sContent);gsPopStyle.document.close();gsPopStyle.visibility="visible"}
    if(ns6){document.getElementById("divPop").innerHTML=sContent;gsPopStyle.display=''}
    if(ie4){document.all("divPop").innerHTML=sContent;gsPopStyle.display=''}
}

function linkPopOff()
{
    yyy=-1000;
    if(ns4){gsPopStyle.visibility="hidden";}
    else if (ns6||ie4)
    gsPopStyle.display="none"
}

function linkPopSort(sFg,sBg)
{
    var sMsg = "click on header to<BR>sort by column";
    var sContent="<TABLE Border=1 CellPadding=2 CellSpacing=0 " + "FgColor="+sFg + " BgColor="+sBg+"><TD Align=Center Class=PopUp> "+sMsg+"</FONT></TD></TABLE>";
    yyy=Yoffset;
     if(ns4){gsPopStyle.document.write(sContent);gsPopStyle.document.close();gsPopStyle.visibility="visible"}
    if(ns6){document.getElementById("divPop").innerHTML=sContent;gsPopStyle.display=''}
    if(ie4){document.all("divPop").innerHTML=sContent;gsPopStyle.display=''}
}


/***********************************************
* Highlight Table Cells Script- © Dynamic Drive DHTML code library (www.dynamicdrive.com)
* Visit http://www.dynamicDrive.com for hundreds of DHTML scripts
* This notice must stay intact for legal use
***********************************************/

//SPECIFY HIGHLIGHT BEHAVIOR. "TD" TO HIGHLIGHT TABLE CELLS, "TR" TO HIGHLIGHT THE ENTIRE ROW:

var highlightbehavior="TD"

function contains_ns6(master,slave) 
{ 
    // CHECK IF SLAVE IS CONTAINED BY MASTEr
    while (slave.parentNode)
    if ((slave = slave.parentNode) == master)
	return true;
	return false;
}

function ChangeTo(e,fsFgColor,fsBgColor)
{
    source=ie? event.srcElement : e.target
    if (source.tagName=="TABLE")
    return

    // while(source.tagName!=highlightbehavior && source.tagName!="HTML")
    while (source.tagName!=highlightbehavior && source.tagName!="HTML" && source.tagName!="TH" && source.tagName!="A")
    {
	source=ns6 ? source.parentNode : source.parentElement
	if (source.style.backgroundColor!=fsBgColor&&source.id!="ignore")
	{
	    source.style.backgroundColor=fsBgColor;
	}
	if (source.style.color!=fsFgColor&&source.id!="ignore")
	{
	    source.style.color=fsFgColor;
	}
    }
}

function ChangeFr(e,fsFgColor,fsBgColor)
{
    if (ie&&(event.fromElement.contains(event.toElement)||source.contains(event.toElement)||source.id=="ignore")||source.tagName=="TABLE")
    {
	return
    }
    else if (ns6&&(contains_ns6(source, e.relatedTarget)||source.id=="ignore"))
    {
	return
    }
    if (ie&&event.toElement!=source||ns6&&e.relatedTarget!=source)
    {
	source.style.color=fsFgColor;
	source.style.backgroundColor=fsBgColor;
    }
}

function changebg(e,highlightcolor)
{
    source=ie? event.srcElement : e.target
    if (source.tagName=="TABLE")
    return
    // while(source.tagName!=highlightbehavior && source.tagName!="HTML")
    while ((source.tagName!=highlightbehavior && source.tagName!="HTML") && (source.tagName!="TH" && source.tagName!="HTML"))
    source=ns6? source.parentNode : source.parentElement
    if (source.style.backgroundColor!=highlightcolor&&source.id!="ignore")
    source.style.backgroundColor=highlightcolor
}

function changeback(e,originalcolor)
{
    if (ie&&(event.fromElement.contains(event.toElement)||source.contains(event.toElement)||source.id=="ignore")||source.tagName=="TABLE")
    return
    else if (ns6&&(contains_ns6(source, e.relatedTarget)||source.id=="ignore"))
    return
    if (ie&&event.toElement!=source||ns6&&e.relatedTarget!=source)
    source.style.backgroundColor=originalcolor
}


BrowserDetect.init();

////////////////////////////////////////////////////////////////////////////////
// Below you see the objects contained by the object navigator. These variables
// can be read out and give information about the browser and computer of your 
// users. Use this information to add new objects to the browser detect.
//

// navigator.userAgent = Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7
// navigator.vendor = 
// navigator.platform = Win32
// navigator.appCodeName = Mozilla
// navigator.appName = Netscape
// navigator.appVersion = 5.0 (Windows; en-US)
// navigator.language = en-US
// navigator.mimeTypes = [object MimeTypeArray]
// navigator.oscpu = Windows NT 5.0
// navigator.vendorSub = 
// navigator.product = Gecko
// navigator.productSub = 20091221
// navigator.plugins = [object PluginArray]
// navigator.securityPolicy = 
// navigator.cookieEnabled = true
// navigator.onLine = true
// navigator.buildID = 20091221164558
// navigator.javaEnabled = function javaEnabled() {
//     [native code]
// }
// navigator.taintEnabled = function taintEnabled() {
//     [native code]
// }
// navigator.preference = function preference() {
//     [native code]
// }
// navigator.geolocation = [object GeoGeolocation]
// navigator.registerContentHandler = function registerContentHandler() {
//     [native code]
// }
// navigator.registerProtocolHandler = function registerProtocolHandler() {
//     [native code]
// }
// navigator.mozIsLocallyAvailable = function mozIsLocallyAvailable() {
//     [native code]
// }

function include_dom(script_filename) 
{
    var html_doc = document.getElementsByTagName('head').item(0);
    var js = document.createElement('script');
    js.setAttribute('language', 'javascript');
    js.setAttribute('type', 'text/javascript');
    js.setAttribute('src', script_filename);
    html_doc.appendChild(js);
    return false;
}

function switchOn(fsPass)
{
    tsTemp = fsPass;
    fsTDA = document.getElementById(tsTemp)
    if (fsTDA != null)
    {
	fsTDA.className='on';
	fsTDA.setAttribute("class", "on");
    }
    tsTemp = fsPass + 'a';
    fsTDA = document.getElementById(tsTemp)
    if (fsTDA != null)
    {
	fsTDA.className='on';
	fsTDA.setAttribute("class", "on");
    }
    tsTemp = fsPass + 'l';
    fsTDA = document.getElementById(tsTemp)
    if (fsTDA != null)
    {
	fsTDA.className='on';
	fsTDA.setAttribute("class", "on");
    }
}

function switchOnB(fsPass)
{
    tsTemp = fsPass;
    fsTDA = document.getElementById(tsTemp)
    if (fsTDA != null)
    {
	fsTDA.className='on2';
	fsTDA.setAttribute("class", "on2");
    }
    tsTemp = fsPass + 'a';
    fsTDA = document.getElementById(tsTemp)
    if (fsTDA != null)
    {
	fsTDA.className='on2';
	fsTDA.setAttribute("class", "on2");
    }
    tsTemp = fsPass + 'l';
    fsTDA = document.getElementById(tsTemp)
    if (fsTDA != null)
    {
	fsTDA.className='on2';
	fsTDA.setAttribute("class", "on2");
    }
}

function switchOff(fsPass)
{
    tsTemp = fsPass;
    fsTDA = document.getElementById(tsTemp)
    if (fsTDA != null)
    {
	fsTDA.className='off';
	fsTDA.setAttribute("class", "off");
    }
    tsTemp = fsPass + 'a';
    fsTDA = document.getElementById(tsTemp)
    if (fsTDA != null)
    {
	fsTDA.className='off';
	fsTDA.setAttribute("class", "off");
    }
    tsTemp = fsPass + 'l';
    fsTDA = document.getElementById(tsTemp)
    if (fsTDA != null)
    {
	fsTDA.className='off';
	fsTDA.setAttribute("class", "off");
    }
}

function switchOffB(fsPass, fsClass)
{
    tsTemp = fsPass;
    fsTDA = document.getElementById(tsTemp)
    if (fsTDA != null)
    {
	fsTDA.className='off2';
	fsTDA.setAttribute("class", "off2");
    }
    tsTemp = fsPass + 'a';
    fsTDA = document.getElementById(tsTemp)
    if (fsTDA != null)
    {
	fsTDA.className='off2';
	fsTDA.setAttribute("class", "off2");
    }
    tsTemp = fsPass + 'l';
    fsTDA = document.getElementById(tsTemp)
    if (fsTDA != null)
    {
	fsTDA.className='off2';
	fsTDA.setAttribute("class", "off2");
    }
}


/* stc_disp_ann2.js
 *
 *
 */

/* Example message arrays for the two demo scrollers*/


var pausecontent2=new Array()
pausecontent2[0]='<a href="http://www.news.com">News.com: Technology and business reports</a>'
pausecontent2[1]='<a href="http://www.cnn.com">CNN: Headline and breaking news 24/7</a>'
pausecontent2[2]='<a href="http://news.bbc.co.uk">BBC News: UK and international news</a>'

/***********************************************
* Pausing up-down scroller- © Dynamic Drive (www.dynamicdrive.com)
* This notice MUST stay intact for legal use
* Visit http://www.dynamicdrive.com/ for this script and 100s more.
***********************************************/

function pausescroller(content, divId, divClass, delay){
this.content=content //message array content
this.tickerid=divId //ID of ticker div to display information
this.delay=delay //Delay between msg change, in miliseconds.
this.mouseoverBol=0 //Boolean to indicate whether mouse is currently over scroller (and pause it if it is)
this.hiddendivpointer=1 //index of message array for hidden div
document.write('<div id="'+divId+'" class="'+divClass+'" style="position: relative; overflow: hidden"><div class="innerDiv" style="position: absolute; width: 100%" id="'+divId+'1">'+content[0]+'</div><div class="innerDiv" style="position: absolute; width: 100%; visibility: hidden" id="'+divId+'2">'+content[1]+'</div></div>')
var scrollerinstance=this
if (window.addEventListener) //run onload in DOM2 browsers
window.addEventListener("load", function(){scrollerinstance.initialize()}, false)
else if (window.attachEvent) //run onload in IE5.5+
window.attachEvent("onload", function(){scrollerinstance.initialize()})
else if (document.getElementById) //if legacy DOM browsers, just start scroller after 0.5 sec
setTimeout(function(){scrollerinstance.initialize()}, 500)
}

// -------------------------------------------------------------------
// initialize()- Initialize scroller method.
// -Get div objects, set initial positions, start up down animation
// -------------------------------------------------------------------

pausescroller.prototype.initialize=function(){
this.tickerdiv=document.getElementById(this.tickerid)
this.visiblediv=document.getElementById(this.tickerid+"1")
this.hiddendiv=document.getElementById(this.tickerid+"2")
this.visibledivtop=parseInt(pausescroller.getCSSpadding(this.tickerdiv))
//set width of inner DIVs to outer DIV's width minus padding (padding assumed to be top padding x 2)
this.visiblediv.style.width=this.hiddendiv.style.width=this.tickerdiv.offsetWidth-(this.visibledivtop*2)+"px"
this.getinline(this.visiblediv, this.hiddendiv)
this.hiddendiv.style.visibility="visible"
var scrollerinstance=this
document.getElementById(this.tickerid).onmouseover=function(){scrollerinstance.mouseoverBol=1}
document.getElementById(this.tickerid).onmouseout=function(){scrollerinstance.mouseoverBol=0}
if (window.attachEvent) //Clean up loose references in IE
window.attachEvent("onunload", function(){scrollerinstance.tickerdiv.onmouseover=scrollerinstance.tickerdiv.onmouseout=null})
setTimeout(function(){scrollerinstance.animateup()}, this.delay)
}


// -------------------------------------------------------------------
// animateup()- Move the two inner divs of the scroller up and in sync
// -------------------------------------------------------------------

pausescroller.prototype.animateup=function(){
var scrollerinstance=this
if (parseInt(this.hiddendiv.style.top)>(this.visibledivtop+5)){
this.visiblediv.style.top=parseInt(this.visiblediv.style.top)-5+"px"
this.hiddendiv.style.top=parseInt(this.hiddendiv.style.top)-5+"px"
setTimeout(function(){scrollerinstance.animateup()}, 50)
}
else{
this.getinline(this.hiddendiv, this.visiblediv)
this.swapdivs()
setTimeout(function(){scrollerinstance.setmessage()}, this.delay)
}
}

// -------------------------------------------------------------------
// swapdivs()- Swap between which is the visible and which is the hidden div
// -------------------------------------------------------------------

pausescroller.prototype.swapdivs=function(){
var tempcontainer=this.visiblediv
this.visiblediv=this.hiddendiv
this.hiddendiv=tempcontainer
}

pausescroller.prototype.getinline=function(div1, div2){
div1.style.top=this.visibledivtop+"px"
div2.style.top=Math.max(div1.parentNode.offsetHeight, div1.offsetHeight)+"px"
}

// -------------------------------------------------------------------
// setmessage()- Populate the hidden div with the next message before it's visible
// -------------------------------------------------------------------

pausescroller.prototype.setmessage=function(){
var scrollerinstance=this
if (this.mouseoverBol==1) //if mouse is currently over scoller, do nothing (pause it)
setTimeout(function(){scrollerinstance.setmessage()}, 100)
else{
var i=this.hiddendivpointer
var ceiling=this.content.length
this.hiddendivpointer=(i+1>ceiling-1)? 0 : i+1
this.hiddendiv.innerHTML=this.content[this.hiddendivpointer]
this.animateup()
}
}

pausescroller.getCSSpadding=function(tickerobj){ //get CSS padding value, if any
if (tickerobj.currentStyle)
return tickerobj.currentStyle["paddingTop"]
else if (window.getComputedStyle) //if DOM2
return window.getComputedStyle(tickerobj, "").getPropertyValue("padding-top")
else
return 0
}
/**
sprintf() for JavaScript 0.7-beta1
http://www.diveintojavascript.com/projects/javascript-sprintf

Copyright (c) Alexandru Marasteanu <alexaholic [at) gmail (dot] com>
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of sprintf() for JavaScript nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Alexandru Marasteanu BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


Changelog:
2010.09.06 - 0.7-beta1
  - features: vsprintf, support for named placeholders
  - enhancements: format cache, reduced global namespace pollution

2010.05.22 - 0.6:
 - reverted to 0.4 and fixed the bug regarding the sign of the number 0
 Note:
 Thanks to Raphael Pigulla <raph (at] n3rd [dot) org> (http://www.n3rd.org/)
 who warned me about a bug in 0.5, I discovered that the last update was
 a regress. I appologize for that.

2010.05.09 - 0.5:
 - bug fix: 0 is now preceeded with a + sign
 - bug fix: the sign was not at the right position on padded results (Kamal Abdali)
 - switched from GPL to BSD license

2007.10.21 - 0.4:
 - unit test and patch (David Baird)

2007.09.17 - 0.3:
 - bug fix: no longer throws exception on empty paramenters (Hans Pufal)

2007.09.11 - 0.2:
 - feature: added argument swapping

2007.04.03 - 0.1:
 - initial release
**/

var sprintf = (function() {
	function get_type(variable) {
		return Object.prototype.toString.call(variable).slice(8, -1).toLowerCase();
	}
	function str_repeat(input, multiplier) {
		for (var output = []; multiplier > 0; output[--multiplier] = input) {/* do nothing */}
		return output.join('');
	}

	var str_format = function() {
		if (!str_format.cache.hasOwnProperty(arguments[0])) {
			str_format.cache[arguments[0]] = str_format.parse(arguments[0]);
		}
		return str_format.format.call(null, str_format.cache[arguments[0]], arguments);
	};

	str_format.format = function(parse_tree, argv) {
		var cursor = 1, tree_length = parse_tree.length, node_type = '', arg, output = [], i, k, match, pad, pad_character, pad_length;
		for (i = 0; i < tree_length; i++) {
			node_type = get_type(parse_tree[i]);
			if (node_type === 'string') {
				output.push(parse_tree[i]);
			}
			else if (node_type === 'array') {
				match = parse_tree[i]; // convenience purposes only
				if (match[2]) { // keyword argument
					arg = argv[cursor];
					for (k = 0; k < match[2].length; k++) {
						if (!arg.hasOwnProperty(match[2][k])) {
							throw(sprintf('[sprintf] property "%s" does not exist', match[2][k]));
						}
						arg = arg[match[2][k]];
					}
				}
				else if (match[1]) { // positional argument (explicit)
					arg = argv[match[1]];
				}
				else { // positional argument (implicit)
					arg = argv[cursor++];
				}

				if (/[^s]/.test(match[8]) && (get_type(arg) != 'number')) {
					throw(sprintf('[sprintf] expecting number but found %s', get_type(arg)));
				}
				switch (match[8]) {
					case 'b': arg = arg.toString(2); break;
					case 'c': arg = String.fromCharCode(arg); break;
					case 'd': arg = parseInt(arg, 10); break;
					case 'e': arg = match[7] ? arg.toExponential(match[7]) : arg.toExponential(); break;
					case 'f': arg = match[7] ? parseFloat(arg).toFixed(match[7]) : parseFloat(arg); break;
					case 'o': arg = arg.toString(8); break;
					case 's': arg = ((arg = String(arg)) && match[7] ? arg.substring(0, match[7]) : arg); break;
					case 'u': arg = Math.abs(arg); break;
					case 'x': arg = arg.toString(16); break;
					case 'X': arg = arg.toString(16).toUpperCase(); break;
				}
				arg = (/[def]/.test(match[8]) && match[3] && arg >= 0 ? '+'+ arg : arg);
				pad_character = match[4] ? match[4] == '0' ? '0' : match[4].charAt(1) : ' ';
				pad_length = match[6] - String(arg).length;
				pad = match[6] ? str_repeat(pad_character, pad_length) : '';
				output.push(match[5] ? arg + pad : pad + arg);
			}
		}
		return output.join('');
	};

	str_format.cache = {};

	str_format.parse = function(fmt) {
		var _fmt = fmt, match = [], parse_tree = [], arg_names = 0;
		while (_fmt) {
			if ((match = /^[^\x25]+/.exec(_fmt)) !== null) {
				parse_tree.push(match[0]);
			}
			else if ((match = /^\x25{2}/.exec(_fmt)) !== null) {
				parse_tree.push('%');
			}
			else if ((match = /^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(_fmt)) !== null) {
				if (match[2]) {
					arg_names |= 1;
					var field_list = [], replacement_field = match[2], field_match = [];
					if ((field_match = /^([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {
						field_list.push(field_match[1]);
						while ((replacement_field = replacement_field.substring(field_match[0].length)) !== '') {
							if ((field_match = /^\.([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {
								field_list.push(field_match[1]);
							}
							else if ((field_match = /^\[(\d+)\]/.exec(replacement_field)) !== null) {
								field_list.push(field_match[1]);
							}
							else {
								throw('[sprintf] huh?');
							}
						}
					}
					else {
						throw('[sprintf] huh?');
					}
					match[2] = field_list;
				}
				else {
					arg_names |= 2;
				}
				if (arg_names === 3) {
					throw('[sprintf] mixing positional and named placeholders is not (yet) supported');
				}
				parse_tree.push(match);
			}
			else {
				throw('[sprintf] huh?');
			}
			_fmt = _fmt.substring(match[0].length);
		}
		return parse_tree;
	};

	return str_format;
})();

var vsprintf = function(fmt, argv) 
{
	argv.unshift(fmt);
	return sprintf.apply(null, argv);
};
/* REQUIRES config.js E-MAIL DEFINES */
function STC_writeLine(sSuffix,sPrefix,sArea,sCountry,sDivisor)
{

    var sSegment1 = "";
    var sSegment2 = "";
    var sSegment3 = "";
    var sSegment4 = "";

    if ((sDivisor == null) || (sDivisor.length == 0))
    {
	sDivisor = STC_DIVISOR;
    }
    if ((sCountry != null) && (sCountry.length > 0))
    {
	sSegment1 = "+" + sCountry + " ";
    }

    if ((sArea != null) || (sArea.length > 0))
    {
	sSegment2 = sArea + sDivisor;
    }
    if ((sPrefix != null) || (sPrefix.length > 0))
    {
	sSegment3 = sPrefix + sDivisor;
    }
    if ((sSuffix != null) || (sSuffix.length > 0))
    {
	sSegment4 = sSuffix;
    }
    document.write (sSegment1 + sSegment2 + sSegment3 + sSegment4);
}

function STC_writeName(sName,sDivisor,sPosition,sDescription)
{
    sDomain = gsDomainName;
    sFullName = sName;

    if ((sDivisor == null) || (sDivisor.length == 0))
    {
	sDivisor = STC_DIVISOR;
    }

    nPos = sName.indexOf(" ");
    if (nPos > 0)
    {
	sFullName = sName.substr(0, nPos) +  sDivisor + sName.substr(nPos+1);
	if (sDivisor == 'c')
	{
	    sFullName = sName.substr(0, nPos);
	    sDomain = sName.substr(nPos+1) + '.com';
	}
	if (sDivisor == 'n')
	{
	    sFullName = sName.substr(0, nPos);
	    sDomain = sName.substr(nPos+1) + '.net';
	}
	if (sDivisor == 'o')
	{
	    sFullName = sName.substr(0, nPos);
	    sDomain = sName.substr(nPos+1) + '.org';
	}
	if (sDivisor == 'u')
	{
	    sFullName = sName.substr(0, nPos);
	    sDomain = sName.substr(nPos+1) + '.us';
	}
    }
    sFullName = sFullName.toLowerCase();
   
    if (sDescription == null)
    {
	document.write ('<A Href="' + STC_COMMAND + sFullName + STC_SYMBOL + sDomain + '">' + sName + '</A>');
    }
    else
    {
	document.write ('<A Href="' + STC_COMMAND + sFullName + STC_SYMBOL + sDomain + '">' + sDescription + '</A>');
    }
    if (sPosition != null) 
    {
	document.write (sPosition);
    }
}

function STC_writePict(sName, sImage, nHeight, nWidth)
{
    sDomain = gsDomainName;
    sFullName = sName;

    nPos = sName.indexOf(" ");
    if (nPos > 0)
    {
	sFullName = sName.substr(0, nPos) +  STC_DIVISOR + sName.substr(nPos+1);
    }

    sFullName = sFullName.toLowerCase();
    // IF NO SLASH, ASSUME image SUB-DIRECTORY
    if (sImage.indexOf("/") < 0)
    {
	sImage = "/images/" + sImage;
    }

    // IF NO HEIGHT, SKIP IT
    if (nHeight == null)
    {
	sHeight = "";
    }
    else
    {
	sHeight = " Height=" + nHeight;
    }

    // IF NO WIDTH, SKIP IT
    if (nWidth == null)
    {
	sWidth = "";
    }
    else
    {
	sWidth = " Width=" + nWidth;
    }

    document.write ('<A Href="' + STC_COMMAND + sFullName + STC_SYMBOL + sDomain + '"><IMG Src="' + sImage + '"' + sHeight + sWidth + '></A>');
}


