/************************

Copyright (c) 2009
Rich Knopman

Use Subject to BSD license.  See http://richk.net/os/license.html

For full commented source, download the Objectsheet package at http://sourceforge.net/projects/objectsheet
*************************/
/* * * * * * * * * *../pgm/core.js * * * * * * * * * * * */

var SPLAY_BREAK_CHARS = 100;
var SPLAY_MAX_ITERS = 30000;
var SPLAY_MAX_LEVELS = 10;
function constrain(expr) {
  return eval(expr) ? "" : ";"+constrain.style+";";
}
constrain.style = "border:solid 1px red";
function hilite(expr, lo, hi) {
	if (lo == null || hi == null) {
		return expr? ";"+hilite.style+";" : "";
	} else {
		if (lo > hi) { var t=lo; lo=hi; hi=t; }
		return (expr >= lo && expr <= hi ? ";"+hilite.style+";":"");
	}
}
hilite.style = "background-color:#ff8";
function prevent(val, expr) {
	return expr ? "" : val;
}
function contains(expr, arg1, arg2) {
  var a = +eval(expr);
  if (arguments.length==2) {
		var vals = arguments[1].toString().split(/\s*,\s*/);
		for (var i=0; i<vals.length; i++) {
			if (vals[i].toString().match(/(-?[\d\.]+)\s*-\s*(-?[\d\.e]+)/)) {
				var hi = RegExp.$1;
				var low = RegExp.$2;
				if (a >= low && a <= hi || a >= hi && a <= low) return true;
			} else {
				if (a == vals[i]) return true;
			}
		}
		return false;
	} else if (arguments.length == 3) {
	  var hi = arguments[1];
		var low = arguments[2];
		return a >= low && a <= hi || a >= hi && a <= low;
	}
}
Math.log10 = function(x) { return Math.log(x)/Math.LN10;}
var days_long = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
var days = ["Sun", "Mon", "Tue", "Wed", "Thur", "Fri", "Sat"];
var months_long = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
var months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
Math.cmp = function(a,b) {return a<b?-1: a==b?0 : 1;} 
Math.sgn = function(a)  { return Math.cmp(a,0) }
Math.fix = function(n,p) {
	with(Math) { 
		var a=pow(10,(p || 0)); 
		return (n ==+n && n != "") ? round(n*a)/a : n != null ? n : ""; 
	}
}
Math.fixz = function(n,p) {
	if (!n || n.toString() =="" || n != +n) return n;
	var a = Math.fix(n,p).toString();
	var wholePart= Math.floor(+a);
	var decPart = (a ==wholePart.toString()) ? "" : a.slice(a.indexOf(".")+1);
	return wholePart+(p>0 ? "."+decPart+("00000000000".substr(0,p-decPart.length)):"");
}
Math.zfill = function(n, p) {
	if (typeof n != "number") return n;
	var l = p - Math.floor(+n).toString().length;
	return ("0000000000").substr(0,l)+n;
}
Math.pct = function(n,p) {
	return (n =="" || n !=+n) ? n : Math.fix(n*100,p)+"%";
}
Math.sci = function(n,p) {
	if (n =="" || n !=+n) return n;
	with(Math){var ex=floor(log(abs(n))/LN10); var b=n/pow(10,ex); var a=pow(10,(p || 9));return n==0?0:(round(b*a)/a)+"e"+ex; }
}
Math.eng = function(n,p) {
	if (n =="" || n !=+n || (n <= 1000 && n >= 0.001)) return Math.fixz(n,p);
	with(Math){var ex=floor(log(abs(n))/LN10/3);var b=n/pow(10,ex*3); var a=pow(10,(p || 9)); return (round(b*a)/a)+"e"+(ex*3); }
}
Math.engu = function(n,p) {
	if (p == null) p=9;
	if (n.toString() =="") return n;
	with(Math){
		var ex=max(-6,min(6,floor(0.00000000001+log(abs(n))/LN10/3)));
		var b=n/pow(10,ex*3);
		var a=pow(10,p);
		return (n!=+n || ex==0)? fix(n,p) : n==0?0:(abs(b)==Infinity|| b==0)?b:(round(b*a)/a)+("afpnum kMGTPE").charAt(ex+6);
	} 
}
function prepEngu(textNum) {
	var m = textNum.toString().match(/^\s*([0-9+-e.]+)([afpnumkMGTPE])\s*$/);
	if (!m) return textNum;
	var mantissa = m[1];
	var ltr = m[2];
  if ( isNaN(mantissa)) return textNum;
  var exp = ltr ? "afpnum kMGTPE".indexOf(ltr) : 6;
  return mantissa * Math.pow(10,(exp-6)*3);
}
function prepArray(self, prepstr, separator) {
	return self.toString().split(separator ||/\s*,\s*/).collect(prepstr);
}
Math.dol = function(n,p) { return n == +n && n.toString() != "" ? (n<0?"-":"")+Math.currencySign + Math.comma(Math.abs(n),p) : n; }
Math.currency = Math.dol;
Math.separator = ",";
Math.currencySign = "$";
Math.currencyRegex = new RegExp(Math.separator+"|"+Math.currencySign, "g");
Math.comma = function(n,p) {
	if (n==null || n.toString() =="" || n !=+n) return n;
	var r9= (n<0?"-":"")+Math.fixz(Math.abs(n),isDefined(p)?p:2).toString(); 
	while (r9.match(/^[^\.]*(\d+)(\d{3})/)) r9 = r9.replace(/(\d+)(\d{3})/, "$1,$2");
	return n!=+n ? "--" : r9;
}
function increment(str) {
  var prefix = str.replace(/(.+)\d+\D*$/, "$1");
  var index = parseInt(str.replace(/(\d+)\D*$/, "$1"))+1;
  str.match(/(.*\D)(\d+)(\D*)$/) || str.match(/(.+)/);
  var newName = (RegExp.$1).concat(parseInt(RegExp.$2 || 0)+1.0,RegExp.$3);
  return newName;
}
function sum() {
  var result = 0;
  if (arguments.length > 1) {
    for (i=0; i<arguments.length;i++) result += sum(arguments[i]); 
  } else {
    var a = arguments[0];
    if (typeof a =="number") result = +a;
    else if (a instanceof Array) for (var i=0; i<a.length; i++) result += sum(a[i]);
    else if (typeof a == "object") for (var i in a) result += sum(a[i]);
  }
  return result;
}
function product(a) {
	var result=1;
	if (a instanceof Array) {
		for (i=0; i<a.length; i++) if (typeof a[i]=='number') result *= +a[i];
	} else if (typeof a == "object") {
		for (i in a) if (typeof a[i]=='number') result *= +a[i];
	} else {
		result = NaN;
	}
	return result;
}
function average(a) {
	var result=1;
	var n = 0;
	if (a instanceof Array) {
		for (i=0; i<a.length; i++) if (a[i] == +a[i]) {n++; result += +a[i]; }
	} else if (typeof a == "object") {
		for (i in a) if (a[i] == +a[i]) { n++; result += +a[i]; }
	} else {
		result = NaN;
	}
	return n ? result/n : 0;
}
function range(start, end, step) {
	var result = [];
	if (!start && !isDefined(end)) return [0];
	if (! isDefined(end)) {end=start-1; start= 0;}
	if (! isDefined(step)) { step = start<end ? 1 : -1; }
	for (var i = start; (step>0?i<= end: i >= end); i+= step) result[result.length] = i;
	return result;
}
function grange(start, end, len) {
	var result = [];
	if (end/start < 0) return;
	if (! isDefined(len)) len = 6;
	var step = Math.pow(end/start, 1/(len-1));
	if (end > start) {
		for (var i = start; i<= end*1.000001; i*= step) 	result[result.length] = i;
	} else if (end < start) {
		for (var i = start; i > end/1.000001; i*= step) 	result[result.length] = i;
	} else { result = [end]; }
	return result;
}
function toDate(str, mask) {
	var dt = new Date(str);
	if (isNaN(dt.valueOf())) return str;
	if (!mask) mask = "mm/dd/yyyy";
	mask = mask.replace(/yyyy/g, dt.getFullYear());
	mask = mask.replace(/yy/g, dt.getFullYear().toString().replace(/^\d\d/,""));
	mask = mask.replace(/mmmm/g, months_long[dt.getMonth()]);
	mask = mask.replace(/mmm/g, months[dt.getMonth()]);
	mask = _parseDT(mask, "m", dt.getMonth()+1);
	mask = _parseDT(mask, "d", dt.getDate());
	mask = _parseDT(mask, "h", dt.getHours()); 
	mask = _parseDT(mask, "n", dt.getMinutes());
	mask = _parseDT(mask, "s", dt.getSeconds()); 
	return mask;
}
function _parseDT(mask, ch, val) {
	return mask.replace(new RegExp("0"+ch+ch, "g"), (val < 10 ? "0"+val : val)).replace(new RegExp(ch+ch, "g"), val);
}
function prepDate(t) {
	var a = new Date(t); 
	if(!a.valueOf()) a = new Date(t+"-"+(new Date()).getYear());
	v = a.valueOf()
	if (!v) return t; 
  if ((typeof t == "string") && !t.toString().match(/\d{4}/)) {
    return v + (v<-1e12?3155760000000:0);	
  } else {
    return v;
  }
}
function toTime(n) {
	if (typeof n != "number") return n;
	n /= 1000;
  var res = n <60 ? ":" : "";
  while (n >= 60) {
    res = res + Math.zfill(Math.floor(n/60),2)+":";
    n -= Math.floor(n/60)*60;
  }
  return res+"" +Math.zfill(n,2);
}
function prepTime(str) {
	var s = str.split(":"), result = 0, mult = 1000;
	for (var i=s.length-1; i>=0; i--) {
		result += s[i] * mult;
		mult *= 60;
	}
	return (isNaN(result) || result ==="") ? str : result;
}
function toDays(n) {return (typeof n=="number") ? n/86400000 : n}
function prepNum(textNum) {return isText(textNum)  && textNum.match(/([+-]?[\d,]*\.?\d+(e[+-]?[\d,]+)?)/) ? RegExp.$1.replace(/,/g,""): textNum }
function grep(aref, expr) {
	var result;
	var self;
	var isRE = expr instanceof RegExp;
	if (typeof(aref) == "string") aref = aref.split("\n");
	if (aref instanceof Array) {
		result = [];
		for (var i=0; i< aref.length; i++) {
			self = aref[i];
			with (self) {
				if (isRE ? typeof self == 'string' && self.match(expr) :
					eval(expr)) result[result.length] = self; 
			}
		}
	} else {
		result = {};
		for (var i=0; i< aref.length; i++) {
			self = aref[i];
			with (self) {
				if ( isRE ? (i.match(expr) || (typeof aref[i]=='string' && aref[i].match(expr)))
					:	eval(expr)) result[i] = aref[i];
			}
		}
	}
  return result;
}
function collect(source, expr) { 
	var result;
	var self;
	if (source instanceof Array) {
		result = [];
		for (var i=0; i<source.length; i++) {
			self = source[i];
			with(self) {
				try { result[i] = eval(expr); } 
				catch(e) { result[i]="ERR: (collect["+i+"]) "+e.message; }
			}
		}
	} else if (typeof source=="object") {
		result = {};
		for (var i in source) {
			self = source[i];
			with(self) {
				try { result[i] = eval(expr); } 
				catch(e) { result[i]="ERR: (collect["+i+"]) "+e.message; }
			}
		}	
	}
	return result;
}
function keys(object) {
	var result = [];
	for (var i in object) {
		if (typeof object[i] == 'object') result = result.concat(keys(object[i]));
		if (typeof object[i] != 'function') result.push(i);
	}
	return result;
}
function values(object) {
	var result = [];
	for (var i in object) if (typeof object[i] != 'function') result.push(object[i]);
	return result;
}
function methods(object) {
	var result = [];
	for (var i in object) if (typeof object[i] == 'function') result.push(i);
	return result;
}
function find(source, criteria, result) {
  var self;
	if (source instanceof Array) {
		for (var i=0; i< source.length; i++) {
			self = source[i];
			with (self) {
				try { if (eval(criteria)) return result ? eval(result) : self;} 
				catch(_e) { return ERR_PREFIX+"(find["+i+"]): "+_e.message; }
			}
		}
	} else if (typeof source=="object") {
		for (var i in source) {
			self = source[i];
			with(self) {
				try { if (eval(criteria)) return result ? eval(result) : self;} 
				catch(_e) { return ERR_PREFIX+"(find["+i+"]): "+_e.message; }
			}
		}	
	}
}
function locate(o,s, prefix) {
  if (!isDefined(prefix)) prefix = "";
  var i;
  var r;
  var reg = s instanceof RegExp;
  var result=[];
  if (o instanceof Array) {
    for (i=0; i<o.length; i++) {
      r = locate(o[i],s,prefix+"["+i+"]");
      if (r) result.append(r);
    }
  } else if (typeof o == "object") {
    for (i in o) {
      i = i.toString();
      if (!o[i] || o[i] instanceof Function || o[i].tagName) continue;
      if (i != "_name"  && i != "_content" && i.charAt(0)=="_") continue;
      r = locate(o[i],s,prefix+"."+i);
      if (r || (reg?i.match(s):i == s)) result.append(r);
    }
  } else {
    if (isDefined(o) && (reg?o.toString().match(s):o.toString()==s)) result.append([{element: prefix, value: o}]);
  }
  return result;
}
var iter;
var wspace=1;
var showEmptyStrings = 1;
function splay(o, lv) {
	var result = "";
	var cr= wspace ? "\n" : "";
	if (!lv) iter = SPLAY_MAX_ITERS;
	if (--iter <0) return result+"\n[ERR: Too Many Iterations]"
	var level = lv || 1;
	if (level >  SPLAY_MAX_LEVELS) return "[ERR: Level overflow("+level+")]";
	var t = typeof(o);
	if (t == "string" && !o && !showEmptyStrings) {return "";}
	if (t == "number" || t == "boolean") return o;
	if (t=="object" && o && isDefined(o.tagName)) return "[DHTML:"+o.tagName+"]";
	if (t == "object" && o instanceof Date) {return o.valueOf();}
	if (t == "function") { o.toString().match(/^([^{]+)/); return RegExp.$1+"{...}"; }
	if (t != "object"  && t == "string") return '"'+o.toString().replace(/\\/g,"\\\\").replace(/\"/g,'\\"').replace(/\n\r|\r\n|\r|\n/g,"\\\n\\n") +'"';
	var child;
	var indent = wspace ? "\n"+("                            ").substr(0,level*2) : "";
	if (o instanceof Array) {
		result += "[";
		for (var i = 0; i< o.length; i++) {
			child = splay(o[i],level+1);
			result += (i?",":"")+indent+child;
		}
		result = result.replace(/[\n\r]+$/,"");
		if (result.length < SPLAY_BREAK_CHARS) result = result.replace(/[\n\r]\s*/g," ");
		result += "]";
	}  else {
		result += "{";
		var firstItem=true;
		for (var i in o) {
			if (i.match(/^_/i)) continue;
			t = typeof o[i];
			if (t == "undefined" || t == "function") continue;
			try {
			child = splay(o[i],level+1);
				if (typeof(child) == "number" || child) {
					idisp = (i.match(/\W/) || i.match(/^[^A-Za-z_]/)) ? "\""+i+"\"" : i;
					result += (firstItem?"":",")+indent+idisp +":"+child;
					firstItem = false;
				}
			} catch(e) {
				return result+"[ERR...]";	
			}
		}
	result = result.replace(/[\n\r]+$/,"");
	if (result.length < SPLAY_BREAK_CHARS) result = result.replace(/[\n\r]\s*/g," ");
	result += "}";
	}	
	if (level==1) iter = SPLAY_MAX_ITERS;
	return result;
}
function ssplay(o, f) { 
	var r=""; 
	if (typeof o != "object") return o;
	for (var a in o) if (!(f instanceof RegExp) || (o[a] && o[a].toString().match(f)))
		r+= a+"="+ (typeof o[a] !='function' ? o[a] : o[a].toString().match(/[^\n\r]+/)[0])+"\n";
	return r;
}
function salert(o,s)  { alert((s?s:"")+splay(o)); }
function ssalert(o,s) { alert((s?s:"")+ssplay(o)); }
function getNewName(prefix) {
	prefix = prefix ? prefix.toLowerCase() : DEFAULT_NAME_PREFIX;
	var num;
	if (prefix.match(/(\d)$/)) { num = RegExp.$1; prefix = prefix.replace(/(.+)\d$/,"$1"); }
	else { num = 1; }
	while(window[prefix+num] && num <1000) {num++}
	return prefix+num;
}
var DELIM = "\t";
function array2table(s) {
  result = "";
  if (! isDefined(s.length)) return "Not an array: "+s;
  for (var i=0; i<s.length; i++) {
    u = s[i];
    if (u instanceof Array) {
      for (var j=0; j< u.length; j++)
        result += (j ? DELIM:"") + u[j];
    } else {
      result += u;
    }
    result += "\n";    
  }
  return result;
}
function qw(s) {return isText(s) ? s.split(/\s+/) : ""}
String.prototype.toArray = function(delim) {
	if (delim == null) delim = (this.count("\t") > this.count(",")) ? "\t" : ",";
	var lines = this.split(/[\n\r]+/);
	var result = new Array(lines.length);
	for (var i=0; i<lines.length; i++) result[i] = (delim=="," ? lines[i].replace(/\s*,\s*/g,","):lines[i]).split(new RegExp(delim));
	return result;
}
String.prototype.repeat = function(n) {
	var result = "";
	var t = isDefined(n)?n:2;
	for (var i=0; i<t; i++)
		result += ""+this;
	return result;
}
String.prototype.count = function(c) {
	var count = 0;
	for (var i=0; i<this.length; i++) if (this.charAt(i)==c) count++;
	return count;
}
String.prototype.words2array = function() {
  return this.split(/\s*,\s*/);
}
function clone(what, into) {
	var i;
	if (into && isText(what)) return what;
	if (what != null && typeof what == "object" && what.length != null) {
		if (!isDefined(into)) into = [];
		for (i = 0; i<what.length; i++) into[i] = clone(what[i], into[i]);
	} else if (typeof what == 'object') {		
		if (!isDefined(into)) into = {};
	   for (i in what) {
			if (typeof(what[i]) == "function" || !isDefined(what[i])) continue;
			if (i.match(/(^_)|html|text/i)) continue;
			into[i] = clone(what[i], into[i]);
		}
 	} else {
	   	into = what;
   }
   return into;
}
function hselect(name, values, options) {
	var result = "<select name='"+name+"' "+(options ||"")+" >";
	var selected;
	if (isText(values)) values = qw(values);
	for (var i=0; i<values.length; i++) {
		result += "<option value='"+values[i]+"'>"+values[i]+"</option>";
	}
	result += "</select>";
	return result;
}
function isDefined(s)   { return typeof s != 'undefined'; }
function isText(s) { return (typeof(s)=="string") }
function isanonymous(str) {
	return str.toString().charAt(0) == "_";
}

/* * * * * * * * * *../pgm/array.js * * * * * * * * * * * */

Array.prototype.sum = function() {
	var result=0;
	for (a=0; a<this.length; a++) if (this[a] == +this[a]) result +=+this[a];
	return result;
}
Array.prototype.product = function() {
	var result=1;
	for (a=0; a<this.length; a++) if (this[a] == +this[a]) result *=+this[a];
	return result;
}
Array.prototype.innerProduct = function(a) {
  var result = 0;
  var a,b;
  for (var i=0; i<Math.min(this.length, that.length); i++) {
    a = this[i];
    b = that[i];
    if ( a ==+a && b == +b) result += a*b;
  }
  return result;
}
Array.prototype.average = function() {
	return this.length ? this.sum()/this.length : 0;
}
Array.prototype.max = function() {
	for (var e=0,result=-Infinity,a=0; a<this.length; a++) {
		e = this[a];
		if (e == +e && e>result) result =+e;
	}
	return result == -Infinity ? null : result;
}
Array.prototype.min = function() {
	for (var e=0,result=Infinity,a=0; a<this.length; a++) {
		e = this[a];
		if (e == +e && e<result) result =+e;
	}
	return result == Infinity ? null : result;
}
Array.prototype.grep = function(expr) {
	var result = [];
	var self;
	var isRegExp= expr instanceof RegExp;
	var match = isRegExp && new RegExp(expr);
	for (var i=0; i< this.length; i++) {
		self = this[i];
		if (self==null) continue;
		if (isRegExp) {
			if (typeof self == "object") { 
				for (var j in self) {
					if (typeof self[j] =="function") continue;
					if (self[j].toString().match(expr)) { result.push(self); break;}
				}
			} else {
				if (self.toString().match(expr)) result[result.length] = self; 
			}
		} else {
			try {
				with (self) {if (eval(expr)) result[result.length] = self; }
			} catch(_err) {
				result[result.length] = "ERR (grep): "+_err.message;
			}
		}
	}
	return result;
}
Array.prototype.histogram = function(bin) {
	if (bin instanceof Array) {
		var keys = [];
		var result = {};
		for (var i=0;i<bin.length; i++) keys[i] = valRange(bin[i]);
		for (var i=0; i<keys.length; i++) result[bin[i]] = 0;
		for (var i=0; i<this.length; i++) {
			for (var j=0; j<keys.length; j++) {
				if ((keys[j] instanceof Array) && contains(this[i], keys[j][0], keys[j][1])
				 || (keys[j] == this[i])) {
					result[bin[j]]++;
				}
			}
		}
	} else if (bin) {
		var result =0;
		var v = valRange(bin); 
		for (var i=0; i<this.length; i++) 
			if ((v instanceof Array)? hilite(this[i], v[0], v[1]):this[i]== bin) result++;
	} else {
		var result = {};
		var keys = this.uniq();
		for (var i=0; i<keys.length; i++) result[keys[i]] = 0;
		for (var i=0; i<this.length; i++) result[this[i]]++;
	}
	return result;
}
function valRange(str) {
	if (str && str.toString().match(/(-?[\d\.]+)\s*-\s*(-?[\d\.e]+)/)) {
		return [+RegExp.$1,+RegExp.$2];
	} else {
		return str;
	}
}
Array.prototype.collect = function(expr, includeNulls) {
	var result = [];
	var self;
	var u;
	for (var i =0; i < this.length; i++) {
		self = this[i];
	try {
		if (self == null) { u = eval(expr) }
		else {with (self) {u = eval(expr); } }
			if (u != null || includeNulls) result.push(u == null? null : u);
	} catch (_err) {
		result[result.length] = "ERR (Array.collect):"+_err.message;
	}
	}
	return result;
}
Array.prototype.select = function(attrs) {
  if (isText(attrs)) attrs = attrs.split(/\s*[,;]\s*/);
  return attrs.length==1 ? this.collect(attrs[0]) : this.collect( "[" + attrs.join(",") + "]");
}
Array.prototype.find = function(expr) {
	var self;
	for (var i =0; i < this.length; i++) {
		self = this[i];
	try {
		with (self) { with (Math) {
			if (eval(expr)) return self;
		} }
	} catch (_err) {
		return "ERR (Array.find):"+_err.message;
	}
	}
}
Array.prototype.indexOf = function(val) {
	for (var i=0; i<this.length; i++) if (this[i] == val) return i;
	return -1;
}
Array.prototype.contains = function(val) {
	return this.indexOf(val)>-1;
}
Array.prototype.removeBlanks= function() {
	var result = [];
	for (var i =0; i < this.length; i++) {
		if (this[i]) result[result.length] = this[i];
	}
	return result;
}
Array.prototype.uniq= function() {
	var result = [];
	var res2 = {};
	var me;
	var u;
	for (var i =0; i < this.length; i++) {
		var me = this[i];
		if (!res2[me]) {
			result[result.length] = me;
			res2[me] = 1;
		}
	}
	return result;
}
Array.prototype.removeValue = function(val) { 
	var v = this.indexOf(val); 
	if (v) this.splice(v,1); 
	return this;
}
Array.prototype.append = function(a) {
  if (a && !(a instanceof Array)) a = [a];
  while(a.length) this.push(a.shift());
  return this;
}
Array.prototype.subtract = function(val) {
  if (!(val instanceof Array))  val = [val];
	result = [];
	for (var i=0; i<this.length; i++) {
		if (val.indexOf(this[i])== -1) result.push(this[i]);
	}
  return result;
}
Array.prototype.rotate = function(n) {
	if (n==null) n=1;
  if (n == 0) return this;
  var result = this.slice();
  if (n > 0) {
    for (var i=0; i<n; i++) 
      result.unshift(result.pop());
  } else {
    for (var i=n; i<0; i++)
      result.push(result.shift())
  }
  return result;
}

/* * * * * * * * * *../pgm/tableCell.js * * * * * * * * * * * */

var TableCell = {
	_storedValue:"", 
	separator:":",
	USE: "object",
	DEFAULT_CLASS: "text_cell",
	widthUnits:"px",
	widthScale: 6.6
}; 
TableCell.DEFAULT_TEXT_WIDTH = 10*TableCell.widthScale;
TableCell.separatorRegex =new RegExp("^.*"+TableCell.separator+"=");
function text(showFormula) {
	var m = TableCell.addInputGetterSetter({}, showFormula);
	m.create = function(section, node, r) {
		var a= "<input size='1' autocomplete='off' class='"   
		+TableCell.DEFAULT_CLASS+"'>";
		node.innerHTML = a;
		var cell = node.childNodes[0];
		cell.onfocus = function () {
			var me = section.us[r];
			var pname = section._iprop[node.cellIndex-1].name;
			TableCell.selected = {section:section._name, row:r, col:node.cellIndex-1};
			TableCell._storedValue = cell.value;
			if (!showFormula)
				cell.value = me.formula && dequoteString(me.formula[pname]) || cell.value; 
			cell.select();
			expandMe(cell)
			setStatus(section._name+".us["+me.index+"]."+pname+"="+TableCell._storedValue,1);
		}
		cell.onblur = function() {
			var me = section.us[r];
			var pname = section._iprop[node.cellIndex-1].name;
			var oldValue = TableCell._storedValue;
			if (this.value != oldValue) {
				section.update(TableCell.USE, r, node.cellIndex-1, m.getValue(this))
				if (!section.offLine) revertValue(this);
				CALC(section, r);
			} else { 
				if (!showFormula) revertValue(this);
			}
			contractMe(this);
		}
		function revertValue(cell) {
			if (!showFormula)	cell.value = TableCell._storedValue;
		}
		setKeyHandler(section, cell, 1);
		return cell;
	};
	m.setWidth = function(node, size) { if (node.style && node.style.width != size+TableCell.widthUnits && size >0) node.style.width = size+TableCell.widthUnits; }
	return m;
}
function text2() {
	var m = TableCell.addInputGetterSetter();
	m.create = function(section, node, r, cellUse) {
		var use = cellUse || TableCell.DEFAULT_USE;
	var a= "<input size='1' onfocus='expandMe(this);' onblur='contractMe(this)' onfocusout='contractMe(this)' autocomplete='off' class='"+TableCell.DEFAULT_CLASS+"'>";
		node.innerHTML = a;
		var cell = node.childNodes[0];
		cell.onchange = function() { 
			TableCell.selected = {section:section._name, row:r, col:node.cellIndex-1};
			section.update(use, r, node.cellIndex-1, this.value);
			CALC(section,r);
		}
		setKeyHandler(section, cell, 1);
		return cell;
	}
	m.setWidth = function(node, size) {if (node.style && node.style.width != size+TableCell.widthUnits && size > 0) node.style.width = size+TableCell.widthUnits;} 
	return m;
}
function bareDiv() {
	var m = {};
	m.create = function(section, node, r){
		var a = "<DIV width='100%' class='"+TableCell.DEFAULT_CLASS+"'></DIV>";		
		node.innerHTML = a;
		var cell = node.childNodes[0];
		return cell;
	};
	m.nodeFromTD = function(TDNode) { return TDNode.childNodes[0]; };
	m.setValue = function(node, newValue) { node.innerHTML = newValue.toString() !=""? newValue:"&nbsp;"; };
	m.setWidth = function(node, size) { node.style.width = size +TableCell.widthUnits; };
	return m;
}
function bare() {
	var m = {};
	m.create = function(section, node, r) { node.style.overflow= "hidden";return node; }
	m.nodeFromTD = function(TDNode) { return TDNode; };
	m.setValue = function(node, newValue){ node.innerHTML = isDefined(newValue) && newValue.toString() || "&nbsp;"; };
	m.setWidth = function(node, size) { node.style.width = size+TableCell.widthUnits;};
	return m;
}
function bare2() {
	var m = {};
	m.nodeFromTD = function(TDNode) { return TDNode; };
	m.setValue = function(node, newValue){ node.innerHTML = isDefined(newValue) && newValue.toString() || "&nbsp;"; };
	m.create = function(section, node, r) { 	
		node.style.overflow= "hidden";
		node.onclick=function() {
			TableCell.selected = {section:section._name, row:r, col:node.cellIndex-1,w: this.clientWidth,h : this.clientHeight};
			var form = section.rcFormula(r, node.cellIndex-1);
			node.innerHTML = "<input class='textinput' style='width:100%;height:100%;border:none' value='"+(form==null?"":form)+"'>";
			node.childNodes[0].onblur= function() {this.className='textinput'; section.update("object", r, node.cellIndex-1, this.value||""); CALC(section,r); }
			node.childNodes[0].focus();
		}
	}
	m.setWidth = function(node, size) { node.style.width = size+TableCell.widthUnits;};
	return m;
}
function text3(rows,cols) {
	var m = {};
	m.create = function(section, node, r) {
		node.onclick=function() {
		if (node.childNodes[0] && node.childNodes[0].className =='textinput') return;
			TableCell.selected = {section:section._name, row:r, col:node.cellIndex-1,w: this.clientWidth,h : this.clientHeight};
			var form = section.rcFormula(r, node.cellIndex-1);
			var nh = node.clientHeight;
			node.innerHTML = "<textarea class='textinput' style='width:100%;height:auto;border:none;background:yellow;overflow:visible;' onkeydown='setStatus(this.style.cssText,1)'>"+(form==null?"":form)+"</textarea>";
		node.childNodes[0].onblur= function() {this.className='textinput';section.update("object", r, node.cellIndex-1, this.value||"");
			CALC(section,r);
			}
			node.childNodes[0].focus();
		}
		return node;
	};
	m.nodeFromTD = function(TDNode) { return TDNode; };
	m.setValue = function(node, newValue) { node.innerHTML = isDefined(newValue) && newValue.toString() || "&nbsp;"; };
	m.setWidth = function(node, size) { node.style.width = size+TableCell.widthUnits;};
	return m;
}
function textarea(taRows) {
	var m = {type:"textarea", rows:taRows };
	TableCell.addInputGetterSetter(m);
	m.create = function(section, node, r) {
		var a = "<TEXTAREA rows='"+(taRows||2)+"' cols='1' class='"+TableCell.DEFAULT_CLASS
			+"'></TEXTAREA>\n"; 
		node.innerHTML = a;
		var cell = node.childNodes[0];	
		cell.onchange = function() { 
			TableCell.selected = {section:section._name, row:r, col:node.cellIndex-1};
			section.update(TableCell.USE, r, node.cellIndex-1, m.getValue(this)); 
			CALC(section,r);
		}
		return cell;
	}
	m.setWidth = function(node,width) {node.style.width= width };
	return m;
}
function select(elements) {
	var m = {type:"select" }
	TableCell.addInputGetterSetter(m);
	if (typeof elements=="string") elements = qw(elements);
	m.create = function(section, node, r) {
		var a = "<SELECT class="+TableCell.DEFAULT_CLASS+">"
		for (var i=0; i< elements.length; i++) a += "<option value='"+elements[i]+"'>"+elements[i]+"\n";
		a += "</SELECT>";
		node.innerHTML = a;
		var cell = node.childNodes[0];		
		cell.onchange = function() { 
			TableCell.selected = {section:section._name, row:r, col:node.cellIndex-1};
			section.update(TableCell.USE, r, node.cellIndex-1, this.value); 
			CALC(section,r);
		}
	};
	m.setValue = function(node, newValue, formula) { node.value = newValue; }
	m.hideInstanceFormula = true;
	m.setWidth = function(node,width)  {};
	return m;
}
function multi(elements, size) {
	size = " size='"+(size == +size && size > 0 ? size : Math.min(elements.length, 6))+"' ";
	var m = {type:"select" }
	if (typeof elements=="string") elements = qw(elements);
	m.create = function(section, node, r) {
		var a = "<SELECT class="+TableCell.DEFAULT_CLASS+" "+size+" multiple>"
		for (var i=0; i< elements.length; i++)
			a += "<option value='"+elements[i]+"'>"+elements[i]+"\n";
		a += "</SELECT>";
		node.innerHTML = a;
		var cell = node.childNodes[0];		
		cell.onchange = function() { 
			TableCell.selected = {section:section._name, row:r, col:node.cellIndex-1};
			var result=new Array();
			var opt=this.options;
		for (var i=0; i<opt.length;i++) if (opt[i].selected) result.push(opt[i].value);
			section.update(TableCell.USE, r, node.cellIndex-1, result); 
			CALC(section,r);
		}
	};
	m.nodeFromTD = firstChildGetter;
	m.setValue = function(node, newValue) { 
		var opt = node.options;
		if (!opt) throw "ERR (display): multi.setValue: couldn't find SELECT node";
		if (!(newValue instanceof Array)) newValue = [ newValue ];
		for (var i=0; i<opt.length; i++) { opt[i].selected = newValue.indexOf(opt[i].value)>-1;
		}
	};
	m.hideInstanceFormula = true;
	m.setWidth = function(node,width)  {};
	return m;
}
function radio(elements, separator) {
	var m = {type:"radio" }
	if (typeof elements=="string") elements = qw(elements);
	m.create = function(section, node, r) {
		var name = section.name;
		var a = "";
		for (var i=0; i< elements.length; i++) {
			 a += "<INPUT type='radio' name='"+name+(node.cellIndex-1)+"_radio"+r+"' value='"
				+elements[i]+"' onclick='this.parentNode.value=\""
				+elements[i]+"\"'>"+elements[i];
			if (i < elements.length-1) a += separator||""; 
		}
		node.innerHTML = a;
		node.onclick = function() {
			TableCell.selected = {section:section._name, row:r, col:node.cellIndex-1};
			section.update(TableCell.USE, r, node.cellIndex-1, this.value); 
			CALC(section,r);
		}
	};
	m.hideInstanceFormula = true;
	m.nodeFromTD = function(TDNode) {return TDNode; };
	m.setWidth = function(node,width)  {};
	m.setValue = function(node, newValue) { 
		var nd = node.childNodes;
		for (var i=0; i<nd.length; i++) { 
			if (nd[i].type=="radio") nd[i].checked = (nd[i].value.toString() == (newValue||"").toString()); 
		}
     };
	return m;
}
function checkbox(label, onValue, offValue) {
	if (onValue==null) onValue=1;
	if (offValue==null) offValue=0;
	if (!isDefined(label)) label="";
	var m = {type:"checkbox", label:label };
	m.create = function(section, node, r) {
		var a = "<INPUT type='checkbox' class='"+TableCell.DEFAULT_CLASS+"'>"+label+"\n"; 
		node.innerHTML = a;
		var cell = node.childNodes[0];
		cell.onclick = function() { TableCell.selected = {section:section._name, row:r, col:node.cellIndex-1};
section.update(TableCell.USE, r, node.cellIndex-1, this.checked?onValue:offValue); CALC(section,r);} 
		return cell;
	}
	m.nodeFromTD = firstChildGetter;
	m.setValue = function(node, newValue) { node.checked = newValue!=offValue?true:false; };
	m.getValue = function(node) { return node.checked; }
	m.setWidth = function(node,width) {node.cols = Math.round(width);};
	return m;
}
function toggleButton(elements) {
	var defaultIndex = -1;
	var m = {type:"button", currentIndex:0};
	TableCell.addInputGetterSetter(m);
	var values;
	m.create = function(section, node, r) {		
		var a = "<INPUT type='button' class='fullWidth' title='"+elements+"'>"
		node.innerHTML = a;
		var cell = node.childNodes[0];
		cell.currentIndex = defaultIndex;
		cell.style.width='100%';
		cell.onclick = function() { TableCell.selected = {section:section._name, row:r, col:node.cellIndex-1};
var v=m.update(cell); section.update(TableCell.USE, r, node.cellIndex-1, v); CALC(section,r);} 
	};
	m.hideInstanceFormula = true;
	m.setWidth = function(node,width)  {};
	m.update = function(node) {
		if (elements.length ==1) {
			result = ++node.currentIndex; }
		else { 
			node.currentIndex = (node.currentIndex+1) % elements.length;
			node.value = elements[node.currentIndex]; 
			result = node.value;
		}
		return result;
	}
	m.setValue = function(node, newValue) {
		if (elements.length==1) { node.value = elements[0]; return; }
		for (var i=0; i< elements.length; i++) {
			if (newValue == elements[i]) {
				node.value = newValue;
				node.currentIndex = i;
				return;
			}
		}
	}
	m.getValue = function(node) { return elements.length==1  && node.currentIndex==-1 ? 0 : node.value; }
	return m;
}
function onOffButton(label) {
	var m = {type:"button"};
	TableCell.addInputGetterSetter(m);
	var values;
	m.create = function(section, node, r) {		
		var a = "<INPUT type='button' class='off' value='"+(label||"on")+"'>";
		node.innerHTML = a;
		var cell = node.childNodes[0];
		cell.style.width='100%';
		cell.onclick = function() { TableCell.selected = {section:section._name, row:r, col:node.cellIndex-1};
section.update(TableCell.USE, r, node.cellIndex-1, this.className=="on"?0:1); CALC(section,r);} 
	};
	m.hideInstanceFormula = true;
	m.setWidth = function(node,width)  {};
	m.setValue = function(node, newValue) {
		node.className = newValue ? "on" : "off"; 		
	}
	m.getValue = function(node) { return node.className == "on"; }
	return m;
}
function onOffArray(labels, buttonCSS) {
	var m = {type:"button"};
	TableCell.addInputGetterSetter(m);
	if (typeof labels=="string") labels = qw(labels);
	var values;
	m.create = function(section, node, r) {
		var a = "";
		for (var i =0; i<labels.length; i++)
			a += "<INPUT type='button' class='off' value='"+labels[i]+"'>";
		node.innerHTML = a;
		for (var i =0; i<labels.length; i++) {
			var cell = node.childNodes[i];
			if (buttonCSS) cell.style.cssText = buttonCSS;
			cell.onclick = function() { 
				TableCell.selected = {section:section._name, row:r, col:node.cellIndex-1};
				this.className = this.className=="on"?"off":"on";
				section.update(TableCell.USE, r, node.cellIndex-1, m.getValue(node)); 
				CALC(section,r);
			}
			cell.onmouseover = function() {this.style.backgroundColor='yellow'};
			cell.onmouseout = function() {this.style.backgroundColor='';}
		}
	}
	m.hideInstanceFormula = true;
	m.setWidth = function(node,width)  {};
	m.setValue = function(node, newValue) {
		if (isText(newValue)) newValue = newValue.split("");
	if (!(newValue instanceof Array)) newValue = [];
		for (var i=0; i<labels.length;i++) { node.childNodes[i].className = newValue.contains(labels[i]) ? "on" : "off"; }
	}
	m.getValue = function(node) { 
		for (var result=[], i=0; i<labels.length;i++) if (node.childNodes[i].className == "on") result.push(labels[i]);
		return result; 
	}
	m.nodeFromTD = function(tdNode) { return tdNode; }
	return m;
}
function setKeyHandler(section, cell, oneLine) {
	cell.onkeydown = function(_e) { if (!_e) _e = window.event; if (section.moveCursor) section.moveCursor(_e, oneLine); }
	cell.onkeyup = function(_e) {if (!_e) _e = window.event;if (section.shortcutKeypress) section.shortcutKeypress(_e, cell) }
}
var firstChildGetter = function(TDNode) { return TDNode.childNodes[0]; }
function expandMe(cell) { 
	TableCell.origWidth = parseInt(getElementStyle(cell,"width"));
	var newCellWidth = (cell.value.length+2)*TableCell.widthScale;
	if (newCellWidth > TableCell.origWidth)
			cell.style.width = newCellWidth+TableCell.widthUnits;
}
function contractMe(cell) {
	if (cell.style.width) { cell.style.width = TableCell.origWidth+TableCell.widthUnits; }
}
TableCell.addInputGetterSetter = function(m, showFormula) {
	m = m || {};
	m.nodeFromTD = firstChildGetter;
	m.setValue = function(node, newValue, formula) { 
		node.value = newValue+(showFormula && formula && formula.toString().charAt(0) == "=" ? TableCell.separator+formula : "");
		node.title = node.value;
	}
	m.getValue = function(node) {
		var v = node.value; 
		if (v != null && !(v instanceof Array)) v = v.toString().replace(TableCell.separatorRegex,"=");
		return v;
	}
	return m;
}
TableCell.removeNameCell = function(TDNode) {
	if (!TDNode) return;
	var cell = TDNode.childNodes[0];
	cell.onchange = null;
	var imgNode = TDNode.childNodes[1];
	Panel.removeElement(imgNode);
	var selectNode = TDNode.childNodes[3];
	Panel.removeElement(selectNode);
}
TableCell.makeNameCell = function(section, TDNode) {
	var cell = TDNode.childNodes[0];
	var changer = cell.onchange;
	var a = TDNode.innerHTML;
	a += "<span title='drag to resize, click or shift-click to sort' class='panel_moveableHoriz' border='0'>&nbsp;</span>";
	a += "<div class='prop_selector unselected' title='click to select property/column' unselectable='on'></div>";
	TDNode.innerHTML = a;
	var cell = TDNode.childNodes[0];
	cell.contentEditable = !section._panel.view.lockTemplate;
	setKeyHandler(section, cell,1);
	cell.className = "table_tpl_cell table_tpl_name_cell";
	cell.onchange = changer;
	var imgNode = TDNode.childNodes[1];
	section._panel.makeDragger(imgNode, section, TableSection.dragStartProps, function(_e) {section.resizeCol(_e, TDNode.cellIndex-1);}, null);
	imgNode.onclick = function(_e) {
		if (!_e) _e = window.event; 
		if (TableSection.draggingCol) return;
		var s = section.sort;
		var v = prepIdentifier(cell.value).replace(/^[+-]/,"");
		if (_e.shiftKey) { section.sort = (s == "-"+v ? "+"+v : (s == "+"+v || s == v) ? "" : "-"+v); }
		else { section.sort = ((s == v || s == "+"+v) ? "-"+v : s == "-"+v ? "" : v); }
		section.calc();
	}
	var selectNode = TDNode.childNodes[2]
	selectNode.height = 5;
	selectNode.onclick = function() { section.setColHighlight(TDNode.cellIndex-1) }
}

/* * * * * * * * * *../pgm/os_mgr.js * * * * * * * * * * * */

if (typeof window.PGM_DIR == "undefined") PGM_DIR = "pgm/";
_lang = "en";
DEFAULT_NAME_PREFIX = "Table";
ERR_PREFIX = "ERR ";
os_mgr.PROGNAME = "ObjectSheet";
os_mgr.DEFAULT_AUTOHIDECELLS = 5000;
os_mgr.RESERVED_WORDS = ["log", "sin", "cos"];
os_mgr.DEFAULT_VIEW = {pasteNames:1,panel:{stacked:0, lockTemplate:0,canClose:1,display:"",canMove:1,canHide:1,hideTitle:0,resizeable:"hv",displayContent:"",displayAll:""}};
os_mgr.PANEL_POSITION = {left:50, top:30};
os_mgr.PANEL_OFFSET = {left:20, top:20};
os_mgr.LOAD_FILE_LIST= ["core.js", "panel.js","array.js", "table.js","tableCell.js","file.js","areaSection.js","simpleMenu.js","tableSection.js", "wiki.js", "panel.css", "section.css", "simpleMenu.css"];
os_mgr.USER_EXTENSION_FILE_NAME = "userExtensions.js";
function includeObject(file, type){
	if (typeof file != "string") {
		WARN(ERR_PREFIX +"(os_mgr.includeObject):"+os_mgr.MSG[_lang].includeErr+ (typeof file));
		return;
	}
	if (!type) type = file;
	try {
		if (type.match(/\.js$/)) {
			var node = document.createElement("script"); 
			node.setAttribute("type", "text/javascript"); 
			node.setAttribute("src", file);
		} else if (type.match(/\.css$/)) {
			var node= document.createElement("link"); 
			node.setAttribute("rel", "stylesheet"); 
			node.setAttribute("type", "text/css"); 
			node.setAttribute("href", file);
		}
		document.getElementsByTagName("head")[0].appendChild(node);
	} catch (_err) {
		WARN(ERR_PREFIX+"(includeObject): "+_err.message);
	}
	return node;
}
function loadedTest(node, handler) { 
	if (handler()) { document.getElementsByTagName("head")[0].appendChild(node);}
	else { setTimeout(function() {loadedTest(node, handler)}, 500); }
}
function _param(n) {
	var r = new RegExp("[?&](?:"+n+"=)(.+?)(?:\\&|$)");
	if (location && location.search && location.search.match(r))
		return unescape(RegExp.$1);
}
function loadjs() {
	for (var i=0; i<os_mgr.LOAD_FILE_LIST.length; i++) {
		includeObject(PGM_DIR+os_mgr.LOAD_FILE_LIST[i]);
	}
	includeObject(os_mgr.USER_EXTENSION_FILE_NAME);
}
if (!window.TableCell) loadjs();
function os_mgr(options) {
	var imgDir = File.BASE_PATH + "/"+Panel.IMG_DIR;
	if (!location.href.match(/.\ht[am]l?(\?|\#|$)/i)) Panel.noImageButtons = !File.exists(imgDir+"/iconS.gif");
	File.currentFile = "os1.os";
	this.autoHideCells = os_mgr.DEFAULT_AUTOHIDECELLS;
	this.isections = [];
	this.sections = {};
	this.undoStack = [];
	this.redoStack = [];
	this.undoPtr = 0;
	this._view = os_mgr.DEFAULT_VIEW;
	var th = this;
	window.onbeforeunload = function() {
		if (th._sheetModified) 
			return "===================\n"
			+os_mgr.MSG[_lang].abandonWarning
			+"\n===================";
	}
	document.onkeyup = function(_e) {window._mgr && _mgr.shortcutKeypress(_e || window.event) }
	this.addMenus();
	this.init(options);
	if (!window._mgr) window._mgr = this;
	createDOMNode().innerHTML = "&nbsp;<br/>";
}
os_mgr.prototype.init = function(options) {
	if (options) {
		var o = options.toString().split(/\s*[;,]\s*/);
		for (var i=0; i<o.length; i++) {
			if (o[i].match(/^\s*(.+?)\s*=\s*(.+)$/)) {
				this._view[RegExp.$1] = RegExp.$2;
			}
		}
	}
	this.start = os_mgr.PANEL_POSITION;
	this._sheetModified = 0;
	this.updateOptionsUI();
}
os_mgr.prototype.addMenus = function() {
 var m = os_mgr.MSG[_lang].menu;
 var a = [ {name:m.file.name, menu: [
	{label:m.file.open+"...", onmouseup:"loadDir(File.currentDir)", shortcut:"Ctrl-Shft-o"},
	{label:m.file.dir+" <input size=18 id='menu_DirName' onclick='return true;' onchange='File.currentDir = File.makePath(this.value);_mgr.updateOptionsUI()'> <span onmouseup='loadDir(File.currentDir, 1)'>set...</span>", onmouseup:'return false' },
	{label:m.file.file+" <input size=20 id='menu_FileName' onchange='File.currentFile=this.value;'"},
	{label:m.file.save, onmouseup:"_mgr.saveFile(File.currentDir, File.currentFile)", shortcut:"Ctrl-Shft-s" },
	{label:m.file.reopen, onmouseup:"_mgr.loadFile(File.currentDir+File.separator+File.currentFile, File.mergeOnLoad)" },
	{label:m.file.saveHTML, title:_idnode("dataArea")?"save html":"needs to be self-contained", onmouseup:"_mgr.saveSelfContained()" },
	{label:m.file.exportFile, onmouseup:"var w=window.open();w.document.write(_mgr.toHTML());w.document.title='Objectsheet export: '+File.currentFile;w.document.close();return false;"},
	{label:m.file.viewSource, onmouseup:"var a=_mgr.makeSaveFunction().replace(/</mg,'&amp;lt;');var w=window.open();w.document.write('<pre>'+a);w.document.title='Objectsheet view source: '+File.currentFile;w.document.close();return false;"},
	{label:m.file.permlink, onmouseup:"if(_mgr.okToClose())document.location.href = document.location.href.replace(/[\?\#].*/,'?file='+escape(File.getRelativePath(File.currentDir)+File.separator+File.currentFile))" },
	{label:m.file.hideTable+"> <input size=5 id='menu_AutoHideCells' class='input' onchange='_mgr.autoHideCells=+this.value'> Cells" }
	] },
	{name:"Edit", menu: [
		{label: m.edit.copyObjects, onmouseup: "_mgr.copyObjects()", shortcut:"Ctrl-Shift-C"},	
		{label: m.edit.pasteObjects, onmouseup: "_mgr.pasteObjects()", shortcut:"Ctrl-Shift-V"},	
		{label: "<input type='checkbox' id='menu_pasteNames'> Copy/Paste Col names", onclick: "_mgr._view.pasteNames=+this.childNodes[0].checked;", persist:1},
		{label: "<input size='2' id='menu_PasteDelim' onchange='_mgr._view.pasteDelim=this.value;'> Paste Delimiter", persist:1},
		{label: m.edit.undo, onmouseup: "_mgr.undo()"},
		{label: m.edit.redo, onmouseup: "_mgr.redo()"},
		{label: m.edit.recalc, onmouseup: "_mgr.calc(1);", shortcut:"F2"}
	] },
	{name:"Insert", menu: [
		{label: m.insert.table, onmouseup: "_mgr.createSection('', 'Table').calc(1);", shortcut:"Ctrl-Alt-T"},
		{label: m.insert.scr, onmouseup: "_mgr.createSection('','scratch').calc(1)", shortcut:"Ctrl-Alt-S"},
		{label: m.insert.html, onmouseup: "_mgr.createSection('','html').calc(1)", shortcut:"Ctrl-Alt-H"},
		{label: m.insert.eng, onmouseup:"var s=_mgr.createSection('eng1', 'Table').calc(1);s.misc='this.prep=&quot;prepEngu(self)&quot;';s.format='engu(self,2)';s.calc();"},
		{label: m.insert.fin, onmouseup:"var s=_mgr.createSection('fin1', 'Table').calc(1);s.misc='this.prep=&quot;prepNum(self)&quot;';s.style='text-align:right';s.format='dol(self,2)';s.calc();"},
		{label: m.insert.scalar, onmouseup: "var s=_mgr.createSection('scalar1','Table',{formula:0}, 3,[{name:'varname',scalarName:2},{name:'expr',cellWidth:25*TableCell.scaleWidth},{name:'result',display:'bare()',formula:'me.expr?eval(me.expr):&quot;&quot;'}]).calc(1)"}
	] },
	{name:"Options", menu: [
		{label: "<input type='checkbox' id='menu_stacked'> Stacked", onclick: "var p=_mgr._view.panel;v=+this.childNodes[0].checked;p.stacked=v;p.canMove=1-v;_mgr.applyView();",persist:1},
		{label: "<input type='checkbox' id='menu_lockTemplate'> Lock Template", onclick: "_mgr._view.panel.lockTemplate=+this.childNodes[0].checked;_mgr.applyView();",persist:1},
		{label: "<input type='checkbox' id='menu_canClose' checked> Can Close", onclick: "_mgr._view.panel.canClose=+this.childNodes[0].checked;_mgr.applyView();", persist:1},
		{label: "<hr>", noselect:1},
		{label: "<input type='checkbox' id='menu_altRowSizer'> Alt Row sizer", onmouseup: "_mgr._view.altRowSizer=(this.childNodes[0].checked?0:1);_mgr.applyView();",persist:1}
	] },
	{name:"Help", menu: [
	{label: m.help.ref, onmouseup: "window.open('objectsheetRef.html','helpWindow')"},
	{label: m.help.func, onmouseup: "window.open('./test_support/osRef.html?calc','helpWindow')"},
	{label: m.help.shortcut, onmouseup: "window.open('./test_support/osRef.html?shortcut','helpWindow')"},
	{label: "<hr>", noselect:1},
	{label: m.help.quick, onmouseup: "var d=File.currentDir;_mgr.loadFile('http://richk.net/os/sheets/QuickStart.os',1);File.currentDir=d;"}, 
	{label: m.help.tut, onmouseup: "window.open('http://richk.net/os/doc/tutorial1-table.html','')"},
	{label: m.help.about, onmouseup: "_mgr.openAbout()"},
	{label: m.help.home, onmouseup: "window.open('http://richk.net/os','')"}
	] },
	{name:"Sections", menu: [ { noselect:1} ] }
	];
	var n = createDOMNode();
	n.style.position="absolute";
	n.style.zIndex = 1002;
	this._menu = new SimpleMenu(a, n);
	window.onscroll=function(_e) {
		if (!_e) _e = window.event; 
		n.style.marginTop = document.body.scrollTop;
		var status = _idnode("ostatus");
		if (status) {
			status.style.marginTop = document.body.scrollTop;
			setStatus("");
		}
	}
	var _sectionsTableNode = _idnode("menu_Sections").childNodes[0].childNodes[0].childNodes[0];
	this.make_sectionsTable(_sectionsTableNode);
	var t = _sectionsTableNode.childNodes[0];
	this._sectionsTable._panel.nodeTitleBar.style.display="none";
	this._sectionsTable.toggleFormula(0);
	t.style.margin="0px 0px 0px 0px";
}
os_mgr.prototype.make_sectionsTable =function(node) {
	var a=[
		{
		name:"order",
		index:0,
		action:"this.calc();",
		prep:"this.us[row].order=self;_mgr.reorder(this.order()); \"\"",
		style:";text-align:center;",
		formula:"row",
		cellWidth:6*TableCell.widthScale},
		{
		name:"Name",
		index:1,
		display:"bare()",
		cellWidth:15*TableCell.widthScale,
		formula:"'<span title=\"click to show\" onclick=\"var s=_mgr.isections['+row+'];sendToFront(s._panel.nodeTable);s.focus();\")\">'+(window._mgr &&_mgr.isections[row]._name) +'</span>'"},
		{
		name:"visible",
		index:2,
		prep:"var s=_mgr.isections[row];s._view.panel.displayAll= (+self?\"\":\"none\");s.applyView();s.showValues();\"\"",
		style:";text-align:center;",
		display:"checkbox()",
		cellWidth:8*TableCell.widthScale,
		formula:"window._mgr &&_mgr.isections[row]._view.panel.displayAll!=\"none\""},
		{
		name:"hide title",
		index:3,
		prep:"var s=_mgr.isections[row];s._view.panel.hideTitle= +self;s.updatePanel();s.applyView();\"\"", 		style:";text-align:center;",
		display:"checkbox()",
		cellWidth:10*TableCell.widthScale,
		formula:"window._mgr &&_mgr.isections[row]._view.panel.hideTitle"},
		{
		name:"resize",
		index:4,
		prep:"var s=_mgr.isections[row];s._panel.view.resizeable=self?'hv':'';s.updatePanel();\"\"",
		style:";text-align:center;",
		display:"checkbox()",
		cellWidth:7*TableCell.widthScale,
		formula:"window._mgr &&_mgr.isections[row]._view.panel.resizeable"},
		{
		name:"Off Line",
		index:6,
		prep:"var s=_mgr.isections[row];s.offLine= self;s.applyView();s.showValues();",
		style:";text-align:center;",
		display:"checkbox()",
		cellWidth:8*TableCell.widthScale,
		formula:"_mgr.isections[row].offLine"}
	];
	this._sectionsTable = new TableSection("ord", {panel:{resizeable:"",hideTitle:1,lockTemplate:0}}, {us:1,prop:a});
	var t = this._sectionsTable;
	t.draw(node);
	t._panel.nodeTable.style.position="relative"; 
	t._view.panel.left=0;
	t._view.panel.top=0;
	node.parentNode.parentNode.onmouseout = function() {clearTimeout(menuLeave) };
	showHide(t._rowt["formula"]);
	t.calc(1);
	for (var i=0; i<t._iprop.length; i++) t._tplrow[5].cells[i+1].className = "ord_name_td";
}
os_mgr.prototype.add = function(section) {
  var idNum = this.isections.length;
  var name = section._name || getNewName("section");
	this.isections[idNum] 		= section;
	this.sections[name]	= section;
	window[name]		= section;
	return section;
}
os_mgr.prototype.reorder= function(order) {
	var presorted = [];
	if (!(order instanceof Array)) WARN("os_mgr.reorder: argument is not an array:"+typeof order);
	for (var i=0; i<order.length; i++) presorted[i] = {pre:i, post:order[i] };
	var sorted = presorted.sort(function(a,b) { return Math.cmp(a.post, b.post) } );
	var oldi;
	var newi = [];
	for (var i=0; i<sorted.length; i++) {
		oldi = sorted[i].pre;
		newi[i] = this.isections[oldi];
	}
	this.isections = newi;
	if (this._view.panel.stacked) {
		var parentNode = window.document.body;
		var isect= this.isections;
		for (var i=0; i<isect.length; i++) {
			var node = isect[i]._panel.nodeTable;
			parentNode.appendChild(node);
		}
	}
}
os_mgr.prototype.removeSection = function(sectionName) {
	var id = this.getSectionIndex(sectionName);
	var section = this.isections[id];
	if (!section) return;
	var a;
	var i = this.undoPtr++;
	this.undoStack[i] = "var t22b=_mgr.createSection('"+section._name+"', '"+section.secType+"',"+splay(section._view)+","+splay(section)+").draw();_mgr.add(t22b)";
	this.redoStack[i] = "_mgr.isections[this.getSectionIndex('"+sectionName+"')].removeNoUndo()";
	this.removeSection2(section);
	this.isections.splice(id,1);
	this.updateSectionTable();
	section = null;
}
os_mgr.prototype.removeSection2 = function(section) {
	if (isDefined(section.remove)) section.remove();
	section._panel.remove();
	section._panel = null;
	window[section._name] = null;
	delete this.sections[section._name];
}
os_mgr.prototype.shortcutKeypress = function(event) {
	if (!event) event = window.event;
	var ctrlKey = event.ctrlKey;
	var shiftKey = event.shiftKey;
	var altKey = event.altKey;
	var keyCode = event.keyCode;
	key = String.fromCharCode(keyCode);
	if (keyCode==113 && !shiftKey && !ctrlKey ) _mgr.calc();
	if (!ctrlKey || keyCode==17) return;
	if (key == "S" && !altKey) {
		this.saveFile(File.currentDir, File.currentFile, File.SILENT);
	} else if (key == "O" && !altKey) {
		loadDir(File.currentDir);
	}
	var found=0; 
	if (altKey && ctrlKey) {
		found = 1;
		if (key == "T") {
			this.createSection("", "Table", "").calc(1);
			if (event.preventDefault) event.preventDefault();
			if (event.stopPropagation) event.stopPropagation();
			return false;
		} else if (key == "S") {
			this.createSection("", "Scratch", {panel:{canClose:1}}).focus().calc(1);
		} else if (key == "H") {
			this.createSection("", "Html").calc(1).focus();
		} else {
			found=0;
		}
	}
	if (found) {
		event.cancelBubble = true;
		if (event.stopPropagation) event.stopPropagation();
	}
	if (!found && this._selected) { this._selected.shortcutKeypress(event); }
}
os_mgr.prototype.calc = function(forceUpdate) {
	setStatus("",1);
	var start = new Date();
	var s = this.isections;
	for (var i=0; i< s.length; i++) {
		if (!s[i].offLine|| forceUpdate) s[i].precalc();
	}
	for (var i=0; i< s.length; i++) if (!s[i].offLine || forceUpdate) s[i].calc(forceUpdate);
	if (forceUpdate) this.updateSectionTable();
	var elapsedSec = (new Date()-start)/1000;
	setStatus("  "+elapsedSec+" sec.<br/>",0);
}
os_mgr.prototype.updateSectionTable = function() {
	this._sectionsTable.us.length = this.isections.length;
	this._sectionsTable.calc();
}
os_mgr.prototype.openAbout = function() {
	if (!window.AboutSection) window.AboutSection = new HtmlSection("About", {displayHeight:140,width:290,panel:{left:400,top:20,lockTemplate:1,resizeable:""}});
	var t = window.AboutSection;
	t._content="!!Objectsheet\n&copy; 1999, 2001 - 2008, Rich Knopman<p>\n\nUse subject to <a href='http://richk.net/os/doc/license.html'>BSD license</a>.";
	t.draw().calc(1);
	this.add(t);
	t._displayNode.style.padding="10px";
	t._displayNode.style.backgroundColor="#ff8";
	sendToFront(t._panel.nodeTable);
}
os_mgr.prototype.undo = function() {
	if (this.undoPtr < 1) return;
	this.undoPtr--;
	eval(this.undoStack[this.undoPtr]);
	this.calc();
}
os_mgr.prototype.redo = function() {
	if (this.undoPtr >= this.redoStack.length) return;
	eval(this.redoStack[this.undoPtr++]);
	this.calc();
}
os_mgr.prototype.createSection = function(name, secType, options, objs, props) {
	var section;
	if (!secType) secType="Table";
	if (!isDefined(name) ||!name) name = getNewName(secType);
	var v = clone(this._view);
	clone(options, v);
	if (secType.match(/table/i)) { section = new TableSection(name, v, objs, props); }
	else if (secType.match(/html/i)) { section = new HtmlSection(name, v); }
	else if (secType.match(/scratch/i)) { section = new ScratchSection(name, v); }
	else setStatus("internal error: bad Section type ("+secType+") for createSection");
	this.add(section);
	if (this._view.lockTemplate) section._view.panel.lockTemplate = 1;
	var view = section._view;
	section.draw();
	if ((typeof options != 'object')&& view.panel) {
		view.panel.left = this.start.left;
		view.panel.top = this.start.top;
	} else if (!section._panel && section._node) {
		section._node.style.marginLeft = this.start.left;
		section._node.style.marginTop = this.start.top;
	}
	this.start.left += os_mgr.PANEL_OFFSET.left; 
	this.start.top += os_mgr.PANEL_OFFSET.top;
	var th = this;
	sendToFront(section._panel.nodeTable);
	this.updateSectionTable();
	if (section.focus) section.focus()
	return section;
}
os_mgr.prototype.renameSection = function(oldName, newName) {
	if (newName == oldName) return;
	var id = this.getSectionIndex(oldName);
	var section = this.isections[id];
	if (newName == "") newName = "_"+id;
	newName = newName.toString().replace(/ /g,"_");
	if (window[newName] || this[newName] || os_mgr.RESERVED_WORDS.contains(newName)) {
		WARN("("+oldName+".rename): name '"+newName+"' already used.");
		section.showValues();
		return;
	}
	var returnValue = this.isections[id].rename(newName);
	if (!returnValue) return;
	if (newName) { this.sections[newName] = this.sections[oldName]; }
	else { newName = "_mgr.isections["+id+"]"; }
	delete this.sections[oldName];
	this.updateSectionTable();
	this.globalRename(oldName, newName, -1);
	return this;
}
os_mgr.prototype.globalRename = function(oldName, newName, sectionName) {
	var isect = this.isections;
	for (var i=0; i<isect.length; i++) {
		isect[i].replaceInAllFormulas(oldName, newName, sectionName);
	}
}
os_mgr.prototype.copyObjects = function() {
	var c = TableCell.selected;
	if (!c) return;
	var section = this.getSectionByName(c.section);
	if (!section) NOTE("_mgr::copyObjects: can't find section named: "+c.section)
	if (!section || section.secType != "Table") return;
	var sel = section.getSelection();
		var s = array2table();
	if (this._view.pasteNames) s = section.getHighlights().iprop.collect("section._iprop[self].name").join("\t")+"\n"+s
	setClipboard(s);
	setStatus("Copied "+ s.length+" rows");
}
os_mgr.prototype.pasteObjects = function() {
	var c = TableCell.selected;
	if (!c) return;
	var section =  this.getSectionByIndex(sectionName);
	if (section.secType != "Table") return;
	var rows = getClipboard().toArray();
	if (this._view.pasteNames) {
		section.setPropNames(rows[0]);
		rows = rows.slice(1);
	}
	section.pasteObjects(rows, c.row, c.col, 0);
	this.calc();
}
os_mgr.prototype.toHTML = function() {
	var a = "<html><h3>"+File.currentFile+"</h3>";
	var isect = this.isections;
	for (var i=0; i<isect.length; i++) {
		var h = isect[i].toHTML();
		if (h) a += "\n\n<h4>"+isect[i]._name+"</h4>\n"+h;
	}
	a +="</html>";
	return a;
}
function getClipboard() {
	if (window.clipboardData) {
		return window.clipboardData.getData("Text");
	} else {
		netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
		var clipboard = Components.classes["@mozilla.org/widget/clipboard;1"].createInstance(Components.interfaces.nsIClipboard);
		var transferable = Components.classes["@mozilla.org/widget/transferable;1"].createInstance(Components.interfaces.nsITransferable);
		if (!clipboard || !transferable) return;
		transferable.addDataFlavor("text/unicode");
		clipboard.getData(transferable, Components.interfaces.nsIClipboard.kGlobalClipboard);		
		var str = new Object();
		var len = new Object();
		transferable.getTransferData ( "text/unicode", str, len );
		if (str) str = str.value.QueryInterface(Components.interfaces.nsISupportsString);
		if (str) clipboard_text = str.data.substring(0,len.value / 2);
		return clipboard_text;
	}
}
function setClipboard(text) {
	if (window.clipboardData) {
		window.clipboardData.setData("Text", text);
	} else {
		netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
		var clip = Components.classes["@mozilla.org/widget/clipboardhelper;1"] .getService(Components.interfaces.nsIClipboardHelper);
		clip.copyString(text);
	}
}
os_mgr.prototype.getSectionIndex = function(name) {
  for (var i=0; i<this.isections.length; i++) if (this.isections[i]._name == name) return i;
}
os_mgr.prototype.getSectionByName = function(name) {
	return this.isections[this.getSectionIndex(name)];
}
os_mgr.prototype.applyView = function() {
	var view = this._view;
	var is = this.isections;
	for (var i=0; i<is.length; i++) {
		clone(view, is[i]._view);
		is[i].updatePanel();
		var v = is[i]._panel.view;
		for (var j in v) {if (v[j] == this._view[j]) delete v[j]; }
	}
	this.updateOptionsUI();
}
os_mgr.prototype.updateOptionsUI = function() {
	var dir = File.getRelativePath(File.currentDir);
	_idnode("menu_DirName").value = dir;
	_idnode("menu_FileName").value = File.currentFile;
	_idnode("menu_AutoHideCells").value = this.autoHideCells || "";
	_idnode("menu_PasteDelim").value = this._view.pasteDelim || "";
	_idnode("menu_pasteNames").checked = this._view.pasteNames || "";
	document.title = os_mgr.PROGNAME+(File.currentFile ? (": "+File.currentFile) : ""); 
	var v = this._view.panel || this._view;
	_idnode("menu_stacked").checked = v.stacked;
	_idnode("menu_lockTemplate").checked = v.lockTemplate;	
	_idnode("menu_canClose").checked = v.canClose;	
	window.onscroll();
}
os_mgr.prototype.loadFile = function(path, merge) {
	setStatus("Loading file: "+path,1);
	var origPath = path;
	var file = File.getFileName(path);
	if (path.match(/\.os$/i)) {
		File.currentDir = File.makePath(File.getDirName(path));
		File.currentFile = file;
		window._newData = null;
		includeObject(path, ".js");	
		var result=this.loadFileHandler(merge,5);
	} else {
		try {var contentAsText = File.loadURL(path, 1);} 
		catch(_e) {
			WARN("(_mgr.loadFile) file='"+path+"':"+_e.message);
			return;
		}
		if (!contentAsText || contentAsText==null)
			throw {type:"FileNotFound", message:os_mgr.MSG[_lang].FileNotFound+path};
		if (file.match(/\.csv$/i)) {
			var newName = getNewName();
			var newSection = this.createSection(newName, "table");
			var data = contentAsText.toArray();
			if (this._view.pasteNames) newSection.setPropNames(data.shift());
			newSection.assimilate(data);
			this.setAutoHide(newSection);
			newSection.calc();
			return;
		} else if (file.match(/\..?htm.?$/i) || file.match(/\.txt$/i )) {
			var newName = getNewName("html");
			var newSection = this.createSection(newName, "html");
			newSection.loadContents(contentAsText).calc(1);
			return;
		}
	}
}
os_mgr.prototype.loadFileHandler = function(merge, n) {
	var th = this;
	if (!window._newData && n>0) {
		setTimeout(function() { th.loadFileHandler(merge, n-1) }, 100);
	} else if (typeof window._newData != "object" || !window._newData) {
			setStatus("<span style='color:red'>"+os_mgr.MSG[_lang].ProblemLoadingFile+"</span>",1);
	} else {
		var loadedSections = window._newData;
		_newData = null;
		return this.createFromObject(loadedSections, merge);
	}
}
os_mgr.prototype.createFromObject = function(loadedSections, merge) {
	this._view = loadedSections.view || os_mgr.DEFAULT_VIEW;
	if (!this._view.panel) this._view.panel = {};
	if (merge) {
	var sect = loadedSections.isections
		for (var i=0; i<sect.length ; i++) this.fixSectionNameCollisions(sect[i].name);
	} else {
		if (!this.okToClose()) return;
		this.unloadSections();
		this.init();
	}
	var newSection;
	var s;
	var secType;
	if (loadedSections.isections instanceof Array) loadedSections = loadedSections.isections;
	var startTime;
	for (var isect=0; isect< loadedSections.length; isect++) {
		startTime = new Date();
		s = loadedSections[isect];
		if (s.type) { s.secType = s.type; delete s.type }
		secType = s.secType || s._name.replace(/\d+/,"");
		if (isDefined(s.secType) && s.secType == "Table") {
			newSection = this.createSection(s.name, secType, s.view, s.len || (s.us && s.us.length) || 1, s.iprop);
		} else {
			newSection = this.createSection(s.name, secType, s.view);
		}
		this.renameSection(newSection._name, s.name);
		newSection.loadContents(s);
		this.setAutoHide(newSection);
		newSection.process(1);
		this._sheetModified = 0;
	}
	startTime = new Date();
	this.calc(1);
	this.updateOptionsUI();
	return this;
}
os_mgr.prototype.okToClose = function() {
	return !this._sheetModified || confirm("Current sheet has changed.  OK to overwrite and lose changes?");
}
os_mgr.prototype.setAutoHide = function(section) {
	if (!section.secType.match(/table/i)) return;
	if (section.us.length*section._iprop.length > this.autoHideCells) {
		section.filter = "0\/\/"+section.filter;
		var a="Inhibiting cells in "+section._name+".  Remove <code>0\/\/</code> from filter or <a href='#' onclick='"+section._name+".filter = "+section._name+".filter.replace(/^0\\/\\//,\"\");CALC()'>click here</a> to fix.";
		NOTE(a);
	}
}
os_mgr.prototype.unloadSections = function() {
	for (i in this.sections) {this.removeSection(this.sections[i]._name);}
}
os_mgr.prototype.fixSectionNameCollisions = function(newSectionName) {
	for (var i=0; i<this.isections.length; i++) {
		if (newSectionName == this.isections[i]._name)
			this.renameSection(newSectionName, increment(newSectionName));
	}
}
function shallowCopy(source, ref) {
	var result;
	if (source instanceof Array) {
		result = isDefined(ref) ? ref : [];
		for (var i=0; i<source.length; i++) result[i] = source[i];
	} else if (typeof source == "object") {
		result = isDefined(ref) ? ref : {};
		for (var i in source) result[i] = source[i];
	} else {
		result = source;
	}
	return result;
}
os_mgr.prototype.saveFile = function(dir, file, silence) {
	if (!dir) dir = File.currentDir;
	if (!file) file = File.currentFile;
	var response = this.saveCopy(dir, file, silence);
	File.currentFile = file;
	this._sheetModified=0;
	this.updateOptionsUI();
	setStatus(file+": "+response, 1);
}
os_mgr.prototype.saveCopy = function(dir, file, silence) {
	var content = this.makeSaveFunction();
	content = content.replace(/^\s+/mg,"");
	var path = dir ? dir+File.separator+file : file;
	var res= File.save(content, path, silence);
	return res;
}
os_mgr.prototype.makeSaveFunction = function() {
	var sheet = {view:(this._view||""), isections:clone(this.isections) };
	for (var i=0; i< this.isections.length; i++) {
		sheet.isections[i].view = this.isections[i]._view;
		if (this.isections[i].saveContents) 
			sheet.isections[i] = this.isections[i].saveContents(sheet.isections[i]);
	}
	return "_newData=\n"+splay(sheet);
}
os_mgr.prototype.saveSelfContained = function() {
	var content = this.makeSaveFunction();
	return saveMe(content);
}
function saveMe(contentAsText) {
	var path= location.href.replace(/\?.+/,"");
	if (!path.match(/file:[\/]+(.+)[\/\\]([^\/\\]+)$/,"")) {
		alert("problem with file name ("+path+")?");
		return;
	}
	path = File.getLocalPath(path);
	var fileName = RegExp.$2;
	var dir = RegExp.$1;
	var content = File.loadURL(path);
	if (0 && !_idnode("dataArea")) {
		alert("Original file needs to be 'objectsheet.html' (couldn't find data area).  Please save os only.");
		return;
	}
	content = content.replace(/(<script\s+id=['"]dataArea['"][^>]*>)(?:.|[\n\r])+?(<\/script>)/m, "$1"+contentAsText+"\n<\/script>");
	var savePath = File.currentDir.replace(/[\/\\]$/,"")+"/"+(File.currentFile.replace(/\.os$/,".html"));
	if (!confirm("Saving to "+savePath)) return;
	var saveResult = File.save(content, savePath);
	setStatus(saveResult);
}
os_mgr.prototype.selectDir = function(path) {
	File.currentDir = path;
	this.updateOptionsUI();
	this.removeSection("Open_File",1);
}
var loadDir = function(path, dirOnly) {
	if (!path) path = File.BASE_PATH;
	path = path.toString().replace(/[\/\\]?$/,"/");
	var s;
	try {
		var dirContent = dirOnly ? File.getSubdirs(path): File.dir(path);
		if (!dirContent) throw {type:"NoDirectoryContents", message:"No directory contents read"};
	} catch (_e) {
		_mgr.removeSection('Open_File',1);
		setStatus("Couldn't read directory ("+path+"): "+_e.message,1);
		return;
	}
	File.currentDir= path;
	if (_mgr.sections['Open_File']) {
		s = _mgr.sections['Open_File'];
		s.us.length=0;
	} else {
		s = _mgr.createSection('Open_File', 'Table', {panel:{canClose:1,moveable:1,stacked:0,lockTemplate:1,resizeable:"",left:"200px", top:"20px"}}, {us:0,prop:0}); 
	}
	setStatus("loading dir for "+path,1);
	s.display = "bare()";
	s._view.formula = "none";
	_mgr._sectionsTable.calc();
	s.applyView();
	path = path.replace(/[\/\\][^\/\\]+[\/\\]\.\.?/, "");
	s.pasteObjects([{date:"",size:"",name:path, extension:File.CURRENT_DIR_EXT}]);
	s.pasteObjects([{date:"",size:"",name:File.UP_DIR_LABEL ,extension:File.DIR_EXT}]);
	s.pasteObjects(dirContent);
	var o;
	var thisPath;
	for (var oIndex=0; oIndex < s.us.length; oIndex++) {
		o = s.us[oIndex];
		if (o.extension == File.DIR_EXT) {
			var upPath = path.replace(/([\/\\])[^\/\\]+[\/\\]?$/,"$1");
			thisPath = o.name == File.UP_DIR_LABEL ? upPath : path +o.name;
			o.name = "<a href='#' onclick='loadDir(\""+thisPath+"\","+(dirOnly?1:0)+")'>"+o.name+"</a>";
		} else if(o.extension == File.CURRENT_DIR_EXT) {
			o.name="<a href='#' onclick='_mgr.selectDir(\""+o.name+"\")'>"+o.name+"</a>";
		} else if (o.extension && (o.extension == "os" || o.extension == "csv" || o.extension =="txt" || o.extension.match(/.?htm.?/i))) {
			o.name = "<a href='#' onclick='_mgr.loadFile(\""+path.replace(/[\/\\]$/,"")+File.separator+o.name+"\",0)'>"+o.name+"</a>";
		} else {
			o.name = "<a href='"+path+o.name+"'>"+o.name+"</a>";
		}
	}
	var p = s.prop
	if (p.date) {p.date.format = "toDate(self,'yyyy/mmm/dd')"; p.date.cellWidth = 14*TableCell.widthScale;}
	if (p.size) { p.size.format = "engu(self,2)"; p.size.cellWidth=9*TableCell.widthScale;}
	if (p.name) { p.name.cellWidth = 30*TableCell.widthScale; p.name.format = "self.replace(/\\\\/g, '/')";} 	if (p.extension) p.extension.cellWidth = 12*TableCell.widthScale;
	sendToFront(s._panel.nodeTable)
	s.showValues(1);
	if (_mgr._view.panel.stacked) s._panel.moveToTopOfScreen();
}
function setStatus(text, clear) {
	var node = _idnode("ostatus");
	if (!node) return;
	if (clear || !node.innerHTML)  node.innerHTML ="";
	node.innerHTML +=text;
}
function NOTE(s) {setStatus("<span style='color:red'>"+s+"</span>")}
function WARN(s) {alert(ERR_PREFIX+s); }
os_mgr.MSG = {
	en: {
		FileNotFound:"File not found or empty: ",
		ProblemLoadingFile:"Problem loading file or file not found.  Please see browser's Javascript error log for details.",
		SectionNotFound:"os_mgr.removeSection(): couldn't find sheet named ",
		includeErr:"File needs to be of type string, actually is:",
		abandonWarning:"Abandon and lose all your changes?\nIf not, please press Cancel and save your work before closing.",
		menu: {
			file:{name:"File",open:"Open", dir:"Dir", file:"File", save:"Save .os (data only)", saveHTML:"Save .html (packaged)", reopen:"Reopen",hideTable:"Hide Table", cells:"Cells", permlink:"Permlink",exportFile:"Export HTML",viewSource:"View Source" },
			edit:{copyObjects:"Copy Objects", pasteObjects:"Paste Objects", undo:"Undo", redo:"Redo", recalc:"Recalc"},
			insert:{table:"Table", scr:"Scratch", html:"HTML", eng:"Eng Table", fin:"Financial Table", scalar:"Scalars Table"},
			help:{ref:"Reference", func:"Functions", shortcut:"Shortcuts", quick:"Online&nbsp;Quick&nbsp;Start", tut:"Online Tutorial", about:"About", home:"Online Homepage"}
		}
	}
}

/* * * * * * * * * *../pgm/table.js * * * * * * * * * * * */

Table.templ = ["action", "prep", "format", "style", "display", "name", "formula"];
Table.sectionTempl = ['filter', 'format', 'style','display','misc', 'formula'];
Table.DEFAULT= {OBJECTS:3, PROPS:3};
Table.reservedWords = ["us", "prev", "prop", "this"];
function Table(name) {}
Table.prototype.init = function(name) {
	this.secType = "Table";
	if (!name) { name = getNewName(this.secType); }
	else if (window[name]) { name = getNewName(name); }
	this._name = name;
	this.prop = {};
	this.us = new Array();
	this._iprop = new Array();
	this.IDindex = -1;
	return 1;
}
Table.prototype.evalAttr = function(attrName, me, self) {
	if (this[attrName]) {
		try { with(me|| window) { with (Math) { 
			eval(this[attrName])
		} } } catch(_e) { return (ERR_PREFIX+" ("+this._name+"."+attrName+") "+_e.message); }
	}
}
Table.prototype.deleteObject = function(oIndex) {
	var oIndex = limitIndex(oIndex, this.us.length);
	if (this.IDindex > -1) {
		var pname = this._iprop[this.IDindex].name;
		var oname = this.us[oIndex][pname];
		delete this[oname];
	}
	this.us.splice(oIndex,1);
	reindex(this.us, oIndex);
}
function reindex(aref, startIndex) {
	for (var i=startIndex || 0; i < aref.length; i++) 
		if (typeof aref[i]== "object") { aref[i].index = i; }
		else {aref[i] = {index:i}}
}
function limitIndex(index, max) {
	index = !isDefined(index) ? max-1 : index < 0 ? index + max : index;
	return Math.min(index, max-1);
}
Table.prototype.addProperty = function(name, index, options) {
	var a = arguments;
	var prop = {index: -1 };
	for (var t, i=0; i<a.length;i++) {
		t = typeof a[i];
		if (t=="number") prop.index = a[i];
		if (t=="string") prop.name = a[i];
		if (t=="object") options = a[i];
	}
	for (var i in options) prop[i] = options[i];
	prop.index = limitIndex(prop.index,this._iprop.length+1);
	if (!prop.name) prop.name=("abcdefghijklmnopqrstuvwxyz").charAt(prop.index%26)+(prop.index>26?Math.floor(prop.index/26):"");
	while (isDefined(this[prop.name])) {
		prop.name = increment(prop.name);
	}
	var pIndex = prop.index;
	var name = prop.name;
	this.prop[name] = prop;
	this[name] = this.makePropFunction(name);
	if (isDefined(this._iprop[pIndex])) this._iprop.splice(pIndex,0,1);
	this._iprop[pIndex] = prop;
	reindex(this._iprop, pIndex);
	return this;
}
Table.prototype.makePropFunction = function(propName) {
	var th = this;
	return function(index1, index2) { 
		if (!isDefined(index1)) {
			return th.colAsArray(propName);
		} else {
			index1 = limitIndex(index1, th.us.length);
			if (!isDefined(index2)) {
				return th.us[index1][propName];
			} else {
				index2 = limitIndex(index2, th.us.length);
				return th.colAsArray(propName).slice(index1,index2+1);
			}
		}
	}
}
Table.prototype.colAsArray = function(pName) {
	var me = this.us;
	var result = new Array(me.length);
	for (var i=0; i<me.length; i++) result[i] = me[i][pName];
	return result;
}
Table.prototype.getPropNames = function() {
	return this._iprop.collect("self.name");
}
Table.prototype.deleteProperty = function(index) {
	var pIndex = limitIndex(index,this._iprop.length);
	var prop = this._iprop[pIndex];
	var name = prop.name;
	delete this[name];
	var o;
	for (var i=0; i<this.us.length; i++) {
		o = this.us[i];
		if (this.IDindex == index) delete this[ o[name]];
		o.removeFormula(name);
		delete o[name];
	}
	delete this.prop[name];
	prop = null;
	this._iprop.splice(pIndex,1);
	reindex(this._iprop, pIndex);
	return this;
}
Table.prototype.clearProp = function(pname) {
	for (var i=0; i<this.us.length; i++) this.us[i][pname]="";
	return this;
}
Table.prototype.setPropCount = function(n) {
	var delta = n - this._iprop.length;
	if (delta == 0) {
		return;
	} else if (delta > 0) {
		for (var i=0; i< delta; i++) this.addProperty();
	} else {
		for (var i=0; i< -delta; i++) this.deleteProperty(-1);
	}
	return this;
}
Table.prototype.setPropNames = function(a) {
	if (!(a instanceof Array)) return;
	var p = this._iprop;
	var oldLength = p.length;
	this.setPropCount(a.length);
	for (var col=0; col < a.length; col++) {
		if (isDefined(a[col]) && (col >= oldLength || a[col] != this._iprop[col].name)) this.renameProperty(col, a[col],1);
	}
	return this;
}
Table.prototype.renameProperty = function(pIndex,newName, overrideOldName) {
  col = limitIndex(pIndex, this._iprop.length);
  if (col < 0 || col >= this._iprop.length) {
		WARN("Table::renameProperty (index="+pIndex+"): "+Table.MSG[lang].PropertyIndexOutOfBounds);
		return this;
	}
	var prop = this._iprop[col];
	var oldName = this._iprop[col].name;
	newName = newName.toString().replace(/[\n\r\t]+/g,"").replace(/^\s*(.+?)\s*$/,"$1");
	if (newName == "*") return this;
	if (Table.reservedWords.contains(newName)) newName += "_";
	var wasID = col == this.IDindex;
	var wasScalarName = prop.scalarName;
	var wasSort = this.sort && this.sort.match(new RegExp("[+-]"+oldName));
	var isSort;
	delete prop.units;
	if (newName.match(/(.+?)(\s*[(,;:].+)/)) {
		newName = RegExp.$1;
		prop.units = RegExp.$2;
	}
	newName = prepIdentifier(newName);
	var isID = (newName.charAt(0) =='*') ? 1:0;
	if (isID)	newName = newName.substr(1);
	if (newName.match(/^[+-]\D/)) {
		this.sort = newName;
		newName = newName.substr(1);
		isSort = 1;
	} else if (this.sort) {
		this.sort="";
	}
	var match = newName.match(/(=*)([^=]+)(=*)$/); 
	if (match && (match[3] || match[1])) {
		this.removeSectionLevelNames(oldName);
		prop.scalarName = match[3].length-match[1].length;
		newName = match[2];
		this.setScalarValues(prop);
	} else {
		delete prop.scalarName;
	}
	if (wasSort == isSort && newName == oldName && isID == wasID && prop.scalarName == wasScalarName) return; 
	if (wasID && !isID || (wasScalarName && !prop.scalarName)) {
		this.removeSectionLevelNames(oldName);
		this.IDindex = -1;	
	}
	if (isID && !wasID) this.IDindex = pIndex;
	if (newName.toString().length == 0) newName = "_"+pIndex;
	if (newName == oldName) return;
	if (this.prop[newName]) {
		if (overrideOldName) {
			var u= this.prop[newName].index;
			NOTE(newName+": "+Table.MSG[_lang].ColExistsSoMakeAnon);
			this.renameProperty(u, "");
		} else {
			setStatus("(Table.renameProperty): Can't rename. Already exists:"+newName);
			return this; 
		}
		return this;
	}
	delete(this.prop[oldName]);
	delete this[oldName];
	var me;
	for (var i=0; i<this.us.length; i++) {
		me = this.us[i];
		if (me == null) continue;
		me[newName] = me[oldName];
		delete me[oldName];
		if (me.formula && me.formula[oldName]) {
			me.formula[newName] = me.formula[oldName];
			delete me.formula[oldName];
		}
	}
	this.prop[newName]=this._iprop[pIndex];
	if (!isDefined(this[newName])) this[newName] = this.makePropFunction(newName);
	this._iprop[pIndex].name=newName;
	if (window._mgr) {
		_mgr.globalRename(oldName, newName, this._name);
	} else {
		this.replaceInAllFormulas(oldName, newName, this._name);
	}
}
Table.prototype.setScalarValues= function(prop) {
	var varName;
	pIndex = prop.index+prop.scalarName;
	if (!prop.scalarName || pIndex<0 || pIndex > this._iprop.length) return;
	var pvname = this._iprop[pIndex].name;
	for (var row=0; row < this.us.length; row++) {
		me = this.us[row];
		varName =me[prop.name];
		if (!isDefined(this[me[pvname]] && varName)) this[varName] = me[pvname];
	}
}
Table.prototype.removeSectionLevelNames = function(pname) {
	var varName;
	for (var row=0; row < this.us.length; row++) {
		varName =this.us[row][pname];
		if (varName) delete this[varName];
	}
}
function prepIdentifier(s) {
	return s.toString().replace(/(\w)\s(\w)/g, "$1_$2");
}
Table.prototype.rename = function(newName) {
	var oldName = this._name;
	var name;
	if (newName == oldName) return;
	if (newName != oldName && window[newName] != null && isDefined(window[newName])) {
		WARN(Table.MSG[_lang].TableRename+": "+newName);
		return;
	}
	this._name = newName;
	window[newName] = this;
	window[oldName] = null;
	return this;
}
Table.prototype.replaceInAllFormulas= function(oldName, newName, sectionName) {
	if (oldName == newName || !oldName || newName.toString().match(/^[\d\.]+$/)) return;
	var oldNameRegex = "(?:^"+oldName+"\\b)|(?=[^\\.])(?:\\b"+oldName+"\\b)";
	if (sectionName != this._name && sectionName !=-1) {
		oldNameRegex = "\\." +oldName+"\\b";
		newName = "."+newName;
	}
	var formulaRe = new RegExp(oldNameRegex,"g");
	var prop;
	for (var i=0; i<this._iprop.length; i++) {
		prop = this._iprop[i];
		for (var t=0; t<Table.templ.length;t++) {
			attrName = Table.templ[t];
			if (isDefined(prop[attrName])) prop[attrName] = prop[attrName].toString().replace(formulaRe, newName);
		}
	}
	var o;
	for (var i=0; i<this.us.length; i++) {
		forms = this.us[i] && this.us[i].formula;
		if (typeof forms != "object") continue;
		for (var f in forms) {
			if (forms[f] && typeof(forms[f])=="string") forms[f] = forms[f].replace(formulaRe, newName);
		}
	}
	for (var i=0; i< Table.sectionTempl.length; i++) {
		if (this[Table.sectionTempl[i]]) this[Table.sectionTempl[i]] = this[Table.sectionTempl[i]].replace(formulaRe, newName);
	}
}
Table.prototype.updateTemplate = function(typ, oIndex, pIndex, newValue) {
	if (typ == 'formula') {
		this.prepFormula(pIndex, newValue);
	} else if (typ == "name") {
		this.renameProperty(pIndex,newValue);
	} else if (typ == 'format' || typ == 'style' || typ == 'prep' || typ == 'action') {
		var prop = this._iprop[pIndex];
		prop[typ] = newValue;
		if (typ=='prep' && newValue.charAt(0)=="*") {
			prop.prep = newValue.substr(1);
			this.forcePrep(prop);
			}
	} else if (typ.match(/^all\./)) {
		this[typ.replace(/all\./,"")] = newValue;
	}
	return this;
}
Table.prototype.forcePrep = function(prop) {
	var pname = prop.name;
	var us = this.us;
	var self;
	var isFormula;
	for (var row=0; row<this.us.length; row++) {
		me = us[row];
		isFormula = me.formula && me.formula[pname] != null;
		self = me[pname];
		self = (self && self== +self) ? parseFloat(self) : self;
			try {
				with (Math) { with (me) {
					self = eval(prop.prep || this.prep);
				}}
			} catch(e) { setStatus(ERR_PREFIX+" ("+pname+".prep) "+e.message); }
		isFormula ? me.formula[pname] = quoteString(self) : me[pname] = self;
	}
}
Table.prototype.prepFormula = function(pIndex, newValue) {
	var prop = this._iprop[pIndex];
	var pname = prop.name;
	var me;
	var self;
	if (!(prop.formula || this.formula) && !newValue) return;
	if (!(prop.formula || this.formula) && newValue) { 
		for (var oIndex=0; oIndex<this.us.length; oIndex++) {
			me = this.us[oIndex];
			self = me[pname];
			if (self!=null && self.toString()!="" && !(me.formula && me.formula[pname])) 
				me.addFormula(pname, self);
		} 
	}
	if (newValue.charAt(0) == "=") {
		NOTE(Table.MSG[_lang].EqualsSignRemoved);
		newValue = newValue.substr(1);
	}
	prop.formula = newValue.toString()=="" ? null : newValue;
	if (newValue.toString() != "") return; 
	var f;
	for (var oIndex=0; oIndex<this.us.length; oIndex++) {
		me = this.us[oIndex];
		f = me.formula ? me.formula[pname] : null;
		if (f !=null) {
			me[pname] = dequoteString(f);
			me.removeFormula(pname);
		} else {
			if (this.IDindex == pIndex && this[me[pname]] === me) delete this[ me[pname] ];
			delete me[pname];
		}
	}
}
function dequoteString(str) {
	return ((typeof str !="string") || str.charAt(0)=="=") ? str : str.replace(/^"(.*)"$/,"$1");
}
function quoteString(str) { 
	return ((typeof str !="string") || str.charAt(0)=="=") ? str : str.replace(/^"?(.*?)"?$/,"\"$1\"");
}
Table.prototype.prepObject = function(row, col, self) {
	var prop = this._iprop[col];
	var pname = prop.name;
	var me = this.us[row];
	var oldValue   = (me.formula != null && me.formula[pname])? dequoteString(me.formula[pname]) : me[pname];
	var isInstanceFormula   = isText(self) && self.match(/^=/);
	if (oldValue != null && oldValue.toString() == self.toString()) return oldValue;
	if (!(self instanceof Array)) self = self.toString()=="" ? window._EOTBUCEU: (self && self== +self) ? parseFloat(self) : self;
	if (!isInstanceFormula && (prop.prep || this.prep)) {
		try { 
		with(me) { with(Math) {
			self = eval(prop.prep || this.prep);
		}}
		} catch(e) { setStatus(ERR_PREFIX+" ("+pname+".prep) "+e.message); }
	}
	if (self && (isInstanceFormula || this.prop[pname].formula || this.formula)) {
		me.addFormula(pname, self);
	} else if (me.formula && ! isInstanceFormula) {
		me.removeFormula(pname);
  }
	me[pname] = self;
	if (this.IDindex == col || prop.scalarName) {
		delete this[oldValue];
		if (window._mgr) { _mgr.globalRename(oldValue, self, this._name); }
		else {this.replaceInAllFormulas(oldValue, self, this._name); }
	}
	var otherP = this.getScalarProp(col);
	if (otherP) {
		varName = me[otherP.name];
		if (varName) this[varName] = me[pname];
	}
	if (this.prop[pname].action || this.action) {
		try { with(this) {
			eval(this.prop[pname].action||this.action);
		} } catch(e) { setStatus("ERR ("+this.action+".action): "+e.message); }
		me[pname] = self;
	}
}
Table.prototype.getScalarProp = function(pIndex) {
	var ip = this._iprop;
	for (var p=0; p<ip.length; p++) {
		if (p==pIndex) continue;
		if (ip[p].scalarName+p == pIndex) return ip[p];
	}
}
Table.prototype.preprocess = function() {
	this.rowLabel="";
}
Table.prototype.process = function() {
	var form;
 	var prop;
	var pName;
	var us = this.us;
	len = us.length;
	var prev;
	var self;
	var _ip = this._iprop;
	with (Math) {
	if (this.misc) {
		try { with(this) {
			eval(this.misc);
		} } catch(e) { setStatus("ERR ("+this._name+".misc): "+e.message); }
	}
	var scalarProps = new Array(_ip.length);
	for (var pIndex = 0; pIndex<_ip.length; pIndex++) {
		if (!isDefined(_ip[pIndex])) reindex(_ip);
		scalarProps[pIndex+_ip[pIndex].scalarName] = pIndex;
	}
	for (row=0; row<this.us.length; row++) {
		me=this.us[row];
		if (!me || !me.addFormula) { me = new object(me); me.index = row; this.us[row] = me; }
		me.index = row;
		meform = me.formula != null && me.formula;
		prev = (row>0) ? this.us[row-1] : {};
		with (me) {
		for (var col=0; col< _ip.length; col++) {
			prop = _ip[col];
			pname = prop.name;
			form = null;
			if (meform && meform[pname]!=null && meform[pname].toString()!="") { form = this.removeEquals(meform[pname]) }
			else if (prop.formula!=null && prop.formula.toString()!="") {form = prop.formula }
			else {if (this.formula != null && this.formula.toString() !="") form = this.formula }
			self = me[pname];
			try {
				if (form!=null) {
					me[pname] = eval(form);
				} else {
					me[pname] = ((self == +self && self.toString() !="" && !(self instanceof Array)) ? +self : self);
				}
			} catch(_err) { 
				me[pname]="ERR (calc): "+_err.message;
			}
			if (this.IDindex == col) {
				if (me[pname] && !this[ me[pname] ]) this[ me[pname] ] = me;
				if (me[pname] != self) delete this[self];
			}
		}
		}
	}
	for (var col = 1; col < _ip.length; col++) {
		if (isDefined(scalarProps[col])) this.processScalars(col, scalarProps[col])
	}
	this.evalAttr("onAfterCalc");
}
return this;
}
Table.prototype.removeEquals = function(s) {
	return s.toString().charAt(0) == "=" ? s.substr(1) : s;
}
Table.prototype.processScalars = function(col, nameCol) {
	var prop = this._iprop[col];
	var pname = prop.name;
	var piname = this._iprop[nameCol].name;
	var self;
	with (Math) {
	for (row= 0; row < this.us.length; row++) {
		me=this.us[row];
		meform = isDefined(me.formula) && me.formula;
		form = prop.formula || this.formula;
		self = isDefined(me[pname]) ? me[pname] : "";
		try {
			if (meform && meform[pname]) {
		with(this) {
				me[pname] = eval(meform[pname].toString().replace(/^=/,""));
			}
			} else if (form) {
		with(this) {
				me[pname] = eval(form);
			}
			} else {
				if (isDefined(self) && self != "" && self == +self) { me[pname] = parseFloat(self); }
				else if (!isDefined(self)) { me[pname]=""; }
			}
		} catch(errEvent) {
			me[pname]="ERR (scalar calc): "+errEvent.message;
		}
		this[ me[piname] ] = me[pname];
	}
	}
}
Table.prototype.reorderProps = function(order) {
	if (isText(order)) order = qw(order);
	for (var i=0; i<order.length; i++) {
		if (this.prop[order[i]]) this.prop[order[i]].index = i;
	}
	this._iprop.sort(function(a,b) {return cmp(a.index,b.index)});
	return this;
}
Table.prototype.rc = function(row,col) {
	return this.us[row][this._iprop[col].name];
}
Table.prototype.rcFormula = function(row,col) {
	var pname = this._iprop[col].name;
	var me = this.us[row];
	return (me.formula && me.formula[pname]) ? dequoteString(me.formula[pname]) : !this._iprop[col].formula ? me[pname] : "";
}
Table.prototype.selectRows = function(otherTable, expr) {
	this.mirror(otherTable);
	this.us = otherTable.us.grep(expr);
}
Table.prototype.mirror = function(other, expr) {
  this._iprop = other._iprop;
  this.prop = other.prop;
	if (expr) { 
		this.us = grep(other.us, expr);
		reindex(this.us);
	}
}
Table.prototype.unmirror = function() {
  this._iprop = clone(this._iprop);
  this.prop = clone(this.prop);
	for (var c=0; c<this._iprop.length; c++) this.updateDisplay(this._iprop[c]);
}
Table.prototype.rowContainsLiteral = function(a) {
	var me = (a == +a) ? this.us[a] : a;
	if (!isDefined(me)) WARN(Table.MSG[_lang].CantFindMeInLiteral+a);
	var form = me.formula;
	for (var p in this.prop)
		if((form && form[p]) || (me[p] && (!this.prop[p].formula && !this.formula) )) return 1;
	return 0;
}
Table.prototype.lastSelf = function(expr) {
	var a = this.us.slice(0,row);
	var res = a && a.grep(expr);
	return res && res.length ? res[res.length-1][pname] : "";
}
function object(params) {
  if (isDefined(params)) {
    for (var p in params) this.pasteValue(p, params[p]);
  }
  this.index = -1;
}
object.prototype.pasteValue = function(pname, value) {
	if (typeof value == "string" && value.slice(0,2) == "\\=") {
		this.addFormula(pname, value.slice(1));
	} else {
		this[pname] = (value!=null && value.toString() != "undefined") ?value:"";
	}
}
object.prototype.removeFormula = function(propName) {
	var f = this.formula;
	if (f && f[propName]) {
		delete f[propName];
		if (isEmptyObject(f)) delete this.formula;
	}
}
object.prototype.addFormula = function(propName, value) {
	if (!this.formula) this.formula = {};
	this.formula[propName] = quoteString(value);
}
object.prototype.range = function(start, end) {
	return row/(len-1)*(end-start)+start;
}
object.prototype.grange = function(start, end) {
	return start*Math.pow(Math.pow(end/start,1/(len-1)),row);
}
function isEmptyObject(o) {
	var isEmpty=1;
	for (var a in o) if (typeof o[a] != "function") {
		isEmpty=0;
		break;
	}
	return isEmpty;
}
object.prototype.thisRow = function(ignorecols) {
	if (!ignorecols) ignorecols = [];
	if (isText(ignorecols)) ignorecols = qw(ignorecols)
	ignorecols = ignorecols.concat("index");
	var result=[];
	var i=0;
	for (var prop in this) if (!ignorecols.contains(prop) && this[prop] == +this[prop]) result.push(+this[prop]);
	return result;
}
Table.prototype.assimilate = function(s, startCol) {
	if (!isDefined(startCol)) startCol=0;
	if (s instanceof Array) {
		if (s[0] instanceof Object) {
			this.us.length=0;
			this.pasteObjects(s,0,startCol,1);
		} else {
			this.setPropNames(s[0].length ? s[0] : s[0].split(/\s*[,;:]\s*/));
			this.us.length=0;
			this.pasteObjects(s.slice(1));
		}
	} else if(typeof s == "object"){
		if (s.iprop) this.addProps(s.iprop || s.prop);
		if (s.us) this.pasteObjects(s.us,0, startCol,1);
	}
	return this;
}
Table.prototype.pasteObjects = function(newUs, startRow, startCol, overWrite) {
	if (isText(newUs)) newUs = newUs.toArray();
	if (!(newUs instanceof Array) && typeof newUs == "object") newUs = [ newUs];
	if (startRow == null) startRow=this.us.length;
	if (startCol == null) startCol = 0;
	if (startRow<0) startRow = this.us.length+startRow+1;
	if (overWrite) this.us = this.us.slice(0, startRow);
	var us = this.us;
	if (!(newUs instanceof Array)) newUs = [[]];
	var me, self;
	var ip = this._iprop;
	var oIndex, pIndex;
	for (var i = 0; i < newUs.length; i++) {
		oIndex = startRow+i;
		if ((oIndex >= us.length) || !overWrite) { us.splice(oIndex, 0, new object()); }
		me = newUs[i];
		if (typeof me == "object" && me.length != null) {
			for (var p = 0; p< me.length; p++) {
				pIndex = startCol+p;
				if (pIndex >= ip.length) this.addProperty();
				if (!us[oIndex] || !this._iprop[pIndex] ) alert("no us @ "+oIndex+" or prop @ (i="+pIndex+"): "+this._iprop[pIndex])
				us[oIndex].pasteValue(this._iprop[pIndex].name, me[p]);
			}
		} else {
			for (var p in me) {
				if (p != "index" && p != "formula" && !this.prop[p]) this.addProperty(p);
				this.us[oIndex].pasteValue(p, me[p]);
			}
		}
	}
	reindex(us, startRow);
	return this;
}
Table.prototype.where = function(expr) { return this.us.grep(expr, me) } 
Table.prototype.addProps = function(props) {
	if (props== +props) { 
		this.setPropCount(props);
	} else if (props instanceof Array) {
		for (var pIndex=0; pIndex < props.length; pIndex++) this.addProperty(props[pIndex]);
		return;
	} else if (typeof props == "object") {
		var pIndex =0;
		for (var p in props) this.addProperty(p, pIndex++,props[p]);
	}
}
Table.MSG = {
	en: {
		ColExistsSoMakeAnon: "'Renaming, but column name already exists. Making anonymous.",
		TableExists: "(Table.rename) name already exists",
		CantFindMeInLiteral: "'me' not defined in Table.rowContainsLiteral, from index or object: ",
		EqualsSignRemoved: "Equals sign prefix removed.  Use for formulas in instance section, not in Template.",
		PropertyIndexOutOfBounds: "Column index is out of range."
	}
}

/* * * * * * * * * *../pgm/tableSection.js * * * * * * * * * * * */

TableSection.CELL_STYLE= {
	literal:	"background-color:#fff;",
	formula:	"background-color:#f3f3ff;",
	calc:			"background-color:#e3e3e3;",
	error:		"background-color:#faa;"
	};
TableSection.baseTempl = ["name", "formula"];
TableSection.PTempl = ["action", "prep", "format", "style", "display"];
TableSection.templLabel = {name:""};
if (!ERR_PREFIX) ERR_PREFIX = "ERR ";
if (typeof TableCell.makeNameCell=="function") { TableSection.TEMPLATE_CELL = text2(); }
	else { WARN("(TableSection.init): tableCell.js must be loaded before TableSection.js") }
TableSection.SORT_SEPARATOR	= "\\";
TableSection.DEFAULT_DISPLAY	= text();
TableSection.DEFAULT_VIEW = {templ:0, formula:1, name:1, sTempl:0, panel:{}};
TableSection.colResizeWidth=4;
if (!isDefined(window._lang)) _lang = "en";
TEMPL_DISPLAY = text2();
function CALC(th, row) {
	if (th && (th.rowCalc || th.offLine) && isDefined(row)) {th.calc(0,row);}
	else if (isDefined(window._mgr) && (!th || window._mgr.sections[th._name] )) { _mgr.calc(); }
	else {th.calc(); }
}
function TableSection(name, options, data) {
	if (!this.init(name)) return;
	var objects;
	var props;
	if (options && options._view && !isDefined(data)) data = {us:options.us, prop:options.prop}
	this._view	= clone(TableSection.DEFAULT_VIEW); 
	this._highlights = {us:{}, prop:{}};
	if (options) clone(options._view || options, this._view);
  if (!(data && data.us != null)) { objects = typeof data == "number" || (data instanceof Array) ? data : Table.DEFAULT.OBJECTS; }
  else { objects = typeof data.us=="number" ? data.us : data.us || Table.DEFAULT.OBJECTS; }
	var a = arguments[3];
	if (!(data && isDefined(data.prop))) { props = typeof a=="number" ? a : a || Table.DEFAULT.PROPS; }
	else {props = typeof data.prop == "number" ? data.prop : data.prop || Table.DEFAULT.PROPS; }
	var u = {};
	if (props == +props) {
		this.setPropCount(props);
	} else if (typeof props == "object" || (props instanceof Array)) {
		u.iprop = props;
	}
	if (objects == +objects) {
		this.us.length = objects;
	} else if (typeof objects == "object") {
		u.us = objects;
	}
	if (u.us || u.iprop) this.assimilate(u);
	return this;
}
TableSection.prototype = new Table;
TableSection.prototype.constructor = TableSection;
TableSection.superclass = Table.prototype;
TableSection.prototype.draw = function(node) {
	if (this._node) this.remove();
	var node = this.drawPanel(node);
	this._node = node;
	node.innerHTML    = this.templateHTML();
	this._preHTML = node.childNodes[0];
	this._topTable  = node.childNodes[1];
	this._table = node.childNodes[2];
	this._postHTML = node.childNodes[3];
	this._topRow = this._topTable.rows;
	this._displayPanelCell = TableSection.TEMPLATE_CELL;
	var cellName;
	for (var i=0; i<Table.sectionTempl.length; i++) {
		cellName = '_node'+Table.sectionTempl[i];
		this[cellName] = this._displayPanelCell.create(this, this._topRow[i].childNodes[1],i, 'all.'+Table.sectionTempl[i], "table_tpl_cell");
		this[cellName].className = "table_tpl_cell";
		setKeyHandler(this, this[cellName],0);
	}
	this._table.cols=1;
	this._tplTable = this._table.childNodes[0];
	this._cellTable = this._table.childNodes[1];
	this._tplrow = this._tplTable.rows;
	this._row = this._cellTable.rows;
	this._rowt = {};
	for (var i=0; i<Table.templ.length; i++) this._rowt[Table.templ[i]] = this._tplrow[i];
	this.updatePanel();
	return this;
}
TableSection.prototype.toHTML= function() {
	var a = "<div>"+(this.preHTML||"")+"</div><table border='1' cellspacing='0'><tbody><tr><th>&nbsp;</th>";
	var ip= this._iprop;
	for (var i=0; i<ip.length; i++) a+="<td align='center'>"+(ip[i].name||"&nbsp;")+"</td>";
	a += "</tr></tbody>\n<tbody>";
	var us = this.us;
	var self, css;
	for (var row=0; row<us.length;row++) {
		a +="<tr><td>"+row+"</td>";
		for (var col=0; col<ip.length; col++) {
			self = this.formatCell(us[row], ip[col]);
			css = this.getCellStyle(us[row],ip[col]);
			a += "<td class='table_objectTD' style='"+css+"'>"+(self==="" ? "&nbsp;" : self)+"</td>";
		}
		a +="</tr>";
	}
	a +="</tbody></table><div>"+(this.postHTML||"")+"</div>\n";
	return a;
}
TableSection.prototype.focus = function() {
	var firstRow = this._shown ? this._shown[0].index : 0;
	if (isDefined(this.instanceCell(firstRow,0)) && this._view.panel.displayContent != "none" && this._view.panel.displayAll != "none") this.instanceCell(firstRow,0).focus();
	return this;
}
TableSection.prototype.drawPanel = function(node) {
	if (!this._panel) this._panel = new Panel();
	var p= this._panel;
	for (var i in this._view.panel) p.view[i] = this._view.panel[i];
	this._view.panel = p.view;
	p.draw(node);
	return p.nodeContent;
}
TableSection.prototype.updatePanel = function() {
	var p = this._panel;
	p.setup();
	var lockTempl = p.view.lockTemplate;
	var th = this;
	p.drawTitleCell(!lockTempl, function() {
		if (isDefined(window._mgr)) { _mgr.renameSection(th._name, this.value).calc() }
		else {this.rename(th._name, this.value)}
		if (isanonymous(this.value)) this.value = "";
	} );
	p.updateTitle(isanonymous(this._name) ? "" : this._name.replace(/_/g," ")); 
	p.setResizeable(!p.view.resizeable ? "" : lockTempl ? "v" : "hv");
	if (!p.hideTitle && !lockTempl && this._tplrow) { this.addButtons(p.nodeTitleRight); }
	else { if (p.nodeTitleRight) p.nodeTitleRight.innerHTML = "";}
		if (this._topRow && this._tplrow) {
			this.toggleSectionTemplate(!lockTempl && (this._view.sTempl||0));
			this.togglePropTemplate(!lockTempl && (this._view.templ||0));
			this.toggleFormula(!lockTempl && this._view.formula);
			for (var c=0; c< this._iprop.length; c++) {
				this.tplCell(5,c).contentEditable = !lockTempl;
				this.tplCell(5,c).readOnly = lockTempl;
			}
		}
	var img = p.nodeVBar;
	img.onclick = function(_e) { if (!_e) _e = window.event; _e.shiftKey ? th.removeObjects(_e.ctrlKey?5:1,1) : th.addObjects(_e.ctrlKey ? 5:1,1); }
	if (this._view.altRowSizer) {
		this._panel.nodeHV.style.backgroundColor = "transparent";
		img.innerHTML = "<div style='background-color:white;text-align:center;cursor:pointer;'>&nbsp;+&nbsp;</div>";
		this._panel.removeDragger(img);
		img.className = "panel_bar";
		img.title="Click to add row, shift-click to delete row Ctrl key: x 5.";
	} else {
		this._panel.nodeHV.style.backgroundColor = "";
		img.title="Drag to add/delete rows OR click to add row, shift-click to delete row Ctrl key: x 5.";
		img.innerHTML = "";
		img.className = "panel_moveableVert";
		var th = this;
		this._panel.makeDragger(img, th, TableSection.dragStartObjects, TableSection.dragObjects, TableSection.dragEnd);
		this._panel.makeDragger(p.nodeHV, th, TableSection.dragStartBoth, TableSection.dragBoth, TableSection.dragEnd);
	}
	var img = p.nodeHBar;
	this._panel.makeDragger(img, th, TableSection.dragStartProps, TableSection.dragProps, TableSection.dragEnd);
	img.onclick = function(_e) { if (!_e) _e = window.event; var i = th.getLastColHighlight();_e.shiftKey ? th.deleteProperty(i).calc(1) : th.addProperty(i).drawProperty(i).calc(1);CALC(th);}
	img.title="Click to add column, shift-click to delete column, drag to add/delete multiple columns.";
	p.onbeforeclose	= function() {if (isDefined(window._mgr)) {_mgr.removeSection(th._name)} else {this.remove();p = null}}
	p.onaftershowhide = function(display) {if (display=="") th.showValues(); }
	for (var row=0; row<this._row.length; row++) this.drawRowLabel(row);
	this.updateRowLabels();
}
TableSection.prototype.remove = function() {
	for (var i=0; i<this._iprop.length; i++) this.undrawProp(0);
	this.removeButtons(this._panel.nodeTitleRight);
	var p = this._panel;
	p.onmoveend = null;
	p.onbeforeclose = null;
	p.onaftershowhide = null;
	Panel.removeElement(p.nodeVBar);
	Panel.removeElement(p.nodeHBar);
	var nodes = qw("_topRow _topTable _table _tplTable _cellTable _tplrow _row _displayPanelCell");
	for (var i=0; i<nodes.length; i++) if (this[nodes[i]]) this[nodes[i]] = null;
}
TableSection.prototype.templateHTML = function() {
	var attrName;
	var i;
	var tooltip;
	var a = "<div display='none'></div><table cellspacing='0' cellpadding='0' border='0'>"
	for (i=0; i<Table.sectionTempl.length; i++) {
		toolTip = TableSection.MSG[_lang].globalToolTip[i]? "title='"+TableSection.MSG[_lang].globalToolTip[i]+"' " : "";
	 	a+= "<tr>"
		+ "<td class='table_tpl_label' width='10%' unselectable='on' "+toolTip+">&nbsp;"+Table.sectionTempl[i]+"&nbsp;</td>"
		+ "<td width='100%' class='table_objectTD'>" 
		+ "</td></tr>";
	}
	a += "</table>";
	a += "<table border='0' class='main_table' cellspacing='0' cellpadding='0'><tbody>";
	for (i = 0; i< Table.templ.length; i++) {
		toolTip = TableSection.MSG[_lang].templToolTip[i]? "title='"+TableSection.MSG[_lang].templToolTip[i]+"' " : "";
		attrName = Table.templ[i];
		if (isDefined(TableSection.templLabel[attrName])) attrName = TableSection.templLabel[attrName];
		a += "<tr>"
		+ "<td class='table_tpl_label' unselectable='on' "+toolTip+">"+attrName+"</td></tr>\n"; 
	}
	a += "</tbody><tbody></tbody></table><div display='none'></div>";
 return a;
}
TableSection.prototype.update = function(typ, oIndex, pIndex, newValue) {
	var oldValue = this.updateNoUndo(typ, oIndex, pIndex, newValue);
	if (!isDefined(window._mgr)) return;
	var i = _mgr.undoPtr++;
	var a = this._name+".updateNoUndo('"+typ+"',"+oIndex+","+pIndex+",'";
	_mgr.undoStack[i] = a+oldValue+"')";
	_mgr.redoStack[i] = a+newValue+"')";
	_mgr._sheetModified = 1;
}
TableSection.prototype.updateNoUndo = function(typ, tableRow, pIndex, newValue) {
	var prop = this._iprop[pIndex];
	var oIndex;
	var oldValue;
	if (typ == "object") {
		this.prepObject(tableRow, pIndex, newValue);
	} else {
		if (newValue == null) newValue = "";
		if (typ.substr(0,4)=="all.") { oldValue = this[typ.substr(4)]; }
		else { oldValue = prop[typ] } 
		if (typ == "display") { 
			prop[typ] = newValue;
			this.updateDisplay(prop);
		} else if (typ=="all.display") {
			this.display = newValue;
			for (var i=0; i<this._iprop.length; i++) this.updateDisplay(this._iprop[i]);
		}
		if(!this.updateTemplate(typ, oIndex, pIndex, newValue)) return;
	}
	return oldValue;
}
TableSection.prototype.shownRow = function(oIndex) {
	if (!this.filter) return oIndex;
	for (var i=oIndex-1; i>=0; i--) if (!isVisible(this._row[i])) oIndex--;
	return oIndex;
}
TableSection.prototype.updateDisplay = function(propx, index, force) {
	var prop = (typeof propx=="string") ? this.prop[propx] : propx;
	if (!prop) {
		throw {message:ERR_PREFIX+" ("+this._name+".updateDisplay):"+TableSection.MSG[_lang].unknownProp+propx}
		return;
	}
	col = prop.index;
	var td;
	var p;
	p = this.createDisplayObject(prop.display || this.display, index);
	if (!p || typeof p.create !="function") {
		WARN("("+this._name+".prop."+prop.name+".updateDisplay (index="+prop.index+")): "+TableSection.MSG[_lang].badDisplayFormula);
		p = TableSection.DEFAULT_DISPLAY;
	}
	if (!force && p == prop._displayObject) { prop._displayObject = p; return; }
	var rowStart = 0;
	var rowEnd = this.us.length-1;
	if (index!= null) {
		rowStart = index;
		rowEnd = index;
	}
	len= this.us.length;
	for (row=rowStart; row<=rowEnd; row++) {
		td = this.instanceTD(row,col);
		if (typeof td != "object") WARN(ERR_PREFIX+" (TableSection.updateDisplay, r="+row+", c="+col+"): no cell in table to update");
		this.removeCell(td);
		td.style.cssText="";
		p = this.createDisplayObject(prop.display || this.display, row);
		p.create(this, td, row);
	}
	prop._displayObject = p;
	return this;
}	
TableSection.prototype.createDisplayObject = function(displayText, row) {
	var dspo;
	var context = row != null ? this.us[row]:this;
	if (!context) { NOTE("INTERNAL: no context for TableSection::createDisplayObject"); return; }
	if (!displayText) {
		dspo = TableSection.DEFAULT_DISPLAY;
	} else {
		try {
		with(Math){ with(context) {
		dspo = eval(displayText);
		} } 
		} catch(_e) {
			WARN("("+this._name+".createDisplayObject: '"+displayText+"'): "+TableSection.MSG[_lang].badDisplayFormula+"\n\nError: "+_e.message);
			dspo = TableSection.DEFAULT_DISPLAY;
		}
	}
	return dspo;
}
TableSection.prototype.applyView = function() {
	if (this._panel) this._panel.applyView(this._name);
}
TableSection.prototype.precalc = function() {
	delete this.rowLabel;
	this.cellWidth = null;
	this.preprocess();
}
TableSection.prototype.calc = function(updateDisplay, row) { 
	this.process(row);
	var vp = this._view && this._view.panel;
	var visible = vp && (!vp.displayContent || vp.displayContent!="none") 
	&& (!vp.displayAll || vp.displayAll!="none");
	if ( !this.isStatic && (visible|| updateDisplay)) {
		this.showValues(updateDisplay, row);
		this.applyView();
	}
	return this;
}
TableSection.prototype.showValues = function(updateDisplay, rowToCalc) {
	var prop;
	var self;
	var filtering = 0;
	var _ip = this._iprop;
	var me;
	var meform;
	if (!this._panel) { this.draw(); WARN("tablesection.showvalues-- no panel to draw in") }
	var p = this._panel;
	var tdNode;
	var cell;
	if (p) p.updateTitle(isanonymous(this._name) ? "" : this._name.replace(/_/g," ")); 
	this.updateProperties();
	var filterAll = this.filter !=null && (this.filter == "0" || this.filter.toString().substr(0,3)=="0\/\/");
	this._cellTable.style.display = filterAll ? "none" : "";
	if (filterAll	|| this._view.panel.displayContent == "none" 
		|| this._view.panel.displayAll == "none") return;
	this._shown = this.sortObjects();
	this.updateObjects();
	this.updateSectionTemplate();
	if (updateDisplay) for (var p=0; p < _ip.length; p++) this.updateDisplay(_ip[p]);
	if (this.filter) {
		var uu="with (Math) {var _f = function(me) { with (me) {return "+this.filter+"}}}";
		try {eval(uu); } 
		catch(_e) {setStatus(ERR_PREFIX+" ("+this._name+".filter) "+_e.message);}
	}
	var lastRow = this.rowCalc && isDefined(rowToCalc) ? rowToCalc: this.us.length-1;
	var firstRow = this.rowCalc && isDefined(rowToCalc) ? rowToCalc: 0;
	for (var row=this.us.length-1; row >=0; row--) {
		var _row = this._row[row];
		_row.style.cssText = "";
		me = this._shown[row];	
		if (!this.filter || _f(me)) {
			_row.style.display = "";
		} else {
			_row.style.display = 'none'; 
			this._shown.splice(row,1);
			continue;
		}
		if (isDefined(rowToCalc) && row != rowToCalc) continue;
		for (var pIndex=0; pIndex< _ip.length; pIndex++) {
			prop = _ip[pIndex];
			TDnode = this.instanceTD(row,pIndex);
			if (!prop._displayObject) this.updateDisplay(prop);
			if (!prop._displayObject || !TDnode) { WARN("tableSection.showValues: INTERNAL error: no _displayObject ("+prop.displayObject+") or TDnode ("+TDnode+"), row="+row+" col="+pIndex);}
			cell = prop._displayObject.nodeFromTD(TDnode);
			self = this.formatCell(me, prop);
			meform = isDefined(me.formula) && me.formula[prop.name];
			this.updateStyle(TDnode, cell, me, prop);
			if (!cell.getValue || self != cell.getValue()) 
				prop._displayObject.setValue(cell, self==null?"":self, meform);
		}
	}
	for (var p=0; p < _ip.length; p++) this.setPropWidth(p);
	this.updateRowLabels();
	this.updatePropTemplate();
	this._preHTML.innerHTML = this.preHTML == null ? "" : this.preHTML;
	this._preHTML.style.display = this.preHTML ? "" : "none";
	this._preHTML.style.width=this._table.clientWidth+"px";
	this._postHTML.innerHTML = this.postHTML== null ? "" : this.postHTML;
	this._postHTML.style.display = this.postHTML ? "" : "none";
	this._postHTML.style.width=this._table.clientWidth+"px";
}
TableSection.prototype.sortObjects = function() {
	var sorted;
	var s = this.sort;
	if (!s) return this.filter ? shallowCopy(this.us) : this.us;
	var varname = "";
	if (isText(s)) {
		for (col= 0; col < this._iprop.length; col++) {
			varname = this._iprop[col].name;
			if (s.toString().match(new RegExp("^\s*[+-]?\s*"+varname+"\s*$"))) { 
				s = s.match(/-/) ? "Math.cmp(o2."+varname+", o1."+varname+")": "Math.cmp(o1."+varname+", o2."+varname+")";
				break; 
			}
		}
	}
	sorted = [];
	sorted = shallowCopy(this.us);
	try {
		if (isText(s)) {
			var u = "var f = function(o1,o2) { return "+s+" }"
			eval(u);
		} else if (typeof s == "function") { f = s };
		sorted.sort(f);
	} catch (_error) {
		setStatus(ERR_PREFIX+" ("+this._name+".sort) "+_error.message);
	}
	return sorted;
}
TableSection.prototype.updatePropTemplate = function() {
	var prop;
	var attrName;
	var attrValue;
	var cell;
	var visible;
	for (var pIndex=0; pIndex< this._iprop.length; pIndex++) {
 		prop = this._iprop[pIndex];
		var sortChar = "";
		for (var tIndex=0; tIndex< Table.templ.length; tIndex++) {
			cell = this.tplCell(tIndex,pIndex)
			attrName = Table.templ[tIndex];
			attrValue = prop[attrName]||"";
			if (attrValue == null || attrValue.toString() == "") delete prop[attrName];
			if (!this._view.templ && TableSection.PTempl.indexOf(attrName)!= -1) continue;
			if ((attrName=="name" || attrName=="formula") && this._row.length > 0)  {
				for (i=0; i<this.us.length && !isVisible(this._row[i]); i++) ;
				var visible = this._view.templ || getElementStyle(this.instanceTD(i,pIndex), "display")!="none";
				cell.parentNode.style.display = visible ?"":"none";
			}
			if (attrName == 'name') {
				if (isanonymous(attrValue)) attrValue = "";
				sortChar = !this.sort ? "" 
					: (this.sort=="-"+attrValue) ? "-" 
					: (this.sort==attrValue || this.sort=="+"+attrValue) ? "+":"";
				attrValue = sortChar + attrValue.replace(/(\w)_(\w)/g, "$1 $2");
				if (this.IDindex == pIndex) attrValue = "*"+attrValue;
				if (prop.scalarName>0) attrValue = attrValue+("==============".substr(0,prop.scalarName));
				if (prop.scalarName<0) attrValue = ("=================".substr(0,-prop.scalarName))+attrValue; 
				if (prop.units) {
					if (this._panel.view.lockTemplate && prop.units.match(/\s*:\s*(.+)/)) {
						attrValue = RegExp.$1;
					} else {
						attrValue += prop.units;
					}
				}
			}
			cell.value = attrValue;
			cell.title = attrValue;
		}
	}
}
TableSection.prototype.updateSectionTemplate = function() {
	if (!this._view.sTempl) return;
	var node;
	var ip = this._iprop;
	var width=1;
	for (var j=0; j<ip.length;j++) width+=(ip[j].cellWidth|| this.cellWidth ||TableCell.DEFAULT_TEXT_WIDTH);
	var tst = Table.sectionTempl;
	for (i=0; i<tst.length; i++) {
			node = this['_node'+tst[i]];
			this._displayPanelCell.setValue(node, this[tst[i]]==null?"":this[tst[i]]);
			this._displayPanelCell.setWidth(node, Math.max(width,30));
	}
}
TableSection.prototype.formatCell = function(me, prop) {
	var self= me[prop.name];
	if (self==null) self=""; 
	var format = prop.format || this.format;
	if (!format) return self;
	row = me.index;
	col = prop.index;
	with(Math){ with(me) {
		try {
			if (self instanceof Array) { var _self = self; var res=[]; for (var i=0; i<_self.length; i++) { self = _self[i];res[i] = eval(format); } self = res;}
			else { self = eval(format); }
		} catch(_err) { self = ERR_PREFIX+" ("+prop.name+".format): "+_err.message; }
	} }
	return self;
}
REGEXP_BORDER = /\bborder\b/i;
TableSection.prototype.updateStyle = function(TDtarget, cellTarget, me, prop) {
	var cellStyle = this.getCellStyle(me,prop);
	TDtarget.style.cssText =cellStyle;
	if (cellStyle && cellStyle.match(REGEXP_BORDER)) { cellStyle += ";border:none; "; }
	if (cellTarget.style.cssText != cellStyle) cellTarget.style.cssText = cellStyle;
	if (TDtarget.style.display=="none" && this._view.templ) TDtarget.style.display="";
} 
TableSection.prototype.getCellStyle = function(me, prop) {
	if (top.self) var self;
	var defaultStyle = this.defaultCalcStyle(me, prop);
	var pname = prop.name;
	var cellStyle = prop.style || "";
	var sectionStyle = this.style || "";
	var evalStyle = cellStyle.charAt(0) == "=";
	var evalGlobal = sectionStyle.charAt(0) == "=";
	if (evalStyle || evalGlobal) { 	
		self = me[prop.name];
		col = prop.index; 
		row = me.index;
		prev = row > 0 && this.us[row-1];
		try { with (me) { with (Math) {
			if (evalStyle) cellStyle= eval(cellStyle.substring(1));
			if (evalGlobal) sectionStyle = eval(sectionStyle.substring(1));
			} }
		} catch(_err) {
			setStatus(ERR_PREFIX+" ("+prop.name+".style) "+_err.message);
			cellStyle=TableSection.CELL_STYLE.error;
		}
	}
	if (!isText(cellStyle)) cellStyle="";
	if (!isText(sectionStyle)) sectionStyle="";
	return defaultStyle+sectionStyle + ";" +cellStyle;
}
TableSection.prototype.defaultCalcStyle = function(me, prop) {
	var result;
	if (me && typeof me[prop.name] =="string" && me[prop.name].substring(0,4)==ERR_PREFIX) {
		result = TableSection.CELL_STYLE.error;
	} else if ((prop.formula || this.formula) && !(isDefined(me.formula) && me.formula[prop.name])) {
		result = TableSection.CELL_STYLE.calc;
	} else {
		result = TableSection.CELL_STYLE.literal;
	}
	return result;
}
TableSection.prototype.updateObjects = function() {
	var oDelta = this.us.length-this._row.length;
	if (oDelta == 0) { return; }
	else if(oDelta > 0) { this.drawObjects(oDelta) }
	else { for (i=0; i > oDelta; i--) this.removeObject(-1); }
}
TableSection.prototype.removeObject = function(oIndex) {
	oIndex = limitIndex(oIndex, this._cellTable.rows.length);
	var row = this._row[oIndex];
	var node;
	for (var col=row.cells.length-1; col>=0; col--) {
		node = row.cells[col];
		if (col > 0) {
			this.removeCell(node);
		} else {
			node.onmouseover = null;
			node.onmousedown = null;
			node.onmouseup = null;
		}
		row.deleteCell(col);
		node = null;
	}
	this._cellTable.deleteRow(oIndex);
}
TableSection.prototype.removeCell = function(tdNode) {
	if (!isDefined(tdNode)) return;
	var pIndex = tdNode.cellIndex-1; 
	m = this._iprop[pIndex] && this._iprop[pIndex]._displayObject; 
	if (!isDefined(m)) return;
	cell = m.nodeFromTD(tdNode);
	if (!isDefined(cell)) {
		WARN(this._name+".UNDEF CELL: "+tdNode.outerHTML+"\n"+m.nodeFromTD);
	}
	cell.onchange = null;		cell.onkeypress=null;
	cell.onkeydown = null;	cell.onkeyup = null;
	cell.setValue=null;			cell.getValue=null;
	cell.setWidth = null;		cell.onfocus=null;
	cell.onblur = null;			cell.ondblclick=null;
}
var VDRAG_THRESHOLD = 12;
TableSection.dragStartObjects = function(_e, th) { 
	TableSection.currentY = _e.clientY+document.body.scrollTop; 
	var cell;
	for (var i=th.us.length-1; i>=0; i--) {
		cell = th.instanceTD(i,0); 
		if (cell && cell.clientHeight>0)  {
			TableSection.thresholdY = cell.clientHeight;
			break;
		}
	}
	if (TableSection.thresholdY < 1) TableSection.thresholdY = 10; 
}
TableSection.dragObjects = function(_e, th) {
	var yOffset = _e.clientY+document.body.scrollTop - TableSection.currentY; 
	th._panel.nodeVBar.height = Math.max(5, 5+yOffset);
	th._panel.nodeHV.height = Math.max(5, 5+yOffset);
	if (yOffset > TableSection.thresholdY) {
		var nRows = Math.floor(yOffset/TableSection.thresholdY);
		if (nRows > 50) return;
		th.addObjects(nRows,1);
		TableSection.currentY = _e.clientY+document.body.scrollTop; 
	} else if (th.us.length > 0 && yOffset < - TableSection.thresholdY) {
		var nRows = Math.floor(-yOffset/TableSection.thresholdY);
		th.removeObjects(nRows,1);
		TableSection.currentY = _e.clientY+document.body.scrollTop;
	}
}
TableSection.prototype.addObjects = function(count, useHighlights) {
	var index = -1;
	var me;
	if (arguments.length==2 && useHighlights) index = this.getLastRowHighlight();
	if (count == null) count=1;
	for (var i=0; i<count; i++) {
		this.pasteObjects("",index);
		me = this.us[limitIndex(index, this.us.length)];
		if (this.onaddobject) this.evalAttr("onaddobject",me);
		if (this.offLine || this.rowCalc) CALC(this, me.index);
	}
	if (!this.offLine && !this.rowCalc) CALC(this);
	return;
}
TableSection.prototype.getRowHighlight = function(row) { return this._row[row].className == "selected"?1:0; }
TableSection.prototype.getColHighlight = function(col) { return this.tplTD(5,col).childNodes[2].className == "prop_selector selected" ? 1:0;}
TableSection.prototype.setRowHighlight = function(row, state) { return this._row[row].className = (state==null ? !this.getRowHighlight(row) : state) ? "selected" : "object"; }
TableSection.prototype.setColHighlight = function(col, state) { return this.tplTD(5,col).childNodes[2].className = (state==null ? !this.getColHighlight(col) : state) ? "prop_selector selected" : "prop_selector unselected"; }
TableSection.prototype.getHighlights = function() {
	var result = {us:[], iprop:[]};
	for (var r=0; r<this._row.length; r++)   if (this.getRowHighlight(r)) result.us.push(r);
	for (var c=0; c<this._iprop.length; c++) if (this.getColHighlight(c)) result.iprop.push(c);
	return result;
}
TableSection.prototype.getLastRowHighlight = function() {return this.getHighlights().us.pop(); }
TableSection.prototype.getLastColHighlight = function() {return this.getHighlights().iprop.pop(); }
TableSection.prototype.removeObjects = function(count, useHighlight) {
	if (count instanceof Array) {
		var s = count.sort();
		for (var i=s.length-1; i>=0; i--) this.deleteObject(s[i]);
		CALC(this);
		return;
	} 
	var oIndex = this._shown.length-1;
	if (arguments.length>1 && useHighlight){
		var h = this.getLastRowHighlight();
		if (h>-1) {
			oIndex = h;
			if (h>0) this.setRowHighlight(h-1, 1);
		}
	}
	var cantDelete=0;
	for (var i = 0; i< count && oIndex >=0; i++) {
		var o = this._shown[oIndex];
if (o == null) WARN("(TableSection.removeObjects["+oIndex+"]): "+TableSection.MSG.en.noObjectAtIndex);
		if (this.deleteLiterals || !this.rowContainsLiteral(o)) {
			this.deleteObject(o.index);
		} else {
			cantDelete =1
		}
		oIndex--;
	}
	CALC(this);
	if (cantDelete) NOTE(TableSection.MSG[_lang].cantDeleteRow);
}
TableSection.dragStartProps = function(_e, th) { 
  var tbl = th._panel.nodeTable;
	TableSection.currentX = _e.clientX+document.body.scrollLeft; 
	var cell = th.instanceTD(0,th._iprop.length-1);
	if (cell) TableSection.thresholdX = cell.clientWidth;
	TableSection.draggingCol = 0;
}
TableSection.dragProps = function(_e, th) {
	var xOffset = _e.clientX+document.body.scrollLeft-TableSection.currentX; 
  var tbl = th._panel.nodeTable;
	var index;
	var ip = th._iprop;
	if (xOffset > TableSection.thresholdX) {
		index = th.getLastColHighlight() ||-1;
		th.addProperty(index);
		if (index>0) ip[index].cellWidth = ip[index-1].cellWidth;
		th.drawProperty(index);
		TableSection.currentX = _e.clientX+document.body.scrollLeft; 
		CALC(th);
	} else if (ip.length > 1 && xOffset < - TableSection.thresholdX) {
		index = th.getLastColHighlight() || ip.length-1;
		th.deleteProperty(index);
		TableSection.currentX = _e.clientX+document.body.scrollLeft; 
		CALC(th);
		if (index < ip.length-1 && index > 0) {
			th.setColHighlight(index-1,1);
			th.setColHighlight(index,0);
		}
	} 
	var imgWidth = Math.max(5, 5+xOffset); 
	th._panel.nodeHBar.width = imgWidth;
	th._panel.nodeHV.width = imgWidth;
}
TableSection.dragStartBoth = function(_e, th) {
	TableSection.dragStartProps(_e, th);
	TableSection.dragStartObjects(_e, th);
}
TableSection.dragBoth = function(_e, th) {
	TableSection.dragProps(_e, th);
	TableSection.dragObjects(_e, th);
}
TableSection.dragEnd = function(_e, th) {
	var p = th._panel;
	p.nodeHBar.width =5;
	p.nodeVBar.height=5;
	p.nodeHV.height  =5;
	p.nodeHV.width   =5;
	delete TableSection.currentX;
}
var _xx=0;
TableSection.prototype.drawObjects = function(count) {
	var firstRow = this._row.length;
	var oIndex
	for (var r=0; r<count; r++) {
		oIndex = this._row.length;
		var newRow = this._cellTable.insertRow(oIndex);
		this.drawRowLabel(oIndex);
		newRow.className = "object";
		for (var col = 0; col<this._iprop.length; col++) newRow.insertCell(-1);
	}
	var td;
	var cell;
	var prop;
	var dspo;
	var cellWidth;
	for (var pIndex = 0; pIndex<this._iprop.length; pIndex++) {
		prop = this._iprop[pIndex];
		cellWidth = prop.cellWidth|| this.cellWidth ||TableCell.DEFAULT_TEXT_WIDTH;
		for (var oIndex = firstRow; oIndex < this.us.length; oIndex++) {
			td = this.instanceTD(oIndex, pIndex);
			dspo = this.createDisplayObject((prop.display||this.display), oIndex);
			try { 
				cell = dspo.create(this, td, oIndex);
			} catch(_e) { WARN(" TableSection.drawObjects: create="+dspo.create+"\n"+oIndex+": "+td.outerHTML)}
			dspo.setWidth(cell, cellWidth);
			td.className = "table_objectTD";
		}
	}
}
TableSection.prototype.drawRowLabel = function(row) {
	var tr = this._cellTable.rows[row];
	var labelCell = tr.cells.length ? tr.cells[0] : tr.insertCell(-1); 
	labelCell.innerHTML = "<a unselectable='on' class='table_tpl_label noselect'></a>&nbsp;"
	if (this._view.altRowSizer) {
		labelCell.innerHTML += "<a style='color:red;text-decoration:none;' unselectable='on' href='#' title='Click to delete row' rowIndex='"+row+"'>x</a>";
		linkElement = labelCell.childNodes[2];
		var th = this;
		linkElement.onclick=function() {if (confirm("Delete Row "+this.parentNode.innerHTML.replace(/^.+([\d\\]+).+$/,"$1") +"?")) {th.deleteObject(this.parentNode.parentNode.rowIndex-Table.templ.length);th.calc();}}
	}
	labelCell.title = "click/drag to select objects/rows";
	var th = this;
	labelCell.onmouseover = function() { if (_xx) th.setRowHighlight(this.parentNode.rowIndex-Table.templ.length, _xx-1); }
	labelCell.onmousedown = function() { var r=this.parentNode.rowIndex-Table.templ.length;_xx= 2-th.getRowHighlight(r);th.setRowHighlight(r,_xx-1);}
	labelCell.onmouseup = TableSection.labelMouseUp;
	labelCell.className =  "table_tpl_label row_label noselect";
	labelCell.unselectable= "on";
}
TableSection.labelMouseUp = function() { _xx=0;}
TableSection.prototype.updateRowLabels = function() {
	var visRow = 0;
	for (var htmlRow=0; htmlRow < this._row.length; htmlRow++) {
		if (isVisible(this._row[htmlRow])) {
			this.setRowLabel(this._shown[visRow].index, visRow, htmlRow);
			visRow++;
		}
	}
}
TableSection.prototype.setRowLabel = function(row, visIndex, htmlRow) {
	var shownRow = isDefined(visIndex)? visIndex : row;
	var td = this._row[htmlRow].cells[0];
	var label = row;
	if (shownRow != row) label = row+TableSection.SORT_SEPARATOR+shownRow;
	if (this.rowLabel) {
		try {with (Math) {
			if (typeof this.rowLabel == "function") label = this.rowLabel(row);
			if (isText(this.rowLabel)) label = eval(this.rowLabel);	
		}} catch (_error) {
			setStatus(ERR_PREFIX+" ("+this._name+".rowLabel) "+_error.message);
		}
	}
	td.childNodes[0].innerHTML = label;
 	this.setRowHighlight(row,this.getRowHighlight(row));
}
TableSection.prototype.updateProperties = function() {
	var ip = this._iprop;
	if (!this._table || !this._table.cols) return;
	var actualPropCount = ip.length;
	var displayedPropCount = this._table.cols-1;
	var newPropCount = actualPropCount-displayedPropCount;
	if (newPropCount==0) {
		return;
	} else if (newPropCount >0) {
		for (var i=displayedPropCount; i<actualPropCount; i++) this.drawProperty(i);
	} else {
		for (var i=displayedPropCount-1; i>=actualPropCount; i--) this.undrawProp(i);
	}
	for (var i=0; i<ip.length; i++)
		if (!ip[i]._displayObject || !ip[i]._displayObject.create) 
			ip[i]._displayObject = this.createDisplayObject(ip[i].display||this.display);
}
TableSection.prototype.drawProperty = function(pIndex) {
	pIndex = limitIndex(pIndex, this._iprop.length);
	var prop = this._iprop[pIndex];
	var p = TEMPL_DISPLAY;
	prop._displayObject = p;
	for (var i=0; i< Table.templ.length; i++) {
		td = this.createTemplTDNode(i,pIndex);
		td.className="table_tpl_td";
		p.create(this, td, i, Table.templ[i], "table_tpl_cell");
		var th = this;
		if (Table.templ[i] == "name") { TableCell.makeNameCell(th, td) }
		else { p.nodeFromTD(td).className = "table_tpl_cell" }
	}
	this._table.cols = this._table.cols+1;
	var p = this.createDisplayObject(prop.display || this.display);
	for (var oIndex=0; oIndex < this._row.length; oIndex++) {
		td = this.createTDNode(oIndex,pIndex);
		p.create(this, td, oIndex);
		td.className = "table_objectTD";
	}
	prop._displayObject = p;
	this.setPropWidth(pIndex,0);
	this.updateSectionTemplate();
	return this;
}
TableSection.prototype.undrawProp = function(col, quick) {
	if (!this._row || !this._tplrow) return;
	var currentCols = this._tplrow[0].cells.length;
	var cellCol = limitIndex(col, currentCols)+1;
	var tdNode;
	for (var i=0; i<this._tplTable.rows.length; i++) { 
		tdNode = this._tplrow[i].cells[cellCol];
		if (Table.templ[i] == "name") TableCell.removeNameCell(tdNode);
		this.removeCell(tdNode);
		try {
		if (tdNode)  {
		tdNode.innerHTML = "";
			this._tplrow[i].deleteCell(cellCol);
		}
		} catch(_e) { alert("ERR (TableCell::undrawProp/internal): deleting cell table:"+this._name+" row "+i+" ("+Table.templ[i]+"),col="+cellCol+":"+_e.message+" of "+(this._tplrow[i].cells.length-1)) }
	}
	for (var i=0; i<this._cellTable.rows.length; i++) { 
		tdNode = this._row[i].cells[cellCol];
		this.removeCell(tdNode);
		this._row[i].cells[cellCol].style.display="";
		this._row[i].deleteCell(cellCol);
	}
	if (this._table.cols>0) this._table.cols = this._table.cols-1;
	if (!quick) for (var i= col; i < this._tplrow[0].cells.length-1;i++) this.updateDisplay(this._iprop[i], null, 1);
}
TableSection.prototype.togglePropTemplate = function(state) {
	var templ = TableSection.PTempl;
	var s = isDefined(state) ? (state ? 1:0) 
		: isVisible(this._rowt[templ[0]]) ? 0:1;
	this._view.templ = s;
	for (var i=0; i< templ.length; i++) showHide(this._rowt[templ[i]], s);
	if (this._shown) for (var pIndex = 0; pIndex< this._iprop.length; pIndex++) this.updateColumnStyle(pIndex);
	this.updatePropTemplate();
}
TableSection.prototype.updateColumnStyle = function(pIndex) {
	var prop = this._iprop[pIndex];
	var me, cell, TDnode;
	for (var row=this.us.length-1; row >=0; row--) {
		me = this._shown[row] || this.us[row];	
		TDnode = this.instanceTD(row,pIndex);
		cell = prop._displayObject.nodeFromTD(TDnode);
		this.updateStyle(TDnode, cell, me, prop);
	}
}
TableSection.prototype.toggleFormula= function(state) {
	var s = isDefined(state) ? (state ? 1:0) 
		: (isVisible(this._rowt.formula) ? 0:1);
	this._view.formula = s;
	showHide(this._rowt["formula"], s);
}
TableSection.prototype.createTDNode = function(row, col) {
	col = limitIndex(col, this._row[0].cells.length);
	return this._row[row].insertCell(col+1);
}
TableSection.prototype.createTemplTDNode = function(row, col) {
	col = limitIndex(col, this._tplrow[0].cells.length);
	return this._tplrow[row].insertCell(col+1);
}
TableSection.prototype.tplCell = function(r,c) {
  var cell = this._tplrow[r].cells[c+1]; 
  return isDefined(cell) && (isDefined(cell.childNodes) ? cell.childNodes[0] : cell); 
}
TableSection.prototype.tplTD = function(r,c) { return this._tplrow[r].cells[c+1]; }
TableSection.prototype.instanceCell = function(oIndex, pIndex) {
	if (! isDefined(this._row[0]) || !isDefined(this._iprop[pIndex])) return;
	var cell= this.instanceTD(oIndex, pIndex);
	return this._iprop[pIndex]._displayObject.nodeFromTD(cell);
}
TableSection.prototype.instanceTD = function(r,c) {
  if (this._row[r]) return this._row[r].cells[c+1];
}
TableSection.prototype.moveCursor = function(event, oneLine) {
	var key = event.charCode || event.keyCode;
	var ctrl = event.ctrlKey;
	var shift = event.shiftKey;
	if (oneLine) {
		if (key==13 && !ctrl) {
			key = shift ? 38: 40;
			shift = 0;
		}
		if (key == 38 || key == 40) ctrl = 1;
	}
	if (shift || !ctrl) return;
	var tdNode = (event.srcElement ? event.srcElement : event.target).parentNode; 
	var r = tdNode.parentNode.rowIndex;
	var c = tdNode.cellIndex-1;
	var maxRow = this._tplrow.length+this._row.length;
	if (key==38) {
		while (--r >= 0 && this.getRow(r).style.display == "none") ;
	} else if (key==40) {
		while (++r < maxRow && this.getRow(r).style.display == "none");
		if (event.keyCode == 13 && r >= maxRow 
			&& r >= Table.templ.length && this._view.panel.resizeable.match(/v/i)) {
			this.instanceCell(r-Table.templ.length-1,c).onblur(); 
			this.addObjects(1);
			this.showValues();
			if (this.getRow(maxRow).style.display != "none") maxRow++; 
		}
	} else {
		return;
	}
	try {
	if (r>=Table.templ.length) {
		if (r < maxRow) this.instanceCell(r-Table.templ.length, c).focus();
	} else if (r >=0) {
		this.tplCell(r,c).focus();
	}
	} catch(_e) {}
}
TableSection.prototype.getRow= function(rowIndex) {
	return rowIndex >= Table.templ.length ? this._row[rowIndex-Table.templ.length] : this._tplrow[rowIndex];
}
TableSection.prototype.shortcutKeypress= function(event, context) {
	if (!event) event = window.event;
	var tdNode = (event.srcElement ? event.srcElement : event.target).parentNode; 
	var ctrlKey = event.ctrlKey;
	if (!ctrlKey) return;
	var shiftKey = event.shiftKey;
	var altKey = event.altKey;
	var keyCode = event.charCode || event.keyCode;
	var key = String.fromCharCode(keyCode);
	var pIndex = (tdNode.cellIndex || 1) -1;
	var prop = this._iprop[pIndex];
	var row = tdNode.parentNode;
	var oIndex = !row ? 0 : row.sectionRowIndex == row.rowIndex ? this.us.length : row.sectionRowIndex;
	var foundShortcut = 1;
	if (keyCode >= "0".charCodeAt(0) && keyCode <= "8".charCodeAt(0) && !shiftKey) {
		var typ = prop.format && prop.format.toString().match(/(pct|fix|eng|engu|sci)\(/i) ? RegExp.$1 : "fixz";
		prop.format = typ+"(self,"+ key +")";
		prop.style = toggleForce(prop.style, /text\-align\:\s*right;?/i, "text-align:right;");
	} else if (keyCode == 190) {
		prop.format = prop.format && prop.format.replace(/(pct|fix|eng|engu|sci)\(self,\s*\d\);?/i, "");
		prop.style  = prop.style && prop.style.replace(/text\-align\:\s*right;?/i, "");
	} else if (key == "B") {
		prop.style = toggleMerge(prop.style, /;?font-weight:\s*bold;?/i, ";font-weight:bold;");
	} else if (keyCode == 191 && shiftKey ) {
		prop.prep = prop.prep&& prop.prep.match(/toDate\(/) ? "" : "prepDate(self)";
		prop.format = prop.format && prop.format.match(/toDate\(/) ? "" : "toDate(self)";
	} else if (key == "E" && shiftKey) {
		prop.prep = prop.format.match(/engu\(/) ? "" : "prepEngu(self)";
		prop.format = prop.format.match(/engu\(/) ? "" : "engu(self)";
		prop.style = toggleMerge(prop.style,/;?text-align:\s*right;?/i,";text-align:right;");
	} else if (key == "4" && shiftKey) {
		var currently = prop.format && prop.format.match(/dol\(/i) ;
		prop.prep = currently ? "" : "prepNum(self)";
		prop.style = toggleForce(prop.style,/;?text-align:\s*right;?/i, currently ? "":";text-align:right;");
		prop.format = currently ? "" : "dol(self)";
	} else if (key == "5" && shiftKey) {
		var currently = prop.format.match(/pct\(/i) ;
		prop.prep = currently ? "" : "parseFloat(self)/100";
		prop.style = toggleForce(prop.style,/;?text-align:\s*right;?/i, currently ?"":";text-align:right;");
		prop.format.toString().match(/fixz\(self,(\d)\)/);
		prop.format = currently ? "": "pct(self,"+(RegExp.$1||1)+")";
	} else if (key == "I") {
		prop.style = toggleMerge(prop.style,/;?font-style:\s*italic;?/i,";font-style:italic;");
	} else if (key == "A" && shiftKey) {
		if (prop.style && prop.style.match(/;?text-align:\s*center;?/i)) {
			prop.style = toggleMerge(prop.style, /;?text-align:\s*center;?/i, ";text-align:center;");
			prop.style = toggleMerge(prop.style,/;?text-align:\s*right;?/i,";text-align:right;");
		} else if (prop.style && prop.style.match(/;?text-align:\s*right;?/i)) { 
			prop.style = toggleMerge(prop.style,/;?text-align:\s*right;?/i,"");
		} else {
			prop.style = toggleMerge(prop.style,/;?text-align:\s*center;?/i,";text-align:center;");
		}
	} else if (key == "O" && altKey) {
		prop.style = '=self=="on"?"background-color:yellow":self=="off"?"background-color:gray":"" ';
		prop.display = 'toggleButton("on", "off")';
		prop.formula = '"off"';
		this.calc(1);
	} else if (key == "X" && shiftKey) {
		setClipboard(array2table(this.getSelection()));
		this.removeObjects(this.getHighlights().us);
	} else if (key == "C" && shiftKey) {
		var t = this.getSelection();
		if (_mgr && _mgr._view.pasteNames) t.unshift(this.getPropNames());
		setClipboard(array2table(t));
	} else if (key == "V" && shiftKey) {
		var rows = getClipboard().toArray(_mgr && _mgr._view.pasteDelim);
		if  (confirm(_mgr._view.pasteDelim+"= delim, paste rows = "+splay(rows))) {
			if (_mgr._view.pasteNames) {
				this.setPropNames(rows[0]);
				rows = rows.slice(1);
			}
		this.pasteObjects(rows, oIndex, pIndex, 1);
		this.process();
		}
	} else if (keyCode == 13 || keyCode ==77) {
		if (context && context.onchange) { context.onchange(); }
		else if (context && context.onblur) { context.onblur(); }
 	} else {
		foundShortcut =0;
	}
	if (foundShortcut) {
		this.showValues();
		event.cancelBubble = true;
		if (event.stopPropagation) event.stopPropagation();
	}
}
TableSection.prototype.getSelection = function() {
	var ip= this._iprop;
	var h = this.getHighlights();
	if (h.us.length==0) h.us = range(this.us.length);
	if (h.iprop.length ==0) h.iprop = range(ip.length);
	var result = [];
	for (var r=0; r<h.us.length; r++) {
		result[r]=[];
		for (var c=0; c<h.iprop.length; c++) result[r][c] = this.us[h.us[r]][ip[h.iprop[c]].name];
	}
	return result;
}
TableSection.prototype.toArray = function() {
	result = [[]];
	var ip = this._iprop;
	for (var pIndex = 0; pIndex < ip.length; pIndex++) {
		result[0][pIndex] = ip[pIndex].name;		
	}
	for (var oIndex = 0; oIndex < this.us.length; oIndex++) {
		result[oIndex+1] = [];
		for (var pIndex = 0; pIndex < ip.length; pIndex++) {
			result[oIndex+1][pIndex] = this.us[oIndex][ip[pIndex].name];
		}
	}
	return result;
}
TableSection.prototype.toString = function() {
	var a = this.toArray();
	var result = "";
	var self="";
	for (var r=0; r<a.length; r++) {
		for (var c=0; c<a[r].length; c++) {
			if (c > 0) result +="\t";
			self = a[r][c];
			value = self == +self && self.toString() !="" ? +self : self;
			if (isDefined(value)) result += value.toString().replace(/\n/g, "\\n");
		}
		result +="\n";
	}
	return result;
}
function toggleMerge(target, regex, mergeString) {
	var result;		
	if (!target) target = "";
	if (target.match(regex)){ target = target.replace(regex,""); }
	else { target += mergeString; }
	return target;
}
function toggleForce(target, regex, mergeString) {
	if (target) target = target.replace(regex,"");
	target += mergeString;
	return target;
}
TableSection.prototype.addButtons = function(node) {
	if (this._panel.view.lockTemplate || this._panel.view.hideTitle) return;
	var classes = "class='panel_icon noselect' onmouseover='this.className=\"panel_icon  noselect panel_icon_omo\"' onmouseout='this.className=\"panel_icon noselect\"' ";
	var labels = TableSection.MSG[_lang].iconToolTip;
	var a = "<span "+classes+" title='"+labels.S+"' unselectable='on'>&nbsp;S&nbsp;</span>"	
	+ "<span "+classes+" title='"+labels.P+"' unselectable='on'>&nbsp;P&nbsp;</span>"
	+ "<span "+classes+" title='"+labels.F+"' unselectable='on'>&nbsp;<i>f</i>()</span>&nbsp;&nbsp;";
	node.innerHTML = a;
	var th = this;
	var iconNodes = node.childNodes;
	iconNodes[0].onclick = function() {th.toggleSectionTemplate()}
	iconNodes[1].onclick = function() {th.togglePropTemplate() }
	iconNodes[2].onclick = function() {th.toggleFormula(); }
}
TableSection.prototype.removeButtons = function() {
	var node = this._panel.nodeTitleRight;
	if (this._panel.view.lockTemplate || this.hideTitle) return; 
	if (!(node && node.childNodes && node.childNodes[0] && node.childNodes[0].childNodes)) return;
	var iconNodes = node.childNodes[0].childNodes;
	Panel.removeElement(iconNodes[0]);
	Panel.removeElement(iconNodes[1]);
	Panel.removeElement(iconNodes[2]);
}
TableSection.prototype.toggleSectionTemplate = function(state) {
	var u = isDefined(state) ? (state ? 1:0) : (!isVisible(this._topRow[1]) ? 1:0) ;
	this._view.sTempl = u;
	for (var i=0; i<Table.sectionTempl.length; i++) showHide(this._topRow[i], u); 
	this.updateSectionTemplate();
}
TableSection.prototype.resizeCol = function(_e, pIndex) {
	var ox = _e.clientX+document.body.scrollLeft-TableSection.currentX; 
	if (this.cellWidth) {
		setStatus("<span style='color:red'>TableSection.CellWidth fixed at "+this.cellWidth+". See section template to change</span>",1);
	} else if (Math.abs(ox) > 4) {
		var delta = ox;
		this.setPropWidth(pIndex, delta);
		var others = this.getHighlights().iprop;
		for (var i=0;i < others.length; i++) if (i != pIndex) this.setPropWidth(i, delta);
		this.updateSectionTemplate();
		TableSection.currentX = _e.clientX+document.body.scrollLeft; 
	}
	TableSection.draggingCol = 1;
}
TableSection.prototype.setPropWidth = function(pIndex, delta) {
	var cell;
	if (!isDefined(delta)) delta = 0;
	var prop = this._iprop[pIndex];
	var cellWidth = Math.max(1, (prop.cellWidth|| this.cellWidth ||TableCell.DEFAULT_TEXT_WIDTH)+delta);
	(cellWidth != this.cellWidth && cellWidth != TableCell.DEFAULT_TEXT_WIDTH )?prop.cellWidth = cellWidth : delete prop.cellWidth;
	var setWidth = TEMPL_DISPLAY.setWidth; 
	var setWidth = TEMPL_DISPLAY.setWidth;
	for (var r = 0; r < Table.templ.length; r++) setWidth(this.tplCell(r, pIndex), cellWidth-(r==5?TableSection.colResizeWidth:0));
	var p = prop._displayObject;
	if (!p) return;
	var setWidth= p.setWidth;
	if (!isDefined(setWidth)) return
	for (var r = 0; r < this._row.length; r++)
		setWidth(this.instanceCell(r, pIndex), cellWidth);
	return cellWidth;
}
TableSection.MAX_FIT_COLUMN_WIDTH = 50;
TableSection.prototype.fitColumn= function(pIndex) {
	var pname = this._iprop[pIndex].name;
	var w = pname.length;
	var l;
	for (var r=0; r< this.us.length; r++) {
		l = this.us[r][pname].toString().length+3;
		if (l > 5) { w = Math.max(w, l * TableCell.widthScale); }
	}
	var currentWidth = this._iprop[pIndex].cellWidth || TableCell.DEFAULT_TEXT_WIDTH;
	var newWidth = Math.floor(Math.min(TableSection.MAX_FIT_COLUMN_WIDTH, Math.max(0, w)));
	alert(currentWidth+"=c n="+newWidth+"==>"+ (newWidth - currentWidth));
	this.setPropWidth(pIndex, newWidth - currentWidth);
	this.updateSectionTemplate();
}
TableSection.prototype.loadContents = function(s) {
	var prop;
	for (i = 0; i< s.iprop.length; i++) {
		prop = s.iprop[i];
		this.renameProperty(i, prop.name);
		shallowCopy(prop, this._iprop[i]);
	}
	if (s.us) {
		this.pasteObjects(s.us,0,0,1);
	} else if (s.form) {
		var ip = this._iprop;
		var u = this.us;
		for (var i in s.form) {
			if (isDefined(s.form[i].index)) this.us[+i] = new object(s.form[+i]);
		}
		for (var i=0; i<s.len; i++) {if (!u[i]) u[i] = new object(); if (!u[i].index) u[i].index =i; }
	}
	reindex(this.us);
	var name;
	for (var i=0; i<Table.sectionTempl.length; i++) {
		name = Table.sectionTempl[i];
		if (isDefined(s[name])) this[name] = s[name];
	}
	if (isDefined(s.IDindex)) this.IDindex = s.IDindex;
	if (isDefined(s.sort)) this.sort = s.sort; 
	if (isDefined(s.offLine)) this.offLine = s.offLine;
	if (!window._mgr) this.rename(s.name);
	return this;
}
TableSection.prototype.saveContents = function() {
	var s = {name:this._name, secType:this.secType, iprop:this._iprop, sort:this.sort, view: this._view, IDindex:this.IDindex};
	var p = this._iprop;
	s.form = {};
	for (var row=0; row < this.us.length; row++)
		if (this.rowContainsLiteral(row)) {s.form[row] = this.us[row]; }
	s.len = this.us.length;
	var name;
	for (var i=0; i<Table.sectionTempl.length; i++) {
		name = Table.sectionTempl[i];
		if (isDefined(this[name])) s[name] = this[name];
	}
	if (isDefined(this.offLine)) s.offLine = this.offLine;
	return s;
}
TableSection.MSG = {
	en: {
	globalToolTip: [
		'Only shows rows where formula evaluates to true.  e.g., "a > 0" only shows rows where the value of a is positive.',
		'Default format for columns.  For details, show Property template and hover over "format".',
		'Default style for columns.  For details, show Property template and hover over "style".',
		'Default display for all properties.  For details, show Property template and hover over "display".',
		'Formulas or statements here will be calculated before the rest of the section is calculated.',
		'Default formula for all properties.  For details, see tooltip help for property template formula row.',
	],
	templToolTip: [
		'Post processing for values entered by hand.',
		'Preprocessing for entered values.  e.g., prepNum(self) removes commas and dollar signs.',
		'Format value before displaying; e.g., fix(self), dol(self), self+" in.".',
		'CSS that styles calculated results.  Prefix "=" for expressions.',
		'HTML element used for display; default is text().  e.g., textarea(), select([...])',
		'This row contains the name of the variable in the column.  Use column names in formulas.',
		'Javascript formulas for values in columns.'
	],
	iconToolTip: {
		S:"Toggle Section Template. Hover over row names for more help.",
		P:"Toggle Property (per-column) Template. Hover over row names for more help.",
		F:"Click to toggle formula row"
	},
	cantDeleteRow: "Can't delete row-- contains literals (safety).",
	noObjectAtIndex: "Internal error: no object at index.",
	badDisplayFormula: "Didn't understand display formula, setting to default. See Help > Reference, Table:Display for valid formulas.",
	unknownProp: "Didn't understand property designation: "
}
}

/* * * * * * * * * *../pgm/file.js * * * * * * * * * * * */

File = {};
File.mergeOnLoad = 0;
File.SILENT = 120;
File.DIR_EXT = "&lt;dir&gt;";
File.CURRENT_DIR_EXT = "&lt;Select dir&gt;";
File.UP_DIR_LABEL = "&lt; Parent Folder &gt;";
File.saveBackup = 1;
File.NSPM = window.netscape && netscape.security && netscape.security.PrivilegeManager;
File.webSaveScript = "http://richk.net/cgi-bin/HttpUpload.pl";
File.init = function() {
	File.BASE_PATH = document.location.href.replace(/[\?\#].+/,"").replace(/[\\\/][^\/\\]+$/,"");
	var path = File.getLocalPath(File.BASE_PATH);
	File.separator = path.match(/^\w\:/) ? "\\" : path.match(/([\/\\])/) ? RegExp.$1 : "\\";
	File.currentDir = File.BASE_PATH +"/";
}
File.save = function(content, path, silence) {
	if (path.match(/^http:\/\//)) {
		return File.webSave(content, path, silence);
	}
	path = File.getLocalPath(path);
	if (File.exists(path)) {
		var d = new Date();
	}
	var result = File.ie.save(content, path, silence);
	if (result == null) { result = File.mozilla.save(content, path, silence); }
	return result;
}
File.webSave = function(content, fileName, silence) {
	var webData = "file="+fileName + "&content=" + encodeURIComponent(content);
	try {
		return File.webPost(File.webSaveScript, webData, silence);
	} catch(_e) {
		if (!silence) return("File.webSave ("+fileName+") Problem: "+_e.message);
		return null;
	}
}
File.webPost = function(url, content, silence) {
	if (window.ActiveXObject) { xmlhttp=new ActiveXObject("Microsoft.XMLHTTP") }
	else if (window.XMLHttpRequest) { xmlhttp=new XMLHttpRequest() }
	xmlhttp.open("POST",url ,false);
	xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
	xmlhttp.setRequestHeader("Content-length", content.length);
	xmlhttp.setRequestHeader("Connection", "close");
	xmlhttp.send(content);
	if (xmlhttp.status == 200) {
		return xmlhttp.responseText;
	} else {
		throw {type:"XMLHttpSend", text:"There was a problem sending the data:\n" +
		xmlhttp.statusText };
	}
}
File.loadURL = function(url) {
  var xmlhttp = File.getURL(url);
	return xmlhttp.responseText;
}
File.loadXML = function(url) {
  var xmlhttp = File.getURL(url);
	if (xmlhttp.responseXML.childNodes.length > 0) {
		return xmlhttp.responseXML;
	} else {
		xmldoc = new ActiveXObject("Msxml2.DOMDocument");
		xmldoc.loadXML(xmlhttp.responseText);
		return xmldoc;
	}
}
File.getURL = function(url) {
	var xmlhttp;
	if (url.match(/^[A-Za-z]:/i)) url = "file:\/\/\/"+url;
	if (window.ActiveXObject) { xmlhttp=new ActiveXObject("Microsoft.XMLHTTP") }
	else if (window.XMLHttpRequest) { xmlhttp=new XMLHttpRequest() }
	if (window.netscape && url.match(/tp:\/\//) && (!document.domain || (url.slice(7, document.domain.length + 7) != document.domain) && File.NSPM)) {
		try {
	netscape.security.PrivilegeManager.enablePrivilege( "UniversalXPConnect");
	netscape.security.PrivilegeManager.enablePrivilege( "UniversalBrowserRead");
		} catch(_e) {
			alert("Cross-site requests prohibited. You will only be able to read from the origin site: " + _e);
			return;
		}
	}
	xmlhttp.open("GET",url,false);
	xmlhttp.send(null);
	return xmlhttp;
}
File.rename = function(oldName, newName) {
	try {
		netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
		var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
	} catch (_e) {
		return null;
	}
	try {file.initWithPath(path) }
	catch(_e) { alert("File.mozilla.dir (path='"+path+"'):"+_e.message) };
	if (!file.isDirectory()) {
	}
}
File.dir = function(path) {
	if (path.match(/^https?:\/\//i)) return File.webDir(path);
	else return File.localDir(path);
}
File.webDir = function(path) {
	path = path.replace(/[\/\\]$/,"/");
	var result = [];
	var dirContent = File.loadURL(path);
	var lines = dirContent.split(/[\n\r]+/);
	var res;
	var li;
	for (var i=0; i<lines.length; i++) {
		res = {};
		li = lines[i];
		if (!li.match(/<a .*?href\s*=\s*"(.+?)"/i)) continue;
		res.name = unescape(RegExp.$1);
		if (li.match(/parent\s*directory/i)) continue;
		if (res.name.match(/[\/\\]$/)) { res.extension = File.DIR_EXT; }
		else { res.extension = res.name.replace(/.+\./,""); }
		if (!li.match(/\s([\w-]{6,15}\s+\d{1,2}:\d\d)\s\s/i)
			) continue;
		res.date = prepDate((RegExp.$1).replace(/[^\w]+/," "));
		if (li.match(/\s\s([\d\.]+[kM]?)\s\s/i))	res.size = prepEngu(RegExp.$1,2);
		if (res.name && res.date) result.push(res);
	}
	if (result.length == 0) throw {type:"CantReadWebDirectory", message:"Does not have HTML index or empty."};
	return result;
}
File.localDir = function(path) {
	path = File.getLocalPath(path);
	var result = File.ie.dir(path);
	if (result == null) result = File.mozilla.dir(path);
	return result;
}
File.getSubdirs = function(path, currentFileObject) {
	path = File.getLocalPath(path);
	var result = File.ie.getSubdirs(path, currentFileObject);
	if (result == null) result = File.mozilla.getSubdirs(path);
	return result;
}
File.exists = function(path) {
	path = File.getLocalPath(path);
	var result = File.ie.exists(path);
	if (result == null) result = File.mozilla.exists(path);
	return result;
}
File.ie = {};
File.ie.forWriting = 2;
File.ie.forReading = 1;
File.ie.save = function(content, path, silence) {
	if (!path || path.match(/[\/\\]$/)) return;
	var fso, file;
	var result;
	try { fso = new ActiveXObject("Scripting.FileSystemObject") }
	catch(_e) { return null; }
	try {
		if (fso.FileExists(path) && !silence) {
			if (!confirm(path+" already exists.  overwrite?")) return;
		}
		file = fso.OpenTextFile(path, File.ie.forWriting, true);
		var chunkSize = 100;
		for (var ptr=0; ptr< content.length;ptr+=chunkSize) {
			file.Write(File.fixUnicode(content.slice(ptr,ptr+chunkSize)));
		}
		file.Close();
		result = "saved.";
	} catch(_e) {
		 result = "File.ie.save (path='"+path+"'):"+_e.message;
	}
	return result;
}
File.fixUnicode = function(s) {
	for (var c,i=0, res=[]; i<s.toString().length; i++) {
		c = s.charCodeAt(i);
		res += c < 128 ? s.charAt(i) : c==8211 ? "-" : c==183 ? "&middot;" : c== 176 ? "&deg;" : c==8220 || c==8221 ? '"' :"";
	}
	return res;
}
File.ie.rename = function(oldPath, newPath) {
	try { fso = new ActiveXObject("Scripting.FileSystemObject") }
	catch(_e) { return null; }
	fso.MoveFile(oldPath, newPath);
}
File.ie.dir = function(path) {
	try { if (ActiveXObject) fso = new ActiveXObject("Scripting.FileSystemObject") }
	catch(_e) { return null; }
	var f;
	var item;
	var folder = fso.GetFolder(path);
	var result = File.getSubdirs(path, folder);
	path += "/";
	var extension;	
	for (var fc = new Enumerator(folder.Files); !fc.atEnd(); fc.moveNext()) {
		f = fc.item();
		extension = f.name.replace(/.+\.([\w$~]+)/, "$1");
		item = {date: prepDate(f.DateLastModified), size:f.size, name: f.name, extension: extension};
		result.push(item);
	}
	return result;
}
File.ie.exists = function(path) {
	try {
		fso = new ActiveXObject("Scripting.FileSystemObject");
	} catch(_e) { return null; }
	return fso.FileExists(path);
}
File.ie.getSubdirs = function(path, fsoFolder) {
	if (!fsoFolder) {
		try {
			fso = new ActiveXObject("Scripting.FileSystemObject");
		} catch(_e) { return null; }
		fsoFolder = fso.GetFolder(path);
		setStatus("Folder '"+path+"' not found.");
	}
	path += "/";
	var result = [];
	var f, item;
	for (var fc = new Enumerator(fsoFolder.SubFolders); !fc.atEnd(); fc.moveNext()) {
		f = fc.item();
		item = {date: prepDate(f.DateLastModified), extension:File.DIR_EXT, size:0, name:f.path.replace(/.+\\/,"")+"/"};
		result.push(item);
	}
	return result;
}
File.mozilla = {};
File.mozilla.dir = function(path) {
	var result = [];
	try {
		netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
		var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
	} catch (_e) {
		return null;
	}
	try {file.initWithPath(path) }
	catch(_e) { alert("File.mozilla.dir (path='"+path+"'):"+_e.message) };
	if (!file.isDirectory()) {
		alert("File.mozilla.dir (path='"+file.path+") does not seem to be a directory.");
		return;
	}
	var els = file.directoryEntries;
	var f;
	var name;
	while (els.hasMoreElements()) {
		f = els.getNext();
		f.QueryInterface(Components.interfaces.nsIFile);
		name = f.path.replace(/^.+[\\\/]/,"");
		if (f.isDirectory()) {
			extension = File.DIR_EXT;
			name += "/";
		} else {
			extension = name.replace(/.+\.([\w$~]+)/, "$1");
		}
		item = {date:prepDate(f.lastModifiedTime), size:f.fileSize, name: name, extension: extension};
		result.push(item);
	} 
	return result;
}
File.mozilla.getSubdirs = function(path) {
	var result = [];
	try {
		netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
		var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
	} catch (_e) {
		return null;
	}
	try {file.initWithPath(path) }
	catch(_e) { alert("File.mozilla.dir (path='"+path+"'):"+_e.message) };
	if (!file.isDirectory()) {
		alert("File.mozilla.dir (path='"+file.path+") does not seem to be a directory.");
		return;
	}
	var els = file.directoryEntries;
	var f;
	var item;
	while (els.hasMoreElements()) {
		f = els.getNext();
		f.QueryInterface(Components.interfaces.nsIFile);
		if (!f.isDirectory()) continue;
		item = {date: prepDate(f.lastModifiedTime), extension:File.DIR_EXT, size:0, name:f.path.replace(/.+[\/\\]/,"")};
	result.push(item);
	}
	return result;
}
File.mozilla.save = function(content, path, silence) {
	if(!window.Components) return null;
	try {
		netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
		var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
	} catch(_e) {return null;}
	try {
		file.initWithPath(path);
		if (!file.exists()) file.create(0, 0664);
		var out = Components.classes["@mozilla.org/network/file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream);
		out.init(file, 0x20 | 0x02, 00004,null);
		out.write(content, content.length);
		out.flush();
		out.close();
		result = "saved.";
	} catch(_e) {
		 result = "File.mozilla.save (path='"+path+"'):"+_e.message;
	}
	return result;
}
File.mozilla.exists = function(path) {
	if (!path) return;
	if(!window.Components) return null;
	try {
		netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
		var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
	} catch(_e) {alert("Problem with Mozilla Security manager"+_e.message);return null;}
	try {
		file.initWithPath(path);
		return file.exists();
	} catch(_e) {
		return null;
	}
}
File.getLocalPath = function(originalPath)
{
	var argPos = originalPath.indexOf("?");
	if(argPos != -1)
		originalPath = originalPath.substr(0,argPos);
	var hashPos = originalPath.indexOf("#");
	if(hashPos != -1)
		originalPath = originalPath.substr(0,hashPos);
	if(originalPath.indexOf("file://localhost/") == 0)
		originalPath = "file://" + originalPath.substr(16);
	var localPath;
	if(originalPath.charAt(9) == ":")
		localPath = unescape(originalPath.substr(8)).replace(new RegExp("/","g"),"\\");
	else if(originalPath.indexOf("file:\/\/\/\/\/") == 0)
		localPath = "\\\\" + unescape(originalPath.substr(10)).replace(new RegExp("/","g"),"\\");
	else if(originalPath.indexOf("file:\/\/\/") == 0)
		localPath = unescape(originalPath.substr(7));
	else if(originalPath.indexOf("file:\/\/") == 0)
		localPath = "\\\\" + unescape(originalPath.substr(7)).replace(new RegExp("/","g"),"\\");
	else if(originalPath.indexOf("file:/") == 0)
		localPath = unescape(originalPath.substr(5));
	else if(originalPath.indexOf(":\\") == 1)
		localPath = originalPath;
	else if(originalPath.indexOf("tp:\/\/") >0 
		|| originalPath.indexOf("\/") ==0 )
		localPath = originalPath;
	return localPath;
}
File.getFileName = function(path) {
	if (path.toString().match(/([^\\\/]+)$/)) { return RegExp.$1; }
	else {return path; }
}
File.getDirName = function(path) {
  path = path || "";
	if (path.toString().match(/(^.+[\\\/]).*[\?#]/)
	|| path.toString().match(/(^.+)[\\\/]/)) { return RegExp.$1; }
	else {
	path = window.location.href.match(/[^\/\\][\/\\][^\/\\]/) 
		? window.location.href.replace(/[\/\\][^\/\\]+(?:\?.+)?$/,"")
		: "";
	}
	return path;
}
File.upPathRegex = /[^\/\\]+[\/\\]\.\.[\/\\]/g;
File.makePath = function(p) {
	p = p.toString();
	while (p.match(File.upPathRegex)) p = p.replace(File.upPathRegex,"");
	if (p.match(/^[\/\\]/) || p.match(/^\w:\\/) || p.match(/^\w{2,8}:\/\//)) return p;
	return File.BASE_PATH+ "/" + p;
}
File.getRelativePath= function(s) {
	return s.replace(new RegExp(File.BASE_PATH+"[\/\\\\]?"),"");
}
File.init();

/* * * * * * * * * *../pgm/panel.js * * * * * * * * * * * */

Panel.DEFAULT_STACK_MARGIN = "10px";
Panel.IMG_DIR = window.PGM_DIR ? PGM_DIR+"img": "pgm/img";
Panel.sharpCorners= 0;
Panel.LEFT_MARGIN = 50;
Panel.TOP_MARGIN = 50;
Panel.HIDE_CHAR = "&oline;";
Panel.DEFAULT_VIEW = { left:Panel.LEFT_MARGIN || 0, top:Panel.TOP_MARGIN||0, display:"",lockTemplate:0,stacked:0,canMove:1, canHide:1,hideTitle:0,canClose:1,resizeable:"hv" };
if (!window.isDefined) window.isDefined = function(o) {return typeof o != "undefined"}
function Panel(title) {
	this.view=clone(Panel.DEFAULT_VIEW);
	if (isDefined(title)) this.title = title;
	return this;
}
Panel.prototype.draw = function(node) {
	this.nodePanel = node || this.nodePanel || createDOMNode();
	this.makePanelFrame(this.nodePanel);
	this.makeTitleBar(this.nodeTable.rows[0].childNodes[0]);
	if (this.title) this.updateTitle(this.title);
	return this;
}
Panel.prototype.setup = function() {
	if (this.view.hideTitle) return;
	var moveable = this.view.stacked ? 0: this.view.canMove;
	this.nodeTable.style.position = this.view.stacked ? "relative" : "absolute";
	var m = moveable ? "panel_moveable" : "panel_titlebar";
	this.nodeTitleMover1.className = m;
	this.nodeTitleMover2.className = m;
	var th = this;
	if (moveable) {
		this.makeDragger(this.nodeTitleMover1, th, 	Panel.moveInit, Panel.moveHandler);
		this.makeDragger(this.nodeTitleMover2, th, Panel.moveInit, Panel.moveHandler);
	}
	var resiz = this.view.resizeable || "";
	if (resiz.match(/h/i))
		this.makeDragger(this.nodeHBar, th, Panel.moveInit, Panel.resizeHandlerH);
	if (resiz.match(/v/i))
		this.makeDragger(this.nodeVBar, th, Panel.moveInit, Panel.resizeHandlerV);
	if (resiz.match(/h/i) && resiz.match(/v/i))
		{this.makeDragger(this.nodeHV, th, Panel.moveInit, Panel.resizeHandlerHV); }
	this.makeHideCloseButtons(this.nodeCloser);
	this.applyView();
	return this;
}
Panel.moveInit = function(_e, th) {
	sendToFront(th.nodeTable);
	Panel.drag.grabX = _e.clientX+document.body.scrollLeft;
	Panel.drag.grabY = _e.clientY+document.body.scrollTop;
	Panel.drag.origX = parseInt(th.view.left);
	Panel.drag.origY = parseInt(th.view.top);
	Panel.drag.origW = th.nodeContent.clientWidth;
	Panel.drag.origH = th.nodeContent.clientHeight;
}
Panel.moveHandler = function(_e, th) {
	var mouseX = _e.clientX+document.body.scrollLeft;
	var mouseY = _e.clientY+document.body.scrollTop;
	var elex = Panel.drag.origX + (mouseX - Panel.drag.grabX);
	var eley = Panel.drag.origY + (mouseY - Panel.drag.grabY);
	th.view.left = elex.toString(10) + 'px';
	th.view.top = eley.toString(10) + 'px';
	th.applyView();
}
Panel.resizeHandlerV = function(_e, th) {
	var mouseY = _e.clientY+document.body.scrollTop;
	var newH = Panel.drag.origH + (mouseY - Panel.drag.grabY);
	th.setHeight(newH);
}
Panel.resizeHandlerH = function(_e, th) {
	var mouseX = _e.clientX+document.body.scrollLeft;
	var newW = Panel.drag.origW + (mouseX - Panel.drag.grabX);
	th.setWidth(newW);
}
Panel.resizeHandlerHV = function(_e, th) {
	Panel.resizeHandlerH(_e, th);
	Panel.resizeHandlerV(_e, th);
}
Panel.prototype.setWidth = function(w) {
	this.nodeContent.style.width = parseInt(w)+"px";
}
Panel.prototype.setHeight = function(h) {
	this.nodeContent.style.height = parseInt(h)+"px";	
}
Panel.prototype.drawTitleCell = function(editable, changeHandler) {
	if (this.view.hideTitle) return;
	var node = this.nodeTitleLeft;
	if (editable) {
		node.innerHTML = "<input type='text' size='15' class='panel_titlebar panel_namecell' "
	+"value='namecell' "
	+"onchange='this.size=Math.max(15,Math.min(25,this.value.length));CALC(section);'>";		this.titleCell = node.childNodes[0];
		if (changeHandler) this.titleCell.onchange = changeHandler;
	} else {
		if (this.titleCell) delete this.titleCell;
	}
}
Panel.prototype.updateTitle = function(newName) {
	if (this.view.hideTitle) return;
	if (this.titleCell) {
		this.titleCell.value = newName;
		this.titleCell.size = newName.length+1; 
	} else {
		this.nodeTitleLeft.innerHTML = " <nobr>"+newName+"&nbsp;&nbsp;</nobr> ";
	}
}
Panel.prototype.remove = function() {
	var n = ["nodeCloseBox","nodeHideBox","nodeTitleMover1","nodeTitleMover2", "nodeHBar", "nodeVBar", "nodeHV"]; 
	for (var i in n) Panel.removeElement(this[n[i]]);
	if (this.titleCell) this.titleCell.onchange = null;
	if (!this.nodeTable) return;
	this.nodeTable.onmousedown = null;
	this.nodeTable.Panel = null;
	delete this.nodeTable;
	this.nodePanel.innerHTML="";
}
Panel.prototype.makePanelFrame = function(node) {
	var tableClassname = "panel_node_panel";
	var a;
	a = "<table border='0' cellspacing='0' class='"+tableClassname+"' cellpadding='0' onmousedown='sendToFront(this)'>" 
	+"<tr><td colspan='2'></td></tr>"
	a +="<tr><td class='panel_node_table' valign='top'>main content</td>"
	+ "<td height='100%' width='5' rowspan='1' class='panel_moveableHoriz'></td>"
	+"</tr>"
	+"<tr><td class='panel_moveableVert' height='5'></td>"
	+"<td class='panel_moveableBoth' height='5' width='5'></td>"
	+"</tr></table>"; 
	node.innerHTML = a;
	this.nodeTable = node.childNodes[0];
	var r = this.nodeTable.rows;
	this.nodeContent = r[1].childNodes[0];
	this.nodeHBar    = r[1].childNodes[1];
	this.nodeVBar    = r[2].childNodes[0];
	this.nodeHV      = r[2].childNodes[1];
}
Panel.prototype.makeTitleBar = function(node) {
	var moveAreaWidth = "90%";
	var a = "<table width='100%' height='100%' border='0' cellspacing='0' cellpadding='0'><tr>"	
if (Panel.sharpCorners) { a += "<td></td>"} else {
	a +="<td width='5' height='100%' align='right' valign='bottom'>"
	+"<table cellspacing='0' cellpadding='0' width='4' height='100%'>"
	+"<tr><td colspan='3'></td></tr>"
	+"<tr><td width='1' style='height:5%;'></td><td width='1'></td>"
	+"<td width='2' class='panel_titlebar'></td></tr>"
	+"<tr><td style='height:10%;'></td>"
	+"<td colspan='2' class='panel_titlebar'></td></tr>"
	+"<tr><td colspan='3' height='85%' class='panel_titlebar'></td>"
	+"</tr></table></td>"
} 
	a+="<td align='left' class='panel_titlebar'></td>"
	+"<td class='panel_titlebar' width='10'>&nbsp;&nbsp;&nbsp;</td>"
	+"<td align='right' width='10' class='panel_titlebar'>lefttitle</td>"
	+"<td width='"+moveAreaWidth+"'>&nbsp;</td>"
	+"<td align='left' class='panel_titlebar'></td>";
	if (Panel.sharpCorners) { a +="<td></td>"}
	else {
	a +="<td width='5' height='100%' align='left' valign='bottom'>"
	+"<table cellspacing='0' cellpadding='0' width='4' height='100%'>"
	+"<tr><td colspan='3' width='4'></td></tr>"
	+"<tr><td width='2' class='panel_titlebar' style='height:5%;'></td>"
	+"<td width='1'></td><td width='1' ></td></tr>"
	+"<tr><td colspan='2' class='panel_titlebar' style='height:10%;'></td>"
	+"<td></td></tr>"
	+"<tr><td colspan='3' height='85%' class='panel_titlebar'></td></tr>"
	+"</table></td>"
	}
	a +="</tr></table>";
	node.innerHTML = a;
	var tb = node.childNodes[0].rows[0];
	this.nodeTitleBar  = tb;
	var lcorner = tb.childNodes[0];
	var rcorner = tb.childNodes[6];
	this.nodeCloser = tb.childNodes[1];
	this.nodeTitleMover1 = tb.childNodes[2];
	this.nodeTitleLeft  = tb.childNodes[3];
	this.nodeTitleMover2 = tb.childNodes[4];
	this.nodeTitleRight = tb.childNodes[5];
}
Panel.prototype.makeHideCloseButtons = function(node) {
	var a="";
	var iconClass= "class='panel_icon noselect' onmouseover='this.className=\"panel_icon noselect panel_icon_omo\"' onmouseout='this.className=\"panel_icon noselect\"' ";
	a += this.view.canClose=="0" ? "<s></s>" 
		: "<span "+iconClass+" title='Close' style='font-family:sans-serif;' unselectable='on'>&nbsp;X </span>";
	a += this.view.canHide=="0" ? "<s></s>" 
		: "<span "+iconClass+" title='Hide/Window Shade' unselectable='on' style=''>&nbsp;"+Panel.HIDE_CHAR+" </span>&nbsp;"
	node.innerHTML = a;
	if (this.view.canClose) {
		var th = this;
		this.nodeCloseBox = node.childNodes[0];
		this.nodeCloseBox.onclick=function() {th.closePanel(); th=null; }
	} else {
		if (this.nodeCloseBox) this.nodeCloseBox.onclick = null;
	}
	if (this.view.canHide) {
		var th = this;
		this.nodeHideBox = node.childNodes[1]
		this.nodeHideBox.onclick=function() {th.showHide(); }
		this.nodeTitleMover1.ondblclick =function() {th.showHide();}
		this.nodeTitleMover2.ondblclick =function() {th.showHide();}
	} else {
		if (this.nodeHideBox) this.nodeHideBox.onclick = null;
		if (this.nodeTitleMover1) this.nodeTitleMover1.ondblclick = null;
		if (this.nodeTitleMover2) this.nodeTitleMover2.ondblclick =null;
	}
}
Panel.prototype.setCloseable = function(state) {
	if (!isDefined(state)) state = this.view.canClose ? 0:1;
	this.view.canClose = state;
	this.setup();
}
Panel.prototype.setResizeable = function(state) {
	this.view.resizeable = state;
	this.updateResizeable(this.view.resizeable);
}
Panel.prototype.updateResizeable = function(state) {
	if (!state || this.view.displayContent=="none") state = "";
	if (state instanceof Array) state = state.join("");
	var h = state.match(/h/i);
	var v = state.match(/v/i);
	this.nodeHBar.style.display = h ? "" : "none";
	this.nodeVBar.style.display = v ? "" : "none";
	this.nodeHV.style.display = h && v ? "" : "none";
}
Panel.prototype.showHideTitle = function(state) {
	var vis = getElementStyle(this.nodeTitleBar, "visibility");
	if (!this.nodeTitleBar || state == vis) return;
	if (isDefined(state)) {
		if (typeof state == "number") state = state >0 ? "hidden" : "visible";
	} else { 
		state = vis == "hidden" ? "visible" : "hidden"
	}
	if (state == "visible" || state == "hidden") this.nodeTitleBar.style.visibility=state;
	if (state == "" || state == "block" || state == "none") this.nodeTitleBar.style.display=state;
}
Panel.drag = {};
function falsefunc() {return false; }
Panel.prototype.makeDragger = function(node, context, init, handler, finalizer) {
	var th = this;
	node.onmousedown = function(_e) {
		if (!_e) _e = window.event;
		Panel.drag.element = (_e.target || _e.srcElement);
		document.onmousedown = falsefunc;
		document.onmousemove = function(_e) {
			if (!_e) _e = window.event; 
			if (handler) handler(_e, context); 
			return false;
		}
		document.onmouseup = function(_e) {if (!_e) _e = window.event; th.dragEnd(_e); if(finalizer) finalizer(_e, context); return false;};
		if (init) init(_e, context);
	}
}
Panel.prototype.removeDragger = function(node) {
	node.onmousedown = null;
}
Panel.prototype.dragEnd = function(event) {
	document.onmousemove = null;
	document.onmouseup = null;
	document.onmousedown = null;
}
Panel.prototype.moveWindowHandler = function(event) {
	this.view.left = event.clientX-Panel.drag.offsetLeft;
	this.view.top = event.clientY-Panel.drag.offsetTop;
	this.applyView();
}
Panel.prototype.applyView = function() {
	if (!this.view) this.view = Panel.DEFAULT_VIEW;
	var v = this.view;
	var s = this.nodeTable.style;
	var st = this.view.stacked;
	s.marginTop = st ? Panel.DEFAULT_STACK_MARGIN : v.top;
	s.marginLeft = st ? Panel.LEFT_MARGIN||0 : v.left;
	this.showHide(v.displayContent || "");
	if (!isDefined(v.displayAll)) v.displayAll = "";
	showHide(this.nodePanel, v.displayAll);
	this.showHideTitle(this.view.hideTitle);
	return this;
}
Panel.prototype.moveToTopOfScreen = function() {
	this.view.top = (50 - document.body.scrollHeight + document.body.scrollTop + this.nodeTable.clientHeight)+"px";
	this.applyView();
}
Panel.prototype.closePanel = function() {
	var willClose=1;
	if (this.onbeforeclose) willClose = this.onbeforeclose();
	if (willClose) this.remove();
}
Panel.prototype.showHide = function(state) {
	if (this.onbeforehide) this.onbeforehide();
	var oldState = getElementStyle(this.nodeContent, "display");
	var newState = showHide(this.nodeContent, state);
	this.view.displayContent = newState;
	this.updateResizeable(state== "none" ? "" : this.view.resizeable);
	if (oldState=="none" && oldState != newState && this.onaftershowhide) this.onaftershowhide("");
}
function createDOMNode(parentNode) {
	if (!isDefined(parentNode)) parentNode = window.document.body;
	var node = document.createElement("SPAN");
	parentNode.appendChild(node);
	return node;
}
function showHide(node,state) {
	if (!node) return;
	var vis = getElementStyle(node, "display");
	var u = !isDefined(state) ? (vis =='none' ? '' : 'none') : typeof state=="string" ? state : (state ? '' : 'none' );
	if (node.style && u != vis) node.style.display = u; 
	return u;
}
function getElementStyle(node, IEStyleProp, CSSStyleProp) {
	if (!node) return;
	return node.currentStyle ? node.currentStyle[IEStyleProp] 
		: window.getComputedStyle(node, "").getPropertyValue(CSSStyleProp||IEStyleProp);
}
function isVisible(node) { return getElementStyle(node, "display") != "none" }
Panel.removeElement = function(a) {
	if (!a || !a.tagName) return;
	a.onclick = null;
	a.onmouseover = null;
	a.onmouseout = null;
	a.onmousedown = null;
	a.ondblclick = null;
}
Panel.zmax = 2;
function sendToFront(node) {
	if (Panel.zmax > getElementStyle(node, "zIndex")) node.style.zIndex = ++Panel.zmax;
}

/* * * * * * * * * *../pgm/areaSection.js * * * * * * * * * * * */

AreaSection.DEFAULT_VIEW = {displayHeight: 100, contentHeight: 100, width: 300, panel:{} }
HtmlSection.HTML_CHANGE = "html";
HtmlSection.VALUE_CHANGE = "value";
HtmlSection.EDIT_CHAR = "E";
function AreaSection(name, options) {
	this.init(name, options);
	return this;
}
AreaSection.prototype.init= function(name, options, secType) {
	this._name = name;
	this.secType = secType;
	this._view	= clone(AreaSection.DEFAULT_VIEW); 
	this._content = "";
	if (options) clone(options._view || options, this._view);
}
AreaSection.prototype.draw = function(node) {
	if (this._contentNode) this.remove();
	if (!this._panel) this._panel = new Panel();
	var p = this._panel;
	for (var i in this._view.panel) p.view[i] = this._view.panel[i];
	this._view.panel = p.view;
	p.draw(node);
	p.nodeContent.innerHTML = "<textarea class='"+TableCell.DEFAULT_CLASS+"'></textarea>";
	this._contentNode = p.nodeContent.childNodes[0];
	this.updatePanel();
	return this;
}
AreaSection.prototype.updatePanel = function() {
	var p = this._panel;
	p.setup();
	var th = this;
	var lockTempl = top._mgr && _mgr._view.panel.lockTemplate || this._view.panel.lockTemplate;
	p.drawTitleCell(!lockTempl, function() {
		if (isDefined(window._mgr)) { _mgr.renameSection(th._name, this.value).calc(); }
		else {this.rename(th._name, this.value)}
		if (isanonymous(this.value)) this.value = "";
	} );
	p.updateTitle(isanonymous(this._name) ? "" : this._name.replace(/_/g," ")); 
	this._contentNode.onkeyup = function(_e) {if (!_e) _e = window.event; return th.shortcutKeypress(_e, HtmlSection.HTML_CHANGE); }
	this._contentNode.onchange = function(_e) {if (!_e) _e = window.event; th.update(HtmlSection.HTML_CHANGE); CALC(th); 	_e.cancelBubble = true;if (_e.stopPropagation) _e.stopPropagation();return true;}
	p.onbeforeclose	= function() {if (isDefined(window._mgr)) {_mgr.removeSection(th._name)} else {this.remove();p = null}}
	p.updateResizeable(p.view.resizeable);
	p.makeDragger(p.nodeHBar, th, 
		function(_e, th) {th.dragStart(_e)}, 
		function(_e,th) { th.colChangeHandler(_e) } );
	p.makeDragger(p.nodeVBar, th, 
		function(_e, th) { th.dragStart(_e) },
		function(_e,th) { th.rowChangeHandler(_e) } );
	p.makeDragger(p.nodeHV, th, 
		function(_e, th) { th.dragStart(_e) },
		function(_e,th) { th.rowChangeHandler(_e);th.colChangeHandler(_e) } );
	p.onaftershowhide = function(isHid) {if (!isHid) th.showValues(); } 
}
AreaSection.prototype.toHTML = function() {
	return this._displayNode ? this._displayNode.innerHTML : "";
}
AreaSection.prototype.dragStart= function(_e) {
	this._startX = _e.clientX + document.body.scrollLeft; 
	this._startY = _e.clientY + document.body.scrollTop;
	this._startContCols = this._contentNode.cols;
	this._startContH = this._contentNode.clientHeight;
	this._startContW = this._contentNode.clientWidth||this._displayNode.clientWidth; 
	if (this._displayNode) {
		this._startDisplW = this._displayNode.clientWidth;
		this._startDispH = this._displayNode.clientHeight;
	}
}
AreaSection.prototype.focus = function() {
	var vp = this._view.panel;
	if (vp.displayContent != "none" && vp.displayAll != "none" && !vp.lockTemplate) this._contentNode.focus();
	return this;
}
AreaSection.prototype.remove = function() {
	if (this._panel) this._panel.remove();
}
AreaSection.prototype.shortcutKeypress = function(event, use) {
	if (window._mgr) _mgr._selected = this;
	var ctrlKey = event.ctrlKey;
	var key = event.charCode || event.keyCode;
	if (!ctrlKey) return;
	if(key==13 || key == 77) {
		this.update(use);
		if (event.shiftKey) {CALC();}
		else {this.calc();}
		event.cancelBubble=true; 
		if (event.stopPropagation) event.stopPropagation();
		return false;
	}
}
AreaSection.prototype.rename = function(newName) {
	var oldName = this._name;
	if (newName == oldName) return;
	if (newName != oldName && window[newName] != null && isDefined(window[newName])) {
		WARN("ERR (Table.rename): "+newName+" already exists ("+ssplay(window[newName])+")");
		return;
	}
	window[oldName] = null;
	window[newName] = this;
	this._name = newName;
	return this;
}
AreaSection.prototype.replaceInAllFormulas= function(oldName, newName, sectionName) {
	if (oldName == newName || !oldName) return;
	var formulaRe;
	if (sectionName == this._name || sectionName ==-1) { 
		formulaRe= new RegExp("(?:^"+oldName+"\\b)|([^\\.])\\b"+oldName+"\\b","g");
		this._content = this._content.replace(formulaRe, "$1"+newName);
	} else {
		formulaRe = new RegExp(sectionName+"\\." +oldName+"\\b","g");
		newName = "."+newName;
		this._content = this._content.replace(formulaRe, newName);
	}
}
AreaSection.prototype.applyView = function() {
	this.resizeContent();
	this._panel.applyView();
}
AreaSection.prototype.resizeContent = function() {
	var view = this._view; 
	var node = this._contentNode;
	if (node && getElementStyle(node, "display") != "none") {
		node.style.width = view.width;
		node.style.height = view.contentHeight;		
	}
	node = this._displayNode;
	if (node && node.style) {
		node.style.width = view.width;
		node.style.height = view.displayHeight;
	}
}
AreaSection.prototype.evalText= function(attrName, s, self) {
	try { with (Math) { with(this) {
	if (typeof s == "function") { s(); }
	else { eval(s) }
	} } } catch(_e) { WARN(" ("+this._name+"."+attrName+") "+_e.message); 
	}
}
AreaSection.prototype.precalc = function() { }
AreaSection.prototype.update = function() {
	var value = this._contentNode.value;
	this._content = isDefined(value) ? value : "";
	if (window._mgr) _mgr._sheetModified = 1;
}
AreaSection.prototype.calc = function(updateDisplay) {
	this.process();
	if (this.onAfterCalc) {
		try { with (Math) { 
			eval(this.onAfterCalc)
		} } catch(_e) { WARN(" ("+this._name+"."+onAfterCalc+") "+_e.message); }
	}
	this.showValues(updateDisplay);
	this.applyView();
	return this;
}
AreaSection.prototype.process = function() { }
AreaSection.prototype.showValues = function() {
	this._panel.updateTitle(isanonymous(this._name) ? "" : this._name.replace(/_/g," ")); 
}
AreaSection.prototype.evalContent = function(content) {
	try {
		with (this) { with (Math) {
			while (content.match(/<%((?:.|\n)+?)%>/m)) {
				content = content.replace(/<%((?:.|\n)+?)%>/, eval(RegExp.$1));
			}
		}}
	} catch(e) {
		if (isDefined(content)) content = content.replace(/<%(.+?)%>/, "["+e.message+"]");
	}
	return content;
}
AreaSection.FORM_ELEMENT_TYPES = ["input", "select", "textarea"];
AreaSection.prototype.formElements = function() {
	var a = [];
	var r;
	if (!this._displayNode) return;
	var types = AreaSection.FORM_ELEMENT_TYPES;
	for (var i=0; i<types.length; i++) {
		r = this._displayNode.getElementsByTagName(types[i]);
		for (var j=0; j<r.length; j++) a.push(r[j]);
	}
	return a;
}
AreaSection.prototype.restoreFormElements = function(elems) {
	var children = this.formElements();
	if (!children) return;
	var c;
	var me;
	for (var i=0; i<children.length; i++) {
		c = children[i];
		me = isDefined(elems[c.name]) ? elems[c.name] : this[c.name];
		if (c.name && this[c.name]==null) this[c.name]="";
		if (c==null || me == null) continue;
		if (c.type=="radio") { c.checked =  (c.value == me); }
		else if(c.type=="checkbox") {c.checked = (me !=0); }
		if(c.tagName.toLowerCase()=="select" && !c.value) {for (var j=0; j<c.options.length;j++) if (c.options[j].text==me) {c.selectedIndex = j;break; }}
		else {c.value = me; }
		this[c.name] = (elems[c.name]!=null) ?elems[c.name] : ((this[c.name]!=null)? this[c.name]: "");
		if (c.name == this.focusName) c.focus();
		if (c.name == this.selectName) c.select();
	}
}
AreaSection.prototype.loadContents = function(s) {
	this._content = (isText(s) ? s : s.content) || "";
	if (typeof s =="object") {
		this._name = s.name; delete s.name;
		this._view = s.view;  delete s.view;
		this._panel.view = this._view.panel;
	}
	if (isDefined(s.offLine)) this.offLine = s.offLine;
	this._contentNode.value = this._content;
}
AreaSection.prototype.saveContents = function() {
	var s = {name:this._name,view:this._view, content:this._content };
	for (var e in this) {
		if (e=="_name" || e=="_view" || e== "_content") continue;
		if (typeof this[e] == "function" || e.charAt(0) =="_") continue;
		s[e] = this[e];
	}
	return s;
}
AreaSection.prototype.colChangeHandler = function(_e) {
	var delta = _e.clientX +document.body.scrollLeft - this._startX;
	this._view.width = Math.max(5, this._startContW+ delta +8);
	this.resizeContent();
}
AreaSection.prototype.rowChangeHandler = function(_e) {
	var delta = _e.clientY +document.body.scrollTop - this._startY;
	if (Math.abs(delta)<5) return;
	var node = this._contentNode;
	if (getElementStyle(node, "display") != "none") {
		var newHeight = Math.max(10, Math.floor(this._startContH+delta));
		this._view.contentHeight = newHeight;
	} else {
		var newHeight = Math.max(10, Math.floor(this._startDispH+delta));
		this._view.displayHeight = newHeight;
	}
	this.resizeContent();
}
function ScratchSection(name, options) {
	this.init(name, options, "Scratch");
	var view = this._view;
	return this;
}
ScratchSection.prototype = new AreaSection;
ScratchSection.prototype.constructor = ScratchSection;
ScratchSection.superclass = AreaSection.prototype;
ScratchSection.prototype.update = function() { 
	ScratchSection.superclass.update.call(this);
}
ScratchSection.prototype.process = function() {
	if (!isDefined(this._content)) return;
  if (this.textOnly) {
		this._result = this._content;
		return;
	}
	window["_"] = window["__"] = ""; 
	ScratchSection._prev = "";
	RegExp.multiline = true;
	var lines = this._content.toString().replace(/ :=\s*\/\*=(.|[\n\r])*?\*\//g,"").split("\n"); 
	var hideResult;
	var li;
	var cli;
	with (Math) {
	for (var _i = 0; _i<lines.length; _i++) {
		li =lines[_i];
		hideResult = li.match(/^:/,"");
		li = li.replace(/^:/,"");
		if (li.match(/^\s*$/)) continue;
		if (li.match(/\{\s*$/) && !li.match(/\/\//)) {
			while (! lines[_i].match(/^}/)) {
				li+="\n"+lines[_i+1];
				lines.splice(_i,1);
			}
		} else { 
			li = li.replace(/[\n\r]/g,"");
		}
		li = li.replace(/ :=.*/, "");
		cli = li;
		window["__"] = ScratchSection._prev;
		ScratchSection._prev = window["_"];
		try { 
			with (this) { window["_"] = eval(li); }
		} catch(_e) {
			window["_"] = "ERR (calc): "+_e.message;
		}
		if  (!hideResult) {
			lines[_i] = li+ (window["_"]==null ? "" : " :=" + this._format(window["_"]));
		} else {
			lines[_i] = ":"+li;
		}
	} }
	this._result = lines.join("\n");
}
ScratchSection.prototype._format = function(self) { 
	if (this.format) {with (Math) {
		try { self = eval(this.format.toString()) }
		catch(_e) { return "ERR (format):"+_e.message; }
	} }
	var result = ""+splay(self).toString().replace(/\\[\n\r]+\\n?/g, "\n");
	if(result.indexOf("\n") != -1) result = "\/\*="+result+"*\/";
	return result;
}
ScratchSection.prototype.showValues = function() {
	ScratchSection.superclass.showValues.call(this);
	this._contentNode.value = this._result || "";
}	
function HtmlSection(name, options) {
	this.init(name, options, "Html");
	this._view.displayMode = "block";
	return this;
}
HtmlSection.prototype = new AreaSection;
HtmlSection.prototype.constructor = HtmlSection;
HtmlSection.superclass = AreaSection.prototype;
HtmlSection.prototype.draw = function(node) {
	HtmlSection.superclass.draw.call(this, node);
	this._displayContainer = textarea();
	this._displayNode = document.createElement("DIV");
	this._displayNode.style.overflow="auto";
	this._displayNode.className="";
	this._displayNode.style.width = "300px";
	var th = this;
	this._displayNode.onkeyup = function(_err) { if (!_err) _err = window.event; th.shortcutKeypress(_err); }
	this._contentNode.parentNode.insertBefore(this._displayNode, null);
	this._contentNode.style.width = "100%";
	if (this._content) this._contentNode.value = this._content;
	return this;
}
HtmlSection.prototype.updatePanel = function() {
	HtmlSection.superclass.updatePanel.call(this);
	var lockTempl = top._mgr && _mgr._view.panel.lockTemplate || this._view.panel.lockTemplate;
	if (lockTempl) {
		this._panel.nodeTitleRight.innerHTML = "";
		this._contentNode.style.display = "none";
		this.setDisplayMode("none");
	} else {
		this.createLinkHTML(this._panel.nodeTitleRight);
	}
}
HtmlSection.prototype.update = function(typ, name, value) {
	if (typ == HtmlSection.HTML_CHANGE || this._hasLiveContent) {
		HtmlSection.superclass.update.call(this);
		if (!this._hasLiveContent) this.updateHTML();  
	}
	if (isDefined(name)) {
		this[name] = (value==+value) ? +value : value;
	}
}
HtmlSection.prototype.updateHTML = function() {
	var children = this.formElements();
	var c;
	var elems = {};
	for (var i=0; i<children.length; i++) {
		c = children[i];
		if (isDefined(c) && c.name && c.exposed) { 
			elems[c.name] = this[c.name];
			delete this[c.name]; 
		}
	}
	var _result = this.evalContent(this._content);
	_result = Wiki.toHTML(_result);
	if (this._displayNode) this._displayNode.innerHTML = _result;
	this.setFormElementHandlers();
	this.restoreFormElements(elems);
	this._hasLiveContent = this._content.match(/<\%(?:.|\n)+\%>/);
}
HtmlSection.prototype.replaceInAllFormulas= function(oldName, newName, sectionName) {
	HtmlSection.superclass.replaceInAllFormulas.call(this, oldName, newName, sectionName);
	if (this._content) this._contentNode.value = this._content;
}
HtmlSection.prototype.setFormElementHandlers  = function() {
	var children = this.formElements();
	var c;
	var th= this;
	for (var i=0; i<children.length; i++) {
		c = children[i];
		if (c.type =="button") { c.onclick = function() {th.doAction(this);};}
		if (!c.name) continue;
		if (c.type=="radio") { c.onclick= function() { th.update(HtmlSection.VALUE_CHANGE, this.name, this.value); th.doAction(this); CALC(th);} }
		else if (c.type =="checkbox") {c.onclick = function() { th.update(HtmlSection.VALUE_CHANGE, this.name, this.checked?1:0); th.doAction(this); CALC(th) } }
		else { c.onchange= function() { var v = HtmlSection.getSelectValue(this);th.update(HtmlSection.VALUE_CHANGE, this.name, v); th.doAction(this); CALC(th);} }
	}
}
HtmlSection.getSelectValue = function(cell) {
	if (cell.tagName.toLowerCase() != "select") return cell.value;
	return cell.value || cell.options[cell.selectedIndex].text;
}
HtmlSection.prototype.doAction  = function(cell) {
	var self;
	if (cell) self = cell.value || (cell.checked != null && (cell.checked?1:0));
	if (!cell.getAttribute) return;
	if (cell.getAttribute("action")) {
		this.evalText("HTML.action", cell.getAttribute("action"), self);
	} else if (cell.onclick) {
		cell.action = cell.onclick;
		this.evalText( "doAction(): HTML.onclick", cell.action);
	}
}
HtmlSection.prototype.showValues = function(forceUpdate) {
	if (this._hasLiveContent || forceUpdate) this.updateHTML();  
	HtmlSection.superclass.showValues.call(this);
	this.restoreFormElements(this);
}
HtmlSection.prototype.applyView = function() {
	this._contentNode.style.display = this._view.displayMode || "";
	HtmlSection.superclass.applyView.call(this);
}
HtmlSection.prototype.setDisplayMode = function(newMode) {
	var v = this._view;
	if (!isDefined(newMode)) newMode = (v.displayMode != "none" ? "none" : "");	
	v.displayMode = newMode;
	if (v.displayMode == "none") {
		this._panel.updateResizeable(v.panel.resizeable);
	} else {
		this._panel.updateResizeable("hv");
	}
	this.applyView();
}
HtmlSection.prototype.saveContents = function(s) {
	s = HtmlSection.superclass.saveContents.call(this, s);
	for (var i in s) if (!i) delete s[i];
	return s;
}
HtmlSection.prototype.loadContents = function(s) {
	HtmlSection.superclass.loadContents.call(this, s);
	for (var i in s) {
		if (typeof i == "function" || i=="view" || i=="content") continue;
		this[i] = s[i];
	}
	this._view.displayMode = "none";
	this.update(HtmlSection.HTML_CHANGE);
	return s;
}
HtmlSection.prototype.createLinkHTML = function(node) {
	var classes = "class='panel_icon' onmouseover='this.className=\"panel_icon panel_icon_omo\"' onmouseout='this.className=\"panel_icon\"' ";
		node.innerHTML = "<span "+classes+" alt='Click to toggle edit-HTML'>&nbsp;"+HtmlSection.EDIT_CHAR+"&nbsp;</span>&nbsp;";
	var th = this;
	node.onclick = function() { th.setDisplayMode() };
}

/* * * * * * * * * *../pgm/simpleMenu.js * * * * * * * * * * * */

var activeMenu = "";
var menuLeave;
var uu=0;
 function SimpleMenu(m, divNode) {
	var a = "<table id='menuBar' class='menuBar' cellspacing=0><tr>";
	for (var i=0; i< m.length; i++) a +="<td class='menuBar' unselectable='on' "
		+SimpleMenu.menuBarMouse("menuBar", m[i].name)+"> &nbsp; "+m[i].name+" &nbsp; </td>";
	a +="</tr></table>\n\n";
	for (var i=0; i< m.length; i++) {
		sm = m[i].menu;
		a +="<table id='menu_"+m[i].name+"' class='menuTable' cellspacing=0 cellpadding=3 border='0' "
		+" onmouseover='clearTimeout(menuLeave)'"
		+" onmouseout='if (menuLeave != -1) SimpleMenu.omoMenu(\""+m[i].name+"\")'>";
		for (var j=0; j< sm.length; j++) {
			a += "<tr><td class='menuItem' ";
			var mitem = sm[j];
			for (var k in mitem) if (k.match(/^on/)) {
				a += k+"=\""+mitem[k];
				if (!mitem.persist) a += "; SimpleMenu.toggle('"+m[i].name+"','none')";
				a +="\"";
			}
			if (!mitem.noselect) a += SimpleMenu.menuItemMouse("menuItem");
			a += " >"+sm[j].label+"</td>";
			a +="<td class='menuItemShortcut'>"+(mitem.shortcut || "")+"</td>";
			a+= "</tr>\n";
		}
		a += "</table>\n\n";
	}
	try {
		divNode.innerHTML = a;
	} catch(e) {
		alert("ERR: Internal problem loading menus: "+e.message);
	}
	var menuBar = _idnode("menuBar");
	var cells= menuBar.childNodes[0].childNodes[0].childNodes;
	menuBar.style.zIndex = 1001;
	var left;
	var tbl;
	var menuName;
	this.nodeMenus = {};
	for (var i=0; i< m.length; i++) {
		left = divNode.offsetLeft + cells[i].offsetLeft;
		menuName = "menu_"+m[i].name;
		tbl = _idnode(menuName);
		tbl.style.left = left;
		this.nodeMenus[menuName] = tbl;
	}
	var inputs;
	for (var i=0; i< m.length; i++) {
		tbl = this.nodeMenus["menu_"+m[i].name];
		inputs = tbl.getElementsByTagName("INPUT");
		for (var j=0; j < inputs.length; j++) {
			if (inputs[j].type=="text") {
				inputs[j].onfocus    = function() {clearTimeout(menuLeave);menuLeave = -1;}
				inputs[j].onfocusout= function() {SimpleMenu.omoMenu(m[j].name); }
				inputs[j].onblur = inputs[j].onfocusout;
			}
		}
	}
	this.nodeMenuBar = menuBar;
	return this;
}
function _idnode(id) { return document.getElementById(id); }
SimpleMenu.mouseoutTimeOut = 500;
SimpleMenu.omoMenu = function(name) {
	menuLeave = setTimeout("SimpleMenu.toggle('"+name+"','none')", SimpleMenu.mouseoutTimeOut);
}
SimpleMenu.menuBarMouse = function(className, menuName) {
	return "onmouseover='this.className=\""+className+"Hover\";clearTimeout(menuLeave);if(activeMenu) SimpleMenu.toggle(\""+menuName+"\", \"block\") ' "
     +" onmouseout='this.className=\""+className+"\";SimpleMenu.omoMenu(\""+menuName+"\")' "
	 +" onmousedown='SimpleMenu.toggle(\""+menuName+"\");this.className=\""+className+"\" ' ";
}
SimpleMenu.menuItemMouse = function(className) {
	return "onmouseover='this.className=\""+className+"Hover\"' "
		+" onmouseout='this.className=\""+className+"\"; event.cancelBubble=false;' ";
}
SimpleMenu.toggle = function(menuName, state) {
	var m = 	_idnode("menu_"+menuName);
	if (!isDefined(m)) return;
	if (!isDefined(state)) state = isVisible(m) ? "none" : "block";
	m.style.display = state;	
	if (state=="block") {
		if (activeMenu && activeMenu != menuName) SimpleMenu.toggle(activeMenu, "none");
		activeMenu = menuName;
	} else {
		activeMenu ="";
	}
}
SimpleMenu.prototype.remove = function() { return; }

/* * * * * * * * * *../pgm/wiki.js * * * * * * * * * * * */

Wiki = {};
Wiki.LIST_REGEX = /^([\*#]+)\s(.*)$/;
Wiki.HEADER_REGEX = /^(!+)(.+)$/; 
Wiki.BOLD_REGEX = /'''(?=[^\s])(.+?)'''/g;
Wiki.ITAL_REGEX = /\/\/(.+?)\/\//g;
Wiki.IMG_REGEX = /(\b\w+tp:\/\/\S+\.(?:gif|jpg|png))/ig;
Wiki.LINK_REGEX = /\[\[([^|]+)\|(\w+tp:\/\/\S+)\]\]/ig;
Wiki.LINK2_REGEX = /\[\[(\w+tp:\/\/\S+)\]\]/ig;
Wiki.toHTML = function(content) {
	var lines = content.toString().split(/\n/);
	var li;
	var result="";
	var inTable=0;
	var tableParams = "";
	var bulletLevel =0;
	var bulletTag = [];
	var currentBulletLevel =0;
	var bulletLevelDelta, prefix;
	for (var i=0; i< lines.length; i++) {
		li = lines[i].toString();
		if (li.match(/^([\-=]{3,})(.*)/)) {
			var chars = RegExp.$1;
			var style = RegExp.$2.replace(/\((.+)\)/, "$1");
			var width= "width="+(chars.length==3?"25%": chars.length==4?"50%" : "100%")+" ";
			var size = "size="+(chars.charAt(0) == "-" ? 1 : 5)+" ";
			li = "<hr "+style+" align=left "+width+size+">";
		}
		if (li.match(Wiki.LIST_REGEX) || bulletLevel) {
			currentBulletLevel = li.match(Wiki.LIST_REGEX) ? RegExp.$1.length : 0;
			bulletLevelDelta = currentBulletLevel - bulletLevel;
			prefix = "";
			if (bulletLevelDelta>0)  {
				bulletTag.push((RegExp.$1.charAt(0) == "#") ? "ol>" : "ul>");
				while (bulletLevelDelta-- > 0) prefix += "<"+bulletTag[bulletTag.length-1];
			} else if (bulletLevelDelta <0) {
				while (bulletLevelDelta++ < 0) prefix += "</"+bulletTag.pop();
			}
			li = prefix+(currentBulletLevel ? "<li>"+RegExp.$2 : li);
			bulletLevel = currentBulletLevel;
		}
		if (li.match(/^\|(.+)\|\s*$/)) {
			row = RegExp.$1
			if (!inTable) {
				inTable = 1;
				tableParams = "";
				if (row.match(/^\(([^|]+)\)(.+)/)) {
					tableParams=RegExp.$1;
					row = RegExp.$2;
				}
				li = "<table "+tableParams+"><tr><td>"+(row.replace(/\|/g,"</td><td>"))+"</td></tr>";
			} else {
				li = "<tr><td>"+(row.replace(/\|/g,"</td><td>"))+"</td></tr>";
			}
		} else if (inTable) {
			li = "</table>" + li;
			inTable = 0;
		}
		if (li.match(Wiki.HEADER_REGEX)) li = "<h"+(RegExp.$1).length+">"+RegExp.$2+"</h"+(RegExp.$1).length+">";
		li = li.replace(Wiki.BOLD_REGEX, "<b>$1</b>");
		li = li.replace(Wiki.ITAL_REGEX, "<i>$1</i>");
		li = li.replace(Wiki.IMG_REGEX, "<img src='$1'>");
		li = li.replace(Wiki.LINK_REGEX, "<a href='$2'>$1</a>");
		li = li.replace(Wiki.LINK2_REGEX, "<a href='$1'>$1</a>");
		result += li + (li.match(/<\/?(h|t|ul|ol)/) ? "": "\n");
	}
	RegExp.multiline = true;
	result = result.replace(/\n\s*?\n/g, "<p/>&nbsp;");
	result = result.replace(/<p>/g, "\n<p>");
	return result;
}