/* phyp */

// TODO
// - set/get range

/// Shortcuts
var d  = document;
var ie = d.all;
var w  = window;

/// Environment
var USER = boot.user;
var LANG = boot.lang;
var DBG  = boot.dbg;

/// Debug
var PHYP_READY        = ":) ";
var PHYP_HALTING      = ";) ";
var PHYP_REBOOTING    = ":| ";
var PHYP_DONE         = ":( ";
var PHYP_MOD_READY    = ".: ";
var PHYP_MOD_DONE     = ":. ";
var PHYP_MOD_WAIT     = ".. ";
var PHYP_BAD_MOD      = ".! ";
var PHYP_NEW_ALIAS    = "+a ";
var PHYP_BAD_ALIAS    = "!a ";
var PHYP_ALIAS_EXISTS = "a! ";
var PHYP_EXEC         = "x: ";
var PHYP_NO_STDI      = "!i ";
/// Callback
var CALLBACK_ERROR    = "!x ";
var CALLBACK_GREEDY   = "x! ";
/// Pile
var PILE_EMPTY        = ">! ";
var PILE_SKIP         = "-> ";
var PILE_DONE         = ">> ";
/// List
var LIST_BROKEN       = "l! ";
/// Cache
var CACHE_FULL        = "!! ";
var CACHE_ADD         = "c+ ";
var CACHE_NO_KEY      = "c! ";
var CACHE_REMOVE      = "c- ";
var CACHE_EMPTY       = "c. ";
/// Codec
var DECODE_ERROR      = "d! ";
/// DOM
var DOM_NO_FRAME      = "!f ";
var DOM_TYPE_ERROR    = "e! ";

/** Compat **/

/// IE lack
//  www.stringify.com/static/js/base64.js
if (typeof btoa == 'undefined') {
    function btoa(s) {
        var cs = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + 
	         'abcdefghijklmnopqrstuvwxyz' +
	         '0123456789+/=';
        var e = [ ], c = 0, b0, b1, b2, b, i0, i1, i2, i3;
        while (c < s.length) {
            b0 = s.charCodeAt(c++);
            b1 = s.charCodeAt(c++);
            b2 = s.charCodeAt(c++);
            b = (b0 << 16) + ((b1 || 0) << 8) + (b2 || 0);
            i0 = (b & (63 << 18)) >> 18;
            i1 = (b & (63 << 12)) >> 12;
            i2 = isNaN(b1)? 64: (b & (63 << 6)) >> 6;
            i3 = isNaN(b2)? 64: (b & 63);
            e.push(cs.charAt(i0));
            e.push(cs.charAt(i1));
            e.push(cs.charAt(i2));
            e.push(cs.charAt(i3));
        }
        return e.join('');
    }
}
if (typeof atob == 'undefined') {
    function atob(s) {
        var cs = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' +
	         'abcdefghijklmnopqrstuvwxyz' +
	         '0123456789+/=';
        var d = [ ], c = 0, i0, i1, i2, i3, b, b0, b1, b2;
        while (c < s.length) {
            i0 = cs.indexOf(s.charAt(c++));
            i1 = cs.indexOf(s.charAt(c++));
            i2 = cs.indexOf(s.charAt(c++));
            i3 = cs.indexOf(s.charAt(c++));
            b = (i0 << 18) + (i1 << 12) + ((i2 & 63) << 6) + (i3 & 63);
            b0 = (b & (255 << 16)) >> 16;
            b1 = (i2 == 64)? -1: (b & (255 << 8)) >> 8;
            b2 = (i3 == 64)? -1: (b & 255);
            d.push(String.fromCharCode(b0));
            if (b1 >= 0) d.push(String.fromCharCode(b1));
            if (b2 >= 0) d.push(String.fromCharCode(b2));
        }
        return d.join('');
    }
}

/** Prototypes **/

var protos = [ 'proto', 'toString', 'toObj', 'toXML', 'msize', 'merge',
	       'clone', 'indexOf', 'inArray', 'except', 'inObj',
	       'setFirst', 'ucFirst', 'lcFirst', 'fu', 'fc', 'lc', 'lw',
	       'fw', 'encode', 'decode', 'html', 'sub', 'path', 'name',
	       'ext', 'isf', 'f', 'pf' ];

/// OOP
//  www.coolpage.com/developer/javascript/Correct%20OOP%20for%20Javascript.html
Object.prototype.proto = function(e) {
    if (arguments.length > 1)
	e.apply(this, Array.prototype.slice.call(arguments, 1));
    else e.call(this);
}
Function.prototype.proto = function(e) {
    this.prototype = new e();
    this.prototype.constructor = this;
}

/// Object to string
Object.prototype.toString = function(z) {
    var i, e = [ ];
    if (z == null) z = 3;
    if (!z) return '>';
    for (i in this) {
	if (this[i] == null) continue;
	switch (tp(this[i])) {
	case 'function': break;
	case 'object': e.push(i + ': ' + this[i].toString(z - 1)); break;
	case 'string': e.push(i + ': \'' + this[i].encode() + '\''); break;
	case 'number': e.push(i + ': ' + this[i]); break;
	case 'boolean': e.push(i + ': ' + (this[i]? 'true': 'false'));
	}
    }
    return '{ ' + e.join(', ') + ' }';
}
Array.prototype.toString = function(z) {
    var i, e = [ ];
    if (z == null) z = 3;
    if (!z) return '>';
    for (i = 0; i < this.length; i++) {
	switch (tp(this[i])) {
	case 'function': break;
	case 'object': e.push(this[i].toString(z - 1)); break;
	case 'string': e.push('\'' + this[i].encode() + '\''); break;
	case 'number': e.push(this[i]); break;
	case 'boolean': e.push(this[i]? 'true': 'false');
	}
    }
    return '[ ' + e.join(', ') + ' ]';
}
Object.prototype.toObj = function() {
    return this.clone();
}
String.prototype.toObj = function() {
    var kv, k, v, i, a, o;
    var s = this.sub(2, -2);
    var es = s.split(', ');
    for (i in es) {
	if (tpf(es[i])) continue;
	a = (es[i].indexOf(':') == -1);
	if (!o) o = a? [ ]: { };
	kv = es[i].split(': ');
	k = kv[0];
	v = (a)? k: kv[1];
	v = v.decode();
	switch (v.fc()) {
	case '\'':
	    v = v.sub(1, -1);
	    break;
	case '[':
	case '{':
	    v = v.toObj();
	    break;
	default:
	    if (v.indexOf('.') != -1)
		v = parseFloat(v);
	    else v = parseInt(v);
	}
	if (a) o.push(v);
	else o[k] = v;
    }
    return o;
}

