(function () {

    Object.beget = function (o, membs) {
        var F = function () {},
            self;
        F.prototype = o;
        self = new F();
        return membs? Object.augment(self, membs): self;
    };

    Object.augment = function (obj, membs, override) {
        var m;
        for (m in membs) {
            obj[m] = override !== false && !obj[m]? membs[m]: obj[m];
        }
        return obj;
    };

    Array.queue = function (arr, context) {
        var args = Array.prototype.slice.call(arguments, 2, arguments.length),
            a,
            cur;
        for (a in arr) {
            cur = arr[a];
            if (typeof cur === 'function') {
                cur.apply(context, args);
            }
        }
    };

    Function.listen = function (object, methodName, listener) {
        var listeners = typeof listener === 'function'? [listener]:[],
            method = object[methodName],
            enabled = true;

        object[methodName] = function () {
            var ret = method.apply(object, Array.coerce(arguments));
            if (enabled) {
                Array.queue(listeners, object, ret);
            }
            return ret;
        };

        Object.augment(object[methodName], {
            getMethod: function () {
                return method;
            },
            releaseListeners: function () {
                object[methodName] = method;
            },
            disableListeners: function () {
                enabled = false;
            },
            enableListeners: function () {
                enabled = true;
            },
            addListener: function (listener) {
                if (typeof listener === 'function') {
                    listeners.push(listener);
                }
                return this;
            },
            removeListener: function () {
                var l;
                for (l in listeners) {
                    if (listener === listeners[l]) {
                        delete listeners[l];
                    }
                }
            }
        });
    };

    Array.each = function (arr, func) {
        var i,
            func = typeof arr === 'function'? arr: func,
            arr = typeof arr === 'function'? this: arr,
            results = [];
        for (i = 0; i < arr.length; i++) {
            results[i] = func.call(arr[i],i) || null;
        }
        return results;
    };

    Array.slice = function (arr, from, to) {
        return Array.prototype.slice.call(arr, from || 0, to || arr.length);
    };

    Array.coerce = function (arrayLikeObj) {
        return Array.slice(arrayLikeObj);
    };

    Object.toElement = function () {
        var handlers = {
                css: function (obj) {
                    $(this).css(obj);
                    return this;
                },
                attr: function (obj) {
                    $(this).attr(obj);
                    return this;
                },
                events: function (obj) {
                    var e;
                    for (e in obj) {
                        $(this).bind(e, obj[e]);
                    }
                    return this;
                },
                data: function (obj) {
                    var d;
                    for (d in obj) {
                        $(this).data(d, obj[d]);
                    }
                    return this;
                },
                text: function (str) {
                    $(this).text(str);
                },
                children: function (child) {
                    var c, i, curChild;
                    for (c in child) {
                        curChild = child[c];
                        for (i = 0; i < (curChild.count || 1); i++) {
                            this.appendChild(Object.toElement(curChild));
                        }
                    }
                    return this;
                }
            };
        return function (obj) {
            var self = null,
                h,
                temp = document.getElementById('_toElement_temp') || function () {
                    var el = document.createElement('div');
                    $(el).css({
                        position: 'absolute',
                        left: '-9999px'
                    }).attr('id','_toElement_temp').appendTo('body');
                    return el;
                }();
            if (typeof obj.tag === 'string') {
                self = document.createElement(obj.tag);
            } else if (obj.template) {
                self = obj.template;
            } else {
                return null;
            }

            $(temp).append(self);

            if (obj.before) {
                obj.before.call(self, obj);
            }
            for (h in handlers) {
                if (obj[h]) {
                    handlers[h].call(self, obj[h]);
                }
            }
            if (obj.callback) {
                obj.callback.call(self);
            }
            return self;

        };
    }();

    window.Prolific = {
        module: function (name, constr) {
            this[name] = constr.call(this) || {};
            this[name].module = this.module;
            return this;
        }
    };

})();
