# ****************************************************************************
# Surgeweb javascript - Utility functions
# Note: sw.js is the primary surgeweb javascript code
# ----------------------------------------------------------------------------
#  - Surgeweb related small self contained utility functions
#  - General utility functions that probably should be split into seperate library
# ****************************************************************************


var status_hist=[];
var status_timer,logging_out;
var U=undefined;
// Setting of status - automatically adds a timeout hiding function
function set_status(status,level)
{
	if(!sw.status) return;
	if(status_timer) clearTimeout(status_timer);
	if(!status){class_add(panel_correct(sw.status),'hidden'); success_string=''; return}
	if(logging_out) return;
	
	sw.status.innerHTML=status;
	var o=panel_correct(sw.status);
	class_set(o,level);
	if(level=="success"){
		status_timer=setTimeout(function(){ class_add(panel_correct(sw.status),'hidden'); },4000);
	}else{
		status_timer=setTimeout(function(){ class_add(panel_correct(sw.status),'hidden'); },15000);
	}
	status_hist.push({'txt':status,'time':mtime(), 'type':level});
	if(status_hist.length>20) status_hist.shift();
}

function status_debug()
{
	var x,i;
	x='';
	for (i=status_hist.length-1;i>=0;i--){
		x+='<div class="'+status_hist[i].type+'" style="border:1px solid #bbb;margin-top:5px;padding:2px 3px;position:relative"> <div style="position:absolute;font-size:9px;top:1px;right:1px">'+time_str2(status_hist[i].time)+'</div>'+status_hist[i].txt+'</div>';
	}

	return x;
}

function hide_loading()
{
	var el=document.getElementById("loading");
	if(el) el.style.display="none";
}

function juggle_ui(el,insert_at)
{
	var frag=document.getElementById(el);
	frag=panel_correct(frag);
	var node=document.getElementById(insert_at);
	node=panel_correct(node);
	node.parentNode.insertBefore(frag,node);
}


# QQSEL
# Not actually sure if this is required...
function alloc_sel_main(jmsg,fld_id,fld_type)
{
	var sel=[];
	sel.push(jmsg.cache_mid);
	sel.fld_id=fld_id;
	sel.fld_type=fld_type;
	return sel;
}

function find_sel(nowarn, xiid, xfld, xfid)
{
	var sel=[],node,row;
	var jmsg=sw.active.jmsg;
	if (sw.is_popup){
		return sw_win.alloc_sel_main(jmsg,jmsg.fld_id,jmsg.fld_type);
	}
	if (class_contains(sw.active,'message')){
 		sel.push(jmsg.cache_mid);
		sel.fld_id=jmsg.fld_id;
		sel.fld_type=jmsg.fld_type;
		sel.fid=jmsg.fid;
		sel.ident=jmsg.ident;
		return sel;
 	}
 	
 	if (sw.util.fldmsg_current&enFLD){	// QQQCC
		sel=gs_find_sel(sw.ml);
		if(sw.sel_all){
			sel.sel_all=true;
			sel.nav_total=sw.nav_total;
		}
 	}else{
 		sel.push(gs_cursor_mid(sw.ml));
 	}
 	
	if (sel.length==0) {
		if (!nowarn) {x_alert('$$st_select_some$$');}
		return U;
	}
 	
 	if(xiid){
# 		Account already switched when saving cached selection! does not need fld_type??
		sel.ident=xiid;
		sel.fld_id=xfld;
		sel.fid=xfid;
 	}else{
		sel.fld_id=sw.fld_id;
		sel.fld_type=sw.fld_type;
		sel.ident=sw.ident;
		sel.fid=sw.fid;
 	}
	return sel;
}

function make_sel(fld_id,mid)
{
	var sel=[mid];
 	sel.fld_id=fld_id;
 	sel.fld_type=sw.fld_type;
	sel.ident=sw.ident;
	sel.fid=sw.fid;
 	return sel;
}

function find_pending(mid)
{
	var pending=[];
	var nodes=sw.msgs_panelist.getElementsByTagName('input');
	for (var i = 0; i < nodes.length; i++) {
	  node = nodes[i];
	  row=sel_to_row(node);
	  if (class_contains(row,'pending'))
	  	pending.push(sel_to_mid(node));
	}
	return pending;
}


function ml_find_row(o,node){ return ancestor_by_tag(node,'tr');}

# QQGSEL msglist generics
function sel_to_row(node){ return ancestor_by_tag(node,'tr');}
function sel_to_mid(node){ return node.id.substring(4);}
function row_to_mid(node){ return node.getAttribute('msg_id')};

function row_to_star(node){};
function row_to_sel(node){};
function row_to_subject(node){};
function row_to_size(node){};
function row_to_labels(node){};
function row_to_comment(node){};
function row_to_email(node){};
function row_to_address(node){};


function row_to_star_n(node){ if(!node) return null; return node.childNodes[0].firstChild.firstChild;}
function row_to_sel_n(node){ if(!node) return null; sw.sel_col=1; return node.childNodes[sw.sel_col].firstChild;}
function row_to_subject_col_n(node){ return node.childNodes[4].firstChild.firstChild;}
function row_to_subject_n(node){ return row_to_subject_col_n(node).childNodes[3].firstChild;}
function row_to_size_n(node){ return node.childNodes[5];}
function row_to_labels_n(node){ return row_to_subject_col_n(node).childNodes[2];}
function row_to_email_n(node){ return node.childNodes[3].firstChild.firstChild.firstChild.title;}
function row_to_address_n(node){ return node.childNodes[3].firstChild.firstChild.firstChild;}
function row_to_comment_n(node){ return row_to_subject_col_n(node).childNodes[0];}


function list_fns_init()
{
	if(pref.preview=='horiz'){
		row_to_star=row_to_star_w;
		row_to_sel=row_to_sel_w;
		row_to_subject=row_to_subject_w;
		row_to_size=row_to_size_w;
		row_to_labels=row_to_labels_w;
		row_to_email=row_to_email_w;
		row_to_address=row_to_address_w;
		row_to_comment=row_to_comment_w;
	}else{
		row_to_star=row_to_star_n;
		row_to_sel=row_to_sel_n;
		row_to_subject=row_to_subject_n;
		row_to_size=row_to_size_n;
		row_to_labels=row_to_labels_n;
		row_to_email=row_to_email_n;
		row_to_address=row_to_address_n;
		row_to_comment=row_to_comment_n;
	}
}


function work_out_from(jmsg)
{
	var o,txt;
	if(sw.is_popup) return sw_win.work_out_from(jmsg);

	if (pref_reply.indexOf("@")!=-1) {
		txt=pref_reply;
	}else if (pref_reply.length>1){
		txt=pref_reply + " <"+email+">";
	}else{
		txt=email;
	}
	
	if(jmsg && jmsg.ident && sw.identities){
		var ident=sw.identities[jmsg.ident];
		if(!ident) return txt;
		if(jmsg.ident>1){
			txt=ident.name + " <"+ident.email+">";
		}
		if(!jmsg.sig_id && ident.sig_id){	// QQSIG
			jmsg.sig_id = ident.sig_id;
		}
	}
	return txt;
}