/// Object memory size
Object.prototype.msize = function() {
    var s = 0;
    try {
	for (i in this) {
	    if (this[i] == null) continue;
	    if (i == 'obj' ||
		i == 'ca' ||
		i == 'parent')
		continue; // skip obj, cache, and parents
	    if (nn(this[i]) !== false) continue;
	    switch (tp(this[i])) {
	    case 'function': break;
	    case 'object': s += this[i].msize(); break;
	    case 'string': s += this[i].length; break;
	    case 'number': s += 8;
	    case 'boolean': s++;
	    }
	}
    } catch(e) { dbg('w', 'mem', DOM_TYPE_ERROR + i); }
    return s;
}
Array.prototype.msize = function() {
    var s = 0;
    try {
	for (i = 0; i < this.length; i++) {
	    if (nn(this[i]) !== false) continue;
	    switch (tp(this[i])) {
	    case 'function': break;
	    case 'object': s += this[i].msize(); break;
	    case 'string': s += this[i].length; break;
	    case 'number': s += 8;
	    case 'boolean': s++;
	    }
	}
    } catch(e) { dbg('w', 'mem', DOM_TYPE_ERROR + i); }
    return s;
}

/// Merge
Object.prototype.merge = function(obj) {
    var i;
    for (i in obj) {
	switch (tp(obj[i])) {
	case 'function': break;
	case 'object':
	    if (this[i] == null) this[i] = { };
	    this[i].merge(obj[i]);
	    break;
	default: this[i] = obj[i];
	}
    }
}

/// Clone
//  www.faqts.com/knowledge_base/view.phtml/aid/6231
Object.prototype.clone = function() {
    var i, e = new this.constructor();
    for (i in this)
	if (this[i] &&
	    tpo(this[i]) &&
	    this[i].clone)
	    e[i] = this[i].clone();
	else e[i] = this[i];
    return e;
}

/// Index of
Array.prototype.indexOf = function(v) {
    var i;
    for (i = 0; i < this.length; i++)
	if (this[i] == v)
	    return i;
    return -1;
}

/// In array
Array.prototype.inArray = function(v) {
    return this.indexOf(v) != -1;
}

/// Except
Array.prototype.except = function(v) {
    if (!this.inArray(v))
	return this;
    var i, vs = [ ];
    for (i = 0; i < this.length; i++)
	if (this[i] != v)
	    vs.push(this[i]);
    return vs;
}

/// In object
Object.prototype.inObj = function(v) {
    var i;
    for (i in this)
	if (nf(this[i]) &&
	    this[i] == v)
	    return true;
    return false;
}

/// Set first
Array.prototype.setFirst = function(v) {
    var j, i = this.indexOf(v);
    if (i == -1) this.unshift(v);
    else {
	for (j = i; j > 0; j--)
	    this[j] = this[j - 1];
	this[0] = v;
    }
}

/// Upper case first letter
String.prototype.ucFirst = function() {
    if (!this) return '';
    return this.fc().toUpperCase() + this.substr(1);
}

/// Lower case first letter
String.prototype.lcFirst = function() {
    if (!this) return '';
    return this.fc().toLowerCase() + this.substr(1);
}

/// Find first upper case letter
String.prototype.fu = function() {
    var i;
    if (!this) return -1;
    for (i = 0; i < this.length; i++)
	if (this.charAt(i).toUpperCase() == this.charAt(i))
	    return i;
    return -1;
}

/// First char
String.prototype.fc = function() {
    return this.charAt(0);
}

/// Last char
String.prototype.lc = function() {
    return this.charAt(this.length - 1);
}

/// Last word
String.prototype.lw = function() {
    return this.substr(this.lastIndexOf(' ') + 1);
}

/// First word
String.prototype.fw = function() {
    if (this.indexOf(' ') == -1)
	return this.substr(0, this.length); // Need to clone
    return this.substr(0, this.indexOf(' '));
}

