    Ext.define('Ext.event.publisher.ComponentDelegation', {
        extend: 'Ext.event.publisher.Publisher',

        requires: [
            'Ext.Component',
            'Ext.ComponentQuery'
        ],

        targetType: 'component',

        optimizedSelectorRegex: /^#([\w\-]+)((?:[\s]*)>(?:[\s]*)|(?:\s*))([\w\-]+)$/i,

        handledEvents: ['*'],

        getSubscribers: function(eventName, createIfNotExist) {
            var subscribers = this.subscribers,
                eventSubscribers = subscribers[eventName];

            if (!eventSubscribers && createIfNotExist) {
                eventSubscribers = subscribers[eventName] = {
                    type: {
                        $length: 0
                    },
                    selector: [],
                    $length: 0
                }
            }

            return eventSubscribers;
        },

        subscribe: function(target, eventName) {
            // Ignore id-only selectors since they are already handled
            if (this.idSelectorRegex.test(target)) {
                return false;
            }

            var optimizedSelector = target.match(this.optimizedSelectorRegex),
                subscribers = this.getSubscribers(eventName, true),
                typeSubscribers = subscribers.type,
                selectorSubscribers = subscribers.selector,
                id, isDescendant, type, map, subMap;

            if (optimizedSelector !== null) {
                id = optimizedSelector[1];
                isDescendant = optimizedSelector[2].indexOf('>') === -1;
                type = optimizedSelector[3];

                map = typeSubscribers[type];

                if (!map) {
                    typeSubscribers[type] = map = {
                        descendents: {
                            $length: 0
                        },
                        children: {
                            $length: 0
                        },
                        $length: 0
                    }
                }

                subMap = isDescendant ? map.descendents : map.children;

                if (subMap.hasOwnProperty(id)) {
                    subMap[id]++;
                    return true;
                }

                subMap[id] = 1;
                subMap.$length++;
                map.$length++;
                typeSubscribers.$length++;
            }
            else {
                if (selectorSubscribers.hasOwnProperty(target)) {
                    selectorSubscribers[target]++;
                    return true;
                }

                selectorSubscribers[target] = 1;
                selectorSubscribers.push(target);
            }

            subscribers.$length++;

            return true;
        },

        unsubscribe: function(target, eventName, all) {
            var subscribers = this.getSubscribers(eventName);

            if (!subscribers) {
                return false;
            }

            var match = target.match(this.optimizedSelectorRegex),
                typeSubscribers = subscribers.type,
                selectorSubscribers = subscribers.selector,
                id, isDescendant, type, map, subMap;

            all = Boolean(all);

            if (match !== null) {
                id = match[1];
                isDescendant = match[2].indexOf('>') === -1;
                type = match[3];

                map = typeSubscribers[type];

                if (!map) {
                    return true;
                }

                subMap = isDescendant ? map.descendents : map.children;

                if (!subMap.hasOwnProperty(id) || (!all && --subMap[id] > 0)) {
                    return true;
                }

                delete subMap[id];
                subMap.$length--;
                map.$length--;
                typeSubscribers.$length--;
            }
            else {
                if (!selectorSubscribers.hasOwnProperty(target) || (!all && --selectorSubscribers[target] > 0)) {
                    return true;
                }

                delete selectorSubscribers[target];
                Ext.Array.remove(selectorSubscribers, target);
            }

            if (--subscribers.$length === 0) {
                delete this.subscribers[eventName];
            }

            return true;
        },

        notify: function(target, eventName) {
            var subscribers = this.getSubscribers(eventName),
                id, component;

            if (!subscribers || subscribers.$length === 0) {
                return false;
            }

            id = target.substr(1);
            component = Ext.ComponentManager.get(id);

            if (component && component.hasParent()) {
                this.dispatcher.doAddListener(this.targetType, target, eventName, 'publish', this, {
                    args: [eventName, component]
                }, 'before');
            }
        },

        matchesSelector: function(component, selector) {
            return Ext.ComponentQuery.is(component, selector);
        },

        dispatch: function(target, eventName, args, connectedController) {
            this.dispatcher.doDispatchEvent(this.targetType, target, eventName, args, null, connectedController);
        },

        publish: function(eventName, component) {
            var subscribers = this.getSubscribers(eventName);

            if (!subscribers) {
                return;
            }

            var eventController = arguments[arguments.length - 1],
                typeSubscribers = subscribers.type,
                selectorSubscribers = subscribers.selector,
                args = Array.prototype.slice.call(arguments, 2, -2),
                types = component.xtypesChain,
                descendentsSubscribers, childrenSubscribers,
                parentId, ancestorIds, ancestorId, parentComponent,
                selector,
                i, ln, type, j, subLn;

            for (i = 0, ln = types.length; i < ln; i++) {
                type = types[i];

                subscribers = typeSubscribers[type];

                if (subscribers && subscribers.$length > 0) {
                    descendentsSubscribers = subscribers.descendents;

                    if (descendentsSubscribers.$length > 0) {
                        if (!ancestorIds) {
                            ancestorIds = component.getAncestorIds();
                        }

                        for (j = 0, subLn = ancestorIds.length; j < subLn; j++) {
                            ancestorId = ancestorIds[j];

                            if (descendentsSubscribers.hasOwnProperty(ancestorId)) {
                                this.dispatch('#' + ancestorId + ' ' + type, eventName, args, eventController);
                            }

                        }
                    }

                    childrenSubscribers = subscribers.children;

                    if (childrenSubscribers.$length > 0) {
                        if (!parentId) {
                            if (ancestorIds) {
                                parentId = ancestorIds[0];
                            }
                            else {
                                parentComponent = component.getParent();
                                if (parentComponent) {
                                    parentId = parentComponent.getId();
                                }
                            }
                        }

                        if (parentId) {
                            if (childrenSubscribers.hasOwnProperty(parentId)) {
                                this.dispatch('#' + parentId + ' > ' + type, eventName, args, eventController);
                            }
                        }
                    }
                }
            }

            ln = selectorSubscribers.length;

            if (ln > 0) {
                for (i = 0; i < ln; i++) {
                    selector = selectorSubscribers[i];

                    if (this.matchesSelector(component, selector)) {
                        this.dispatch(selector, eventName, args, eventController);
                    }
                }
            }
        }
    });