function apply_quick_search(txt)
{
	var count=0;
	var x,matches;
	var match=txt.toLowerCase();
	var c1=match.substr(0,1);
	if(c1=='#' || c1=='@' || c1=='$' || match.indexOf(' or ')!=-1 || match.indexOf(' not ')!=-1 || match.indexOf(' and ')!=-1){
		return apply_quick_search2(match);
	}
	var nodes=msglist_rows(sw.ml.list_root);
   	for(var i=0; i < nodes.length; i++){
        var node = nodes[i];
		x=node.innerHTML.toLowerCase();
        if(x.indexOf(match) != -1){
            class_remove(node,"hidden");
        }else{
	        class_add(node,"hidden");
	        count++;
        }
    }
    return count;
}
function apply_quick_search2(whole_match)
{
	var count=0;
	var x,match,node,wanted,want_one,or_match,not_match;
	var matches=whole_match.split(' ');
	var plain=true;
	for(var i=0; i < matches.length; i++){
		var match=matches[i];
		if(match=='and' || match=='or' || match=='not') plain=false;
	}
	var nodes=msglist_rows(sw.ml.list_root);
   	for(var i=0; i < nodes.length; i++){
        node = nodes[i];
        wanted=true;
		x=node.innerHTML.toLowerCase();
		if(plain){
			for(var j=0;j<matches.length;j++){
				match = matches[j];
				if(match.length==0) continue;
				want_one = x.indexOf(match) != -1;
				wanted=wanted&&want_one;
			}
		}else{
			or_match=not_match=false;
			for(var j=0;j<matches.length;j++){
				match = matches[j];
				if(match.length==0) continue;
				if(match=='and') continue;
				if(match=='or'){ or_match=true; continue; }
				if(match=='not'){ not_match=true; continue; }
				
				want_one = x.indexOf(match) != -1;
				if(or_match){
					wanted=wanted||want_one;
				}else if(not_match){
					wanted=wanted&&!want_one;
				}else{
					wanted=wanted&&want_one;
				}
			}
		}
        if(wanted){
            class_remove(node,"hidden");
        }else{
	        class_add(node,"hidden");
	        count++;
        }
    }
    return count;
}
function swcmd_s(input,e)
{
	swcmd(input.value,e,input);
	if(input.value=='sw_copy' || input.value=='sw_move'){
#		do nothing
	}else{
		input.options[0].selected = true;
	}
}
function swcmd_c(ctl,e)
{
	var action=ctl.value;

	if (action=='swc_new') 	contacts_new();
	else if (action=='swc_import')	contacts_import(1);
	else if (action=='swc_export')	contacts_export(1);
	else if (action=='swc_new_shared')	contacts_new_shared();
	else if (action=='swc_copy')	contacts_copy_shared();
	else if (action=='swc_refresh')	cm_contacts_refresh(false);	
	else if (action=='swc_print')	cm_contact_print();	
	else if (action=='swc_printlist')	cm_contact_printlist();	
	else if (action.length>0)
		alert('Sorry  not yet implemented.');

	if(action=='sw_copy' || action=='sw_move'){
#		do nothing
	}else{
		ctl.options[0].selected = true;
	}
}

function options_init(opt)
{
	option_mode_onchange(pref.mode,true);
	usercgi_summary();
	toolbar_buttons_init(pref.toolbar_buttons);
	user_cgi_iframe('usercgi_spam_iframe')
	
	var tb=dge("etbar");
	if(!tb) return;
	var ed=dge("eframe");
	tb.id='etbar_sig';
	ed.id='eframe_sig';
	var xed=ed.parentNode;
	xed.id='xeframe_sig';
	xed.tbar=tb;
	
	if(opt.hide_filtering)
		class_add(dge('ot2'),'hidden');

	if(opt.lock_options_basic){
		class_add(dge('ot3'),'hidden');
		class_add(dge('ot5'),'hidden');
	}
	if(pref.editor_textonly){
		init_editor('eframe_sig');
		var et=xed.firstChild;
		setTimeout(function(){
			et.style.width=px(xed.offsetWidth-24);
			et.value=dge('pref_signature').value; 
		},5);
		
	}else{
		tb.eframe=ed;
		tb.field_switch=dge('editor_switch_button');
		setTimeout(function(){
			var xwin = init_editor('eframe_sig');
			var xdoc=xwin.document;
			if(isWebkit){
#				Hack to fix weird "not scrolling" bug in Safari & chrome 
				xdoc.body.innerHTML = dge('pref_signature').value;			
			}else{
				xdoc.open();
				xdoc.write('<html><head>');
				xdoc.write('<style>');
				xdoc.write(' P {margin:0px;padding:0px;}');
				xdoc.write(' body {FONT-SIZE: 11pt;FONT-FAMILY:Arial,Helvetica,sans-serif;background:white;}');
				xdoc.write('</style></head>');
				xdoc.write('<body>'+dge('pref_signature').value+'</body></html>')
				xdoc.close();
			}

		},5);
	}
}
function option_mode_onchange(type,init)
{
	var form=document.options;
	var o=form.pref_preview;
	if (type=='web'){
		if(!init){
			radio_set(form.pref_preview,'none');
			radio_set(form.pref_windows,'inline');
		}		
		class_add(document.getElementById('preview_web_disable'),'option_disabled');
		o[0].disabled=o[1].disabled=true;
	}else{
		if(!init){
			radio_set(form.pref_preview,'vert');
			radio_set(form.pref_windows,'popup');
		}
		class_remove(document.getElementById('preview_web_disable'),'option_disabled');
		o[0].disabled=o[1].disabled=false;
	}		
}

// Give the server 200 ms to respond before we allow the user to do other things :-)
var send_timer;
function x_hide_msg_soon(oMessage,sel)
{
	if (send_timer)	clearTimeout(send_timer);
	send_timer=setTimeout(function(){
		if (sel) window_manager_minimise(oMessage);	
		message_done_action(sel);
	}
	,200);
}

# Set "Loading..." string in message list and preview panes
var loading_timer;
function set_loading(type){
	var el=dge(type);
	var h;
	var html=||iftrue(loading_animate_dev)||'<div class="wait_dots"><div class="dot1"></div><div class="dot2"></div><div class="dot3"></div></div>'||else||'$$st_pane_loading$$'||endif||;

	h=el.offsetHeight;
	if(type=="message_preview"){ 
		sw.msgs_preview.innerHTML="";
	}else{
		sw.msgs_panelist.innerHTML="";	
		dge('msg_navigator').innerHTML='';
	}
	loading_timer=setTimeout(function(h){
			var el=dge(type);
			el.innerHTML=html;
		},100);

}
function doneloading(){
	clearTimeout(loading_timer);
}

function find_msgs(limit)
{
	var sel=[];
 	var nodes=sw.msgs_panelist.getElementsByTagName('input');
	var n=nodes.length;
	if(limit && n>limit) n=limit;
	for (var i = 0; i < n; i++) {
		var node = nodes[i];
		if (node.id.substring(0,4)!="sel_") continue;
		var row=sel_to_row(node);
		if(class_contains(row,'hidden')) continue;
		sel.push(sel_to_mid(node));
	}
	sel.fld_id=sw.fld_id;
	sel.ident=sw.ident;
	sel.fid=sw.fid;
	return sel;
}


function fld_expand(e,myfld,el)
{
	dbg('fld expand')
//	if (!e) e = window.event
	if(!el){
		var t = target(e);
		var el = ancestor_by_tag(t,'li');
	}
	var v_old,v_new;
	if (class_contains(el,"open")){
		v_old="open";v_new="closed";
	}else{
		v_old="closed";v_new="open";
	}
	class_remove(el,v_old);
	class_add(el,v_new);
	if(class_contains(el,'tog_save')){
		ajax_pref_save('pref_fldopen_'+(el.getAttribute('cm_gid')=="All Contacts"?'contacts':'addresses')+'='+v_new);
	}else if (class_contains(el,'myfld')){
		ajax_pref_save("pref_fldopen="+v_new);
	}else if (class_contains(el,'ltree')){
		ajax_pref_save("pref_fldopen_label="+v_new);		
	}else if (class_contains(el,'stree')){
		ajax_pref_save("pref_fldopen_search="+v_new);		
	}
	
	if(e)stopEvent(e);
	return false;
}