/// Encode
String.prototype.encode = function(p) {
    var e = encodeURIComponent(this);
    if (!p) return e;
    e = e.replace(/%2F/g, '/').replace(/%3A/g, ':');
    return e.replace(/\/\.\.?\//g, '');
}

/// HTML special chars
String.prototype.html = function(noq) {
    var s = this.replace(/&/g, '&amp;');
    if (!noq) s = s.replace(/\"/g, '&quot;');
    s = s.replace(/</g, '&lt;');
    s = s.replace(/>/g, '&gt;');
    return s;
}

/// Decode
String.prototype.decode = function() {
    try {
	return decodeURIComponent(this);
    } catch(e) {
	dbg('w', 'decode', DECODE_ERROR + this);
	return this;
    }
}

/// Decode
Boolean.prototype.decode = function() {
    dbg('w', 'protos', DECODE_ERROR + 'boolean');
    return this;
}

/// Substring
String.prototype.sub = function(a, b) {
    if (a < 0) a += this.length;
    if (b == null) return this.substring(a);
    if (b < 0) b += this.length;
    return this.substring(a, b);
}

/// Human time
Date.humanTime = function(t, o) {
    if (!o) o = { };
    var s = o.sep? o.sep: ':';
    var dt = t? new Date(t * 1000): new Date();
    return zeros(dt.getHours()) + s +
           zeros(dt.getMinutes()) +
           (o.sec? s + zeros(dt.getSeconds()): '');
}

/// Human date
Date.humanDate = function(t, o) {
    if (!o) o = { };
    var m, n, s = '';
    var ds = [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ];
    var ms = [ "Jan", "Fev", "Mar", "Apr", "May", "Jun",
	       "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ];
    if (t == false) return '';
    m = t? new Date(t * 1000): new Date();
    n = new Date();
    if (o.today &&
	(m.getDate() == n.getDate()) &&
	(m.getMonth() == n.getMonth()) &&
	(m.getYear() == n.getYear()))
	s += "Today" + ' ';
    if (o.day && (!o.today || m.getDate() != n.getDate()))
	s += ds[m.getDay()] + ' ';
    if (!o.today || (m.getMonth() != n.getMonth()))
	s += ms[m.getMonth()];
    if (!o.today || (m.getDate() != n.getDate()))
	s += ' ' + blanks(m.getDate(), 2, true);
    if (!o.short || (m.getYear() != n.getYear()))
	s += ' ' + m.getFullYear();
    if (o.time && m.getYear() == n.getYear())
	s += ' ' + this.humanTime(t, o);
    return s;
}

/// Human datetime
Date.humanDatetime = function(t, o) {
    if (!o) o = { };
    o.merge({ time: true });
    return this.humanDate(t, o);
}

/// Human delay
function humanDelay(e) {
    var s = rn(e / 1000);
    if (s > 4500) return __("hours", { n: rn(s / 3600) });
    if (s > 90) return __("minutes", { n: rn(s / 60) });
    if (s > 30) return __("aminute");
    if (s > 10) return __("tensecs");
    return __("seconds", { n: s });
}

/** Misc **/

/// Default core shortcuts
function ___(s, o) {
    var i;
    if (tpo(o))
	for (i in o)
	    if (tps(o[i]) || tpn(o[i]))
		s += ' ' + o[i];
    return s;
}
function __(s, o) { return ___(s, o); }
function stdo(s) { alert(s); }
function nil() { return false; }
var dbg = nil;
var tce = nil;
var bt = nil;

/// Now
function now() { var n = new Date(); return n.getTime(); }

/// Zeros filler
function zeros(n, l) {
    if (!l) l = 2;
    return blanks(n, l, true, '0');
}
function blanks(n, l, rl, c) {
    if (!c) c = ' ';
    n += '';
    while (n.length < l)
	if (rl) n = c + n;
	else n += c;
    if (n.length > l)
	n = n.substr(0, l - 3) + '...';
    return n;
}

/// Type
function tp(i) { return (typeof i); }
function tpo(i) { return (typeof i == 'object'); }
function tpf(i) { return (typeof i == 'function'); }
function tps(i) { return (typeof i == 'string'); }
function tpb(i) { return (typeof i == 'boolean'); }
function tpn(i) { return (typeof i == 'number'); }
function tpu(i) { return (typeof i == 'undefined'); }
function nf(i) { return !tpf(i); }

/// Human size
function humanSize(s) {
    if (!tpn(s)) s = parseInt(s);
    var u = 0, us = [ '', 'k', 'M', 'G', 'T' ];
    while (s > 1000) { u++; s /= 1024; }
    if (s < 2)
	return rn(s * 10) / 10 + us[u];
    return rn(s) + us[u];
}

/// Encode argument
function arg(f) {
    if (!tps(f))
	return '';
    if (f.fc() != '/') f = '/' + f;
    return f.encode(true);
}

/// Encode options
function opts(os) {
    if (!tpo(os))
	return '';
    var v, i, s = '';
    for (i in os) {
	switch (tp(os[i])) {
	case 'function': continue;
	case 'object': v = '{' + opts(os[i]).encode(true) + '}'; break;
	case 'boolean': v = os[i]? 'true': 'false'; break;
	case 'string': v = (os[i].fc() == '/')? os[i].substr(1): os[i]; break;
	default: v = '' + os[i];
	}
	s += '&' + i.encode() + '/' + v.encode(true);
    }
    return s;
}

/// Callback
function cb(a, e, o, f) {
    var k, cc, t = now();
    if (!a || !a.obj) return true;
    cc = a.obj.constructor.toString().match(/function\ (.+)\(/)[1];
    if (!f) {
	if (a.obj && a.obj[a.done])
	    k = a.obj[a.done](a.args, e, o);
	else
	    k = dbg('w', 'cb', CALLBACK_ERROR + [ cc, a.done ]);
    }
    if ((f || !k) && a.fail)
	if (a.obj && a.obj[a.fail])
	    a.obj[a.fail](a.args, e, o);
	else dbg('w', '!cb', CALLBACK_ERROR + [ cc, a.fail ]);
    if (now() - t > 400)
	dbg('b', 'cb', CALLBACK_GREEDY + [ cc, a.done, (now() - t) ]);
    return k;
}

/// Convert 32bit unsigned value to 8bit hex
function hex32(val) {
    var n, str1, str2;
    n = val & 0xFFFF;
    str1 = n.toString(16).toUpperCase();
    while (str1.length < 4)
	str1 = '0' + str1;
    n = (val >>> 16) & 0xFFFF;
    str2 = n.toString(16).toUpperCase();
    while (str2.length < 4)
	str2 = '0' + str2;
    return '0x' + str2 + str1;
}

/** DOM **/

/// JsDOM
function jd(e) { this.e = e; }

/// Create
function ce(t) { return d.createElement(t); }
function ct(v) { return d.createTextNode(v); }

/// Attributes
function ga(e, k) { return (e && nn(e))? e.getAttribute(k): null; }
function gas(e) { return e.attributes; }
function sa(e, k, v) { return e.setAttribute(k, v); }
function ra(e, k) { return e.removeAttribute(k); }

/// Insert, move & remove
function ac(e, c) { return e.appendChild(c); }
function ib(e, c) { return e? pn(e).insertBefore(c, e): false; }
function ia(e, c) { return e? pn(e).insertBefore(c, ns(e)): false; }
function ifc(e, c) { return e.insertBefore(c, fc(e)); }
function rc(e, c) { return nn(e)? e.removeChild(c): false; }
function rcp(c) { return rc(pn(c), c); }
function rfc(e) { return rc(e, fc(e)); }
function rlc(e) { return rc(e, lc(e)); }
function me(c) { var e = pn(c); return rc(e, c) && ac(e, c); }
function mb(e, c) { return rcp(c) && ib(e, c); }

/// Childnodes
function nl(e) { return e.childNodes.length; }
function ni(c) {
    var i, e = pn(c);
    for (i = 0; i < nl(e); i++)
	if (cn(e, i) == c)
	    return i;
    return -1;
}
function cn(e, i) { return e.childNodes[parseInt(i)]; }
function fc(e) { return e? e.firstChild: false; }
function gfc(e) { return fc(fc(e)); }
function lc(e, i) { return e.childNodes[nl(e) - 1]; }
function clr(e, n) { n |= 0; while (nl(e) > n) rfc(e); }

/// Siblings
function ps(e, t) { var f = e.previousSibling; return (f && !nn(f) && !t)? ps(f): f; }
function ns(e, t) { var f = e.nextSibling; return (f && !nn(f) && !t)? ns(f): f; }

/// Parents
function pn(e) { return e? e.parentNode: false; }
function gpn(e) { return pn(pn(e)); }

/// Elements
function gi(e, i) {
    if (!i) return d.getElementById(e);
    return e.getElementById(i);
}
function gts(e, i) { return e.getElementsByTagName(i); }
function gt(e, i) { return gts(e, i)[0]; }
function gcs(e, c) {
    var i, e = e.all || gts(e, '*'), a = [ ];
    for (i = 0; i < e.length; i++)
	if (e[i].className && e[i].className.split(' ').inArray(c))
	    a.push(e[i]);
    return a;
}
function gc(e, c) { return gcs(e, c)[0]; }
function gxs(e, t) {
    var i, e = e.all || gts(e, '*'), a = [ ];
    for (i = 0; i < e.length; i++)
	if (nn(e[i]) && ga(e[i], t) != null)
	    a.push(e[i]);
    return a;
}
function gx(e, t) {
    return gxs(e, t)[0];
}

/// Frame body
function fb(e) {
    var doc = fd(e);
    return doc? doc.body: false;
}

/// Frame document
function fd(e) {
    var doc;
    if (e.contentDocument) doc = e.contentDocument; // NS6
    else if (e.contentWindow) doc = e.contentWindow.document; // IE5.5, IE6
    else if (e.document) doc = e.document; // IE5
    else return dbg('e', 'fb', DOM_NO_FRAME);
    return doc;
}

/// Contents
function ih(e, v) { return (v == null)? e.innerHTML: e.innerHTML = v; }
function it(e, v) {
    if (ie) return (v == null)? e.innerText: e.innerText = v;
    return (v == null)? e.textContent: e.textContent = v;
}
function nn(e) {
    if (!e || !e.nodeName) return false;
    var n = e.nodeName.toLowerCase();
    return (n.fc() == '#')? '': n;
}
function nv(e) { return e? e.nodeValue: false; }

/// Get coords
function gd(e, mod, rec) {
    if (!e || !nn(e))
	return dbg('w', 'gd', DOM_TYPE_ERROR + e);
    var cs = { };
    var nns = [ 'ol', 'ul', 'li', 'img', 'div', 'tr', 'table' ];
    var recs = [ 'ol', 'ul', 'li' ];
    var cls = [ 'so', 'sf', 'm' ];
    if (!ie) {
	cls.push('bs');
	cls.push('c');
    }
    if (!mod || mod % 2) {
	cs.x = e.offsetLeft;
	cs.y = e.offsetTop;
    }
    if (!mod || mod == 2) {
	cs.w = e.offsetWidth;
	cs.h = e.offsetHeight;
    }
    if (rec) {
	if (rec === true) rec = { };
	if (!nns.inArray(nn(e)) ||
	    (nn(e) == 'ul' && mod == 3) ||
	    (c(e).fw() == 'bk' && !ie) ||
	    cls.inArray(c(e).fw()) ||
	    (nn(e) == 'li' &&
	     (rec.li || rec.ul))) {
	    cs.x = cs.y = 0;
	} else {
	    if (recs.inArray(nn(e)))
		rec[nn(e)] = true;
	}
	if (mod == 3) {
	    cs.w = cs.h = 0;
	    if (pn(e) && pn(e).scrollLeft)
		cs.x -= pn(e).scrollLeft;
	    if (pn(e) && pn(e).scrollTop)
		cs.y -= pn(e).scrollTop;
	}
    }
    if (rec && e != d.body) {
	// if (cs.x || cs.y)
	// dbg('v', 'gd' ,"+ " + cs + " (" + nn(e) + "." + c(e).fw() + ")");
	var a = gd(pn(e), 3, rec);
	// dbg('v', 'gd' ,"= " + da(cs, a));
	return da(cs, a);
    }
    return cs;
}

/// Set coords (& alpha...)
function sd(e, cs) {
    if (cs.x != null && !isNaN(cs.x))
	ss(e, { left: cs.x + 'px' });
    if (cs.y != null && !isNaN(cs.y))
	ss(e, { top: cs.y + 'px' });
    if (cs.w != null)
	ss(e, { width: max(10, cs.w) + 'px' });
    if (cs.h != null)
	ss(e, { height: max(10, cs.h) + 'px' });
    if (cs.a != null)
	alpha(e, cs.a);
}

/// Zone coords
function gz(e) {
    var zs, n;
    switch (nn(e)) {
    case 'ul':
    case 'img': n = e; break;
    default: n = gpn(e);
    }
    zs = gd(n, 1, true);
    zs.merge(gd(pn(n), 2));
    return zs;
}

/// Is in zone
function iz(m, z) {
    var zs = gd(z, 0, true);
    return (m.x >= zs.x &&
	    m.x <= zs.x + zs.w &&
	    m.y >= zs.y &&
	    m.y <= zs.y + zs.h);
}

/// Is in mask zone
function im(e, zs, f) {
    var ds = gd(e, 0, true);
    if (!f)
	return (ds.x + ds.w > zs.x &&
		ds.x < zs.x + zs.w &&
		ds.y + ds.h > zs.y &&
		ds.y < zs.y + zs.h);
    return (ds.x >= zs.x &&
	    ds.x + ds.w <= zs.x + zs.w &&
	    ds.y >= zs.y &&
	    ds.y + ds.h <= zs.y + zs.h);
}

/// Set mask coords
function sm(m, e, zs, wd, os) {
    var ds = gd(e, 0, true);
    if (os)
	ds = da(ds,
		{ x: -os, y: -os,
		  w: 2 * os, h: 2 * os });
    if (!wd) wd = { x: 0, y: 0 };
    if (ds.x + ds.w > zs.x + zs.w)
	ds.w = (zs.x + zs.w - ds.x);
    if (ds.y + ds.h > zs.y + zs.h)
	ds.h = (zs.y + zs.h - ds.y);
    if (ds.x < zs.x) {
	ds.w -= (zs.x - ds.x);
	ds.x = zs.x;
    }
    if (ds.y < zs.y) {
	ds.h -= (zs.y - ds.y);
	ds.y = zs.y;
    }
    sd(m, da(ds, { x: -wd.x, y: -wd.y, w: 0, h: 0 }));
}

/// Coords substract
function ds(a, b) {
    var i, c = { };
    for (i in b)
	if (nf(b[i]))
	    c[i] = -b[i];
    return da(a, c);
}

/// Coords add
function da(a, b) {
    var i, c = { };
    for (i in a)
	if (nf(a[i]) && b[i] != null)
	    c[i] = a[i] + b[i];
    return c;
}

/// Coords diff
function dd(e, d) {
    sd(e, da(d, gd(e)));
}

/// Coords prop
function dp(a, b, e) {
    var i, c = { };
    for (i in a)
	if (nf(a[i]) && b[i] != null) {
	    c[i] = b[i] + (a[i] - b[i]) * e;
	    if (i != 'a') c[i] = rn(c[i]);
	}
    return c;
}

/// Classname
function c(e, c, a) {
    tce('c', c);
    var cs;
    if (!e || e.className == null)
	dbg('e', 'c', DOM_TYPE_ERROR + e);
    if (c == null)
	return e.className;
    if (a != null) {
	cs = e.className.split(' ');
	if (a && !cs.inArray(c))
	    cs.push(c);
	if (!a)
	    cs = cs.except(c);
	e.className = cs.join(' ');
    } else e.className = c;
    return true;
}

/// Toggle class
function tcs(e, b, c) {
    var i, s = gcs(e, b);
    for (i = 0; i < s.length; i++)
	c(s[i], c(s[i]).replace(b, c));
    return s.length;
}

/// Toggle scrolling
function tsc(e, on) {
    var i, s = gcs(e, 'so');
    for (i = 0; i < s.length; i++) {
	if (on) {
	    s[i].scrollLeft = parseInt(ga(s[i], 'sx'));
	    s[i].scrollTop = parseInt(ga(s[i], 'sy'));
	} else {
	    sa(s[i], 'sx', s[i].scrollLeft);
	    sa(s[i], 'sy', s[i].scrollTop);
	}
    }
    return s.length;
}

/// Get style
function gs(e, i) {
    return e.style[cs(i)];
}

/// Set style
function ss(e, v) {
    var i;
    if (!e || !e.style)
	return dbg('w', 'ss', DOM_TYPE_ERROR + [ nn(e), v ]);
    for (i in v)
	if (nf(v[i]) && v[i] != null)
	    e.style[cs(i)] = v[i];
    return true;
}

/// Alpha
function alpha(e, a) {
    if (ie) {
	if (a == null) ss(e, { filter: '' });
	else ss(e, { filter: 'Alpha(opacity=' + rn(a * 100) + ',style=0)' });
    } else {
	if (a == null) ss(e, { opacity: '' });
	else ss(e, { opacity: a });
    }
}

/// Correct style
function cs(i) {
    if (i == 'float')
	return ie? 'styleFloat': 'cssFloat';
    if (i.indexOf('-') == -1)
	return i;
    var j, a = i.split('-');
    j = a.shift();
    while (a.length)
	j += a.shift().ucFirst();
    return j;
}

/// Range
function sr() { }
function gr() { }

/// Clear range
function cr() {
    var s;
    if (d.selection && d.selection.empty)
	d.selection.empty();
    else if (w.getSelection
	     && (s = w.getSelection())
	     && s.removeAllRanges)
	s.removeAllRanges();
    else select();
}

/// Math
function rn(f) { return (tp(f) == 'number')? Math.round(f): 0; }
function fl(f) { return (tp(f) == 'number')? Math.floor(f): 0; }
function cl(f) { return (tp(f) == 'number')? Math.ceil(f): 0; }
function sq(f) { return (tp(f) == 'number')? Math.sqrt(f): 0; }
function max(a, b) { return Math.max(a, b); }
function min(a, b) { return Math.min(a, b); }
function btw(a, b, c) { return Math.min(c, Math.max(a, b)); }

/// Create DOM element
function dom(t, a, c) {
    var i, s, e = ce(t);
    if (!tpo(a)) {
	s = a;
	a = (tpo(c))? c: { };
	c = s;
    }
    for (i in a)
	if (nf(a[i]))
	    if (i == 'c') e.className = a[i];
	    else sa(e, i, a[i]);
    if (c)
	if (tps(c)) ac(e, ct(c));
	else if (c.nodeName) ac(e, c);
	else
	    for (i in c)
		if (tps(c[i])) ac(e, ct(c[i]));
		else if (tpo(c[i])) ac(e, c[i]);
    return e;
}

/// URL infos
function infos(url) {
    var i, j, proto, port, dom, opts = { };
    var os = url.search.sub(1).split('&');
    for (i = 0; i < os.length; i++) {
	if (!os[i]) continue;
	j = os[i].indexOf('=');
	if (j == -1) opts[os[i]] = true;
	else opts[os[i].sub(0, j)] = os[i].sub(j + 1).decode();
    }
    if (boot.sign) proto = boot.sign;
    else proto = url.protocol.sub(0, -1);
    port = url.port;
    if (!port) port = 80;
    dom = proto + '://' + url.host;
    if (port != 80) dom += ':' + port;
    return { dom:   dom,
	     proto: proto,
	     host:  url.host,
	     port:  port,
  	     path:  url.pathname.sub(1),
	     hash:  url.hash.sub(1),
	     opts:  opts };
}

/// Popup
function pop(e) {
    e.blur();
    w.open(e.href);
    return false;
}

/** Files **/

/// Path
String.prototype.path = function(dir) {
    var f = this;
    if (!f || (!f.match(/^[a-z]+:/) && f.fc() != '/'))
	f = '/' + f;
    f = f.replace(/^.*\/~\//, '/home/' + USER + '/');
    while (f.indexOf('./') != -1)
	f = f.replace(/\/+\.\//g, '/').replace(/\/*[^\/]*\/\.\.\//g, '/');
    return f;
}

/// Name
String.prototype.name = function(h) {
    var s = this;
    if (s.indexOf('&') != -1)
	s = s.substr(0, s.indexOf('&'));
    if (s.isf())
	s = s.substr(0, s.length - 1);
    if (!h)
	return s.substr(s.lastIndexOf('/') + 1);
    return s.substring(s.lastIndexOf('/') + 1, s.lastIndexOf('.'));
}

/// Extension
String.prototype.ext = function() {
    if (this.isf())
	return 'folder';
    if (this.lastIndexOf('/') >= this.lastIndexOf('.'))
	return false;
    return this.substr(this.lastIndexOf('.') + 1).toLowerCase();
}

/// Is folder?
String.prototype.isf = function() {
    return (this.lc() == '/');
}

/// Folder
String.prototype.f = function() {
    if (this.isf()) return this + '';
    return this.substr(0, this.lastIndexOf('/') + 1);
}

/// Parent folder
String.prototype.pf = function() {
    if (this.isf() && this != '/')
	return this.sub(0, -1).f();
    return this.f();
}

/** Cache **/
function cache(n, o) {

    /// Init

    // Name
    this.n = n;
    // Options
    this.o = o || { };
    // Expire time (in sec.)
    if (!this.o.expire)
	this.o.expire |= 60;
    // Content
    this.c = { };
    // Size
    this.s = 0;

    /// Update options
    this.opts = function(o) {
	this.o.merge(o);
    }

    /// Push
    this.push = function(e) {
	var s;
	// Element size
	e.size |= 0;
	// Remove existing?
	if (this.c[e.key])
	    this.remove(e.key);
	// Cache size
	if (this.o.max)
	    if (e.size > this.o.max)
		return dbg('e', this.n, CACHE_FULL + [ e.size, this.o.max ]);
	    else this.clear(this.o.max - e.size);
	this.s += e.size || 0;
	// Cache value
	this.c[e.key] = { value:  e.value,
			  cached: now(),
			  size:   e.size,
			  expire: e.expire || this.o.expire };
	s = (this.o.max)? rn(100 * this.s / this.o.max) + '%': this.s;
	dbg('v', this.n, CACHE_ADD + [ e.key, e.size ] + ' ' + s);
	// Automatic flush?
	if (p.tms && (this.o.auto || e.expire))
	    p.tms.r({ obj:  this,
		      done: 'flush',
		      args: { key:    e.key,
			      cached: this.c[e.key].cached },
		      ms:   e.expire * 1000 });
	return true;
    }

    /// Cached?
    this.cached = function(k) {
	var k;
	if (!this.c[k]) return false;
	if (!this.c[k].expire) return true;
	k = (this.c[k].cached + this.c[k].expire * 1000 > now());
	if (!k) this.flush({ key: k }, true);
	return k;
    }

    /// Value
    this.value = function(k) {
	if (!this.c[k])
	    return dbg('w', this.n, CACHE_NO_KEY + k);
	return this.c[k].value;
    }

    /// Remove
    this.remove = function(k) {
	return this.flush({ key: k }, true);
    }

    /// Flush
    this.flush = function(e, f) {
	// Already flushed?
	if (!this.c[e.key])
	    return false;
	// Check
	if (f !== true && this.c[e.key].cached != e.cached)
	    return false;
	// Flush?
	if (f === true || !this.o.off || !p.off) {
	    this.s -= this.c[e.key].size;
	    delete(this.c[e.key]);
	    dbg('v', this.n, CACHE_REMOVE + [ e.key, this.s ]);
	}
	return true;
    }

    /// Clear
    this.clear = function(s) {
	while (this.s > s)
	    this.flush(this.oldest());
	return true;
    }

    /// Oldest
    this.oldest = function() {
	var i, o = { key: -1, cached: now() };
	for (i in this.c)
	    if (nf(this.c[i]) && this.c[i].cached < o.cached)
		o = { key: i, cached: this.c[i].cached };
	return o;
    }

    /// Empty
    this.empty = function() {
	var i;
	for (i in this.c)
	    if (nf(this.c[i]))
		delete(this.c[i]);
	this.s = 0;
	dbg('i', this.n, CACHE_EMPTY);
    }

}

/** Pile **/
function pile(n) {

    this.v = [ ];
    this.l = 0;
    this.n = n;

    /// Add
    this.add = function(e) {
	this.rm(e);
	this.push(e);
	return true;
    }

    /// Push
    this.push = function(e) {
	this.v.push(e);
	this.l = this.v.length;
	return true;
    }

    /// Remove
    this.rm = function(e) {
	while (this.v.indexOf(e) != -1)
	    this.skip(this.v.indexOf(e));
	this.l = this.v.length;
	return true;
    }
    
    /// Skip
    this.skip = function(id) {
	var i;
	if (id == -1) return false;
	for (i = id; i < this.v.length - 1; i++)
	    this.v[i] = this.v[i + 1];
	this.v.pop();
	return true;
    }
    
    /// Back
    this.back = function(a) {
	var e, ok = false;
	if (!this.v.length)
	    return dbg('v', this.n, PILE_EMPTY);
	do {
	    e = this.v.pop();
	    ok = a.obj[a.done](e);
	    if (!ok)
		dbg('v', this.n, PILE_SKIP + e);
	} while (!ok && this.v.length);
	if (ok) {
	    this.v.push(e);
	    dbg('v', this.n, PILE_DONE + e);
	} else {
	    if (a.fail)
		a.obj[a.fail]();
	    dbg('v', this.n, PILE_EMPTY);
	}
	this.l = this.v.length;
	return ok;
    }
    
    /// Empty
    this.empty = function() {
	delete(this.v);
	this.v = [ ];
	this.l = 0;
    }
    
}

/** History **/
function history(n) {

    /// Init
    this.p = -1;
    this.v = [ ];
    this.n = n;

    /// Go
    this.go = function(i) {
	// Out of bounds?
	if (this.p + i < 0 || this.p + i >= this.v.length)
	    return false;
	this.p += i;
	return { p: this.p,
		 m: this.v.length,
		 v: this.v[this.p] };
    }

    /// Back
    this.back = function() {
	return this.go(-1);
    }

    /// Current
    this.current = function() {
	return this.go(0);
    }

    /// Forward
    this.forward = function() {
	return this.go(1);
    }
    
    /// Push
    this.push = function(v) {
	while (this.v.length > this.p + 1)
	    this.v.pop();
	this.append(v);
    }

    /// Append
    this.append = function(v) {
	this.v.push(v);
	this.p = this.v.length - 1;
    }

    /// Replace
    this.replace = function(v) {
	this.p = this.v.length - 1;
	this.v[this.p] = v;
    }

    /// Free
    this.free = function() {
	delete(this.v);
	this.v = [ ];
	this.p = -1;
    }
    
}

/** List **/
function list(n) {

    /// Init
    this.l = 0;
    this.v = [ ];
    this.n = n;

    /// Next
    this.next = function() {
	var i;
	for (i = 0; i <= this.l; i++)
	    if (this.v[i] == null)
		break;
	return i;
    }
    
    /// Put
    this.put = function(i, v, f) {
	if (this.v[i] != null && !f)
	    return false;
	if (this.v[i] == null) this.l++;
	this.v[i] = v;
	return true;
    }

    /// Get
    this.get = function(i) {
	return this.v[i];
    }

    /// Add
    this.add = function(v) {
	var i = this.next();
	return this.put(i, v)? i: false;
    }

    /// Index of
    this.indexOf = function(v) {
	var i;
	for (i = 0; i < this.v.length; i++)
	    if (this.v[i] == v)
		return i;
	return -1;
    }

    /// First
    this.first = function(v) {
	var i;
	for (i = 0; i < this.v.length; i++)
	    if (this.v[i])
		return i;
	return -1;
    }

    /// Remove
    this.rm = function(i) {
	if (this.v[i] == null || !delete(this.v[i]))
	    return dbg('w', this.n, LIST_BROKEN + i);
	this.l--;
	this.free();
	return true;
    }
    
    /// Empty
    this.empty = function() {
	var i;
	for (i = 0; i < this.v.length; i++)
	    this.rm(i);
	this.free();
	return !this.l;
    }

    /// Exec
    this.exec = function(a) {
	var i, o, r = true;
	for (i = 0; i < this.v.length; i++) {
	    if (this.v[i] == null) continue;
	    o = a.obj[a.done](a.key? i: this.v[i], a.args);
	    r &= (a.reverse)? !o: o;
	}
	return r;
    }

    /// Free
    this.free = function() {
	var i;
	for (i = this.v.length - 1; i >= 0; i--)
	    if (this.v[i] == null)
		this.v.pop();
	    else break;
	return true;
    }

}

/** Phyp **/
var p = {

    /** Core **/
    
    /// Core modules
    cs: { debug: 'debug',
	  tms:   'timers',
	  evts:  'events',
	  xml:   'xml',
	  sql:   'sql',
	  cpto:  'crypto',
	  io:    'io',
	  prefs: 'prefs',
	  bb:    'babel',
	  usr:   'user',
	  apps:  'apps',
	  jsd:   'jsdom',
	  X:     'X'
    },

    /// Boot
    bs: false,
    bi: false,
    rl: -1,
    ld: { },

    /// Eko
    eko: 'eko> ',
    stdi: false,
    als: { },

    /// Language
    lang: LANG,

    /// Init core
    init: function() {
	tce('phyp.init');
	if (p.rl != -1)
	    return false;
	// Bootstrap
	p.bi = dom('input', { onchange: 'p.x(this)' });
	p.bs = dom('pre', { c: 'term' },
		   dom('p', { },
	               { eko: dom('b', p.eko),
			 inp: p.bi }));
	p.bp = dom('div',
                   { id: 'hello',
		     c:  'loader' },
                   { tt: dom('p', __("loading")),
		     pb: dom('div', { },
			     dom('span')) });
	// Shortcut
	stdo = function(s, app, rep) { return p.stdo(s, app, rep); }
	// Read location
	p.loc = infos(d.location);
	p.title = d.title.sub(0, d.title.lastIndexOf(' ') + 1);
	// Error handler
	w.onerror = p.bug;
	// Run
	switch (parseInt(p.loc.opts.run)) {
	case 1: p.rl = 1; break;
	case 2:
	case 3: p.rl = 2; break;
	case 4:
	case 5: p.rl = 4; break;
	default: p.rl = 4;
	}
	return p.run(p.rl);
    },

    /// Quit core
    quit: function(r) {
	tce('phyp.quit');
	return this.run(0);
    },

    /// Reboot
    reboot: function() {
	tce('phyp.reboot');
	return this.run(6);
    },

    /// Start X
    startX: function() {
	tce('phyp.startX');
	if (this.rl != 3)
	    return false;
	this.stdi = false;
	rcp(this.bs);
	this.rl = 5;
	return this.run(6);
    },

    /// Stop X
    stopX: function() {
	tce('phyp.stopX');
	if (this.rl != 5)
	    return false;
	this.rl = 3;
	return this.run(6);
    },

    /** Public **/

    /// Turn on
    on: function(e) {
	e.blur();
	rcp(pn(e));
	return !p.init();
    },

    /// Exec
    x: function(e) {
	tce('phyp.x', e.value);
	var a, b, as, os, vs, cmd, app, r;
	var v = e.value;
	var n = nn(e);
	if (n) {
	    e.value = '';
	    e.focus();
	}
	vs = v.split(' ');
	a = vs.shift();
	// Check alias or cmd
	if (this.als[a]) {
	    cmd = 'p.' + this.als[a].app +
		  '.' + this.als[a].mth;
	    app = p[this.als[a].app];
	} else if (tpf(this[a])) {
	    cmd = 'p.' + a;
	    app = this;
	} else if (n && a.match(/^[a-z]+$/i)) {
	    cmd = 'p.apps.launch';
	    vs.unshift(a);
	    app = p.apps;
	} else {
	    app = this;
	    cmd = v;
	}
	// Build args & opts
	if (cmd != v) {
	    as = [ ];
	    os = { };
	    while (b = vs.shift()) {
		if (b.fc() == '-') {
		    b = b.substr(1);
		    /* if (b.length > 1)
		       for (i = 0; i < b.length; i++)
		       os[b.charAt(i)] = true;
		       else */
		    if (vs[0] && vs[0].fc() != '-')
			os[b] = vs.shift();
		    else os[b] = true;
		} else as.push(b);
	    }
	    cmd += '("' + as.join('", "') + '", ' +
 	           os.toString() + ')';
	}
	// Eval
	if (n)
	    stdo(app.eko + v, 'cmd');
	try {
	    dbg('v', 'phyp', PHYP_EXEC + cmd);
	    r = eval(cmd);
	    if (this.debug && tpo(r))
		r = this.debug.d(r, '');
	} catch(err) {
	    r = err.name;
	    if (this.debug)
		this.debug.handler(err.message,
				   err.fileName,
				   err.lineNumber);
	}
	if (cmd == v && !tpu(r))
	    stdo(r, 'phyp');
	// Focus
	if (n)
	    ps(e).innerHTML = app.eko;
	return true;
    },

    /// Launch
    l: function(a, o) {
	tce('phyp.l', a);
	if (this.apps)
	    return this.apps.launch(a, o);
	return dbg('w', 'phyp', PHYP_NO_LAUNCHER + a);
    },

    /// Alias
    alias: function(app, als) {
	tce('phyp.alias');
	var i, s, k = true;
	if (app) {
	    for (i in als) {
		if (tpf(als[i])) continue;
		if (!this.als[i]) {
		    this.als[i] = { app: app,
				    mth: als[i] };
		    // dbg('v', 'phyp', PHYP_NEW_ALIAS + i);
		} // else k &= dbg('w', 'phyp', PHYP_ALIAS_EXISTS + i);
	    }
	    return k;
	}
	s = [ ];
	for (i in this.als)
	    if (nf(this.als[i]))
		s.push([ i, this.als[i].app,
			 this.als[i].mth ]);
	stdo(s, 'phyp');
	return true;
    },

    /// Clear standard output
    clear: function() {
	tce('phyp.clear');
	if (!this.stdi)
	    return false;
	clr(gpn(this.stdi), 1);
	return true;
    },

    /// Standard output
    stdo: function(s, app, rep) {
	tce('phyp.stdo');
	if (!this.stdi)
	    return false;
	var i, str, o = s;
	if (tpo(app)) {
	    i = s;
	    s = app;
	    app = i;
	    alert("got something strange: " + s);
	}
	if (app != 'dom') {
	    o = dom('p', { c: app });
	    if (tpo(s)) {
		str = '';
		for (i = 0; i < s.length; i++)
		    str += s[i].join('\t') + '\n';
		it(o, str);
	    } else it(o, s);
	}
	// Insert or replace
	if (rep) rcp(ps(pn(this.stdi)));
	try { ib(pn(this.stdi), o); }
	catch(e) { dbg('w', 'phyp', PHYP_NO_STDI); }
	// Scroll down
	pn(gpn(this.stdi)).scrollTop = 100000;
	gpn(this.stdi).scrollTop = 100000;
	return true;
    },

    /// Memory usage
    mem: function(o) {
	tce('phyp.mem');
	if (!o) o = { };
	var i, s = [ ];
	var cs, ms, ts = [ 0, 0, 0, 0 ];
	s.push([ '', 'Size', 'Cache', 'Max', 'Available' ]);
	for (i in this.cs) {
	    if (tpf(this.cs[i]) ||
		!this[i])
		continue;
	    if (this[i].mem)
		cs = this[i].mem();
	    else cs = [ 0, 0 ];
	    ms = this[i].msize();
	    s.push([ this.cs[i],
		     humanSize(ms),
		     humanSize(cs[0]),
		     humanSize(cs[1]),
		     humanSize(cs[1] - cs[0]) ]);
	    ts[0] += ms;
	    ts[1] += cs[0];
	    ts[2] += cs[1];
	    ts[3] += cs[1] - cs[0];
	}
	s.push([ 'Total',
		 humanSize(ts[0]),
		 humanSize(ts[1]),
		 humanSize(ts[2]),
		 humanSize(ts[3]) ]);
	// Send
	if (!o.quiet) stdo(s);
	return s;
    },

    /** Private **/

    /// Run level
    run: function(r) {
	tce('phyp.run', r);
	var i;
	// Update level
	this.ol = this.rl;
	this.rl = r;
	this.us = [ ];
	this.fs = { };
	this.inc(__("runlevel", { r: r }), 0);
	// Pre-action
	if (r == 4 || this.ol == 5) {
	    ac(d.body, this.bp);
	    while (nl(this.bp) > 2)
		rlc(this.bp);
	    this.stdi = false;
	}
	if (r == 2 || r == 1) {
	    ac(d.body, this.bs);
	    this.stdi = this.bi;
	}
	if (!r || r == 6) {
	    sd(fc(cn(this.bp, 1)), { w: 400 });
	    while (nl(this.bp) > 2)
		rlc(this.bp);
	}
	if (r == 2 || r == 4) {
	    sd(fc(cn(this.bp, 1)), { w: 0 });
	}
	// Run level
	for (i in this.cs) {
	    if (tpf(this.cs[i]))
		continue;
	    switch (r) {
	    case 2: if (i == 'X') continue;
	    case 4: this.load(this.cs[i]); break;
	    case 3:
	    case 5: if (this[i]) this[i].init(); break;
	    case 6:
	    case 0: if (this[i]) this.us.unshift(i); break;
	    }
	}
	// Check
	if (r != 1) this.check(r);
	return true;
    },

    /// Bug
    bug: function(m, f, l) {
	tce('phyp.bug');
	var fn = f.name(true);
	p.inc('failed ' + fn, 0, fn + ': ' + m + (l? ' (' + l + ')': ''));
	p.crashed = true;
	return true;
    },

    /// Increment progress bar
    inc: function(m, b, n) {
	tce('phyp.inc');
	sd(fc(cn(this.bp, 1)),
	   da(gd(fc(cn(this.bp, 1)), 2),
	      { w: 24 * b }));
	if (this.rl == 4 || this.rl == 5 ||
	    this.ol == 5) {
	    ih(fc(this.bp), m);
	    ac(this.bp, dom('p', { c: 'dbg' }, n || m));
	} else this.stdo(m, 'phyp');
	return true;
    },

    /// Core up!
    up: function() {
	tce('phyp.up');
	// Ready!
	dbg('i', 'phyp', PHYP_READY);
	if (this.rl == 5) {
	    rcp(this.bp);
	    this.apps.launch('X');
	} else {
	    this.stdi.value = '';
	    this.stdi.focus();
	    this.io.cat('~/.login');
	}
	return true;
    },

    /// Core down!
    down: function() {
	tce('phyp.down');
	// Ready!
	dbg('i', 'phyp', PHYP_READY);
	if (this.ol == 5) {
	    rcp(this.bp);
	    ac(d.body,
	       dom('div',
		   { id: 'bye',
		     c:  'loader' },
		   dom('p', __("bye"))));
	    setTimeout("rcp(gi('bye'))", 2000);
	} else this.stdi.value = '';
	this.rl = -1;
	return true;
    },

    /// Load
    load: function(js) {
	tce('phyp.load', js);
	if (this.ld[js])
	    return true;
	var base, src;
	this.ld[js] = true;
	base = boot.sign? 'jar:' + this.loc.dom + '/signed.jar!/': '/js/';
	src = base + js + '.js';
	ac(gt(d, 'head'),
	   dom('script',
	       { src:  src,
		 type: 'text/javascript' }));
	return true;
    },

    /// Check run level
    check: function(r, s) {
	tce('phyp.check', r);
	var chrs = [ '|', '/', '-', '\\' ];
	var i, k = true;
	if (!s) s = 0;
	for (i in p.cs) {
	    if (tpf(p.cs[i]))
		continue;
	    switch (r) {
	    case 2: if (i == 'X') continue;
	    case 4:
		if (p[i]) {
		    if (p.us.indexOf(i) == -1) {
			p.us.push(i);
			p.inc(__("modloaded", { i: i }), 1);
		    }
		} else {
		    if (!p.fs[i]) p.fs[i] = 0;
		    if (!(s % 50)) {
			// p.inc(__("modwaiting", { i: i }), 0);
			if (++p.fs[i] == 10) {
			    p.inc(__("modfailed", { i: i }), 0);
			    return dbg('e', 'phyp', "failed: " + i);
			}
		    }
		    k = false;
		}
		break;
	    case 3:
	    case 5:
		if (p[i] && p[i].read) {
		    if (p[i].ready) {
			if (p.us.indexOf(i) == -1) {
			    p.us.push(i);
			    p.inc(__("modready", { i: i }), 1);
			}
		    } else k = false;
		}
		break;
	    case 6:
	    case 0:
		if (p.us.indexOf(i) != 0)
		    continue;
		if (p[i].quit()) {
		    p.inc(__("modhalted", { i: i }), -1.5);
		    p.us.shift();
		    k = (p.us.length == 0);
		} else {
		    if (!p.fs[i]) p.fs[i] = 0;
		    if (!(s % 50)) {
			// p.inc(__("modhalting", { i: i }), 0);
			if (++p.fs[i] == 10) {
			    p.inc(__("modfailed", { i: i }), 0);
			    return dbg('e', 'phyp', "failed: " + i);
			}
		    }
		    k = false;
		}
		break;
	    }
	}
	if (k) {
	    switch (r) {
	    case 0: p.down(); break;
	    case 2: p.run(3); break;
	    case 3: p.up(); break;
	    case 4: p.run(5); break;
	    case 5: p.up(); break;
	    case 6: p.run(max(1, p.ol - 1)); break;
	    }
	    return true;
	}
	if (p.stdi && p.ol != 5 && r != 4 && r != 5)
	    p.stdi.value = chrs[s % 4];
	if (!p.crashed || p.loc.opts.force)
	    setTimeout('p.check(' + r + ', ' + (++s) + ')', 20);
	return false;
    }

}
