function curry(f) { var args = slice(arguments, 1); return function() { return f.apply(this, args.concat(slice(arguments))); }; }; function prog1(ret) { if (ret instanceof Function) ret = ret(); for (var i = 1, n = arguments.length; --n > 0; ++i) arguments[i](); return ret; }; function array_to_hash(a) { var ret = {}; for (var i = 0; i < a.length; ++i) ret[a[i]] = true; return ret; }; function slice(a, start) { return Array.prototype.slice.call(a, start || 0); }; function characters(str) { return str.split(""); }; function member(name, array) { for (var i = array.length; --i >= 0;) if (array[i] == name) return true; return false; }; function find_if(func, array) { for (var i = 0, n = array.length; i < n; ++i) { if (func(array[i])) return array[i]; } }; function HOP(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }; function repeat_string(str, i) { if (i <= 0) return ""; if (i == 1) return str; var d = repeat_string(str, i >> 1); d += d; if (i & 1) d += str; return d; }; function defaults(args, defs) { var ret = {}; if (args === true) args = {}; for (var i in defs) if (HOP(defs, i)) { ret[i] = (args && HOP(args, i)) ? args[i] : defs[i]; } return ret; }; function noop() {}; var MAP = (function(){ function MAP(a, f, o) { var ret = [], top = [], i; function doit() { var val = f.call(o, a[i], i); if (val instanceof AtTop) { val = val.v; if (val instanceof Splice) { top.push.apply(top, val.v); } else { top.push(val); } } else if (val !== skip) { if (val instanceof Splice) { ret.push.apply(ret, val.v); } else { ret.push(val); } } }; if (a instanceof Array) for (i = 0; i < a.length; ++i) doit(); else for (i in a) if (HOP(a, i)) doit(); return top.concat(ret); }; MAP.at_top = function(val) { return new AtTop(val) }; MAP.splice = function(val) { return new Splice(val) }; var skip = MAP.skip = {}; function AtTop(val) { this.v = val }; function Splice(val) { this.v = val }; return MAP; })(); // XXX: currently this is optimized for jQuery, though I have the // feeling it works well in general for many scripts (well, better // than alphabetical order). It would be nice if we could adapt it to // the currently running script. // var BASE54_DIGITS = "etnrisouaflchpdvmgybwESxTNCkLAOM_DPHBjFIqRUzWXV$JKQGYZ0516372984"; var BASE54_DIGITS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_0123456789"; function base54(num) { var ret = "", base = 54; do { ret += BASE54_DIGITS.charAt(num % base); num = Math.floor(num / base); base = 64; } while (num > 0); return ret; }; function push_uniq(array, el) { if (array.indexOf(el) < 0) array.push(el); }; function string_template(text, props) { return text.replace(/\{(.+?)\}/g, function(str, p){ return props[p]; }); };