function for_each_msg(msgs,action,param)
{
	var fn;
	if(action=='pending') {
		fn=function(o){class_add(o,'action_pending');}
	}else if (action=='nopending'){
		fn=function(o){class_remove(o,'action_pending');}
	}else if(action=='pending_hide') {
		fn=function(o){class_add(o,'action_pending');if(!pref.no_pending_hide)class_add(o,'action_pending_hide');}
	}else if (action=='nopending_hide'){
		fn=function(o){class_remove(o,'action_pending');if(!pref.no_pending_hide)class_remove(o,'action_pending_hide');}
	}else{
		fn=action;
	}
	if(!fn)return;
	for (var i=0;i<msgs.length;i++){
		var sel=dge('sel_'+msgs[i]);
		if (!sel) continue;	// may already have been removed
		var node = sel_to_row(sel);
		fn(node,msgs[i],param);
	}
}

function messages_text(msgs){
	var count=(msgs.sel_all)?msgs.nav_total:msgs.length;
	return (count>1?count+' ':'')+'Message'+(count>1?'s':'')	
}



# ****************************************************************************
# Second half is utility functions that should be split into seperate library


function ClientHeight(){
	var y=500
	if (self.innerHeight)
		y = self.innerHeight
	else if (document.documentElement && document.documentElement.clientHeight)
		y = document.documentElement.clientHeight
	else if (document.body)
		y = document.body.clientHeight
	return y
}
function ClientWidth() {
  var w=0;
#  if(Op6Dn) w=window.innerWidth;
#  else if(IE4Up && document.documentElement && document.documentElement.clientWidth)
  if(document.documentElement && document.documentElement.clientWidth)
    w=document.documentElement.clientWidth;
  else if(document.body && document.body.clientWidth)
    w=document.body.clientWidth;
  else if(Def(window.innerWidth,window.innerHeight,document.height)) {
    w=window.innerWidth;
    if(document.height>window.innerHeight) w-=16;
  }
  return w;
}

var CLASSNAME = "className";

function class_remove(o,name){
	if(o[CLASSNAME]==undefined) debugger;	
	o[CLASSNAME] = o[CLASSNAME].replace(' '+name,'').replace(name,'');
}
function class_add(o,name){
    var val = o[CLASSNAME];
	if (val.indexOf(name) == -1) 
		o[CLASSNAME] += (val?' ':'')+name;
}
function class_contains(o,name){
    return (o[CLASSNAME].indexOf(name) != -1);
}
function class_set(o,name){
    o[CLASSNAME]=name;
}
function show_hide(o,show)
{
	if(show){
		class_remove(o,'hidden');
	} else {
		class_add(o,'hidden');
	}
}
function class_update(o,txt,show)
{
	if(show){
		class_add(o,txt);
	} else {
		class_remove(o,txt);
	}
}
function show_hide2(o,show)
{
	if(show){
		o.style.display = 'block';
	} else {
		o.style.display = 'none';
	}
}
function elH(o,hidden)
{
	if(hidden){
		class_add(o,'hidden');
	} else {
		class_remove(o,'hidden');
	}
}
function elS(o,show)
{
	if(show){
		class_remove(o,'hidden');
	} else {
		class_add(o,'hidden');
	}
}
function class_ra(o,remove,add)
{
	if(remove) class_remove(o,remove);
	if(add) class_add(o,add);
}
function class_add_id(id,txt)
{
	var el=dge(id);
	if(!el) return;
	class_add(el,txt);
}

function popup_sizing(w,h) 
{
	var left = (screen.width/2)-(w/2);
	var top = ((screen.height/2)-(h/2))*(2/3);
	return 'width='+w+',height='+h+',top='+top+',left='+left;
} 

function open_popup(cmd,nowarn,opt)
{	
	if(!opt) opt={};
	var sizing=popup_sizing(800,600);
	if(opt.width&&opt.height) sizing=popup_sizing(opt.width,opt.height);
	var new_win = window.open(cgibase+cmd,'','dependent=1,hotkeys=0,menubar=0,personalbar=0,resizable=1,scrollbars=1,'+sizing+',status=0,titlebar=0,toolbar=1,z-lock=1');	
	if (!new_win&&!nowarn) x_alert("Popup could not be opened. If you have a popup blocker please allow popups.");
	return new_win;
}
function open_popup2(cmd,nowarn)
{
	var new_win = window.open(cmd,'','dependent=1,hotkeys=0,menubar=0,personalbar=0,resizable=1,scrollbars=1,'+popup_sizing(700,500)+',status=0,titlebar=0,toolbar=1,z-lock=1');	
	if (!new_win&&!nowarn) x_alert("Popup could not be opened. If you have a popup blocker please allow popups.");
	return new_win;
}
function open_download(cmd)
{			
	document.location=cgibase+cmd;	
}



function radio_value(radio)
{
	var n;
	for (n=0; n<radio.length; n++)	{
		if (radio[n].checked)
			return radio[n].value;
	}
}
function radio_set(radio,val)
{
	var n;
	for (n=0; n<radio.length; n++)	{
		radio[n].checked=(radio[n].value==val);
	}
}
function radio_disable(radio,val)
{
	var n;
	for (n=0; n<radio.length; n++)	{
		radio[n].disabled=true;
	}
}

function target(e){
	var src;
	if(e.target){
		src = e.target;
	}else if(e.srcElement){
		src = e.srcElement;
	}
	if (src.nodeType==3) src = src.parentNode;
	return src;
}
# Find parent of an object
function pe(e){
	return e.parentNode?e.parentNode:e.parentElement;
}


function set_instance(node_name,instance_id)
{
	var node=document.getElementById(node_name);
	node.id=node.id+instance_id;
	return node;
}

# Support for dynamic switching of css files
var included_files = new Array();
function include_once(script_filename) {
  if (!in_array(script_filename, included_files)) {
    included_files[included_files.length] = script_filename;
    include_dom(script_filename);
  }
}
function include_dom(script_filename) {
  var html_doc = xdoc.getElementsByTagName('head').item(0);
  t=script_filename.substring(script_filename.lastIndexOf('.')+1);
  if (t=='js'){
    var file = xdoc.createElement('script');
    file.setAttribute('language','javascript');
    file.setAttribute('type','text/javascript');
    file.setAttribute('src',script_filename);
  }else if (t=='css'){
    var file = xdoc.createElement('link');
    file.setAttribute('rel','stylesheet');
    file.setAttribute('type','text/css');
    file.setAttribute('href',script_filename);
  }
  html_doc.appendChild(file);
  return false;
}
function in_array(needle, haystack) {
  for (var i = 0; i < haystack.length; i++) {
    if (haystack[i] == needle) {
      return true;
    }
  }
  return false;
}

function pos_window_width(){
    return (window.innerWidth)?window.innerWidth:document.body.clientWidth;
}

