function delegate(type, fn, el, filter) {
    var args     = toArray(arguments, 0, true),
        query    = isString(el) ? el : null,
        typeBits, synth, container, categories, cat, i, len, handles, handle;

    // Support Y.delegate({ click: fnA, key: fnB }, context, filter, ...);
    // and Y.delegate(['click', 'key'], fn, context, filter, ...);
    if (isObject(type)) {
        handles = [];

        if (isArray(type)) {
            for (i = 0, len = type.length; i < len; ++i) {
                args[0] = type[i];
                handles.push(Y.delegate.apply(Y, args));
            }
        } else {
            // Y.delegate({'click', fn}, context, filter) =>
            // Y.delegate('click', fn, context, filter)
            args.unshift(null); // one arg becomes two; need to make space

            for (i in type) {
                if (type.hasOwnProperty(i)) {
                    args[0] = i;
                    args[1] = type[i];
                    handles.push(Y.delegate.apply(Y, args));
                }
            }
        }

        return new Y.EventHandle(handles);
    }

    typeBits = type.split(/\|/);

    if (typeBits.length > 1) {
        cat  = typeBits.shift();
        type = typeBits.shift();
    }

    synth = Y.Node.DOM_EVENTS[type];

    if (isObject(synth) && synth.delegate) {
        handle = synth.delegate.apply(synth, arguments);
    }

    if (!handle) {
        if (!type || !fn || !el || !filter) {
            Y.log("delegate requires type, callback, parent, & filter", "warn");
            return;
        }

        container = (query) ? Y.Selector.query(query, null, true) : el;

        if (!container && isString(el)) {
            handle = Y.on('available', function () {
                Y.mix(handle, Y.delegate.apply(Y, args), true);
            }, el);
        }

        if (!handle && container) {
            args.splice(2, 2, container); // remove the filter

            handle = Y.Event._attach(args, { facade: false });
            handle.sub.filter  = filter;
            handle.sub._notify = delegate.notifySub;
        }
    }

    if (handle && cat) {
        categories = detachCategories[cat]  || (detachCategories[cat] = {});
        categories = categories[type] || (categories[type] = []);
        categories.push(handle);
    }

    return handle;
}
<p>Sets up event delegation on a container element.  The delegated event
will use a supplied selector or filtering function to test if the event
references at least one node that should trigger the subscription
callback.</p>

<p>Selector string filters will trigger the callback if the event originated
from a node that matches it or is contained in a node that matches it.
Function filters are called for each Node up the parent axis to the
subscribing container node, and receive at each level the Node and the event
object.  The function should return true (or a truthy value) if that Node
should trigger the subscription callback.  Note, it is possible for filters
to match multiple Nodes for a single event.  In this case, the delegate
callback will be executed for each matching Node.</p>

<p>For each matching Node, the callback will be executed with its 'this'
object set to the Node matched by the filter (unless a specific context was
provided during subscription), and the provided event's
<code>currentTarget</code> will also be set to the matching Node.  The
containing Node from which the subscription was originally made can be
referenced as <code>e.container</code>.

@method delegate
@param type {String} the event type to delegate
@param fn {Function} the callback function to execute.  This function
             will be provided the event object for the delegated event.
@param el {String|node} the element that is the delegation container
@param spec {string|Function} a selector that must match the target of the
             event or a function to test target and its parents for a match
@param context optional argument that specifies what 'this' refers to.
@param args* 0..n additional arguments to pass on to the callback function.
             These arguments will be added after the event object.
@return {EventHandle} the detach handle
@for YUI