/*

lib.js

by Caio Chassot (http://v2studio.com/k/code/)

parts by other authors, see commented version for details



version 0.5.75 

File generated on Fri Sep 24 00:35:55 E. South America Standard Time 2004



for documentation, see commented version.

get commented version at http://v2studio.com/k/code/lib/lib_c.js



Use freely. Credit is appreciated but not required.

*/

Array.prototype.indexOf = function(value, start, strict) {

    start = start || 0;

    for (var i=start; i<this.length; i++) {

        var item = this[i];

        if (strict            ? item === value   :

            isRegexp(value)   ? value.test(item) :

            isFunction(value) ? value(item)      :

            item == value)

            return i;

    }

    return -1;

}



Array.prototype.find = function(value, start, strict) {

    var i = this.indexOf(value, start, strict);

    if (i != -1) return this[i];

    return null

}



Array.prototype.contains = function(value,strict) {

    return this.indexOf(value,0,strict) !== -1;

}



Array.prototype.has     = Array.prototype.contains;



Array.prototype.include = Array.prototype.contains;



Array.prototype.count = function(value, strict) {

    var pos, start = 0, count = 0;

    while ((pos = this.indexOf(value, start, strict)) !== -1) {

        start = pos + 1;

        count++;

    }

    return count;

}



Array.prototype.remove = function(value,all,strict) {

    while (this.contains(value,strict)) {

        this.splice(this.indexOf(value,0,strict),1);

        if (!all) break

    }

    return this;

}



Array.prototype.merge = function() {

    var a = [];

    for (var i=0; i<arguments.length; i++)

        for (var j=0; j<arguments[i].length; j++)

            a.push(arguments[i][j]);

    for (var i=0; i<a.length; i++) this.push(a[i]);

    return this

}



Array.prototype.min = function() {

    if (!this.length) return;

    var n = this[0];

    for (var i=1; i<this.length; i++) if (n>this[i]) n=this[i];

    return n;

}



Array.prototype.max = function() {

    if (!this.length) return;

    var n = this[0];

    for (var i=1; i<this.length; i++) if (n<this[i]) n=this[i];

    return n;

}



Array.prototype.first = function() { return this[0] }



Array.prototype.last = function() { return this[this.length-1] }



Array.prototype.sjoin = function() { return this.join(' ') }



Array.prototype.njoin = function() { return this.join('\n') }



Array.prototype.cjoin = function() { return this.join(', ') }



Array.prototype.equals = function(a, strict){

    if (this==a) return true;

    if (a.length != this.length) return false;

    return this.map(function(item,idx){

        return strict? item === a[idx] : item == a[idx]

    }).all();

}



Array.prototype.all = function(fn) {

    return filter(this, fn).length == this.length;

}



Array.prototype.any = function(fn) {

    return filter(this, fn).length > 0;

}



Array.prototype.each = function(fn) { return each(this, fn) }



Array.prototype.map = function(fn) { return map(this, fn) }



Array.prototype.filter = function(fn) { return filter(this, fn) }



Array.prototype.select = Array.prototype.filter



Array.prototype.reduce = function() {

    var args = map(arguments);

    fn = args.pop();

    d  = args.pop();

    return reduce(this, d, fn); 

}



Array.prototype.inject = Array.prototype.reduce



Array.prototype.reject = function(fn) {

    if (typeof(fn)=='string') fn = __strfn('item,idx,list', fn);

    var self = this;

    var itemsToRemove = [];

    fn = fn || function(v) {return v};

    map(self, function(item,idx,list) { if (fn(item,idx,list)) itemsToRemove.push(idx) } );

    itemsToRemove.reverse().each(function(idx) { self.splice(idx,1) });

    return self;

}