function dummy_action()
{
	dbg('dummy action clicked');
}
# Grab the first two lines from web request for debug output
function firstlines(txt,type){
	return '';
	var i, line1, line2;
	var lines=txt.split('\n');
	for (i in lines){
		if (lines[i].length>0)
			break;
	}
	line1=lines[i]; line2=lines[++i]; 
	if (type=='html'){
		line1=line1.replace(/</, "&lt;").replace(/>/, "&gt;");	// make sure we can see html comments in the dbg console
		if (line2)
			line2=line2.replace(/</, "&lt;").replace(/>/, "&gt;");
	}	
	return line1+" "+line2;
}
function new_anchor2(el,insert_at)
{
	var frag=document.createElement("span");
	frag.className = el+'_class';
	frag.id = el+'_id';
	var node=document.getElementById(insert_at);
	node.parentNode.insertBefore(frag,node);
	return frag;
}
function new_anchor(type,content,node)
{
	var frag=document.createElement(type);
	frag.innerHTML=content;
	if(!node) node=document.body;
	node.appendChild(frag);
#	frag.className = el+'_class';
#	frag.id = el+'_id';	
	return frag;
}
function new_anchor_b4(type,content,b4)
{
	var frag=document.createElement(type);
	frag.innerHTML=content;
	b4.parentNode.insertBefore(frag,b4);
	return frag;
}
function new_anchor3(el,insert_at)
{
	var frag=document.createElement("div");
	frag.className = el+'_class';
	frag.id = el+'_id';
	var node=document.getElementById(insert_at);
	node.appendChild(frag);
	return frag;
}
function new_anchor4(tag,el,node)
{
	var frag=document.createElement(tag);
	frag.className = el+'_class';
	frag.id = el+'_id';
	node.parentNode.insertBefore(frag,node);
	return frag;
}

function new_anchor_before(el,insert_at)
{
	var frag=document.createElement("div");
	frag.className = 'el_class';
	frag.id = 'el_id';
	var node=document.getElementById(insert_at);
	node=panel_correct(node);
	node.parentNode.insertBefore(frag,node);
	return frag;
}
function new_button(name,id,node)
{
	var frag=document.createElement('input');
	frag.setAttribute('type', 'button');
	frag.setAttribute('name', name);
	frag.onclick=function(){dlg_clk(id)};
	node.parentNode.insertBefore(frag,node);
	return frag;
}
function btn_set(o,name,cname,width)
{
	if(name) o.value=name;
	if(width!=U) o.style.width=(width>0?px(width):'');
	if(cname) o.className=cname;
}

function first_child(node){
	var el;
	el=node.firstChild;
	if (!el.id &&!el.className)
		el=el.nextSibling;
	return el;
}

function remove_children(node){
	if (!node.hasChildNodes()) return;
    while(node.childNodes.length>=1){
        node.removeChild(node.firstChild);
    } 
}

function px(value){
	if (value<=0) return "1px";
	return value+"px";
}
function nodef(e){return false}
function dodef(e){return true}
function stop_def_action(e){	// stopEvent
	if (e.preventDefault) e.preventDefault()
	else if (window.event.returnValue) window.event.returnValue=false
	if (e.stopPropagation) e.stopPropagation()
	e.cancelBubble = true
}

function stopEvent(e) {
	if(!e) return;
	
	//e.cancelBubble is supported by IE - this will kill the bubbling process.
	e.cancelBubble = true;
	e.returnValue = false;

	//e.stopPropagation works only in Firefox.
	if (e.stopPropagation) {
#DOES NOT GET CALLED	
		dbg('*Q* stopEvent isFF='+isFF)
		if(isFF)ignore_one_hide=true;
		e.stopPropagation();
		e.preventDefault();
	}
#	return false;
}
function stopBubble(e) {
	if(!e) var e = window.event;
	e.cancelBubble = true;
	if (e.stopPropagation) {
		e.stopPropagation();
	}
}



# Play one of the named sounds in the Flash based sound file
function play_sound(type)
{
    flash_sound('/MySoundPlayer', 'stop');
    flash_sound('/MySoundPlayer', 'start_'+type);
}

function pos_window_height(){
    return (window.innerHeight)?window.innerHeight:document.body.clientHeight;
}
function pos_scroll_height(){
    return (window.pageYOffset)?window.pageYOffset:document.body.scrollTop;
}
function doc_scroll_height(win,doc){
    return (win.pageYOffset)?win.pageYOffset:doc.body.scrollTop;
}

function cloneObject(obj) {
	if (obj==undefined) return undefined;
  	var newObj = (obj instanceof Array) ? [] : {};
    for (i in obj) {
        if (typeof obj[i] == 'object') {
            newObj[i] = cloneObject(obj[i]);
        }else{
        	newObj[i] = obj[i];
        }
    }
    return newObj;
}

var time_calls=0;
var time_bad=0;
function time()
{
	return Math.round(mtime()/1000);
}
function mtime()
{
	time_calls++;	
#	try{
	return new Date().getTime();
#	}catch(ex){
#		// getTime sometiems results in infinitely recursive getTimeOverride Chrome 4.0.223.16 ??
#		return time_bad++;
#	}
}

function time_str()
{	
	var now = new Date();
	var hrs=now.getHours();
	var mins=zero_prefix(now.getMinutes());
	var ap=(hrs>=12?"PM":"AM");
	if (hrs==0) hrs=12;
	if (hrs>12) hrs-=12;
	return hrs+':'+mins+' '+ap;
}
function time_str2(now)
{	
	if(!now) now=mtime();
	var ticks=Math.round((now%1000)/10);
	var time=(window.clock ? (clock(now)+'.'+prefix_time(ticks)) : ('('+ticks+')'))
	return time;
}	

function zero_prefix(n)
{
	return (n<10?'0':'')+n;
}

# Generic css based div tables nesting
function xrow_toggle(el,e)
{
	var el=target(e);
	while(!class_contains(el,'xrow')) {el=el.parentNode;}
	var r=el.parentNode;
	var v_old,v_new;
	dbg('y el.id='+el.id+' class='+el.className+' el='+el);
	if (class_contains(r,"open")){
		v_old="open";v_new="closed";
	}else{
		v_old="closed";v_new="open";
	}
	class_remove(r,v_old);
	class_add(r,v_new);
	for (;el;el=el.nextSibling){
		if(!class_contains(el,'xrow_container')) continue;
		if(v_new=='open')
			class_remove(el,'hidden');
		else
			class_add(el,'hidden');
	}
	stopEvent(e);
}


function custom_edit_disable(el)
{
	el.readOnly=true;
	class_add(el,'custom_edit_disabled');
	class_add(el.parentNode,'custom_edit_disabled');
}

function customise_edit(el,type)
{
	var new_ctl;
	if(type=='fancy' && pref.no_fancy_rcpt) type='plain';
	if(type=='plain'){
#		Plain customised edit controls to make layout of horizontal sizing nicer
		var id=el.id, idx=el.tabIndex;
		var label_div=el.parentNode.previousSibling;
		var edit_div=el.parentNode;
		label_div.innerHTML="<div class=\"contact_hdrleft\">"+label_div.innerHTML+"</div>";
#		This seemingly useless div is required to keep IE formatting happy :-(
		edit_div.innerHTML="<div>"+edit_div.innerHTML+"</div>";
		new_ctl=dge(id);
		class_add(new_ctl,'custom_edit_inner');
		class_add(new_ctl,'no_round');
		class_add(edit_div,'custom_edit_outer');
	}else{
#		Turn our edit fields into full blown address lister fields		
		var id=el.id, idx=el.tabIndex;
		var label_div=el.parentNode.previousSibling;
		var edit_div=el.parentNode;
		
		label_div.innerHTML="<a href=\"#\" onclick=\"cp_show(\'"+id+"_fancy\')\" style=\"color:black;font-weight:bold;\"><div class=\"contact_button\">"+
					label_div.innerHTML+"</div></a>";

		edit_div.innerHTML =		 
				 "<div id=\""+id+"_fancy\" class=\"contact_lister\" onclick=\"cl_outer_onclick(this,event)\" ondblclick=\"cp_show(\'"+id+"_fancy\')\">"
				+	"<div class=\"cl_ruler\"><span id=\"text_size\"></span></div>"
				+	"<ul style=\"list-style-type:none;margin:0;padding:0;\">"
				+		"<li><textarea id=\""+id+"\" tabindex=\""+idx+"\" class=\"cl_text no_round\" onkeydown=\"cl_onkeydown(this,event)\" onkeyup=\"cl_onkeyup(this,event)\" onpaste=\"cl_onpaste(this,event)\"></textarea></li>"
				+	"</ul>"
				+	"<input type=hidden id=\""+id+"_plain\">"
				+"</div>";
		new_ctl=dge(id);
		new_ctl.edit_fancy=true;
		new_ctl.ruler=new_ctl.parentNode.parentNode.previousSibling;
		edit_div.firstChild.edit_li=new_ctl.parentNode;
	}
	return new_ctl;
}

