Show:
                            
                            /**
                             * Custom event engine, DOM event listener abstraction layer, synthetic DOM
                             * events.
                             * @module event-custom
                             * @submodule event-custom-base
                             */
                            
                            
                            // var onsubscribeType = "_event:onsub",
                            var YArray = Y.Array,
                            
                                AFTER = 'after',
                                CONFIGS = [
                                    'broadcast',
                                    'monitored',
                                    'bubbles',
                                    'context',
                                    'contextFn',
                                    'currentTarget',
                                    'defaultFn',
                                    'defaultTargetOnly',
                                    'details',
                                    'emitFacade',
                                    'fireOnce',
                                    'async',
                                    'host',
                                    'preventable',
                                    'preventedFn',
                                    'queuable',
                                    'silent',
                                    'stoppedFn',
                                    'target',
                                    'type'
                                ],
                            
                                CONFIGS_HASH = YArray.hash(CONFIGS),
                            
                                nativeSlice = Array.prototype.slice,
                            
                                YUI3_SIGNATURE = 9,
                                YUI_LOG = 'yui:log',
                            
                                mixConfigs = function(r, s, ov) {
                                    var p;
                            
                                    for (p in s) {
                                        if (CONFIGS_HASH[p] && (ov || !(p in r))) {
                                            r[p] = s[p];
                                        }
                                    }
                            
                                    return r;
                                };
                            
                            /**
                             * The CustomEvent class lets you define events for your application
                             * that can be subscribed to by one or more independent component.
                             *
                             * @param {String} type The type of event, which is passed to the callback
                             * when the event fires.
                             * @param {object} defaults configuration object.
                             * @class CustomEvent
                             * @constructor
                             */
                            
                             /**
                             * The type of event, returned to subscribers when the event fires
                             * @property type
                             * @type string
                             */
                            
                            /**
                             * By default all custom events are logged in the debug build, set silent
                             * to true to disable debug outpu for this event.
                             * @property silent
                             * @type boolean
                             */
                            
                            Y.CustomEvent = function(type, defaults) {
                            
                                this._kds = Y.CustomEvent.keepDeprecatedSubs;
                            
                                this.id = Y.guid();
                            
                                this.type = type;
                                this.silent = this.logSystem = (type === YUI_LOG);
                            
                                if (this._kds) {
                                    /**
                                     * The subscribers to this event
                                     * @property subscribers
                                     * @type Subscriber {}
                                     * @deprecated
                                     */
                            
                                    /**
                                     * 'After' subscribers
                                     * @property afters
                                     * @type Subscriber {}
                                     * @deprecated
                                     */
                                    this.subscribers = {};
                                    this.afters = {};
                                }
                            
                                if (defaults) {
                                    mixConfigs(this, defaults, true);
                                }
                            };
                            
                            /**
                             * Static flag to enable population of the <a href="#property_subscribers">`subscribers`</a>
                             * and  <a href="#property_subscribers">`afters`</a> properties held on a `CustomEvent` instance.
                             *
                             * These properties were changed to private properties (`_subscribers` and `_afters`), and
                             * converted from objects to arrays for performance reasons.
                             *
                             * Setting this property to true will populate the deprecated `subscribers` and `afters`
                             * properties for people who may be using them (which is expected to be rare). There will
                             * be a performance hit, compared to the new array based implementation.
                             *
                             * If you are using these deprecated properties for a use case which the public API
                             * does not support, please file an enhancement request, and we can provide an alternate
                             * public implementation which doesn't have the performance cost required to maintiain the
                             * properties as objects.
                             *
                             * @property keepDeprecatedSubs
                             * @static
                             * @for CustomEvent
                             * @type boolean
                             * @default false
                             * @deprecated
                             */
                            Y.CustomEvent.keepDeprecatedSubs = false;
                            
                            Y.CustomEvent.mixConfigs = mixConfigs;
                            
                            Y.CustomEvent.prototype = {
                            
                                constructor: Y.CustomEvent,
                            
                                /**
                                 * Monitor when an event is attached or detached.
                                 *
                                 * @property monitored
                                 * @type boolean
                                 */
                            
                                /**
                                 * If 0, this event does not broadcast.  If 1, the YUI instance is notified
                                 * every time this event fires.  If 2, the YUI instance and the YUI global
                                 * (if event is enabled on the global) are notified every time this event
                                 * fires.
                                 * @property broadcast
                                 * @type int
                                 */
                            
                                /**
                                 * Specifies whether this event should be queued when the host is actively
                                 * processing an event.  This will effect exectution order of the callbacks
                                 * for the various events.
                                 * @property queuable
                                 * @type boolean
                                 * @default false
                                 */
                            
                                /**
                                 * This event has fired if true
                                 *
                                 * @property fired
                                 * @type boolean
                                 * @default false;
                                 */
                            
                                /**
                                 * An array containing the arguments the custom event
                                 * was last fired with.
                                 * @property firedWith
                                 * @type Array
                                 */
                            
                                /**
                                 * This event should only fire one time if true, and if
                                 * it has fired, any new subscribers should be notified
                                 * immediately.
                                 *
                                 * @property fireOnce
                                 * @type boolean
                                 * @default false;
                                 */
                            
                                /**
                                 * fireOnce listeners will fire syncronously unless async
                                 * is set to true
                                 * @property async
                                 * @type boolean
                                 * @default false
                                 */
                            
                                /**
                                 * Flag for stopPropagation that is modified during fire()
                                 * 1 means to stop propagation to bubble targets.  2 means
                                 * to also stop additional subscribers on this target.
                                 * @property stopped
                                 * @type int
                                 */
                            
                                /**
                                 * Flag for preventDefault that is modified during fire().
                                 * if it is not 0, the default behavior for this event
                                 * @property prevented
                                 * @type int
                                 */
                            
                                /**
                                 * Specifies the host for this custom event.  This is used
                                 * to enable event bubbling
                                 * @property host
                                 * @type EventTarget
                                 */
                            
                                /**
                                 * The default function to execute after event listeners
                                 * have fire, but only if the default action was not
                                 * prevented.
                                 * @property defaultFn
                                 * @type Function
                                 */
                            
                                /**
                                 * Flag for the default function to execute only if the
                                 * firing event is the current target. This happens only
                                 * when using custom event delegation and setting the
                                 * flag to `true` mimics the behavior of event delegation
                                 * in the DOM.
                                 *
                                 * @property defaultTargetOnly
                                 * @type Boolean
                                 * @default false
                                 */
                            
                                /**
                                 * The function to execute if a subscriber calls
                                 * stopPropagation or stopImmediatePropagation
                                 * @property stoppedFn
                                 * @type Function
                                 */
                            
                                /**
                                 * The function to execute if a subscriber calls
                                 * preventDefault
                                 * @property preventedFn
                                 * @type Function
                                 */
                            
                                /**
                                 * The subscribers to this event
                                 * @property _subscribers
                                 * @type Subscriber []
                                 * @private
                                 */
                            
                                /**
                                 * 'After' subscribers
                                 * @property _afters
                                 * @type Subscriber []
                                 * @private
                                 */
                            
                                /**
                                 * If set to true, the custom event will deliver an EventFacade object
                                 * that is similar to a DOM event object.
                                 * @property emitFacade
                                 * @type boolean
                                 * @default false
                                 */
                            
                                /**
                                 * Supports multiple options for listener signatures in order to
                                 * port YUI 2 apps.
                                 * @property signature
                                 * @type int
                                 * @default 9
                                 */
                                signature : YUI3_SIGNATURE,
                            
                                /**
                                 * The context the the event will fire from by default.  Defaults to the YUI
                                 * instance.
                                 * @property context
                                 * @type object
                                 */
                                context : Y,
                            
                                /**
                                 * Specifies whether or not this event's default function
                                 * can be cancelled by a subscriber by executing preventDefault()
                                 * on the event facade
                                 * @property preventable
                                 * @type boolean
                                 * @default true
                                 */
                                preventable : true,
                            
                                /**
                                 * Specifies whether or not a subscriber can stop the event propagation
                                 * via stopPropagation(), stopImmediatePropagation(), or halt()
                                 *
                                 * Events can only bubble if emitFacade is true.
                                 *
                                 * @property bubbles
                                 * @type boolean
                                 * @default true
                                 */
                                bubbles : true,
                            
                                /**
                                 * Returns the number of subscribers for this event as the sum of the on()
                                 * subscribers and after() subscribers.
                                 *
                                 * @method hasSubs
                                 * @return Number
                                 */
                                hasSubs: function(when) {
                                    var s = 0,
                                        a = 0,
                                        subs = this._subscribers,
                                        afters = this._afters,
                                        sib = this.sibling;
                            
                                    if (subs) {
                                        s = subs.length;
                                    }
                            
                                    if (afters) {
                                        a = afters.length;
                                    }
                            
                                    if (sib) {
                                        subs = sib._subscribers;
                                        afters = sib._afters;
                            
                                        if (subs) {
                                            s += subs.length;
                                        }
                            
                                        if (afters) {
                                            a += afters.length;
                                        }
                                    }
                            
                                    if (when) {
                                        return (when === 'after') ? a : s;
                                    }
                            
                                    return (s + a);
                                },
                            
                                /**
                                 * Monitor the event state for the subscribed event.  The first parameter
                                 * is what should be monitored, the rest are the normal parameters when
                                 * subscribing to an event.
                                 * @method monitor
                                 * @param what {string} what to monitor ('detach', 'attach', 'publish').
                                 * @return {EventHandle} return value from the monitor event subscription.
                                 */
                                monitor: function(what) {
                                    this.monitored = true;
                                    var type = this.id + '|' + this.type + '_' + what,
                                        args = nativeSlice.call(arguments, 0);
                                    args[0] = type;
                                    return this.host.on.apply(this.host, args);
                                },
                            
                                /**
                                 * Get all of the subscribers to this event and any sibling event
                                 * @method getSubs
                                 * @return {Array} first item is the on subscribers, second the after.
                                 */
                                getSubs: function() {
                            
                                    var sibling = this.sibling,
                                        subs = this._subscribers,
                                        afters = this._afters,
                                        siblingSubs,
                                        siblingAfters;
                            
                                    if (sibling) {
                                        siblingSubs = sibling._subscribers;
                                        siblingAfters = sibling._afters;
                                    }
                            
                                    if (siblingSubs) {
                                        if (subs) {
                                            subs = subs.concat(siblingSubs);
                                        } else {
                                            subs = siblingSubs.concat();
                                        }
                                    } else {
                                        if (subs) {
                                            subs = subs.concat();
                                        } else {
                                            subs = [];
                                        }
                                    }
                            
                                    if (siblingAfters) {
                                        if (afters) {
                                            afters = afters.concat(siblingAfters);
                                        } else {
                                            afters = siblingAfters.concat();
                                        }
                                    } else {
                                        if (afters) {
                                            afters = afters.concat();
                                        } else {
                                            afters = [];
                                        }
                                    }
                            
                                    return [subs, afters];
                                },
                            
                                /**
                                 * Apply configuration properties.  Only applies the CONFIG whitelist
                                 * @method applyConfig
                                 * @param o hash of properties to apply.
                                 * @param force {boolean} if true, properties that exist on the event
                                 * will be overwritten.
                                 */
                                applyConfig: function(o, force) {
                                    mixConfigs(this, o, force);
                                },
                            
                                /**
                                 * Create the Subscription for subscribing function, context, and bound
                                 * arguments.  If this is a fireOnce event, the subscriber is immediately
                                 * notified.
                                 *
                                 * @method _on
                                 * @param fn {Function} Subscription callback
                                 * @param [context] {Object} Override `this` in the callback
                                 * @param [args] {Array} bound arguments that will be passed to the callback after the arguments generated by fire()
                                 * @param [when] {String} "after" to slot into after subscribers
                                 * @return {EventHandle}
                                 * @protected
                                 */
                                _on: function(fn, context, args, when) {
                            
                                    if (!fn) { this.log('Invalid callback for CE: ' + this.type); }
                            
                                    var s = new Y.Subscriber(fn, context, args, when),
                                        firedWith;
                            
                                    if (this.fireOnce && this.fired) {
                            
                                        firedWith = this.firedWith;
                            
                                        // It's a little ugly for this to know about facades,
                                        // but given the current breakup, not much choice without
                                        // moving a whole lot of stuff around.
                                        if (this.emitFacade && this._addFacadeToArgs) {
                                            this._addFacadeToArgs(firedWith);
                                        }
                            
                                        if (this.async) {
                                            setTimeout(Y.bind(this._notify, this, s, firedWith), 0);
                                        } else {
                                            this._notify(s, firedWith);
                                        }
                                    }
                            
                                    if (when === AFTER) {
                                        if (!this._afters) {
                                            this._afters = [];
                                        }
                                        this._afters.push(s);
                                    } else {
                                        if (!this._subscribers) {
                                            this._subscribers = [];
                                        }
                                        this._subscribers.push(s);
                                    }
                            
                                    if (this._kds) {
                                        if (when === AFTER) {
                                            this.afters[s.id] = s;
                                        } else {
                                            this.subscribers[s.id] = s;
                                        }
                                    }
                            
                                    return new Y.EventHandle(this, s);
                                },
                            
                                /**
                                 * Listen for this event
                                 * @method subscribe
                                 * @param {Function} fn The function to execute.
                                 * @return {EventHandle} Unsubscribe handle.
                                 * @deprecated use on.
                                 */
                                subscribe: function(fn, context) {
                                    Y.log('ce.subscribe deprecated, use "on"', 'warn', 'deprecated');
                                    var a = (arguments.length > 2) ? nativeSlice.call(arguments, 2) : null;
                                    return this._on(fn, context, a, true);
                                },
                            
                                /**
                                 * Listen for this event
                                 * @method on
                                 * @param {Function} fn The function to execute.
                                 * @param {object} context optional execution context.
                                 * @param {mixed} arg* 0..n additional arguments to supply to the subscriber
                                 * when the event fires.
                                 * @return {EventHandle} An object with a detach method to detch the handler(s).
                                 */
                                on: function(fn, context) {
                                    var a = (arguments.length > 2) ? nativeSlice.call(arguments, 2) : null;
                            
                                    if (this.monitored && this.host) {
                                        this.host._monitor('attach', this, {
                                            args: arguments
                                        });
                                    }
                                    return this._on(fn, context, a, true);
                                },
                            
                                /**
                                 * Listen for this event after the normal subscribers have been notified and
                                 * the default behavior has been applied.  If a normal subscriber prevents the
                                 * default behavior, it also prevents after listeners from firing.
                                 * @method after
                                 * @param {Function} fn The function to execute.
                                 * @param {object} context optional execution context.
                                 * @param {mixed} arg* 0..n additional arguments to supply to the subscriber
                                 * when the event fires.
                                 * @return {EventHandle} handle Unsubscribe handle.
                                 */
                                after: function(fn, context) {
                                    var a = (arguments.length > 2) ? nativeSlice.call(arguments, 2) : null;
                                    return this._on(fn, context, a, AFTER);
                                },
                            
                                /**
                                 * Detach listeners.
                                 * @method detach
                                 * @param {Function} fn  The subscribed function to remove, if not supplied
                                 *                       all will be removed.
                                 * @param {Object}   context The context object passed to subscribe.
                                 * @return {Number} returns the number of subscribers unsubscribed.
                                 */
                                detach: function(fn, context) {
                                    // unsubscribe handle
                                    if (fn && fn.detach) {
                                        return fn.detach();
                                    }
                            
                                    var i, s,
                                        found = 0,
                                        subs = this._subscribers,
                                        afters = this._afters;
                            
                                    if (subs) {
                                        for (i = subs.length; i >= 0; i--) {
                                            s = subs[i];
                                            if (s && (!fn || fn === s.fn)) {
                                                this._delete(s, subs, i);
                                                found++;
                                            }
                                        }
                                    }
                            
                                    if (afters) {
                                        for (i = afters.length; i >= 0; i--) {
                                            s = afters[i];
                                            if (s && (!fn || fn === s.fn)) {
                                                this._delete(s, afters, i);
                                                found++;
                                            }
                                        }
                                    }
                            
                                    return found;
                                },
                            
                                /**
                                 * Detach listeners.
                                 * @method unsubscribe
                                 * @param {Function} fn  The subscribed function to remove, if not supplied
                                 *                       all will be removed.
                                 * @param {Object}   context The context object passed to subscribe.
                                 * @return {int|undefined} returns the number of subscribers unsubscribed.
                                 * @deprecated use detach.
                                 */
                                unsubscribe: function() {
                                    return this.detach.apply(this, arguments);
                                },
                            
                                /**
                                 * Notify a single subscriber
                                 * @method _notify
                                 * @param {Subscriber} s the subscriber.
                                 * @param {Array} args the arguments array to apply to the listener.
                                 * @protected
                                 */
                                _notify: function(s, args, ef) {
                            
                                    this.log(this.type + '->' + 'sub: ' + s.id);
                            
                                    var ret;
                            
                                    ret = s.notify(args, this);
                            
                                    if (false === ret || this.stopped > 1) {
                                        this.log(this.type + ' cancelled by subscriber');
                                        return false;
                                    }
                            
                                    return true;
                                },
                            
                                /**
                                 * Logger abstraction to centralize the application of the silent flag
                                 * @method log
                                 * @param {string} msg message to log.
                                 * @param {string} cat log category.
                                 */
                                log: function(msg, cat) {
                                    if (!this.silent) { Y.log(this.id + ': ' + msg, cat || 'info', 'event'); }
                                },
                            
                                /**
                                 * Notifies the subscribers.  The callback functions will be executed
                                 * from the context specified when the event was created, and with the
                                 * following parameters:
                                 *   <ul>
                                 *   <li>The type of event</li>
                                 *   <li>All of the arguments fire() was executed with as an array</li>
                                 *   <li>The custom object (if any) that was passed into the subscribe()
                                 *       method</li>
                                 *   </ul>
                                 * @method fire
                                 * @param {Object*} arguments an arbitrary set of parameters to pass to
                                 *                            the handler.
                                 * @return {boolean} false if one of the subscribers returned false,
                                 *                   true otherwise.
                                 *
                                 */
                                fire: function() {
                            
                                    // push is the fastest way to go from arguments to arrays
                                    // for most browsers currently
                                    // http://jsperf.com/push-vs-concat-vs-slice/2
                            
                                    var args = [];
                                    args.push.apply(args, arguments);
                            
                                    return this._fire(args);
                                },
                            
                                /**
                                 * Private internal implementation for `fire`, which is can be used directly by
                                 * `EventTarget` and other event module classes which have already converted from
                                 * an `arguments` list to an array, to avoid the repeated overhead.
                                 *
                                 * @method _fire
                                 * @private
                                 * @param {Array} args The array of arguments passed to be passed to handlers.
                                 * @return {boolean} false if one of the subscribers returned false, true otherwise.
                                 */
                                _fire: function(args) {
                            
                                    if (this.fireOnce && this.fired) {
                                        this.log('fireOnce event: ' + this.type + ' already fired');
                                        return true;
                                    } else {
                            
                                        // this doesn't happen if the event isn't published
                                        // this.host._monitor('fire', this.type, args);
                            
                                        this.fired = true;
                            
                                        if (this.fireOnce) {
                                            this.firedWith = args;
                                        }
                            
                                        if (this.emitFacade) {
                                            return this.fireComplex(args);
                                        } else {
                                            return this.fireSimple(args);
                                        }
                                    }
                                },
                            
                                /**
                                 * Set up for notifying subscribers of non-emitFacade events.
                                 *
                                 * @method fireSimple
                                 * @param args {Array} Arguments passed to fire()
                                 * @return Boolean false if a subscriber returned false
                                 * @protected
                                 */
                                fireSimple: function(args) {
                                    this.stopped = 0;
                                    this.prevented = 0;
                                    if (this.hasSubs()) {
                                        var subs = this.getSubs();
                                        this._procSubs(subs[0], args);
                                        this._procSubs(subs[1], args);
                                    }
                                    if (this.broadcast) {
                                        this._broadcast(args);
                                    }
                                    return this.stopped ? false : true;
                                },
                            
                                // Requires the event-custom-complex module for full funcitonality.
                                fireComplex: function(args) {
                                    this.log('Missing event-custom-complex needed to emit a facade for: ' + this.type);
                                    args[0] = args[0] || {};
                                    return this.fireSimple(args);
                                },
                            
                                /**
                                 * Notifies a list of subscribers.
                                 *
                                 * @method _procSubs
                                 * @param subs {Array} List of subscribers
                                 * @param args {Array} Arguments passed to fire()
                                 * @param ef {}
                                 * @return Boolean false if a subscriber returns false or stops the event
                                 *              propagation via e.stopPropagation(),
                                 *              e.stopImmediatePropagation(), or e.halt()
                                 * @private
                                 */
                                _procSubs: function(subs, args, ef) {
                                    var s, i, l;
                            
                                    for (i = 0, l = subs.length; i < l; i++) {
                                        s = subs[i];
                                        if (s && s.fn) {
                                            if (false === this._notify(s, args, ef)) {
                                                this.stopped = 2;
                                            }
                                            if (this.stopped === 2) {
                                                return false;
                                            }
                                        }
                                    }
                            
                                    return true;
                                },
                            
                                /**
                                 * Notifies the YUI instance if the event is configured with broadcast = 1,
                                 * and both the YUI instance and Y.Global if configured with broadcast = 2.
                                 *
                                 * @method _broadcast
                                 * @param args {Array} Arguments sent to fire()
                                 * @private
                                 */
                                _broadcast: function(args) {
                                    if (!this.stopped && this.broadcast) {
                            
                                        var a = args.concat();
                                        a.unshift(this.type);
                            
                                        if (this.host !== Y) {
                                            Y.fire.apply(Y, a);
                                        }
                            
                                        if (this.broadcast === 2) {
                                            Y.Global.fire.apply(Y.Global, a);
                                        }
                                    }
                                },
                            
                                /**
                                 * Removes all listeners
                                 * @method unsubscribeAll
                                 * @return {Number} The number of listeners unsubscribed.
                                 * @deprecated use detachAll.
                                 */
                                unsubscribeAll: function() {
                                    return this.detachAll.apply(this, arguments);
                                },
                            
                                /**
                                 * Removes all listeners
                                 * @method detachAll
                                 * @return {Number} The number of listeners unsubscribed.
                                 */
                                detachAll: function() {
                                    return this.detach();
                                },
                            
                                /**
                                 * Deletes the subscriber from the internal store of on() and after()
                                 * subscribers.
                                 *
                                 * @method _delete
                                 * @param s subscriber object.
                                 * @param subs (optional) on or after subscriber array
                                 * @param index (optional) The index found.
                                 * @private
                                 */
                                _delete: function(s, subs, i) {
                                    var when = s._when;
                            
                                    if (!subs) {
                                        subs = (when === AFTER) ? this._afters : this._subscribers;
                                    }
                            
                                    if (subs) {
                                        i = YArray.indexOf(subs, s, 0);
                            
                                        if (s && subs[i] === s) {
                                            subs.splice(i, 1);
                                        }
                                    }
                            
                                    if (this._kds) {
                                        if (when === AFTER) {
                                            delete this.afters[s.id];
                                        } else {
                                            delete this.subscribers[s.id];
                                        }
                                    }
                            
                                    if (this.monitored && this.host) {
                                        this.host._monitor('detach', this, {
                                            ce: this,
                                            sub: s
                                        });
                                    }
                            
                                    if (s) {
                                        s.deleted = true;
                                    }
                                }
                            };