function __strfn(args, fn) {

    function quote(s) { return '"' + s.replace(/"/g,'\\"') + '"' }

    if (!/\breturn\b/.test(fn)) {

        fn = fn.replace(/;\s*$/, '');

        fn = fn.insert(fn.lastIndexOf(';')+1, ' return ');

    }

    return eval('new Function('

        + map(args.split(/\s*,\s*/), quote).join()

        + ','

        + quote(fn)

        + ')'

        );

}



function each(list, fn) {

    if (typeof(fn)=='string') return each(list, __strfn('item,idx,list', fn));

    for (var i=0; i < list.length; i++) fn(list[i], i, list);

}



function map(list, fn) {

    if (typeof(fn)=='string') return map(list, __strfn('item,idx,list', fn));



    var result = [];

    fn = fn || function(v) {return v};

    for (var i=0; i < list.length; i++) result.push(fn(list[i], i, list));

    return result;

}



function combine() {

    var args   = map(arguments);

    var lists  = map(args.slice(0,-1),'map(item)');

    var fn     = args.last();

    var toplen = map(lists, "item.length").max();

    var vals   = [];



    if (!fn) fn = function(){return map(arguments)};

    if (typeof fn == 'string') {

        if (lists.length > 26) throw 'string functions can take at most 26 lists';

        var a = 'a'.charCodeAt(0);

        fn = __strfn(map(range(a, a+lists.length),'String.fromCharCode(item)').join(','), fn);

    }



    map(lists, function(li) {

        while (li.length < toplen) li.push(null);

        map(li, function(item,ix){

            if (ix < vals.length) vals[ix].push(item);

            else vals.push([item]);

        });

    });



    return map(vals, function(val) { return fn.apply(fn, val) });

}



function filter(list, fn) {

    if (typeof(fn)=='string') return filter(list, __strfn('item,idx,list', fn));



    var result = [];

    fn = fn || function(v) {return v};

    map(list, function(item,idx,list) { if (fn(item,idx,list)) result.push(item) } );

    return result;

}



function reduce(list, initial, fn) {

    if (undef(fn)) {

        fn      = initial;

        initial = window.undefined; 

    }

    if (typeof(fn)=='string') return reduce(list, initial, __strfn('a,b', fn));

    if (isdef(initial)) list.splice(0,0,initial);

    if (list.length===0) return false;

    if (list.length===1) return list[0];

    var result = list[0];

    var i = 1;

    while(i<list.length) result = fn(result,list[i++]);

    return result;

}



function isAlien(a)     { return isObject(a) && typeof a.constructor != 'function' }



function isArray(a)     { return isObject(a) && a.constructor == Array }



function isBoolean(a)   { return typeof a == 'boolean' }



function isFunction(a)  { return typeof a == 'function' }



function isNull(a)      { return typeof a == 'object' && !a }



function isNumber(a)    { return typeof a == 'number' && isFinite(a) }



function isObject(a)    { return (a && typeof a == 'object') || isFunction(a) }



function isRegexp(a)    { return a && a.constructor == RegExp }



function isString(a)    { return typeof a == 'string' }



function isUndefined(a) { return typeof a == 'undefined' }



function isEmpty(o)     {

    var i, v;

    if (isObject(o)) {

        for (i in o) {

            v = o[i];

            if (isUndefined(v) && isFunction(v)) {

                return false;

            }

        }

    }

    return true;

}



if (!Function.prototype.apply) Function.prototype.apply = function (o, a) {

    var r, x = '____apply';

    if (!isObject(o)) {

        o = {};

    }

    o[x] = this;

    switch ((a && a.length) || 0) {

    case 0:

        r = o[x]();

        break;

    case 1:

        r = o[x](a[0]);

        break;

    case 2:

        r = o[x](a[0], a[1]);

        break;

    case 3:

        r = o[x](a[0], a[1], a[2]);

        break;

    case 4:

        r = o[x](a[0], a[1], a[2], a[3]);

        break;

    case 5:

        r = o[x](a[0], a[1], a[2], a[3], a[4]);

        break;

    case 6:

        r = o[x](a[0], a[1], a[2], a[3], a[4], a[5]);

        break;

    default:

        alert('Too many arguments to apply.');

    }

    delete o[x];

    return r;

}



if (!Array.prototype.pop) Array.prototype.pop = function () {

    return this.splice(this.length - 1, 1)[0];

}



if (!Array.prototype.push) Array.prototype.push = function() {

    for (var i=0; i<arguments.length; i++) this[this.length] = arguments[i];

    return this.length;

}



if (!Array.prototype.shift) Array.prototype.shift = function () {

    return this.splice(0, 1)[0];

}



if (!Array.prototype.splice) Array.prototype.splice = function (s, d) {

    var max = Math.max,

        min = Math.min,

        a = [], 

        e,  

        i = max(arguments.length - 2, 0),   

        k = 0,

        l = this.length,

        n,  

        v,  

        x;  



    s = s || 0;

    if (s < 0) {

        s += l;

    }

    s = max(min(s, l), 0);  

    d = max(min(isNumber(d) ? d : l, l - s), 0);    

    v = i - d;

    n = l + v;

    while (k < d) {

        e = this[s + k];

        if (!isUndefined(e)) {

            a[k] = e;

        }

        k += 1;

    }

    x = l - s - d;

    if (v < 0) {

        k = s + i;

        while (x) {

            this[k] = this[k - v];

            k += 1;

            x -= 1;

        }

        this.length = n;

    } else if (v > 0) {

        k = 1;

        while (x) {

            this[n - k] = this[l - k];

            k += 1;

            x -= 1;

        }

    }

    for (k = 0; k < i; ++k) {

        this[s + k] = arguments[k + 2];

    }

    return a;

}



if (!Array.prototype.unshift) Array.prototype.unshift = function () {

    this.splice.apply(this,

        [0, 0].concat(Array.prototype.slice.apply(arguments)));

    return this.length;

}



if ( /^function\s*\(\s*\)\s*\{\s*\}$/.test('a'.replace(/a/,function(){})) ) {

    String.prototype.replace_ = String.prototype.replace;

    String.prototype.replace = function(rx, rf) { 

        if (isFunction(rf)) {

            var s = this,

                r,   

                rfv, 

                replaceList = [];

            while ((r=rx.exec(s))!==null) {

                rfv = rf.apply(rf, map(r).concat([r.index, s]));

                replaceList.push({ start: r.index, length: r[0].length, value: rfv });

                if (!rx.global) break;

            }

            for (var i=replaceList.length-1; i>=0; i--) {

                var rli = replaceList[i];

                s = s.splice(rli.start, rli.length, rli.value);

            }

            return s;

        } else return this.replace_(rx, rf);

    }

}



String.prototype.trimLeft = function() { return this.replace(/^\s+/,'') }



String.prototype.trimRight = function() { return this.replace(/\s+$/,'') }



String.prototype.trim = function() { return this.replace(/^\s+|\s+$/g,'') }



String.prototype.insert = function(idx,value) { return this.slice(0,idx) + value + this.slice(idx) }



String.prototype.strip = function(idx1,idx2) {

    if (arguments.length==1) idx2 = this.length;

    return this.slice(0,idx1) + this.slice(idx2);

}



String.prototype.splice = function(idx,count,value) { return this.strip(idx, idx+count).insert(idx, value) }



String.prototype.subArgs = function() { return this.subDict(map(arguments)) }



String.prototype.subDict = function(dict) {

    var

        parts = this.split('{'),

        r = parts[0],

        part, ci, k, v;

    for (var i = 1; i < parts.length; i++) {

        part = parts[i];

        ci   = part.indexOf('}');

        k    = part.substring(0,ci);

        v    = dict[k];

        r   += isdef(v) ? v + part.substring(ci+1) : '{' + part;

    }

    return r;

}



String.prototype.subn = function(d) {

    if (arguments.length > 1 || !isObject(arguments[0])) d = map(arguments);

    return this.subDict(d);

}



String.prototype.wrap = function(left,right) {

    if (undef(left)) throw 'S.wrap takes 1 argument (none given)';

    if (undef(right)) right = left;

    return left + this + right;

}



String.prototype.quote = function() { return this.wrap('"') }



String.prototype.squote = function() { return this.wrap("'") }



String.prototype.pad = function(side, len, chr) {

    if (undef(chr)) chr = ' ';

    var s = this;

    var left = side.toLowerCase()=='left';

    while (s.length<len) s = left? chr + s : s + chr;

    return s;

}



String.prototype.padLeft = function(len, chr) { return this.pad('left',len,chr) }



String.prototype.padRight = function(len, chr) { return this.pad('right',len,chr) }



String.prototype.zerofill = function(len) {

    var s = this;

    var ix = /^[+-]/.test(s) ? 1 : 0;

    while (s.length<len) s = s.insert(ix, '0');

    return s;

}



String.prototype.isEmpty = function(donttrim) { return !(donttrim? this : this.trim()).length }



function undef(v) { return  isUndefined(v) }



function isdef(v) { return !isUndefined(v) }



function cmp(a,b) { return a<b?-1:a==b?0:1 }



function list(s, sep) {

    if (!isString(sep) && !isRegexp(sep))

        sep = sep? ',' : /\s*,\s*/;

    return s.split(sep);

}



function range(start,stop,step) {

    if (isUndefined(stop)) return range(0,start,step);

    if (isUndefined(step)) step = 1;

    var ss = (step/Math.abs(step)); 

    var r = [];

    for (i=start; i*ss<stop*ss; i=i+step) r.push(i);

    return r;

}



function maprange(start, stop, fn) {

    if (arguments.length==2) return maprange(0, start, stop);

    if (arguments.length!=3) throw "maprange takes 2 or 3 arguments";

    return map(range(start,stop), fn);

}



function isList(o) { return o && isObject(o) && (isArray(o) || o.item) }



function isElement(o, strict) {

    return o && isObject(o) && ((!strict && (o==window || o==document)) || o.nodeType == 1)

}



function getElem(el) {

    var ge = (document.getElementById && function(id){return document.getElementById(id)} ) ||

             (document.all && function(id){return document.all[id]} ) ||

             function(){return null};

    return isElement(el)? el : isString(el) ? ge(el) : null;

}



function getElemList(el) {

    if      (isElement(el)) return [el];

    else if (isString(el) ) return getElemList(el.split(/\s+/g)); 

    else if (isList(el)   ) {

        var r = map(el, getElem);

        return filter(r, isElement).length==r.length? r : null;

    }

    else return null;

}



function filterElementNodes(nodeList, tagName) {

    return filter(nodeList, function(n){

        

        

        

        

        return n.nodeType==1 && n.nodeName!='!' && 

               (undef(tagName) || tagName == '*' || n.nodeName.toUpperCase()==tagName.toUpperCase())

    })

}



function getAll(tagName, parent) {

    parent = isdef(parent)? getElem(parent) : document;

    if (undef(tagName)) tagName = '*';

    var r = parent.getElementsByTagName(tagName);

    

    return r.length || tagName != '*'?  map(r) :

        reduce(filterElementNodes(parent.childNodes), [], function(l,c){

            return l.merge([c], getAll(tagName, c))

        })

}



function getElementsByClass(className, tagName, parentNode) {

    

    

    

    var noClassTags = list('#comment,BASE,BASEFONT,HEAD,HTML,META,PARAM,SCRIPT,STYLE,TITLE');

    return filter(getAll(tagName,parentNode),

        function(elem) {

            return !noClassTags.include(elem.nodeName) && hasClass(elem, className) 

        });

}



getElementsByClassName = getElementsByClass;



function hasClass(elem, className) {

    return getElem(elem).className.split(' ').count(className);

}



function remClass(elem, className, all) {

    elem = getElem(elem);

    elem.className = elem.className.split(' ').remove(className,all).join(' ');

}



function addClass(elem, className, allowDuplicates) {

    elem = getElem(elem);

    if (!allowDuplicates && elem.className.split(' ').contains(className)) return;

    elem.className += (elem.className.length?' ':'') + className;

}



function swapClass(e,c) {

    if (hasClass(e,c)) remClass(e,c); else addClass(e,c);

    return !!hasClass(e,c);

}



function condClass(e,c,cond) { (cond?addClass:remClass)(e,c) }



function insertBefore(newChild, refChild) {

    return refChild.parentNode.insertBefore(newChild, refChild);

}



function insertAfter(newChild, refChild) {

    if (refChild.nextSibling) insertBefore(newChild, refChild.nextSibling);

    else refChild.parentNode.appendChild(newChild);

    return newChild;

}



var ALLOW_LEGACY_EVENTS = true;



function getEventModel() {

    var d = document;

    return d.addEventListener? 'DOM' :

           d.attachEvent     ? 'IE'  :

                               'legacy';

}



function IE_Event(currentTarget) {

    this.currentTarget   = currentTarget;

    this.preventDefault  = function() { window.event.returnValue  = false }

    this.stopPropagation = function() { window.event.cancelBubble = true }

    this.target  = window.event.srcElement;

    var self = this;

    

    list('altKey,ctrlKey,shiftKey,clientX,clientY').map(function(p){ self[p] = event[p] });

    return this;

}



function Legacy_Event(currentTarget) {

    this.currentTarget   = currentTarget;

    return this;

}



function addEvent(els, ev, fn, capture) {

    if (!ALLOW_LEGACY_EVENTS && getEventModel()=='legacy') return false;

    if (undef(capture)) capture = true;

    function DOM_addEvent   (el, ev, fn, capture) { el.addEventListener(ev, fn, capture) }

    function legacy_addEvent(el, ev, fn) {

        var evn = 'on'+ev;

        if (!el[evn] || undef(el[evn].handlers)) {

            el[evn] = function() {

                map(el[evn].handlers, function(h){  h( new (el.attachEvent?IE_Event:Legacy_Event)(el) ) });

            }

            el[evn].handlers = [];

        }

        el[evn].handlers.push(fn);

    }

    var addEventFn = getEventModel()=='DOM'? DOM_addEvent : legacy_addEvent;

    map(getElemList(els), function(el) { addEventFn(el, ev, fn, capture) });

}



function remEvent(els, ev, fn, capture) {

    if (!ALLOW_LEGACY_EVENTS && getEventModel()=='legacy') return false;

    if (undef(capture)) capture = true;

    map(getElemList(els), function(el) {

        if(getEventModel()=='DOM') el.removeEventListener(ev, fn, capture);

        else el['on'+ev].handlers.remove(fn);

    });

}



function addEventDict(els, evDict, capture) {

    for (ev in evDict) addEvent(els, ev, evDict[ev], capture);

}



function addLoadEvent(fn) {

    

    var w = getEventModel()=="DOM" && !window.addEventListener ? document : window;

    return addEvent(w, 'load', fn, true)

}