# return the value of the to / cc / bcc addressing field
function fancy_edit_value(ctl)
{
	if(!ctl.edit_fancy)
		return [ctl.value];

	var a=ctl.value!=''?[ctl.value]:[];
	var el=ctl.parentNode;
	for (var el=ctl.parentNode.previousSibling;el;el=el.previousSibling){
		a.unshift(el.email);
	}
	
	return a;
}
function fancy_edits_validity(arr)
{
	var a;
	var valid=0, invalid=0;
	for (var i=0;i<arr.length;i++){
		var ctl=arr[i];
		if(!ctl.edit_fancy) return [1,0];

		var el=ctl.parentNode;
		for (var el=ctl.parentNode.previousSibling;el;el=el.previousSibling){
			if(class_contains(el,'rcpt_invalid')){
				invalid++;
			}else{
				valid++;
			}
		}
	}	
	return [valid,invalid];
}



function fancy_edit_set(ctl,rcpts,strip)
{
	if(!ctl.edit_fancy)
		return ctl.value=rcpts.join(', ');

	for(var i=0;i<rcpts.length;i++){
		if(rcpts[i].length==0) continue;
		if(strip && rcpts[i].indexOf(email)!=-1) continue; 
		cl_add_contact(text2contact(rcpts[i]),0,ctl.parentNode);
	}
}
function dispatch_click(el) {
	var evt;
	if(!el) return;
	if (document.createEvent){
		evt = document.createEvent("MouseEvents");
		evt.initMouseEvent("click", true, true, window,
				0, 0, 0, 0, 0, false, false, false, false, 0, null);
		evt._dispatched=true;
	}
	(evt)? el.dispatchEvent(evt):(el.click && el.click());
}


function prefix_time(i){
	if (i<10){i="0" + i;}
	return i;
}

function clock(tm){
	var today=new Date(tm);
	return today.getHours()+':'+prefix_time(today.getMinutes())+':'+prefix_time(today.getSeconds());	
}


function log_element(el){
	if (!el) return undefined;
	return '{'+el.tagName+':id='+el.id+':class='+el.className+'}';
}


# Event handlers that make window.event object available in NON IE browsers 
function xadd_event(el, txt, fn)
{
	if(!fn) return;
	if (el.addEventListener){
		txt='on'+txt;
		fn._mozillaEventHandler = function(e)
		{
			window.event = e;
			var ret = fn();
			return e._returnValueSet && txt != "onbeforeunload" ? e.returnValue : ret
		};
		el.addEventListener(txt.slice(2), fn._mozillaEventHandler, false)
	}else if (el.attachEvent) {
		el.attachEvent('on' + txt, fn);
	}else{
		el['on'+txt] = fn;
	}
}
function xremove_event(el, txt, fn){
	if(!fn) return;
	if (el.removeEventListener){
		txt='on'+txt;
		if (fn._mozillaEventHandler) {
			var eh = fn._mozillaEventHandler;
			delete fn._mozillaEventHandler;
			el.removeEventListener(txt.slice(2), eh, false)
		}
	}else if (el.detachEvent) {
		el.detachEvent('on' + txt, fn); 
	}else{
		e['on'+txt] = "";
	}
}


# Compact event capturing implementation that fits my mindset
var capture_evts = ["click","mousedown","mouseup","mousemove","mouseover","mouseout"];
var capture_current;
function capture_cb(e)
{
#	dbg("capture cb1");
	if (e.isCapturing) return;
#	dbg("capture cb2");
	var evt = window.document.createEvent("MouseEvents");
	evt.initMouseEvent(e.type, e.bubbles, e.cancelable, e.view, e.detail, e.screenX, e.screenY, e.clientX,
						e.clientY, e.ctrlKey, e.altKey, e.shiftKey, e.metaKey, e.button, e.relatedTarget);
	evt._data = e.target;
#	dbg(e.type+":: capture cb3 "+e.target+' tag='+e.target.tagName+' id='+e.target.id+' class='+e.target.className+' parent ['+e.target.parentNode.tagName+']');
#	dbg("capture cb4 "+capture_current+' tag='+capture_current.tagName+' id='+capture_current.id);
	evt.isCapturing = true;
	capture_current.dispatchEvent(evt)
};
function capture_events(el)
{
	dbg("capture start");
	if (el.setCapture) {el.setCapture(); dbg('capture_start (native)'); return;}
	dbg("capture start2");
	capture_current=el;
#	dbg("capture start3 : "+capture_evts.length);
	for (var i=capture_evts.length-1; i>=0; i--) window.addEventListener(capture_evts[i], capture_cb, true);
};

function capture_release(el)
{
	dbg("capture end");
	if (!el) return;
	if (el.releaseCapture) {el.releaseCapture(); dbg('capture_release (native)'); return;}
	if (!capture_current) return;
	for (var i=capture_evts.length-1; i>=0; i--) window.removeEventListener(capture_evts[i], capture_cb, true);
	capture_current = null
};



# Not yet reviewed function
function get_location(b, c)
{
    c = c || { };
    var d = c.x || 0, e = c.y || 0;
    for (var a = b; a && a.tagName != "BODY"; a = a.offsetParent) {
        d += a.offsetLeft; e += a.offsetTop;
#        dbg('*** a.id='+a.id+' a.tagName='+a.tagName+' a.left='+a.offsetLeft+' a.top='+a.offsetTop+' ltot='+d+' ttot='+e)
    }
    function f(a, b) { return this.left <= a && a <= this.right && this.top <= b && b <= this.bottom }
    return {left: d,top: e,right: d + (b ? b.offsetWidth : 0),bottom: e + (b ? b.offsetHeight : 0),containsPoint: f};
}

function scroll_to(e, a)
{
    var b = parseInt(e.offsetTop), d = b + parseInt(e.offsetHeight), 
    	c = parseInt(a.scrollTop), f = c + parseInt(a.clientHeight);

    if (d - b > f - c){
    	a.scrollTop = b;	
    } else {
        if (d > f) a.scrollTop = Math.max(d - a.clientHeight, 0);
        if (b < c) a.scrollTop = b
    }
}

function selection_clear()
{
	try{
		if (document.selection){
			document.selection.empty();
			dbg('RANGES IE selection native')
		}else if (window.getSelection){		
			window.getSelection().removeAllRanges();
			dbg('RANGES cleared')
		}else{
			dbg('No selection handling functionality??');
		}
	}catch(e){}
}

function rtrim(val){
	while(val.charAt(val.length-1)==' ')
		val=val.substring(0,val.length-1);
	return val;
}

# Fudge function to force the redraw (nor refresh) of elements as sometimes they 
# do not get rendered when dynamically updating the page 
function force_redraw(el)
{
	el.style.display = 'none';
	el.style.display = 'block';
}	


