tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

Base.js (41910B)


      1 /***
      2 
      3 MochiKit.Base 1.4
      4 
      5 See <http://mochikit.com/> for documentation, downloads, license, etc.
      6 
      7 (c) 2005 Bob Ippolito.  All rights Reserved.
      8 
      9 ***/
     10 
     11 if (typeof(dojo) != 'undefined') {
     12    dojo.provide("MochiKit.Base");
     13 }
     14 if (typeof(MochiKit) == 'undefined') {
     15    MochiKit = {};
     16 }
     17 if (typeof(MochiKit.Base) == 'undefined') {
     18    MochiKit.Base = {};
     19 }
     20 if (typeof(MochiKit.__export__) == "undefined") {
     21    MochiKit.__export__ = (MochiKit.__compat__  ||
     22        (typeof(JSAN) == 'undefined' && typeof(dojo) == 'undefined')
     23    );
     24 }
     25 
     26 MochiKit.Base.VERSION = "1.4";
     27 MochiKit.Base.NAME = "MochiKit.Base";
     28 /** @id MochiKit.Base.update */
     29 MochiKit.Base.update = function (self, obj/*, ... */) {
     30    if (self === null) {
     31        self = {};
     32    }
     33    for (var i = 1; i < arguments.length; i++) {
     34        var o = arguments[i];
     35        if (typeof(o) != 'undefined' && o !== null) {
     36            for (var k in o) {
     37                self[k] = o[k];
     38            }
     39        }
     40    }
     41    return self;
     42 };
     43 
     44 MochiKit.Base.update(MochiKit.Base, {
     45    __repr__: function () {
     46        return "[" + this.NAME + " " + this.VERSION + "]";
     47    },
     48 
     49    toString: function () {
     50        return this.__repr__();
     51    },
     52 
     53    /** @id MochiKit.Base.camelize */
     54    camelize: function (selector) {
     55        /* from dojo.style.toCamelCase */
     56        var arr = selector.split('-');
     57        var cc = arr[0];
     58        for (var i = 1; i < arr.length; i++) {
     59            cc += arr[i].charAt(0).toUpperCase() + arr[i].substring(1);
     60        }
     61        return cc;
     62    },
     63 
     64    /** @id MochiKit.Base.counter */
     65    counter: function (n/* = 1 */) {
     66        if (arguments.length === 0) {
     67            n = 1;
     68        }
     69        return function () {
     70            return n++;
     71        };
     72    },
     73 
     74    /** @id MochiKit.Base.clone */
     75    clone: function (obj) {
     76        var me = arguments.callee;
     77        if (arguments.length == 1) {
     78            me.prototype = obj;
     79            return new me();
     80        }
     81    },
     82 
     83    _flattenArray: function (res, lst) {
     84        for (var i = 0; i < lst.length; i++) {
     85            var o = lst[i];
     86            if (o instanceof Array) {
     87                arguments.callee(res, o);
     88            } else {
     89                res.push(o);
     90            }
     91        }
     92        return res;
     93    },
     94 
     95    /** @id MochiKit.Base.flattenArray */
     96    flattenArray: function (lst) {
     97        return MochiKit.Base._flattenArray([], lst);
     98    },
     99 
    100    /** @id MochiKit.Base.flattenArguments */
    101    flattenArguments: function (lst/* ...*/) {
    102        var res = [];
    103        var m = MochiKit.Base;
    104        var args = m.extend(null, arguments);
    105        while (args.length) {
    106            var o = args.shift();
    107            if (o && typeof(o) == "object" && typeof(o.length) == "number") {
    108                for (var i = o.length - 1; i >= 0; i--) {
    109                    args.unshift(o[i]);
    110                }
    111            } else {
    112                res.push(o);
    113            }
    114        }
    115        return res;
    116    },
    117 
    118    /** @id MochiKit.Base.extend */
    119    extend: function (self, obj, /* optional */skip) {
    120        // Extend an array with an array-like object starting
    121        // from the skip index
    122        if (!skip) {
    123            skip = 0;
    124        }
    125        if (obj) {
    126            // allow iterable fall-through, but skip the full isArrayLike
    127            // check for speed, this is called often.
    128            var l = obj.length;
    129            if (typeof(l) != 'number' /* !isArrayLike(obj) */) {
    130                if (typeof(MochiKit.Iter) != "undefined") {
    131                    obj = MochiKit.Iter.list(obj);
    132                    l = obj.length;
    133                } else {
    134                    throw new TypeError("Argument not an array-like and MochiKit.Iter not present");
    135                }
    136            }
    137            if (!self) {
    138                self = [];
    139            }
    140            for (var i = skip; i < l; i++) {
    141                self.push(obj[i]);
    142            }
    143        }
    144        // This mutates, but it's convenient to return because
    145        // it's often used like a constructor when turning some
    146        // ghetto array-like to a real array
    147        return self;
    148    },
    149 
    150 
    151    /** @id MochiKit.Base.updatetree */
    152    updatetree: function (self, obj/*, ...*/) {
    153        if (self === null) {
    154            self = {};
    155        }
    156        for (var i = 1; i < arguments.length; i++) {
    157            var o = arguments[i];
    158            if (typeof(o) != 'undefined' && o !== null) {
    159                for (var k in o) {
    160                    var v = o[k];
    161                    if (typeof(self[k]) == 'object' && typeof(v) == 'object') {
    162                        arguments.callee(self[k], v);
    163                    } else {
    164                        self[k] = v;
    165                    }
    166                }
    167            }
    168        }
    169        return self;
    170    },
    171 
    172    /** @id MochiKit.Base.setdefault */
    173    setdefault: function (self, obj/*, ...*/) {
    174        if (self === null) {
    175            self = {};
    176        }
    177        for (var i = 1; i < arguments.length; i++) {
    178            var o = arguments[i];
    179            for (var k in o) {
    180                if (!(k in self)) {
    181                    self[k] = o[k];
    182                }
    183            }
    184        }
    185        return self;
    186    },
    187 
    188    /** @id MochiKit.Base.keys */
    189    keys: function (obj) {
    190        var rval = [];
    191        for (var prop in obj) {
    192            rval.push(prop);
    193        }
    194        return rval;
    195    },
    196 
    197    /** @id MochiKit.Base.values */
    198    values: function (obj) {
    199        var rval = [];
    200        for (var prop in obj) {
    201            rval.push(obj[prop]);
    202        }
    203        return rval;
    204    },
    205 
    206     /** @id MochiKit.Base.items */
    207    items: function (obj) {
    208        var rval = [];
    209        var e;
    210        for (var prop in obj) {
    211            var v;
    212            try {
    213                v = obj[prop];
    214            } catch (e) {
    215                continue;
    216            }
    217            rval.push([prop, v]);
    218        }
    219        return rval;
    220    },
    221 
    222 
    223    _newNamedError: function (module, name, func) {
    224        func.prototype = new MochiKit.Base.NamedError(module.NAME + "." + name);
    225        module[name] = func;
    226    },
    227 
    228 
    229    /** @id MochiKit.Base.operator */
    230    operator: {
    231        // unary logic operators
    232        /** @id MochiKit.Base.truth */
    233        truth: function (a) { return !!a; },
    234        /** @id MochiKit.Base.lognot */
    235        lognot: function (a) { return !a; },
    236        /** @id MochiKit.Base.identity */
    237        identity: function (a) { return a; },
    238 
    239        // bitwise unary operators
    240        /** @id MochiKit.Base.not */
    241        not: function (a) { return ~a; },
    242        /** @id MochiKit.Base.neg */
    243        neg: function (a) { return -a; },
    244 
    245        // binary operators
    246        /** @id MochiKit.Base.add */
    247        add: function (a, b) { return a + b; },
    248        /** @id MochiKit.Base.sub */
    249        sub: function (a, b) { return a - b; },
    250        /** @id MochiKit.Base.div */
    251        div: function (a, b) { return a / b; },
    252        /** @id MochiKit.Base.mod */
    253        mod: function (a, b) { return a % b; },
    254        /** @id MochiKit.Base.mul */
    255        mul: function (a, b) { return a * b; },
    256 
    257        // bitwise binary operators
    258        /** @id MochiKit.Base.and */
    259        and: function (a, b) { return a & b; },
    260        /** @id MochiKit.Base.or */
    261        or: function (a, b) { return a | b; },
    262        /** @id MochiKit.Base.xor */
    263        xor: function (a, b) { return a ^ b; },
    264        /** @id MochiKit.Base.lshift */
    265        lshift: function (a, b) { return a << b; },
    266        /** @id MochiKit.Base.rshift */
    267        rshift: function (a, b) { return a >> b; },
    268        /** @id MochiKit.Base.zrshift */
    269        zrshift: function (a, b) { return a >>> b; },
    270 
    271        // near-worthless built-in comparators
    272        /** @id MochiKit.Base.eq */
    273        eq: function (a, b) { return a == b; },
    274        /** @id MochiKit.Base.ne */
    275        ne: function (a, b) { return a != b; },
    276        /** @id MochiKit.Base.gt */
    277        gt: function (a, b) { return a > b; },
    278        /** @id MochiKit.Base.ge */
    279        ge: function (a, b) { return a >= b; },
    280        /** @id MochiKit.Base.lt */
    281        lt: function (a, b) { return a < b; },
    282        /** @id MochiKit.Base.le */
    283        le: function (a, b) { return a <= b; },
    284 
    285        // strict built-in comparators
    286        seq: function (a, b) { return a === b; },
    287        sne: function (a, b) { return a !== b; },
    288 
    289        // compare comparators
    290        /** @id MochiKit.Base.ceq */
    291        ceq: function (a, b) { return MochiKit.Base.compare(a, b) === 0; },
    292        /** @id MochiKit.Base.cne */
    293        cne: function (a, b) { return MochiKit.Base.compare(a, b) !== 0; },
    294        /** @id MochiKit.Base.cgt */
    295        cgt: function (a, b) { return MochiKit.Base.compare(a, b) == 1; },
    296        /** @id MochiKit.Base.cge */
    297        cge: function (a, b) { return MochiKit.Base.compare(a, b) != -1; },
    298        /** @id MochiKit.Base.clt */
    299        clt: function (a, b) { return MochiKit.Base.compare(a, b) == -1; },
    300        /** @id MochiKit.Base.cle */
    301        cle: function (a, b) { return MochiKit.Base.compare(a, b) != 1; },
    302 
    303        // binary logical operators
    304        /** @id MochiKit.Base.logand */
    305        logand: function (a, b) { return a && b; },
    306        /** @id MochiKit.Base.logor */
    307        logor: function (a, b) { return a || b; },
    308        /** @id MochiKit.Base.contains */
    309        contains: function (a, b) { return b in a; }
    310    },
    311 
    312    /** @id MochiKit.Base.forwardCall */
    313    forwardCall: function (func) {
    314        return function () {
    315            return this[func].apply(this, arguments);
    316        };
    317    },
    318 
    319    /** @id MochiKit.Base.itemgetter */
    320    itemgetter: function (func) {
    321        return function (arg) {
    322            return arg[func];
    323        };
    324    },
    325 
    326    /** @id MochiKit.Base.typeMatcher */
    327    typeMatcher: function (/* typ */) {
    328        var types = {};
    329        for (var i = 0; i < arguments.length; i++) {
    330            var typ = arguments[i];
    331            types[typ] = typ;
    332        }
    333        return function () {
    334            for (var i = 0; i < arguments.length; i++) {
    335                if (!(typeof(arguments[i]) in types)) {
    336                    return false;
    337                }
    338            }
    339            return true;
    340        };
    341    },
    342 
    343    /** @id MochiKit.Base.isNull */
    344    isNull: function (/* ... */) {
    345        for (var i = 0; i < arguments.length; i++) {
    346            if (arguments[i] !== null) {
    347                return false;
    348            }
    349        }
    350        return true;
    351    },
    352 
    353    /** @id MochiKit.Base.isUndefinedOrNull */
    354    isUndefinedOrNull: function (/* ... */) {
    355        for (var i = 0; i < arguments.length; i++) {
    356            var o = arguments[i];
    357            if (!(typeof(o) == 'undefined' || o === null)) {
    358                return false;
    359            }
    360        }
    361        return true;
    362    },
    363 
    364    /** @id MochiKit.Base.isEmpty */
    365    isEmpty: function (obj) {
    366        return !MochiKit.Base.isNotEmpty.apply(this, arguments);
    367    },
    368 
    369    /** @id MochiKit.Base.isNotEmpty */
    370    isNotEmpty: function (obj) {
    371        for (var i = 0; i < arguments.length; i++) {
    372            var o = arguments[i];
    373            if (!(o && o.length)) {
    374                return false;
    375            }
    376        }
    377        return true;
    378    },
    379 
    380    /** @id MochiKit.Base.isArrayLike */
    381    isArrayLike: function () {
    382        for (var i = 0; i < arguments.length; i++) {
    383            var o = arguments[i];
    384            var typ = typeof(o);
    385            if (
    386                (typ != 'object' && !(typ == 'function' && typeof(o.item) == 'function')) ||
    387                o === null ||
    388                typeof(o.length) != 'number' ||
    389                o.nodeType === 3
    390            ) {
    391                return false;
    392            }
    393        }
    394        return true;
    395    },
    396 
    397    /** @id MochiKit.Base.isDateLike */
    398    isDateLike: function () {
    399        for (var i = 0; i < arguments.length; i++) {
    400            var o = arguments[i];
    401            if (typeof(o) != "object" || o === null
    402                    || typeof(o.getTime) != 'function') {
    403                return false;
    404            }
    405        }
    406        return true;
    407    },
    408 
    409 
    410    /** @id MochiKit.Base.xmap */
    411    xmap: function (fn/*, obj... */) {
    412        if (fn === null) {
    413            return MochiKit.Base.extend(null, arguments, 1);
    414        }
    415        var rval = [];
    416        for (var i = 1; i < arguments.length; i++) {
    417            rval.push(fn(arguments[i]));
    418        }
    419        return rval;
    420    },
    421 
    422    /** @id MochiKit.Base.map */
    423    map: function (fn, lst/*, lst... */) {
    424        var m = MochiKit.Base;
    425        var itr = MochiKit.Iter;
    426        var isArrayLike = m.isArrayLike;
    427        if (arguments.length <= 2) {
    428            // allow an iterable to be passed
    429            if (!isArrayLike(lst)) {
    430                if (itr) {
    431                    // fast path for map(null, iterable)
    432                    lst = itr.list(lst);
    433                    if (fn === null) {
    434                        return lst;
    435                    }
    436                } else {
    437                    throw new TypeError("Argument not an array-like and MochiKit.Iter not present");
    438                }
    439            }
    440            // fast path for map(null, lst)
    441            if (fn === null) {
    442                return m.extend(null, lst);
    443            }
    444            // disabled fast path for map(fn, lst)
    445            /*
    446            if (false && typeof(Array.prototype.map) == 'function') {
    447                // Mozilla fast-path
    448                return Array.prototype.map.call(lst, fn);
    449            }
    450            */
    451            var rval = [];
    452            for (var i = 0; i < lst.length; i++) {
    453                rval.push(fn(lst[i]));
    454            }
    455            return rval;
    456        } else {
    457            // default for map(null, ...) is zip(...)
    458            if (fn === null) {
    459                fn = Array;
    460            }
    461            var length = null;
    462            for (i = 1; i < arguments.length; i++) {
    463                // allow iterables to be passed
    464                if (!isArrayLike(arguments[i])) {
    465                    if (itr) {
    466                        return itr.list(itr.imap.apply(null, arguments));
    467                    } else {
    468                        throw new TypeError("Argument not an array-like and MochiKit.Iter not present");
    469                    }
    470                }
    471                // find the minimum length
    472                var l = arguments[i].length;
    473                if (length === null || length > l) {
    474                    length = l;
    475                }
    476            }
    477            rval = [];
    478            for (i = 0; i < length; i++) {
    479                var args = [];
    480                for (var j = 1; j < arguments.length; j++) {
    481                    args.push(arguments[j][i]);
    482                }
    483                rval.push(fn.apply(this, args));
    484            }
    485            return rval;
    486        }
    487    },
    488 
    489    /** @id MochiKit.Base.xfilter */
    490    xfilter: function (fn/*, obj... */) {
    491        var rval = [];
    492        if (fn === null) {
    493            fn = MochiKit.Base.operator.truth;
    494        }
    495        for (var i = 1; i < arguments.length; i++) {
    496            var o = arguments[i];
    497            if (fn(o)) {
    498                rval.push(o);
    499            }
    500        }
    501        return rval;
    502    },
    503 
    504    /** @id MochiKit.Base.filter */
    505    filter: function (fn, lst, self) {
    506        var rval = [];
    507        // allow an iterable to be passed
    508        var m = MochiKit.Base;
    509        if (!m.isArrayLike(lst)) {
    510            if (MochiKit.Iter) {
    511                lst = MochiKit.Iter.list(lst);
    512            } else {
    513                throw new TypeError("Argument not an array-like and MochiKit.Iter not present");
    514            }
    515        }
    516        if (fn === null) {
    517            fn = m.operator.truth;
    518        }
    519        if (typeof(Array.prototype.filter) == 'function') {
    520            // Mozilla fast-path
    521            return Array.prototype.filter.call(lst, fn, self);
    522        } else if (typeof(self) == 'undefined' || self === null) {
    523            for (var i = 0; i < lst.length; i++) {
    524                var o = lst[i];
    525                if (fn(o)) {
    526                    rval.push(o);
    527                }
    528            }
    529        } else {
    530            for (i = 0; i < lst.length; i++) {
    531                o = lst[i];
    532                if (fn.call(self, o)) {
    533                    rval.push(o);
    534                }
    535            }
    536        }
    537        return rval;
    538    },
    539 
    540 
    541    _wrapDumbFunction: function (func) {
    542        return function () {
    543            // fast path!
    544            switch (arguments.length) {
    545                case 0: return func();
    546                case 1: return func(arguments[0]);
    547                case 2: return func(arguments[0], arguments[1]);
    548                case 3: return func(arguments[0], arguments[1], arguments[2]);
    549            }
    550            var args = [];
    551            for (var i = 0; i < arguments.length; i++) {
    552                args.push("arguments[" + i + "]");
    553            }
    554            return eval("(func(" + args.join(",") + "))");
    555        };
    556    },
    557 
    558    /** @id MochiKit.Base.methodcaller */
    559    methodcaller: function (func/*, args... */) {
    560        var args = MochiKit.Base.extend(null, arguments, 1);
    561        if (typeof(func) == "function") {
    562            return function (obj) {
    563                return func.apply(obj, args);
    564            };
    565        } else {
    566            return function (obj) {
    567                return obj[func].apply(obj, args);
    568            };
    569        }
    570    },
    571 
    572    /** @id MochiKit.Base.method */
    573    method: function (self, func) {
    574        var m = MochiKit.Base;
    575        return m.bind.apply(this, m.extend([func, self], arguments, 2));
    576    },
    577 
    578    /** @id MochiKit.Base.compose */
    579    compose: function (f1, f2/*, f3, ... fN */) {
    580        var fnlist = [];
    581        var m = MochiKit.Base;
    582        if (arguments.length === 0) {
    583            throw new TypeError("compose() requires at least one argument");
    584        }
    585        for (var i = 0; i < arguments.length; i++) {
    586            var fn = arguments[i];
    587            if (typeof(fn) != "function") {
    588                throw new TypeError(m.repr(fn) + " is not a function");
    589            }
    590            fnlist.push(fn);
    591        }
    592        return function () {
    593            var args = arguments;
    594            for (var i = fnlist.length - 1; i >= 0; i--) {
    595                args = [fnlist[i].apply(this, args)];
    596            }
    597            return args[0];
    598        };
    599    },
    600 
    601    /** @id MochiKit.Base.bind */
    602    bind: function (func, self/* args... */) {
    603        if (typeof(func) == "string") {
    604            func = self[func];
    605        }
    606        var im_func = func.im_func;
    607        var im_preargs = func.im_preargs;
    608        var im_self = func.im_self;
    609        var m = MochiKit.Base;
    610        if (typeof(func) == "function" && typeof(func.apply) == "undefined") {
    611            // this is for cases where JavaScript sucks ass and gives you a
    612            // really dumb built-in function like alert() that doesn't have
    613            // an apply
    614            func = m._wrapDumbFunction(func);
    615        }
    616        if (typeof(im_func) != 'function') {
    617            im_func = func;
    618        }
    619        if (typeof(self) != 'undefined') {
    620            im_self = self;
    621        }
    622        if (typeof(im_preargs) == 'undefined') {
    623            im_preargs = [];
    624        } else  {
    625            im_preargs = im_preargs.slice();
    626        }
    627        m.extend(im_preargs, arguments, 2);
    628        var newfunc = function () {
    629            var args = arguments;
    630            var me = arguments.callee;
    631            if (me.im_preargs.length > 0) {
    632                args = m.concat(me.im_preargs, args);
    633            }
    634            var self = me.im_self;
    635            if (!self) {
    636                self = this;
    637            }
    638            return me.im_func.apply(self, args);
    639        };
    640        newfunc.im_self = im_self;
    641        newfunc.im_func = im_func;
    642        newfunc.im_preargs = im_preargs;
    643        return newfunc;
    644    },
    645 
    646    /** @id MochiKit.Base.bindMethods */
    647    bindMethods: function (self) {
    648        var bind = MochiKit.Base.bind;
    649        for (var k in self) {
    650            var func = self[k];
    651            if (typeof(func) == 'function') {
    652                self[k] = bind(func, self);
    653            }
    654        }
    655    },
    656 
    657    /** @id MochiKit.Base.registerComparator */
    658    registerComparator: function (name, check, comparator, /* optional */ override) {
    659        MochiKit.Base.comparatorRegistry.register(name, check, comparator, override);
    660    },
    661 
    662    _primitives: {'boolean': true, 'string': true, 'number': true},
    663 
    664    /** @id MochiKit.Base.compare */
    665    compare: function (a, b) {
    666        if (a == b) {
    667            return 0;
    668        }
    669        var aIsNull = (typeof(a) == 'undefined' || a === null);
    670        var bIsNull = (typeof(b) == 'undefined' || b === null);
    671        if (aIsNull && bIsNull) {
    672            return 0;
    673        } else if (aIsNull) {
    674            return -1;
    675        } else if (bIsNull) {
    676            return 1;
    677        }
    678        var m = MochiKit.Base;
    679        // bool, number, string have meaningful comparisons
    680        var prim = m._primitives;
    681        if (!(typeof(a) in prim && typeof(b) in prim)) {
    682            try {
    683                return m.comparatorRegistry.match(a, b);
    684            } catch (e) {
    685                if (e != m.NotFound) {
    686                    throw e;
    687                }
    688            }
    689        }
    690        if (a < b) {
    691            return -1;
    692        } else if (a > b) {
    693            return 1;
    694        }
    695        // These types can't be compared
    696        var repr = m.repr;
    697        throw new TypeError(repr(a) + " and " + repr(b) + " can not be compared");
    698    },
    699 
    700    /** @id MochiKit.Base.compareDateLike */
    701    compareDateLike: function (a, b) {
    702        return MochiKit.Base.compare(a.getTime(), b.getTime());
    703    },
    704 
    705    /** @id MochiKit.Base.compareArrayLike */
    706    compareArrayLike: function (a, b) {
    707        var compare = MochiKit.Base.compare;
    708        var count = a.length;
    709        var rval = 0;
    710        if (count > b.length) {
    711            rval = 1;
    712            count = b.length;
    713        } else if (count < b.length) {
    714            rval = -1;
    715        }
    716        for (var i = 0; i < count; i++) {
    717            var cmp = compare(a[i], b[i]);
    718            if (cmp) {
    719                return cmp;
    720            }
    721        }
    722        return rval;
    723    },
    724 
    725    /** @id MochiKit.Base.registerRepr */
    726    registerRepr: function (name, check, wrap, /* optional */override) {
    727        MochiKit.Base.reprRegistry.register(name, check, wrap, override);
    728    },
    729 
    730    /** @id MochiKit.Base.repr */
    731    repr: function (o) {
    732        if (typeof(o) == "undefined") {
    733            return "undefined";
    734        } else if (o === null) {
    735            return "null";
    736        }
    737        try {
    738            if (typeof(o.__repr__) == 'function') {
    739                return o.__repr__();
    740            } else if (typeof(o.repr) == 'function' && o.repr != arguments.callee) {
    741                return o.repr();
    742            }
    743            return MochiKit.Base.reprRegistry.match(o);
    744        } catch (e) {
    745            if (typeof(o.NAME) == 'string' && (
    746                    o.toString == Function.prototype.toString ||
    747                    o.toString == Object.prototype.toString
    748                )) {
    749                return o.NAME;
    750            }
    751        }
    752        try {
    753            var ostring = (o + "");
    754        } catch (e) {
    755            return "[" + typeof(o) + "]";
    756        }
    757        if (typeof(o) == "function") {
    758            o = ostring.replace(/^\s+/, "");
    759            var idx = o.indexOf("{");
    760            if (idx != -1) {
    761                o = o.substr(0, idx) + "{...}";
    762            }
    763        }
    764        return ostring;
    765    },
    766 
    767    /** @id MochiKit.Base.reprArrayLike */
    768    reprArrayLike: function (o) {
    769        var m = MochiKit.Base;
    770        return "[" + m.map(m.repr, o).join(", ") + "]";
    771    },
    772 
    773    /** @id MochiKit.Base.reprString */
    774    reprString: function (o) {
    775        return ('"' + o.replace(/(["\\])/g, '\\$1') + '"'
    776            ).replace(/[\f]/g, "\\f"
    777            ).replace(/[\b]/g, "\\b"
    778            ).replace(/[\n]/g, "\\n"
    779            ).replace(/[\t]/g, "\\t"
    780            ).replace(/[\r]/g, "\\r");
    781    },
    782 
    783    /** @id MochiKit.Base.reprNumber */
    784    reprNumber: function (o) {
    785        return o + "";
    786    },
    787 
    788    /** @id MochiKit.Base.registerJSON */
    789    registerJSON: function (name, check, wrap, /* optional */override) {
    790        MochiKit.Base.jsonRegistry.register(name, check, wrap, override);
    791    },
    792 
    793 
    794    /** @id MochiKit.Base.evalJSON */
    795    evalJSON: function () {
    796        return eval("(" + MochiKit.Base._filterJSON(arguments[0]) + ")");
    797    },
    798 
    799    _filterJSON: function (s) {
    800        var m = s.match(/^\s*\/\*(.*)\*\/\s*$/);
    801        if (m) {
    802            return m[1];
    803        }
    804        return s;
    805    },
    806 
    807    /** @id MochiKit.Base.serializeJSON */
    808    serializeJSON: function (o) {
    809        var objtype = typeof(o);
    810        if (objtype == "number" || objtype == "boolean") {
    811            return o + "";
    812        } else if (o === null) {
    813            return "null";
    814        }
    815        var m = MochiKit.Base;
    816        var reprString = m.reprString;
    817        if (objtype == "string") {
    818            return reprString(o);
    819        }
    820        // recurse
    821        var me = arguments.callee;
    822        // short-circuit for objects that support "json" serialization
    823        // if they return "self" then just pass-through...
    824        var newObj;
    825        if (typeof(o.__json__) == "function") {
    826            newObj = o.__json__();
    827            if (o !== newObj) {
    828                return me(newObj);
    829            }
    830        }
    831        if (typeof(o.json) == "function") {
    832            newObj = o.json();
    833            if (o !== newObj) {
    834                return me(newObj);
    835            }
    836        }
    837        // array
    838        if (objtype != "function" && typeof(o.length) == "number") {
    839            var res = [];
    840            for (var i = 0; i < o.length; i++) {
    841                var val = me(o[i]);
    842                if (typeof(val) != "string") {
    843                    val = "undefined";
    844                }
    845                res.push(val);
    846            }
    847            return "[" + res.join(", ") + "]";
    848        }
    849        // look in the registry
    850        try {
    851            newObj = m.jsonRegistry.match(o);
    852            if (o !== newObj) {
    853                return me(newObj);
    854            }
    855        } catch (e) {
    856            if (e != m.NotFound) {
    857                // something really bad happened
    858                throw e;
    859            }
    860        }
    861        // undefined is outside of the spec
    862        if (objtype == "undefined") {
    863            throw new TypeError("undefined can not be serialized as JSON");
    864        }
    865        // it's a function with no adapter, bad
    866        if (objtype == "function") {
    867            return null;
    868        }
    869        // generic object code path
    870        res = [];
    871        for (var k in o) {
    872            var useKey;
    873            if (typeof(k) == "number") {
    874                useKey = '"' + k + '"';
    875            } else if (typeof(k) == "string") {
    876                useKey = reprString(k);
    877            } else {
    878                // skip non-string or number keys
    879                continue;
    880            }
    881            val = me(o[k]);
    882            if (typeof(val) != "string") {
    883                // skip non-serializable values
    884                continue;
    885            }
    886            res.push(useKey + ":" + val);
    887        }
    888        return "{" + res.join(", ") + "}";
    889    },
    890 
    891 
    892    /** @id MochiKit.Base.objEqual */
    893    objEqual: function (a, b) {
    894        return (MochiKit.Base.compare(a, b) === 0);
    895    },
    896 
    897    /** @id MochiKit.Base.arrayEqual */
    898    arrayEqual: function (self, arr) {
    899        if (self.length != arr.length) {
    900            return false;
    901        }
    902        return (MochiKit.Base.compare(self, arr) === 0);
    903    },
    904 
    905    /** @id MochiKit.Base.concat */
    906    concat: function (/* lst... */) {
    907        var rval = [];
    908        var extend = MochiKit.Base.extend;
    909        for (var i = 0; i < arguments.length; i++) {
    910            extend(rval, arguments[i]);
    911        }
    912        return rval;
    913    },
    914 
    915    /** @id MochiKit.Base.keyComparator */
    916    keyComparator: function (key/* ... */) {
    917        // fast-path for single key comparisons
    918        var m = MochiKit.Base;
    919        var compare = m.compare;
    920        if (arguments.length == 1) {
    921            return function (a, b) {
    922                return compare(a[key], b[key]);
    923            };
    924        }
    925        var compareKeys = m.extend(null, arguments);
    926        return function (a, b) {
    927            var rval = 0;
    928            // keep comparing until something is inequal or we run out of
    929            // keys to compare
    930            for (var i = 0; (rval === 0) && (i < compareKeys.length); i++) {
    931                var key = compareKeys[i];
    932                rval = compare(a[key], b[key]);
    933            }
    934            return rval;
    935        };
    936    },
    937 
    938    /** @id MochiKit.Base.reverseKeyComparator */
    939    reverseKeyComparator: function (key) {
    940        var comparator = MochiKit.Base.keyComparator.apply(this, arguments);
    941        return function (a, b) {
    942            return comparator(b, a);
    943        };
    944    },
    945 
    946    /** @id MochiKit.Base.partial */
    947    partial: function (func) {
    948        var m = MochiKit.Base;
    949        return m.bind.apply(this, m.extend([func, undefined], arguments, 1));
    950    },
    951 
    952    /** @id MochiKit.Base.listMinMax */
    953    listMinMax: function (which, lst) {
    954        if (lst.length === 0) {
    955            return null;
    956        }
    957        var cur = lst[0];
    958        var compare = MochiKit.Base.compare;
    959        for (var i = 1; i < lst.length; i++) {
    960            var o = lst[i];
    961            if (compare(o, cur) == which) {
    962                cur = o;
    963            }
    964        }
    965        return cur;
    966    },
    967 
    968    /** @id MochiKit.Base.objMax */
    969    objMax: function (/* obj... */) {
    970        return MochiKit.Base.listMinMax(1, arguments);
    971    },
    972 
    973    /** @id MochiKit.Base.objMin */
    974    objMin: function (/* obj... */) {
    975        return MochiKit.Base.listMinMax(-1, arguments);
    976    },
    977 
    978    /** @id MochiKit.Base.findIdentical */
    979    findIdentical: function (lst, value, start/* = 0 */, /* optional */end) {
    980        if (typeof(end) == "undefined" || end === null) {
    981            end = lst.length;
    982        }
    983        if (typeof(start) == "undefined" || start === null) {
    984            start = 0;
    985        }
    986        for (var i = start; i < end; i++) {
    987            if (lst[i] === value) {
    988                return i;
    989            }
    990        }
    991        return -1;
    992    },
    993 
    994    /** @id MochiKit.Base.mean */
    995    mean: function(/* lst... */) {
    996        /* http://www.nist.gov/dads/HTML/mean.html */
    997        var sum = 0;
    998 
    999        var m = MochiKit.Base;
   1000        var args = m.extend(null, arguments);
   1001        var count = args.length;
   1002 
   1003        while (args.length) {
   1004            var o = args.shift();
   1005            if (o && typeof(o) == "object" && typeof(o.length) == "number") {
   1006                count += o.length - 1;
   1007                for (var i = o.length - 1; i >= 0; i--) {
   1008                    sum += o[i];
   1009                }
   1010            } else {
   1011                sum += o;
   1012            }
   1013        }
   1014 
   1015        if (count <= 0) {
   1016            throw new TypeError('mean() requires at least one argument');
   1017        }
   1018 
   1019        return sum/count;
   1020    },
   1021 
   1022    /** @id MochiKit.Base.median */
   1023    median: function(/* lst... */) {
   1024        /* http://www.nist.gov/dads/HTML/median.html */
   1025        var data = MochiKit.Base.flattenArguments(arguments);
   1026        if (data.length === 0) {
   1027            throw new TypeError('median() requires at least one argument');
   1028        }
   1029        data.sort(compare);
   1030        if (data.length % 2 == 0) {
   1031            var upper = data.length / 2;
   1032            return (data[upper] + data[upper - 1]) / 2;
   1033        } else {
   1034            return data[(data.length - 1) / 2];
   1035        }
   1036    },
   1037 
   1038    /** @id MochiKit.Base.findValue */
   1039    findValue: function (lst, value, start/* = 0 */, /* optional */end) {
   1040        if (typeof(end) == "undefined" || end === null) {
   1041            end = lst.length;
   1042        }
   1043        if (typeof(start) == "undefined" || start === null) {
   1044            start = 0;
   1045        }
   1046        var cmp = MochiKit.Base.compare;
   1047        for (var i = start; i < end; i++) {
   1048            if (cmp(lst[i], value) === 0) {
   1049                return i;
   1050            }
   1051        }
   1052        return -1;
   1053    },
   1054 
   1055    /** @id MochiKit.Base.nodeWalk */
   1056    nodeWalk: function (node, visitor) {
   1057        var nodes = [node];
   1058        var extend = MochiKit.Base.extend;
   1059        while (nodes.length) {
   1060            var res = visitor(nodes.shift());
   1061            if (res) {
   1062                extend(nodes, res);
   1063            }
   1064        }
   1065    },
   1066 
   1067 
   1068    /** @id MochiKit.Base.nameFunctions */
   1069    nameFunctions: function (namespace) {
   1070        var base = namespace.NAME;
   1071        if (typeof(base) == 'undefined') {
   1072            base = '';
   1073        } else {
   1074            base = base + '.';
   1075        }
   1076        for (var name in namespace) {
   1077            var o = namespace[name];
   1078            if (typeof(o) == 'function' && typeof(o.NAME) == 'undefined') {
   1079                try {
   1080                    o.NAME = base + name;
   1081                } catch (e) {
   1082                    // pass
   1083                }
   1084            }
   1085        }
   1086    },
   1087 
   1088 
   1089    /** @id MochiKit.Base.queryString */
   1090    queryString: function (names, values) {
   1091        // check to see if names is a string or a DOM element, and if
   1092        // MochiKit.DOM is available.  If so, drop it like it's a form
   1093        // Ugliest conditional in MochiKit?  Probably!
   1094        if (typeof(MochiKit.DOM) != "undefined" && arguments.length == 1
   1095            && (typeof(names) == "string" || (
   1096                typeof(names.nodeType) != "undefined" && names.nodeType > 0
   1097            ))
   1098        ) {
   1099            var kv = MochiKit.DOM.formContents(names);
   1100            names = kv[0];
   1101            values = kv[1];
   1102        } else if (arguments.length == 1) {
   1103            // Allow the return value of formContents to be passed directly
   1104            if (typeof(names.length) == "number" && names.length == 2) {
   1105                return arguments.callee(names[0], names[1]);
   1106            }
   1107            var o = names;
   1108            names = [];
   1109            values = [];
   1110            for (var k in o) {
   1111                var v = o[k];
   1112                if (typeof(v) == "function") {
   1113                    continue;
   1114                } else if (typeof(v) != "string" &&
   1115                        typeof(v.length) == "number") {
   1116                    for (var i = 0; i < v.length; i++) {
   1117                        names.push(k);
   1118                        values.push(v[i]);
   1119                    }
   1120                } else {
   1121                    names.push(k);
   1122                    values.push(v);
   1123                }
   1124            }
   1125        }
   1126        var rval = [];
   1127        var len = Math.min(names.length, values.length);
   1128        var urlEncode = MochiKit.Base.urlEncode;
   1129        for (var i = 0; i < len; i++) {
   1130            v = values[i];
   1131            if (typeof(v) != 'undefined' && v !== null) {
   1132                rval.push(urlEncode(names[i]) + "=" + urlEncode(v));
   1133            }
   1134        }
   1135        return rval.join("&");
   1136    },
   1137 
   1138 
   1139    /** @id MochiKit.Base.parseQueryString */
   1140    parseQueryString: function (encodedString, useArrays) {
   1141        // strip a leading '?' from the encoded string
   1142        var qstr = (encodedString.charAt(0) == "?")
   1143            ? encodedString.substring(1)
   1144            : encodedString;
   1145        var pairs = qstr.replace(/\+/g, "%20").split(/(\&amp\;|\&\#38\;|\&#x26;|\&)/);
   1146        var o = {};
   1147        var decode;
   1148        if (typeof(decodeURIComponent) != "undefined") {
   1149            decode = decodeURIComponent;
   1150        } else {
   1151            decode = unescape;
   1152        }
   1153        if (useArrays) {
   1154            for (var i = 0; i < pairs.length; i++) {
   1155                var pair = pairs[i].split("=");
   1156                var name = decode(pair.shift());
   1157                if (!name) {
   1158                    continue;
   1159                }
   1160                var arr = o[name];
   1161                if (!(arr instanceof Array)) {
   1162                    arr = [];
   1163                    o[name] = arr;
   1164                }
   1165                arr.push(decode(pair.join("=")));
   1166            }
   1167        } else {
   1168            for (i = 0; i < pairs.length; i++) {
   1169                pair = pairs[i].split("=");
   1170                var name = pair.shift();
   1171                if (!name) {
   1172                    continue;
   1173                }
   1174                o[decode(name)] = decode(pair.join("="));
   1175            }
   1176        }
   1177        return o;
   1178    }
   1179 });
   1180 
   1181 /** @id MochiKit.Base.AdapterRegistry */
   1182 MochiKit.Base.AdapterRegistry = function () {
   1183    this.pairs = [];
   1184 };
   1185 
   1186 MochiKit.Base.AdapterRegistry.prototype = {
   1187    /** @id MochiKit.Base.AdapterRegistry.prototype.register */
   1188    register: function (name, check, wrap, /* optional */ override) {
   1189        if (override) {
   1190            this.pairs.unshift([name, check, wrap]);
   1191        } else {
   1192            this.pairs.push([name, check, wrap]);
   1193        }
   1194    },
   1195 
   1196    /** @id MochiKit.Base.AdapterRegistry.prototype.match */
   1197    match: function (/* ... */) {
   1198        for (var i = 0; i < this.pairs.length; i++) {
   1199            var pair = this.pairs[i];
   1200            if (pair[1].apply(this, arguments)) {
   1201                return pair[2].apply(this, arguments);
   1202            }
   1203        }
   1204        throw MochiKit.Base.NotFound;
   1205    },
   1206 
   1207    /** @id MochiKit.Base.AdapterRegistry.prototype.unregister */
   1208    unregister: function (name) {
   1209        for (var i = 0; i < this.pairs.length; i++) {
   1210            var pair = this.pairs[i];
   1211            if (pair[0] == name) {
   1212                this.pairs.splice(i, 1);
   1213                return true;
   1214            }
   1215        }
   1216        return false;
   1217    }
   1218 };
   1219 
   1220 
   1221 MochiKit.Base.EXPORT = [
   1222    "flattenArray",
   1223    "noop",
   1224    "camelize",
   1225    "counter",
   1226    "clone",
   1227    "extend",
   1228    "update",
   1229    "updatetree",
   1230    "setdefault",
   1231    "keys",
   1232    "values",
   1233    "items",
   1234    "NamedError",
   1235    "operator",
   1236    "forwardCall",
   1237    "itemgetter",
   1238    "typeMatcher",
   1239    "isCallable",
   1240    "isUndefined",
   1241    "isUndefinedOrNull",
   1242    "isNull",
   1243    "isEmpty",
   1244    "isNotEmpty",
   1245    "isArrayLike",
   1246    "isDateLike",
   1247    "xmap",
   1248    "map",
   1249    "xfilter",
   1250    "filter",
   1251    "methodcaller",
   1252    "compose",
   1253    "bind",
   1254    "bindMethods",
   1255    "NotFound",
   1256    "AdapterRegistry",
   1257    "registerComparator",
   1258    "compare",
   1259    "registerRepr",
   1260    "repr",
   1261    "objEqual",
   1262    "arrayEqual",
   1263    "concat",
   1264    "keyComparator",
   1265    "reverseKeyComparator",
   1266    "partial",
   1267    "merge",
   1268    "listMinMax",
   1269    "listMax",
   1270    "listMin",
   1271    "objMax",
   1272    "objMin",
   1273    "nodeWalk",
   1274    "zip",
   1275    "urlEncode",
   1276    "queryString",
   1277    "serializeJSON",
   1278    "registerJSON",
   1279    "evalJSON",
   1280    "parseQueryString",
   1281    "findValue",
   1282    "findIdentical",
   1283    "flattenArguments",
   1284    "method",
   1285    "average",
   1286    "mean",
   1287    "median"
   1288 ];
   1289 
   1290 MochiKit.Base.EXPORT_OK = [
   1291    "nameFunctions",
   1292    "comparatorRegistry",
   1293    "reprRegistry",
   1294    "jsonRegistry",
   1295    "compareDateLike",
   1296    "compareArrayLike",
   1297    "reprArrayLike",
   1298    "reprString",
   1299    "reprNumber"
   1300 ];
   1301 
   1302 MochiKit.Base._exportSymbols = function (globals, module) {
   1303    if (!MochiKit.__export__) {
   1304        return;
   1305    }
   1306    var all = module.EXPORT_TAGS[":all"];
   1307    for (var i = 0; i < all.length; i++) {
   1308        globals[all[i]] = module[all[i]];
   1309    }
   1310 };
   1311 
   1312 MochiKit.Base.__new__ = function () {
   1313    // A singleton raised when no suitable adapter is found
   1314    var m = this;
   1315 
   1316    // convenience
   1317    /** @id MochiKit.Base.noop */
   1318    m.noop = m.operator.identity;
   1319 
   1320    // Backwards compat
   1321    m.forward = m.forwardCall;
   1322    m.find = m.findValue;
   1323 
   1324    if (typeof(encodeURIComponent) != "undefined") {
   1325        /** @id MochiKit.Base.urlEncode */
   1326        m.urlEncode = function (unencoded) {
   1327            return encodeURIComponent(unencoded).replace(/\'/g, '%27');
   1328        };
   1329    } else {
   1330        m.urlEncode = function (unencoded) {
   1331            return escape(unencoded
   1332                ).replace(/\+/g, '%2B'
   1333                ).replace(/\"/g,'%22'
   1334                ).rval.replace(/\'/g, '%27');
   1335        };
   1336    }
   1337 
   1338    /** @id MochiKit.Base.NamedError */
   1339    m.NamedError = function (name) {
   1340        this.message = name;
   1341        this.name = name;
   1342    };
   1343    m.NamedError.prototype = new Error();
   1344    m.update(m.NamedError.prototype, {
   1345        repr: function () {
   1346            if (this.message && this.message != this.name) {
   1347                return this.name + "(" + m.repr(this.message) + ")";
   1348            } else {
   1349                return this.name + "()";
   1350            }
   1351        },
   1352        toString: m.forwardCall("repr")
   1353    });
   1354 
   1355    /** @id MochiKit.Base.NotFound */
   1356    m.NotFound = new m.NamedError("MochiKit.Base.NotFound");
   1357 
   1358 
   1359    /** @id MochiKit.Base.listMax */
   1360    m.listMax = m.partial(m.listMinMax, 1);
   1361    /** @id MochiKit.Base.listMin */
   1362    m.listMin = m.partial(m.listMinMax, -1);
   1363 
   1364    /** @id MochiKit.Base.isCallable */
   1365    m.isCallable = m.typeMatcher('function');
   1366    /** @id MochiKit.Base.isUndefined */
   1367    m.isUndefined = m.typeMatcher('undefined');
   1368 
   1369    /** @id MochiKit.Base.merge */
   1370    m.merge = m.partial(m.update, null);
   1371    /** @id MochiKit.Base.zip */
   1372    m.zip = m.partial(m.map, null);
   1373 
   1374    /** @id MochiKit.Base.average */
   1375    m.average = m.mean;
   1376 
   1377    /** @id MochiKit.Base.comparatorRegistry */
   1378    m.comparatorRegistry = new m.AdapterRegistry();
   1379    m.registerComparator("dateLike", m.isDateLike, m.compareDateLike);
   1380    m.registerComparator("arrayLike", m.isArrayLike, m.compareArrayLike);
   1381 
   1382    /** @id MochiKit.Base.reprRegistry */
   1383    m.reprRegistry = new m.AdapterRegistry();
   1384    m.registerRepr("arrayLike", m.isArrayLike, m.reprArrayLike);
   1385    m.registerRepr("string", m.typeMatcher("string"), m.reprString);
   1386    m.registerRepr("numbers", m.typeMatcher("number", "boolean"), m.reprNumber);
   1387 
   1388    /** @id MochiKit.Base.jsonRegistry */
   1389    m.jsonRegistry = new m.AdapterRegistry();
   1390 
   1391    var all = m.concat(m.EXPORT, m.EXPORT_OK);
   1392    m.EXPORT_TAGS = {
   1393        ":common": m.concat(m.EXPORT_OK),
   1394        ":all": all
   1395    };
   1396 
   1397    m.nameFunctions(this);
   1398 
   1399 };
   1400 
   1401 MochiKit.Base.__new__();
   1402 
   1403 //
   1404 // XXX: Internet Explorer blows
   1405 //
   1406 if (MochiKit.__export__) {
   1407    compare = MochiKit.Base.compare;
   1408    compose = MochiKit.Base.compose;
   1409    serializeJSON = MochiKit.Base.serializeJSON;
   1410 }
   1411 
   1412 MochiKit.Base._exportSymbols(this, MochiKit.Base);