text: YUI.add('widget-uievents', function (Y, NAME) {
  
  /**
   * Support for Widget UI Events (Custom Events fired by the widget, which wrap the underlying DOM events - e.g. widget:click, widget:mousedown)
   *
   * @module widget
   * @submodule widget-uievents
   */
  
  var BOUNDING_BOX = "boundingBox",
      Widget = Y.Widget,
      RENDER = "render",
      L = Y.Lang,
      EVENT_PREFIX_DELIMITER = ":",
  
      //  Map of Node instances serving as a delegation containers for a specific
      //  event type to Widget instances using that delegation container.
      _uievts = Y.Widget._uievts = Y.Widget._uievts || {};
  
  Y.mix(Widget.prototype, {
  
      /**
       * Destructor logic for UI event infrastructure,
       * invoked during Widget destruction.
       *
       * @method _destroyUIEvents
       * @for Widget
       * @private
       */
      _destroyUIEvents: function() {
  
          var widgetGuid = Y.stamp(this, true);
  
          Y.each(_uievts, function (info, key) {
              if (info.instances[widgetGuid]) {
                  //  Unregister this Widget instance as needing this delegated
                  //  event listener.
                  delete info.instances[widgetGuid];
  
                  //  There are no more Widget instances using this delegated 
                  //  event listener, so detach it.
  
                  if (Y.Object.isEmpty(info.instances)) {
                      info.handle.detach();
  
                      if (_uievts[key]) {
                          delete _uievts[key];
                      }
                  }
              }
          });
      },
  
      /**
       * Map of DOM events that should be fired as Custom Events by the  
       * Widget instance.
       *
       * @property UI_EVENTS
       * @for Widget
       * @type Object
       */
      UI_EVENTS: Y.Node.DOM_EVENTS,
  
      /**
       * Returns the node on which to bind delegate listeners.
       *
       * @method _getUIEventNode
       * @for Widget
       * @protected
       */
      _getUIEventNode: function () {
          return this.get(BOUNDING_BOX);
      },
  
      /**
       * Binds a delegated DOM event listener of the specified type to the 
       * Widget's outtermost DOM element to facilitate the firing of a Custom
       * Event of the same type for the Widget instance.  
       *
       * @method _createUIEvent
       * @for Widget 
       * @param type {String} String representing the name of the event
       * @private
       */
      _createUIEvent: function (type) {
  
          var uiEvtNode = this._getUIEventNode(),
              key = (Y.stamp(uiEvtNode) + type),
              info = _uievts[key],
              handle;
  
          //  For each Node instance: Ensure that there is only one delegated
          //  event listener used to fire Widget UI events.
  
          if (!info) {
  
              handle = uiEvtNode.delegate(type, function (evt) {
  
                  var widget = Widget.getByNode(this);
  
                  // Widget could be null if node instance belongs to
                  // another Y instance.
  
                  if (widget) {
                      if (widget._filterUIEvent(evt)) {
                          widget.fire(evt.type, { domEvent: evt });
                      }
                  }
  
              }, "." + Y.Widget.getClassName());
  
              _uievts[key] = info = { instances: {}, handle: handle };
          }
  
          //  Register this Widget as using this Node as a delegation container.
          info.instances[Y.stamp(this)] = 1;
      },
  
      /**
       * This method is used to determine if we should fire
       * the UI Event or not. The default implementation makes sure
       * that for nested delegates (nested unrelated widgets), we don't 
       * fire the UI event listener more than once at each level.
       *
       * <p>For example, without the additional filter, if you have nested 
       * widgets, each widget will have a delegate listener. If you 
       * click on the inner widget, the inner delegate listener's 
       * filter will match once, but the outer will match twice 
       * (based on delegate's design) - once for the inner widget, 
       * and once for the outer.</p>
       *
       * @method _filterUIEvent
       * @for Widget 
       * @param {DOMEventFacade} evt
       * @return {boolean} true if it's OK to fire the custom UI event, false if not.
       * @private
       * 
       */
      _filterUIEvent: function(evt) {
          // Either it's hitting this widget's delegate container (and not some other widget's), 
          // or the container it's hitting is handling this widget's ui events.
          return (evt.currentTarget.compareTo(evt.container) || evt.container.compareTo(this._getUIEventNode()));        
      },
  
      /**
       * Determines if the specified event is a UI event.
       *
       * @private
       * @method _isUIEvent
       * @for Widget 
       * @param type {String} String representing the name of the event
       * @return {String} Event Returns the name of the UI Event, otherwise 
       * undefined.
       */
      _getUIEvent: function (type) {
  
          if (L.isString(type)) {
              var sType = this.parseType(type)[1],
                  iDelim,
                  returnVal;
  
              if (sType) {
                  // TODO: Get delimiter from ET, or have ET support this.
                  iDelim = sType.indexOf(EVENT_PREFIX_DELIMITER);
                  if (iDelim > -1) {
                      sType = sType.substring(iDelim + EVENT_PREFIX_DELIMITER.length);
                  }
  
                  if (this.UI_EVENTS[sType]) {
                      returnVal = sType;
                  }
              }
  
              return returnVal;
          }
      },
  
      /**
       * Sets up infrastructure required to fire a UI event.
       * 
       * @private
       * @method _initUIEvent
       * @for Widget
       * @param type {String} String representing the name of the event
       * @return {String}     
       */
      _initUIEvent: function (type) {
          var sType = this._getUIEvent(type),
              queue = this._uiEvtsInitQueue || {};
  
          if (sType && !queue[sType]) {
  
              this._uiEvtsInitQueue = queue[sType] = 1;
  
              this.after(RENDER, function() { 
                  this._createUIEvent(sType);
                  delete this._uiEvtsInitQueue[sType];
              });
          }
      },
  
      //  Override of "on" from Base to facilitate the firing of Widget events
      //  based on DOM events of the same name/type (e.g. "click", "mouseover").
      //  Temporary solution until we have the ability to listen to when 
      //  someone adds an event listener (bug 2528230)
      on: function (type) {
          this._initUIEvent(type);
          return Widget.superclass.on.apply(this, arguments);
      },
  
      //  Override of "publish" from Base to facilitate the firing of Widget events
      //  based on DOM events of the same name/type (e.g. "click", "mouseover").    
      //  Temporary solution until we have the ability to listen to when 
      //  someone publishes an event (bug 2528230)     
      publish: function (type, config) {
          var sType = this._getUIEvent(type);
          if (sType && config && config.defaultFn) {
              this._initUIEvent(sType);
          }        
          return Widget.superclass.publish.apply(this, arguments);
      }
  
  }, true); // overwrite existing EventTarget methods
  
  
  }, '@VERSION@', {"requires": ["node-event-delegate", "widget-base"]});
  