function serialise(o,noblank,noquote)
{
	var quote=noquote?'':'\'';
	switch(typeof o){
		case 'object':
			return serialise_object(o,noblank);
		case 'string':
			return quote+encode_quotes(o)+quote;
		case 'number':
		case 'boolean':
			return quote+o+quote;
	}
}
function serialise_object(o,noblank)
{
	if (typeof o != 'object') return '';
	var a=[],k,i,tmp;
	if(o.length!=undefined){
#		Treat it as an array	
		for (i=0;i<o.length;i++) {
			var tmp=serialise(o[i],noblank);
			if(!tmp) continue;
			a.push(tmp);
		}
		return '['+a.join(',')+']';
	}else{
#		Treat it as an object
		if (noblank && o['value']=='') return undefined;
		for (k in o) a.push("'"+encode_quotes(k)+"':"+serialise(o[k],noblank));
		return '{'+a.join(',')+'}';
	}
}

function is_array(obj) {
   return (obj.constructor.toString().indexOf("Array") == -1) ?  false : true;
}
function is_string(obj) {
   return (typeof obj === 'string') ? true : false;
}
function pparent(el){
	if(!el) return undefined;
	return el.parentNode.parentNode;
}
function ppparent(el){
	if(!el) return undefined;
	return el.parentNode.parentNode.parentNode;
}

function remove_node(o)
{
	if (!o) return;
	o.parentNode.removeChild(o);
}

function el_info(el)
{
	if(!el) return el;
	return el+' type='+el.type+' tag='+el.tagName+' id='+el.id+' class='+el.className+' parent_tag='+el.parentNode.tagName;
}

function el_info2(el)
{
	if(!el) return el;
	return ' t='+el.tagName+' i='+el.id+' c='+el.className+' -> ('+el.parentNode.tagName+')';
}

function istrue(el)
{
	if(el==true) return true;
	if(el==false || el==undefined) return false;
	var txt=el.toLowerCase();
	if(txt=='true'||txt=='on') return true;
	return false;
}

function rcpts_as_plain(arr)
{
	return arr.join(', ');
}
function rcpts_as_html(arr)
{
	return encode_lt_gt(arr.join(', '));
}
function rcpts_as_param(arr)
{
	return xescape(arr.join(', '));
}
function str_trim(txt,len){
	if(txt==undefined||txt==null) return '';
	if(txt.length<len) return txt;
	return txt.substring(0,len)+'...';
}

function ctl_dynamic_info(ctl,custom){
	if(ctl.extra_info){
		class_add(ctl.extra_info,'hidden');
	}
	var el=dge('info__'+ctl.name+'__'+(custom?custom:ctl.value));
	if(el){
		ctl.extra_info=el;
		class_remove(el,'hidden');
	}
}

function ctl_dynamic_select(ctl,options,content)
{
	var i,o,j;
	for(i=ctl.options.length-1;i>=0;i--) ctl.remove(i);		

	var x=content[ctl.id];	
	for (i=0;i<options.length;i++) {
		o=new Option(x[options[i]],options[i]);
		ctl.options.add(o);
	}
}

function mouseX(evt) {
	if (evt.pageX) return evt.pageX;
	else if (evt.clientX) return evt.clientX + (document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft);
	else return null;
}
function mouseY(evt) {
	if (evt.pageY) return evt.pageY;
	else if (evt.clientY) return evt.clientY + (document.documentElement.scrollTop ? document.documentElement.scrollTop :document.body.scrollTop);
	else return null;
}
function parse_float_following(str,pfx)
{
	var i=str.indexOf(pfx);
	if(i!=-1){
		var v=parseFloat(str.substring(i+pfx.length));
		if(!isNaN(v))
			return v
	}
	return null
}

function get_focus_element(xdoc,xwin) 
{
	if (typeof window.getSelection === 'function') { 
		dbg('--> W3C DOM selection API available :)'); 
	} else { 
		if (typeof document.selection === 'object') { 
			dbg('--> IE selection API available :| ');
		} else { 
			dbg('--> No selection API available :( ');
		} 
	} 

#	dbg("fns getFocusElement");
	var inst = this.instance, doc, rng, sel, elm;
dbg('***1')
	if (isIE) {
#		// IE codepath
		rng = xdoc.selection.createRange();
		rng.collapse();
		elm = rng.item ? rng.item(0) : rng.parentElement();
	} else {
# 		// Non IE codepath
dbg('***2')
#		dbg("fns getFocusElement (non IE)");
#		if (!tinyMCE.isSafari && inst.isHidden())
#			return inst.getBody();
		sel=xwin.getSelection();
#		sel.collapseToStart();
dbg('***5 n=' + sel.rangeCount)
		elm=sel.focusNode;
#		rng=sel.rangeCount==0? xwin.getSelection() : sel.getRangeAt(0);
dbg('***5b')
#		elm=rng.commonAncestorContainer;
dbg('***6' +elm+'['+elm.innerHTML)
dbg('***6b' +elm.parentNode+'['+elm.parentNode.innerHTML)
#el_info(elm)

		return elm;
		
		
#commonAncestorContainer


		sel = this.selection.getSel();
		rng = this.selection.getRng();
dbg('***3')

		if (!sel || !rng){
			dbg("sel returning null as (!sel || !rng)");
			return null;
		}
dbg('***4')

		elm = rng.commonAncestorContainer;
		dbg("elm: elm has .nodeName="+elm.nodeName+" .nodeId="+elm.nodeId);

		// Handle selection a image or other control like element such as anchors
		if (!rng.collapsed) {
			// Is selection small
			if (rng.startContainer == rng.endContainer) {
				if (rng.startOffset - rng.endOffset < 2) {
					if (rng.startContainer.hasChildNodes())
						elm = rng.startContainer.childNodes[rng.startOffset];
				}
			}
		}

		// Get the element parent of the node
#		elm = tinyMCE.getParentElement(elm);
	}
	return elm;
}

||ifdef||_junk_||
	getSel : function() {
		var inst = this.instance;

		if (tinyMCE.isRealIE)
			return inst.getDoc().selection;

		return inst.contentWindow.getSelection();
	},

	getRng : function() {
		var s = this.getSel();

		if (s == null)
			return null;

		if (tinyMCE.isRealIE)
			return s.createRange();

		if (tinyMCE.isSafari && !s.getRangeAt)
			return '' + window.getSelection();

		if (s.rangeCount > 0)
			return s.getRangeAt(0);

		return null;
	},
||endif||

function dom_split(src,frag,pivot)
{
	var d,dup,next_parent;
	for(d;src!=pivot&&(next_parent=src.parentNode);){
		for(dup=next_parent.cloneNode(false);src.nextSibling;)
			dup.appendChild(src.nextSibling);
		frag&&dup.insertBefore(frag,dup.firstChild);
		frag=dup;
		src=next_parent;
	}
	return frag;
}

function sametext(v1,v2)
{
	if(v1==undefined||v2==undefined) return false;
	return remove_cr_lf(v1)==remove_cr_lf(v2);
}
function sametext_nc(v1,v2)
{
	if(v1==undefined||v2==undefined) return false;
	return remove_cr_lf(v1.toLowerCase())==remove_cr_lf(v2.toLowerCase());
}

function cmd_key(e)
{
	return isMac&&e.metaKey;
}
function ctl_cmd_key(e)
{
	return e.ctrlKey||(isMac&&e.metaKey);
}
function ctl_and_cmd_key(e)
{
	return e.ctrlKey&&((isMac&&e.metaKey)||((!isMac)&&e.altKey));
}

