Show:
                            /**
                            Mixes support for JSONP and YQL result sources into AutoCompleteBase.
                            
                            @module autocomplete
                            @submodule autocomplete-sources
                            **/
                            
                            var ACBase = Y.AutoCompleteBase,
                                Lang   = Y.Lang,
                            
                                _SOURCE_SUCCESS = '_sourceSuccess',
                            
                                MAX_RESULTS         = 'maxResults',
                                REQUEST_TEMPLATE    = 'requestTemplate',
                                RESULT_LIST_LOCATOR = 'resultListLocator';
                            
                            // Add prototype properties and methods to AutoCompleteBase.
                            Y.mix(ACBase.prototype, {
                                /**
                                Regular expression used to determine whether a String source is a YQL query.
                            
                                @property _YQL_SOURCE_REGEX
                                @type RegExp
                                @protected
                                @for AutoCompleteBase
                                **/
                                _YQL_SOURCE_REGEX: /^(?:select|set|use)\s+/i,
                            
                                /**
                                Runs before AutoCompleteBase's `_createObjectSource()` method and augments
                                it to support additional object-based source types.
                            
                                @method _beforeCreateObjectSource
                                @param {String} source
                                @protected
                                @for AutoCompleteBase
                                **/
                                _beforeCreateObjectSource: function (source) {
                                    // If the object is a <select> node, use the options as the result
                                    // source.
                                    if (source instanceof Y.Node &&
                                            source.get('nodeName').toLowerCase() === 'select') {
                            
                                        return this._createSelectSource(source);
                                    }
                            
                                    // If the object is a JSONPRequest instance, try to use it as a JSONP
                                    // source.
                                    if (Y.JSONPRequest && source instanceof Y.JSONPRequest) {
                                        return this._createJSONPSource(source);
                                    }
                            
                                    // Fall back to a basic object source.
                                    return this._createObjectSource(source);
                                },
                            
                                /**
                                Creates a DataSource-like object that uses `Y.io` as a source. See the
                                `source` attribute for more details.
                            
                                @method _createIOSource
                                @param {String} source URL.
                                @return {Object} DataSource-like object.
                                @protected
                                @for AutoCompleteBase
                                **/
                                _createIOSource: function (source) {
                                    var ioSource = {type: 'io'},
                                        that     = this,
                                        ioRequest, lastRequest, loading;
                            
                                    // Private internal _sendRequest method that will be assigned to
                                    // ioSource.sendRequest once io-base and json-parse are available.
                                    function _sendRequest(request) {
                                        var cacheKey = request.request;
                            
                                        // Return immediately on a cached response.
                                        if (that._cache && cacheKey in that._cache) {
                                            that[_SOURCE_SUCCESS](that._cache[cacheKey], request);
                                            return;
                                        }
                            
                                        // Cancel any outstanding requests.
                                        if (ioRequest && ioRequest.isInProgress()) {
                                            ioRequest.abort();
                                        }
                            
                                        ioRequest = Y.io(that._getXHRUrl(source, request), {
                                            on: {
                                                success: function (tid, response) {
                                                    var data;
                            
                                                    try {
                                                        data = Y.JSON.parse(response.responseText);
                                                    } catch (ex) {
                                                        Y.error('JSON parse error', ex);
                                                    }
                            
                                                    if (data) {
                                                        that._cache && (that._cache[cacheKey] = data);
                                                        that[_SOURCE_SUCCESS](data, request);
                                                    }
                                                }
                                            }
                                        });
                                    }
                            
                                    ioSource.sendRequest = function (request) {
                                        // Keep track of the most recent request in case there are multiple
                                        // requests while we're waiting for the IO module to load. Only the
                                        // most recent request will be sent.
                                        lastRequest = request;
                            
                                        if (loading) { return; }
                            
                                        loading = true;
                            
                                        // Lazy-load the io-base and json-parse modules if necessary,
                                        // then overwrite the sendRequest method to bypass this check in
                                        // the future.
                                        Y.use('io-base', 'json-parse', function () {
                                            ioSource.sendRequest = _sendRequest;
                                            _sendRequest(lastRequest);
                                        });
                                    };
                            
                                    return ioSource;
                                },
                            
                                /**
                                Creates a DataSource-like object that uses the specified JSONPRequest
                                instance as a source. See the `source` attribute for more details.
                            
                                @method _createJSONPSource
                                @param {JSONPRequest|String} source URL string or JSONPRequest instance.
                                @return {Object} DataSource-like object.
                                @protected
                                @for AutoCompleteBase
                                **/
                                _createJSONPSource: function (source) {
                                    var jsonpSource = {type: 'jsonp'},
                                        that        = this,
                                        lastRequest, loading;
                            
                                    function _sendRequest(request) {
                                        var cacheKey = request.request,
                                            query    = request.query;
                            
                                        if (that._cache && cacheKey in that._cache) {
                                            that[_SOURCE_SUCCESS](that._cache[cacheKey], request);
                                            return;
                                        }
                            
                                        // Hack alert: JSONPRequest currently doesn't support
                                        // per-request callbacks, so we're reaching into the protected
                                        // _config object to make it happen.
                                        //
                                        // This limitation is mentioned in the following JSONP
                                        // enhancement ticket:
                                        //
                                        // http://yuilibrary.com/projects/yui3/ticket/2529371
                                        source._config.on.success = function (data) {
                                            that._cache && (that._cache[cacheKey] = data);
                                            that[_SOURCE_SUCCESS](data, request);
                                        };
                            
                                        source.send(query);
                                    }
                            
                                    jsonpSource.sendRequest = function (request) {
                                        // Keep track of the most recent request in case there are multiple
                                        // requests while we're waiting for the JSONP module to load. Only
                                        // the most recent request will be sent.
                                        lastRequest = request;
                            
                                        if (loading) { return; }
                            
                                        loading = true;
                            
                                        // Lazy-load the JSONP module if necessary, then overwrite the
                                        // sendRequest method to bypass this check in the future.
                                        Y.use('jsonp', function () {
                                            // Turn the source into a JSONPRequest instance if it isn't
                                            // one already.
                                            if (!(source instanceof Y.JSONPRequest)) {
                                                source = new Y.JSONPRequest(source, {
                                                    format: Y.bind(that._jsonpFormatter, that)
                                                });
                                            }
                            
                                            jsonpSource.sendRequest = _sendRequest;
                                            _sendRequest(lastRequest);
                                        });
                                    };
                            
                                    return jsonpSource;
                                },
                            
                                /**
                                Creates a DataSource-like object that uses the specified `<select>` node as
                                a source.
                            
                                @method _createSelectSource
                                @param {Node} source YUI Node instance wrapping a `<select>` node.
                                @return {Object} DataSource-like object.
                                @protected
                                @for AutoCompleteBase
                                **/
                                _createSelectSource: function (source) {
                                    var that = this;
                            
                                    return {
                                        type: 'select',
                                        sendRequest: function (request) {
                                            var options = [];
                            
                                            source.get('options').each(function (option) {
                                                options.push({
                                                    html    : option.get('innerHTML'),
                                                    index   : option.get('index'),
                                                    node    : option,
                                                    selected: option.get('selected'),
                                                    text    : option.get('text'),
                                                    value   : option.get('value')
                                                });
                                            });
                            
                                            that[_SOURCE_SUCCESS](options, request);
                                        }
                                    };
                                },
                            
                                /**
                                Creates a DataSource-like object that calls the specified  URL or executes
                                the specified YQL query for results. If the string starts with "select ",
                                "use ", or "set " (case-insensitive), it's assumed to be a YQL query;
                                otherwise, it's assumed to be a URL (which may be absolute or relative).
                                URLs containing a "{callback}" placeholder are assumed to be JSONP URLs; all
                                others will use XHR. See the `source` attribute for more details.
                            
                                @method _createStringSource
                                @param {String} source URL or YQL query.
                                @return {Object} DataSource-like object.
                                @protected
                                @for AutoCompleteBase
                                **/
                                _createStringSource: function (source) {
                                    if (this._YQL_SOURCE_REGEX.test(source)) {
                                        // Looks like a YQL query.
                                        return this._createYQLSource(source);
                                    } else if (source.indexOf('{callback}') !== -1) {
                                        // Contains a {callback} param and isn't a YQL query, so it must be
                                        // JSONP.
                                        return this._createJSONPSource(source);
                                    } else {
                                        // Not a YQL query or JSONP, so we'll assume it's an XHR URL.
                                        return this._createIOSource(source);
                                    }
                                },
                            
                                /**
                                Creates a DataSource-like object that uses the specified YQL query string to
                                create a YQL-based source. See the `source` attribute for details. If no
                                `resultListLocator` is defined, this method will set a best-guess locator
                                that might work for many typical YQL queries.
                            
                                @method _createYQLSource
                                @param {String} source YQL query.
                                @return {Object} DataSource-like object.
                                @protected
                                @for AutoCompleteBase
                                **/
                                _createYQLSource: function (source) {
                                    var that      = this,
                                        yqlSource = {type: 'yql'},
                                        lastRequest, loading, yqlRequest;
                            
                                    if (!that.get(RESULT_LIST_LOCATOR)) {
                                        that.set(RESULT_LIST_LOCATOR, that._defaultYQLLocator);
                                    }
                            
                                    function _sendRequest(request) {
                                        var query      = request.query,
                                            env        = that.get('yqlEnv'),
                                            maxResults = that.get(MAX_RESULTS),
                                            callback, opts, yqlQuery;
                            
                                        yqlQuery = Lang.sub(source, {
                                            maxResults: maxResults > 0 ? maxResults : 1000,
                                            request   : request.request,
                                            query     : query
                                        });
                            
                                        if (that._cache && yqlQuery in that._cache) {
                                            that[_SOURCE_SUCCESS](that._cache[yqlQuery], request);
                                            return;
                                        }
                            
                                        callback = function (data) {
                                            that._cache && (that._cache[yqlQuery] = data);
                                            that[_SOURCE_SUCCESS](data, request);
                                        };
                            
                                        opts = {proto: that.get('yqlProtocol')};
                            
                                        // Only create a new YQLRequest instance if this is the
                                        // first request. For subsequent requests, we'll reuse the
                                        // original instance.
                                        if (yqlRequest) {
                                            yqlRequest._callback   = callback;
                                            yqlRequest._opts       = opts;
                                            yqlRequest._params.q   = yqlQuery;
                            
                                            if (env) {
                                                yqlRequest._params.env = env;
                                            }
                                        } else {
                                            yqlRequest = new Y.YQLRequest(yqlQuery, {
                                                on: {success: callback},
                                                allowCache: false // temp workaround until JSONP has per-URL callback proxies
                                            }, env ? {env: env} : null, opts);
                                        }
                            
                                        yqlRequest.send();
                                    }
                            
                                    yqlSource.sendRequest = function (request) {
                                        // Keep track of the most recent request in case there are multiple
                                        // requests while we're waiting for the YQL module to load. Only the
                                        // most recent request will be sent.
                                        lastRequest = request;
                            
                                        if (!loading) {
                                            // Lazy-load the YQL module if necessary, then overwrite the
                                            // sendRequest method to bypass this check in the future.
                                            loading = true;
                            
                                            Y.use('yql', function () {
                                                yqlSource.sendRequest = _sendRequest;
                                                _sendRequest(lastRequest);
                                            });
                                        }
                                    };
                            
                                    return yqlSource;
                                },
                            
                                /**
                                Default resultListLocator used when a string-based YQL source is set and the
                                implementer hasn't already specified one.
                            
                                @method _defaultYQLLocator
                                @param {Object} response YQL response object.
                                @return {Array}
                                @protected
                                @for AutoCompleteBase
                                **/
                                _defaultYQLLocator: function (response) {
                                    var results = response && response.query && response.query.results,
                                        values;
                            
                                    if (results && Lang.isObject(results)) {
                                        // If there's only a single value on YQL's results object, that
                                        // value almost certainly contains the array of results we want. If
                                        // there are 0 or 2+ values, then the values themselves are most
                                        // likely the results we want.
                                        values  = Y.Object.values(results) || [];
                                        results = values.length === 1 ? values[0] : values;
                            
                                        if (!Lang.isArray(results)) {
                                            results = [results];
                                        }
                                    } else {
                                        results = [];
                                    }
                            
                                    return results;
                                },
                            
                                /**
                                Returns a formatted XHR URL based on the specified base _url_, _query_, and
                                the current _requestTemplate_ if any.
                            
                                @method _getXHRUrl
                                @param {String} url Base URL.
                                @param {Object} request Request object containing `query` and `request`
                                  properties.
                                @return {String} Formatted URL.
                                @protected
                                @for AutoCompleteBase
                                **/
                                _getXHRUrl: function (url, request) {
                                    var maxResults = this.get(MAX_RESULTS);
                            
                                    if (request.query !== request.request) {
                                        // Append the request template to the URL.
                                        url += request.request;
                                    }
                            
                                    return Lang.sub(url, {
                                        maxResults: maxResults > 0 ? maxResults : 1000,
                                        query     : encodeURIComponent(request.query)
                                    });
                                },
                            
                                /**
                                URL formatter passed to `JSONPRequest` instances.
                            
                                @method _jsonpFormatter
                                @param {String} url
                                @param {String} proxy
                                @param {String} query
                                @return {String} Formatted URL
                                @protected
                                @for AutoCompleteBase
                                **/
                                _jsonpFormatter: function (url, proxy, query) {
                                    var maxResults      = this.get(MAX_RESULTS),
                                        requestTemplate = this.get(REQUEST_TEMPLATE);
                            
                                    if (requestTemplate) {
                                        url += requestTemplate(query);
                                    }
                            
                                    return Lang.sub(url, {
                                        callback  : proxy,
                                        maxResults: maxResults > 0 ? maxResults : 1000,
                                        query     : encodeURIComponent(query)
                                    });
                                }
                            });
                            
                            // Add attributes to AutoCompleteBase.
                            Y.mix(ACBase.ATTRS, {
                                /**
                                YQL environment file URL to load when the `source` is set to a YQL query.
                                Set this to `null` to use the default Open Data Tables environment file
                                (http://datatables.org/alltables.env).
                            
                                @attribute yqlEnv
                                @type String
                                @default null
                                @for AutoCompleteBase
                                **/
                                yqlEnv: {
                                    value: null
                                },
                            
                                /**
                                URL protocol to use when the `source` is set to a YQL query.
                            
                                @attribute yqlProtocol
                                @type String
                                @default 'http'
                                @for AutoCompleteBase
                                **/
                                yqlProtocol: {
                                    value: 'http'
                                }
                            });
                            
                            // Tell AutoCompleteBase about the new source types it can now support.
                            Y.mix(ACBase.SOURCE_TYPES, {
                                io    : '_createIOSource',
                                jsonp : '_createJSONPSource',
                                object: '_beforeCreateObjectSource', // Run our version before the base version.
                                select: '_createSelectSource',
                                string: '_createStringSource',
                                yql   : '_createYQLSource'
                            }, true);