function ctl_opt_key(e)
{
	return e.ctrlKey||(isMac&&e.altKey);
}

function any_modifier(e)
{
	return e.ctrlKey || e.shiftKey || e.metaKey || e.altKey;
}
function primary_modifier(e)
{
	return e.ctrlKey || e.metaKey || e.altKey;
}
function single_modifier(e)
{
	if(e.shiftKey && !(e.ctrlKey || e.metaKey || e.altKey)) return true;
	if(e.ctrlKey && !(e.shiftKey || e.metaKey || e.altKey)) return true;
	if(e.metaKey && !(e.ctrlKey || e.shiftKey || e.altKey)) return true;
	return false;
}
function shift(e)
{
	return e.shiftKey;
}
function shift_alt(e)
{
	return e.shiftKey||(isMac&&e.altKey);
}
function with_shift_alt(e)
{
	return ((e.ctrlKey || e.metaKey) && (e.shiftKey || e.altKey)) || (e.shiftKey && e.altKey);
}
function n_mod(e)
{
	var n=0;
	if(e.ctrlKey) n++;
	if(e.metaKey) n++;
	if(e.altKey) n++;
	if(e.shiftKey) n++;
	return n;
}
function multi_mod(e)
{
	return n_mod(e)>1;
}
function keys_altonly(e)
{
	return e.altKey && !(e.shiftKey || e.metaKey);
}
function keys_2vert(e)
{
	return (e.shiftKey && e.ctrlKey) || (e.shiftKey && e.altKey);
}
function keys_2horiz(e)
{
	return (e.ctrlKey&&(e.altKey || e.metaKey)) || (e.altKey&&e.metaKey);
}

function cx_menu(e)
{
	return e.button==2 || (isMac&&e.ctrlKey&&!e.metaKey);
}

function select_el(el)
{
	var r,sel;
	if(isIE){
		r=document.selection.createRange();
		r.moveToElementText(el);
		r.select();
	}else{
		r=document.createRange();
		r.selectNodeContents(el);
		sel=window.getSelection();
		sel.removeAllRanges();
		sel.addRange(r);
	}
}

function do_anypopup_init()
{
	sw_win = window.opener;
	var pp=sw_win.pending_popups[window];
	if(!pp){
#	//	Just for what seems to be bug in Microsoft Edge!!		
		pp=sw_win.pending_popups[sw_win];
	}
	if (!pp){
		setTimeout(do_anypopup_init,20);
		return;
	}
	if(pp.type=='print'){
		var txt=pp.cb();
		if(txt) document.body.innerHTML=txt
		if(pp.extra=='format_boxes') format_boxes();
		document.body.style.scroll='normal';
		setTimeout(function(){self.print()},500);
	}else{
		alert('unknown popup action');
	}
}

function mymax(arr1,arr2)
{
	var l1=arr1&&arr1.length?arr1.length:0;
	var l2=arr2&&arr2.length?arr2.length:0;
	return Math.max(l1,l2);
}
function allow_scroll_arrow(e)
{
	switch(e.keyCode){
		case vkUpArrow:
		case vkDownArrow:
		case vkZ: break;		
		default:
			stopBubble(e);
	}
}

function msg_draft(mid)
{
	if(!mid) return false;
	var el=sel_to_row(dge('sel_'+mid));
	if(!el) return false;
	var val=el.getAttribute('msg_draft');
	if(val!='true') return false;
	return true;
}


||ifdef||__FOR_REFERENCE|||

# there are better functions available though...
String.format = function( text )
{
    //check if there are two arguments in the arguments list
    if ( arguments.length <= 1 ){
        //if there are not 2 or more arguments thereﾒs nothing to replace
        //just return the original text
        return text;
    }

    //decrement to move to the second argument in the array
    var tokenCount = arguments.length - 2;
    for( var token = 0; token <= tokenCount; token++ ){
        //iterate through the tokens and replace their placeholders from the original text in order
        text = text.replace( new RegExp( "\\{" + token + "\\}", "gi" ), arguments[ token + 1 ] );
    }
    
    return text;
};


document.write( String.format( "two tokens swapped, two args ({1},{0})<br />", "arg1", "arg2" ) );
document.write( String.format( "four tokens interwoven, two args ({0},{1},{0},{1})<br />", "arg1", "arg2" ) );

function str_repeat(i, m) { for (var o = []; m > 0; o[--m] = i); return(o.join('')); }
function sprintf() 
{
  var i = 0, a, f = arguments[i++], o = [], m, p, c, x;
  while (f) {
    if (m = /^[^\x25]+/.exec(f)) o.push(m[0]);
    else if (m = /^\x25{2}/.exec(f)) o.push('%');
    else if (m = /^\x25(?:(\d+)\$)?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(f)) {
      if (((a = arguments[m[1] || i++]) == null) || (a == undefined)) throw("Too few arguments.");
      if (/[^s]/.test(m[7]) && (typeof(a) != 'number'))
        throw("Expecting number but found " + typeof(a));
      switch (m[7]) {
        case 'b': a = a.toString(2); break;
        case 'c': a = String.fromCharCode(a); break;
        case 'd': a = parseInt(a); break;
        case 'e': a = m[6] ? a.toExponential(m[6]) : a.toExponential(); break;
        case 'f': a = m[6] ? parseFloat(a).toFixed(m[6]) : parseFloat(a); break;
        case 'o': a = a.toString(8); break;
        case 's': a = ((a = String(a)) && m[6] ? a.substring(0, m[6]) : a); break;
        case 'u': a = Math.abs(a); break;
        case 'x': a = a.toString(16); break;
        case 'X': a = a.toString(16).toUpperCase(); break;
      }
      a = (/[def]/.test(m[7]) && m[2] && a > 0 ? '+' + a : a);
      c = m[3] ? m[3] == '0' ? '0' : m[3].charAt(1) : ' ';
      x = m[5] - String(a).length;
      p = m[5] ? str_repeat(c, x) : '';
      o.push(m[4] ? a + p : p + a);
    }
    else throw ("Huh ?!");
    f = f.substring(m[0].length);
  }
  return o.join('');
}
||endif||

function $2()
{
	var i,len=arguments.length;
	var txt=string_table[arguments[0]];
	if(!txt) return '';
	for (i=1;i<len;i++){
		txt=txt.replace('%s',arguments[i]);
	}
	return txt;
}

var string_table={	// QQSTQQ
	'st_err_comms':'||web_encode_js(($$st_err_comms$$))||',
	'foo':'bar'
}

function err_general(chan,n)
{
	if(chan.status!=200 && chan.statusText.length>0){
		var txt = ''+chan.status+' - '+chan.statusText;
		if (chan.status==403){
			auth_error(txt);
		}
		return txt;
	}else{
		return err_comms(n);
	}
}
function err_comms(n)
{
	return $2('st_err_comms');
}
function object_length(o)
{
	if(!o) return 0;
	var j=0; 
	for (i in o) {j++;}
	return j
}
function size(bytes)
{
	var i = 0;
	while(1023 < bytes){
		bytes /= 1024;
		++i;
	};
	return  i ? bytes.toFixed(1) + ["", " KB", " MB", " GB", " TB"][i] : bytes + " bytes";
};

# Detect Flash version
function swf_id()
{
	var version=0;
	if(navigator.plugins && navigator.plugins.length>0){
		var type = 'application/x-shockwave-flash';
		var mimeTypes = navigator.mimeTypes;
		if(mimeTypes && mimeTypes[type] && mimeTypes[type].enabledPlugin && mimeTypes[type].enabledPlugin.description){
			txt = mimeTypes[type].enabledPlugin.description;
			dbg('FLASH id string: '+txt)
			var desc='Shockwave Flash ';
			var i=txt.indexOf(desc);
			if(i!=-1) version=parseInt(txt.substring(i+desc.length));
		}
	}else{
		try{
			var o = new ActiveXObject("ShockwaveFlash.ShockwaveFlash");
			if(!o.activeXError){
				version = 0;
				try{
					txt = o.GetVariable("$version");
					dbg('FLASH id string2: '+txt)
					var desc='WIN ';
					var i=txt.indexOf(desc);
					if(i!=-1) version=parseInt(txt.substring(i+desc.length));
				}catch(err){}
			}
		}catch(err){}
	}
	dbg('FLASH VERSION='+version);
	sw.swf_version=version;
}

function wincontext(txt)
{
	dbg(txt+' CONTEXT:'+(sw.is_popup?'POPUP':'MAIN'));
}

function set_xol(status,level)	//set_status
{
	var el = dge('xol_status');
	el.innerHTML = status;
}

# Colored checkbox functionality
var cbox_clicked;
function cbx(id,col,cb_name,sel)
{
#	end of line add class: icon_at
	return '<div id="'+id+'" class="cbox_outer '+(sel?'sel':'')+'" onmousedown="cbox_mousedown(this,event)" onmouseout="cbox_mouseout(this,event)" onmouseover="cbox_mouseover(this,event)" onclick="cbox_click(this,event)" cb_name="'+cb_name+'"><div class="cbox_col" style="background:'+col+';"></div><div class="cbox_bg"></div></div>'; 
}
function cbox_mousedown(o,e)
{
	o.cbox_mdown=true;
	o.cbox_cbpending=false;
	class_add(o,'active');
	stopEvent(e);
}
function cbox_mouseout(o,e)
{
	if(o.cbox_cbpending) return;
	class_remove(o,'active');	
}
function cbox_mouseover(o,e)
{
	if(!o.cbox_mdown) return;
	class_add(o,'active');	
}
function cbox_click(o,e)
{
	if(!e) e=window.event;
	o.cbox_mdown=false;
	var cb_name=o.getAttribute('cb_name');
	var ticked=!class_contains(o,'sel');
	cbox_assign(o,ticked);
	if(cb_name && cb_name!=U) {
		o.cbox_cbpending=true;
		cbox_clicked = o;
		cbox_ticked = ticked;
		eval(cb_name+'(e,cbox_clicked,ticked)');
	}
}
function cbox_assign(o,ticked)
{
	class_remove(o,'active');	
	if(ticked){
		class_add(o,'sel');	
	}else{
		class_remove(o,'sel');	
	}
}
function format_hr(hr)
{
	var txt=hr%12;
	if(txt==0) txt=12;
	var txt2=(hr>=0 && hr<12?"AM":"PM");
	return txt+'&nbsp;'+txt2;
}
function el_assign(txt,txt2)
{
	var el=dge(txt);
	if(!el) return;
	el.innerHTML=txt2;
}
/*
function calcTime(city, offset) {

    // create Date object for current location
    d = new Date();
    
    // convert to msec
    // add local time zone offset 
    // get UTC time in msec
    utc = d.getTime() + (d.getTimezoneOffset() * 60000);
    
    // create new Date object for different city
    // using supplied offset
    nd = new Date(utc + (3600000*offset));
    
    // return time as a string
    return "The local time in " + city + " is " + nd.toLocaleString();

}
*/

function ms2dvDZ(ms,allday,zulu)
{
	var txt=dt2dv(new Date(ms),zulu);
	if(allday) txt=txt.substr(0,8);
	return txt;
}
function ms2dvZ(ms)
{
	ms+=((new Date()).getTimezoneOffset() * 60000);
	return dt2dv(new Date(ms), true);
}
function ms2dv(ms,zulu)
{
	return dt2dv(new Date(ms),zulu);
}
function twodigit(txt)
{
	if(txt.length==2) return txt;
	return '0'+txt;
}
function dt2dv(d,zulu)
{
	var dy=d.getFullYear().toString();
	var dm=twodigit((d.getMonth()+1).toString());
	var dd=twodigit(d.getDate().toString());
	var dh=twodigit(d.getHours().toString());
	var dn=twodigit(d.getMinutes().toString());
	var ds=twodigit(d.getSeconds().toString());
	var tm=dy+dm+dd+'T'+dh+dn+ds;
	if(zulu) tm+='Z';
	return tm;
}
function dv2dt(txt)
{
	return new Date(txt.substr(0,4),txt.substr(4,2)-1,txt.substr(6,2),txt.substr(9,2),txt.substr(11,2),txt.substr(13,2),0);
}
function range_limit(p1,p2,p3)
{
	if(p2<p1) return p1;
	if(p2>p3) return p3;
	return p2
}
function jmsg2rcpt(jmsg)
{
	if(!jmsg.to || jmsg.to.length==0) return U;
	var txt=jmsg.to[0];
	var c=text2contact(txt)
	if (!c.email || c.email.length==0) return U;
	return c.email[0].value;
}	

function num_abbrev(num) 
{
	if (typeof num == 'number') {
		num = num.toString()
	}
	var len = num.length, last_char = num.charAt(len - 1), abbrev;
	if (len == 2 && num.charAt(0) == '1') {
		abbrev = 'th'
	} else {
		if (last_char == '1') {
			abbrev = 'st';
		} else if (last_char == '2') {
			abbrev = 'nd';
		} else if (last_char == '3') {
			abbrev = 'rd';
		} else {
			abbrev = 'th';
		}
	}
	return num + abbrev;
}

function for_each(msgs,action,param)
{
	var fn=action;
	for (var i=0;i<msgs.length;i++){
		var node = msgs[i];
		fn(node,msgs[i],param);
	}
}
function siblings(o)
{
	return o.parentNode.childNodes;
}

function dom_clear(id)
{
	var el=dge(id);
	if(!el) return;
	el.innerHTML='';
}

function text_to_date(txt)
{
	if(!txt||txt.length!=8) return txt;
	return txt.substring(0,4)+'-'+txt.substring(4,6)+'-'+txt.substring(6,8);
}
function text_to_time(txt)
{
	if(!txt||txt.length!=6) return txt;
	return txt.substring(0,2)+':'+txt.substring(2,4)+':'+txt.substring(4,6);
}
function msec_thisweek()
{
	return 60*60*24*7*1000;
}
function msec_month()
{
	return 60*60*24*35*1000;
}

function string_empty(s)
{
	if(!s) return true;
	if(s.length==0) return true;
	return false;
}
function hexToCanvasColor(hexColor,opacity)
{
    opacity=opacity || "1.0";
    hexColor=hexColor.replace("#","");
    var r=parseInt(hexColor.substring(0,2),16);
    var g=parseInt(hexColor.substring(2,4),16);
    var b=parseInt(hexColor.substring(4,6),16);
    return "rgba("+r+","+g+","+b+","+opacity+")";
}

function eventFire(el, etype)
{
   if (el.fireEvent) {
     (el.fireEvent('on' + etype));
   } else {
     var evObj = document.createEvent('Events');
     evObj.initEvent(etype, true, false);
     el.dispatchEvent(evObj);
   }
}

function first_alpha(txt)
{
	txt = txt.replace(/[ \t0-9]/g, "");
	if (txt.length==0) return "";
	return txt.charAt(0);
}

function isInt(value) 
{
  if (isNaN(value)) {
    return false;
  }
  var x = parseFloat(value);
  return (x | 0) === x;
}