src/cm/media/js/lib/yui/yui_3.10.3/build/get/get-debug.js
changeset 525 89ef5ed3c48b
equal deleted inserted replaced
524:322d0feea350 525:89ef5ed3c48b
       
     1 /*
       
     2 YUI 3.10.3 (build 2fb5187)
       
     3 Copyright 2013 Yahoo! Inc. All rights reserved.
       
     4 Licensed under the BSD License.
       
     5 http://yuilibrary.com/license/
       
     6 */
       
     7 
       
     8 YUI.add('get', function (Y, NAME) {
       
     9 
       
    10 /*jslint boss:true, expr:true, laxbreak: true */
       
    11 
       
    12 /**
       
    13 Provides dynamic loading of remote JavaScript and CSS resources.
       
    14 
       
    15 @module get
       
    16 @class Get
       
    17 @static
       
    18 **/
       
    19 
       
    20 var Lang = Y.Lang,
       
    21 
       
    22     CUSTOM_ATTRS, // defined lazily in Y.Get.Transaction._createNode()
       
    23 
       
    24     Get, Transaction;
       
    25 
       
    26 Y.Get = Get = {
       
    27     // -- Public Properties ----------------------------------------------------
       
    28 
       
    29     /**
       
    30     Default options for CSS requests. Options specified here will override
       
    31     global defaults for CSS requests.
       
    32 
       
    33     See the `options` property for all available options.
       
    34 
       
    35     @property cssOptions
       
    36     @type Object
       
    37     @static
       
    38     @since 3.5.0
       
    39     **/
       
    40     cssOptions: {
       
    41         attributes: {
       
    42             rel: 'stylesheet'
       
    43         },
       
    44 
       
    45         doc         : Y.config.linkDoc || Y.config.doc,
       
    46         pollInterval: 50
       
    47     },
       
    48 
       
    49     /**
       
    50     Default options for JS requests. Options specified here will override global
       
    51     defaults for JS requests.
       
    52 
       
    53     See the `options` property for all available options.
       
    54 
       
    55     @property jsOptions
       
    56     @type Object
       
    57     @static
       
    58     @since 3.5.0
       
    59     **/
       
    60     jsOptions: {
       
    61         autopurge: true,
       
    62         doc      : Y.config.scriptDoc || Y.config.doc
       
    63     },
       
    64 
       
    65     /**
       
    66     Default options to use for all requests.
       
    67 
       
    68     Note that while all available options are documented here for ease of
       
    69     discovery, some options (like callback functions) only make sense at the
       
    70     transaction level.
       
    71 
       
    72     Callback functions specified via the options object or the `options`
       
    73     parameter of the `css()`, `js()`, or `load()` methods will receive the
       
    74     transaction object as a parameter. See `Y.Get.Transaction` for details on
       
    75     the properties and methods available on transactions.
       
    76 
       
    77     @static
       
    78     @since 3.5.0
       
    79     @property {Object} options
       
    80 
       
    81     @property {Boolean} [options.async=false] Whether or not to load scripts
       
    82         asynchronously, meaning they're requested in parallel and execution
       
    83         order is not guaranteed. Has no effect on CSS, since CSS is always
       
    84         loaded asynchronously.
       
    85 
       
    86     @property {Object} [options.attributes] HTML attribute name/value pairs that
       
    87         should be added to inserted nodes. By default, the `charset` attribute
       
    88         will be set to "utf-8" and nodes will be given an auto-generated `id`
       
    89         attribute, but you can override these with your own values if desired.
       
    90 
       
    91     @property {Boolean} [options.autopurge] Whether or not to automatically
       
    92         purge inserted nodes after the purge threshold is reached. This is
       
    93         `true` by default for JavaScript, but `false` for CSS since purging a
       
    94         CSS node will also remove any styling applied by the referenced file.
       
    95 
       
    96     @property {Object} [options.context] `this` object to use when calling
       
    97         callback functions. Defaults to the transaction object.
       
    98 
       
    99     @property {Mixed} [options.data] Arbitrary data object to pass to "on*"
       
   100         callbacks.
       
   101 
       
   102     @property {Document} [options.doc] Document into which nodes should be
       
   103         inserted. By default, the current document is used.
       
   104 
       
   105     @property {HTMLElement|String} [options.insertBefore] HTML element or id
       
   106         string of an element before which all generated nodes should be
       
   107         inserted. If not specified, Get will automatically determine the best
       
   108         place to insert nodes for maximum compatibility.
       
   109 
       
   110     @property {Function} [options.onEnd] Callback to execute after a transaction
       
   111         is complete, regardless of whether it succeeded or failed.
       
   112 
       
   113     @property {Function} [options.onFailure] Callback to execute after a
       
   114         transaction fails, times out, or is aborted.
       
   115 
       
   116     @property {Function} [options.onProgress] Callback to execute after each
       
   117         individual request in a transaction either succeeds or fails.
       
   118 
       
   119     @property {Function} [options.onSuccess] Callback to execute after a
       
   120         transaction completes successfully with no errors. Note that in browsers
       
   121         that don't support the `error` event on CSS `<link>` nodes, a failed CSS
       
   122         request may still be reported as a success because in these browsers
       
   123         it can be difficult or impossible to distinguish between success and
       
   124         failure for CSS resources.
       
   125 
       
   126     @property {Function} [options.onTimeout] Callback to execute after a
       
   127         transaction times out.
       
   128 
       
   129     @property {Number} [options.pollInterval=50] Polling interval (in
       
   130         milliseconds) for detecting CSS load completion in browsers that don't
       
   131         support the `load` event on `<link>` nodes. This isn't used for
       
   132         JavaScript.
       
   133 
       
   134     @property {Number} [options.purgethreshold=20] Number of nodes to insert
       
   135         before triggering an automatic purge when `autopurge` is `true`.
       
   136 
       
   137     @property {Number} [options.timeout] Number of milliseconds to wait before
       
   138         aborting a transaction. When a timeout occurs, the `onTimeout` callback
       
   139         is called, followed by `onFailure` and finally `onEnd`. By default,
       
   140         there is no timeout.
       
   141 
       
   142     @property {String} [options.type] Resource type ("css" or "js"). This option
       
   143         is set automatically by the `css()` and `js()` functions and will be
       
   144         ignored there, but may be useful when using the `load()` function. If
       
   145         not specified, the type will be inferred from the URL, defaulting to
       
   146         "js" if the URL doesn't contain a recognizable file extension.
       
   147     **/
       
   148     options: {
       
   149         attributes: {
       
   150             charset: 'utf-8'
       
   151         },
       
   152 
       
   153         purgethreshold: 20
       
   154     },
       
   155 
       
   156     // -- Protected Properties -------------------------------------------------
       
   157 
       
   158     /**
       
   159     Regex that matches a CSS URL. Used to guess the file type when it's not
       
   160     specified.
       
   161 
       
   162     @property REGEX_CSS
       
   163     @type RegExp
       
   164     @final
       
   165     @protected
       
   166     @static
       
   167     @since 3.5.0
       
   168     **/
       
   169     REGEX_CSS: /\.css(?:[?;].*)?$/i,
       
   170 
       
   171     /**
       
   172     Regex that matches a JS URL. Used to guess the file type when it's not
       
   173     specified.
       
   174 
       
   175     @property REGEX_JS
       
   176     @type RegExp
       
   177     @final
       
   178     @protected
       
   179     @static
       
   180     @since 3.5.0
       
   181     **/
       
   182     REGEX_JS : /\.js(?:[?;].*)?$/i,
       
   183 
       
   184     /**
       
   185     Contains information about the current environment, such as what script and
       
   186     link injection features it supports.
       
   187 
       
   188     This object is created and populated the first time the `_getEnv()` method
       
   189     is called.
       
   190 
       
   191     @property _env
       
   192     @type Object
       
   193     @protected
       
   194     @static
       
   195     @since 3.5.0
       
   196     **/
       
   197 
       
   198     /**
       
   199     Mapping of document _yuid strings to <head> or <base> node references so we
       
   200     don't have to look the node up each time we want to insert a request node.
       
   201 
       
   202     @property _insertCache
       
   203     @type Object
       
   204     @protected
       
   205     @static
       
   206     @since 3.5.0
       
   207     **/
       
   208     _insertCache: {},
       
   209 
       
   210     /**
       
   211     Information about the currently pending transaction, if any.
       
   212 
       
   213     This is actually an object with two properties: `callback`, containing the
       
   214     optional callback passed to `css()`, `load()`, or `js()`; and `transaction`,
       
   215     containing the actual transaction instance.
       
   216 
       
   217     @property _pending
       
   218     @type Object
       
   219     @protected
       
   220     @static
       
   221     @since 3.5.0
       
   222     **/
       
   223     _pending: null,
       
   224 
       
   225     /**
       
   226     HTML nodes eligible to be purged next time autopurge is triggered.
       
   227 
       
   228     @property _purgeNodes
       
   229     @type HTMLElement[]
       
   230     @protected
       
   231     @static
       
   232     @since 3.5.0
       
   233     **/
       
   234     _purgeNodes: [],
       
   235 
       
   236     /**
       
   237     Queued transactions and associated callbacks.
       
   238 
       
   239     @property _queue
       
   240     @type Object[]
       
   241     @protected
       
   242     @static
       
   243     @since 3.5.0
       
   244     **/
       
   245     _queue: [],
       
   246 
       
   247     // -- Public Methods -------------------------------------------------------
       
   248 
       
   249     /**
       
   250     Aborts the specified transaction.
       
   251 
       
   252     This will cause the transaction's `onFailure` callback to be called and
       
   253     will prevent any new script and link nodes from being added to the document,
       
   254     but any resources that have already been requested will continue loading
       
   255     (there's no safe way to prevent this, unfortunately).
       
   256 
       
   257     *Note:* This method is deprecated as of 3.5.0, and will be removed in a
       
   258     future version of YUI. Use the transaction-level `abort()` method instead.
       
   259 
       
   260     @method abort
       
   261     @param {Get.Transaction} transaction Transaction to abort.
       
   262     @deprecated Use the `abort()` method on the transaction instead.
       
   263     @static
       
   264     **/
       
   265     abort: function (transaction) {
       
   266         var i, id, item, len, pending;
       
   267 
       
   268         Y.log('`Y.Get.abort()` is deprecated as of 3.5.0. Use the `abort()` method on the transaction instead.', 'warn', 'get');
       
   269 
       
   270         if (!transaction.abort) {
       
   271             id          = transaction;
       
   272             pending     = this._pending;
       
   273             transaction = null;
       
   274 
       
   275             if (pending && pending.transaction.id === id) {
       
   276                 transaction   = pending.transaction;
       
   277                 this._pending = null;
       
   278             } else {
       
   279                 for (i = 0, len = this._queue.length; i < len; ++i) {
       
   280                     item = this._queue[i].transaction;
       
   281 
       
   282                     if (item.id === id) {
       
   283                         transaction = item;
       
   284                         this._queue.splice(i, 1);
       
   285                         break;
       
   286                     }
       
   287                 }
       
   288             }
       
   289         }
       
   290 
       
   291         transaction && transaction.abort();
       
   292     },
       
   293 
       
   294     /**
       
   295     Loads one or more CSS files.
       
   296 
       
   297     The _urls_ parameter may be provided as a URL string, a request object,
       
   298     or an array of URL strings and/or request objects.
       
   299 
       
   300     A request object is just an object that contains a `url` property and zero
       
   301     or more options that should apply specifically to that request.
       
   302     Request-specific options take priority over transaction-level options and
       
   303     default options.
       
   304 
       
   305     URLs may be relative or absolute, and do not have to have the same origin
       
   306     as the current page.
       
   307 
       
   308     The `options` parameter may be omitted completely and a callback passed in
       
   309     its place, if desired.
       
   310 
       
   311     @example
       
   312 
       
   313         // Load a single CSS file and log a message on completion.
       
   314         Y.Get.css('foo.css', function (err) {
       
   315             if (err) {
       
   316                 Y.log('foo.css failed to load!');
       
   317             } else {
       
   318                 Y.log('foo.css was loaded successfully');
       
   319             }
       
   320         });
       
   321 
       
   322         // Load multiple CSS files and log a message when all have finished
       
   323         // loading.
       
   324         var urls = ['foo.css', 'http://example.com/bar.css', 'baz/quux.css'];
       
   325 
       
   326         Y.Get.css(urls, function (err) {
       
   327             if (err) {
       
   328                 Y.log('one or more files failed to load!');
       
   329             } else {
       
   330                 Y.log('all files loaded successfully');
       
   331             }
       
   332         });
       
   333 
       
   334         // Specify transaction-level options, which will apply to all requests
       
   335         // within the transaction.
       
   336         Y.Get.css(urls, {
       
   337             attributes: {'class': 'my-css'},
       
   338             timeout   : 5000
       
   339         });
       
   340 
       
   341         // Specify per-request options, which override transaction-level and
       
   342         // default options.
       
   343         Y.Get.css([
       
   344             {url: 'foo.css', attributes: {id: 'foo'}},
       
   345             {url: 'bar.css', attributes: {id: 'bar', charset: 'iso-8859-1'}}
       
   346         ]);
       
   347 
       
   348     @method css
       
   349     @param {String|Object|Array} urls URL string, request object, or array
       
   350         of URLs and/or request objects to load.
       
   351     @param {Object} [options] Options for this transaction. See the
       
   352         `Y.Get.options` property for a complete list of available options.
       
   353     @param {Function} [callback] Callback function to be called on completion.
       
   354         This is a general callback and will be called before any more granular
       
   355         callbacks (`onSuccess`, `onFailure`, etc.) specified in the `options`
       
   356         object.
       
   357 
       
   358         @param {Array|null} callback.err Array of errors that occurred during
       
   359             the transaction, or `null` on success.
       
   360         @param {Get.Transaction} callback.transaction Transaction object.
       
   361 
       
   362     @return {Get.Transaction} Transaction object.
       
   363     @static
       
   364     **/
       
   365     css: function (urls, options, callback) {
       
   366         return this._load('css', urls, options, callback);
       
   367     },
       
   368 
       
   369     /**
       
   370     Loads one or more JavaScript resources.
       
   371 
       
   372     The _urls_ parameter may be provided as a URL string, a request object,
       
   373     or an array of URL strings and/or request objects.
       
   374 
       
   375     A request object is just an object that contains a `url` property and zero
       
   376     or more options that should apply specifically to that request.
       
   377     Request-specific options take priority over transaction-level options and
       
   378     default options.
       
   379 
       
   380     URLs may be relative or absolute, and do not have to have the same origin
       
   381     as the current page.
       
   382 
       
   383     The `options` parameter may be omitted completely and a callback passed in
       
   384     its place, if desired.
       
   385 
       
   386     Scripts will be executed in the order they're specified unless the `async`
       
   387     option is `true`, in which case they'll be loaded in parallel and executed
       
   388     in whatever order they finish loading.
       
   389 
       
   390     @example
       
   391 
       
   392         // Load a single JS file and log a message on completion.
       
   393         Y.Get.js('foo.js', function (err) {
       
   394             if (err) {
       
   395                 Y.log('foo.js failed to load!');
       
   396             } else {
       
   397                 Y.log('foo.js was loaded successfully');
       
   398             }
       
   399         });
       
   400 
       
   401         // Load multiple JS files, execute them in order, and log a message when
       
   402         // all have finished loading.
       
   403         var urls = ['foo.js', 'http://example.com/bar.js', 'baz/quux.js'];
       
   404 
       
   405         Y.Get.js(urls, function (err) {
       
   406             if (err) {
       
   407                 Y.log('one or more files failed to load!');
       
   408             } else {
       
   409                 Y.log('all files loaded successfully');
       
   410             }
       
   411         });
       
   412 
       
   413         // Specify transaction-level options, which will apply to all requests
       
   414         // within the transaction.
       
   415         Y.Get.js(urls, {
       
   416             attributes: {'class': 'my-js'},
       
   417             timeout   : 5000
       
   418         });
       
   419 
       
   420         // Specify per-request options, which override transaction-level and
       
   421         // default options.
       
   422         Y.Get.js([
       
   423             {url: 'foo.js', attributes: {id: 'foo'}},
       
   424             {url: 'bar.js', attributes: {id: 'bar', charset: 'iso-8859-1'}}
       
   425         ]);
       
   426 
       
   427     @method js
       
   428     @param {String|Object|Array} urls URL string, request object, or array
       
   429         of URLs and/or request objects to load.
       
   430     @param {Object} [options] Options for this transaction. See the
       
   431         `Y.Get.options` property for a complete list of available options.
       
   432     @param {Function} [callback] Callback function to be called on completion.
       
   433         This is a general callback and will be called before any more granular
       
   434         callbacks (`onSuccess`, `onFailure`, etc.) specified in the `options`
       
   435         object.
       
   436 
       
   437         @param {Array|null} callback.err Array of errors that occurred during
       
   438             the transaction, or `null` on success.
       
   439         @param {Get.Transaction} callback.transaction Transaction object.
       
   440 
       
   441     @return {Get.Transaction} Transaction object.
       
   442     @since 3.5.0
       
   443     @static
       
   444     **/
       
   445     js: function (urls, options, callback) {
       
   446         return this._load('js', urls, options, callback);
       
   447     },
       
   448 
       
   449     /**
       
   450     Loads one or more CSS and/or JavaScript resources in the same transaction.
       
   451 
       
   452     Use this method when you want to load both CSS and JavaScript in a single
       
   453     transaction and be notified when all requested URLs have finished loading,
       
   454     regardless of type.
       
   455 
       
   456     Behavior and options are the same as for the `css()` and `js()` methods. If
       
   457     a resource type isn't specified in per-request options or transaction-level
       
   458     options, Get will guess the file type based on the URL's extension (`.css`
       
   459     or `.js`, with or without a following query string). If the file type can't
       
   460     be guessed from the URL, a warning will be logged and Get will assume the
       
   461     URL is a JavaScript resource.
       
   462 
       
   463     @example
       
   464 
       
   465         // Load both CSS and JS files in a single transaction, and log a message
       
   466         // when all files have finished loading.
       
   467         Y.Get.load(['foo.css', 'bar.js', 'baz.css'], function (err) {
       
   468             if (err) {
       
   469                 Y.log('one or more files failed to load!');
       
   470             } else {
       
   471                 Y.log('all files loaded successfully');
       
   472             }
       
   473         });
       
   474 
       
   475     @method load
       
   476     @param {String|Object|Array} urls URL string, request object, or array
       
   477         of URLs and/or request objects to load.
       
   478     @param {Object} [options] Options for this transaction. See the
       
   479         `Y.Get.options` property for a complete list of available options.
       
   480     @param {Function} [callback] Callback function to be called on completion.
       
   481         This is a general callback and will be called before any more granular
       
   482         callbacks (`onSuccess`, `onFailure`, etc.) specified in the `options`
       
   483         object.
       
   484 
       
   485         @param {Array|null} err Array of errors that occurred during the
       
   486             transaction, or `null` on success.
       
   487         @param {Get.Transaction} Transaction object.
       
   488 
       
   489     @return {Get.Transaction} Transaction object.
       
   490     @since 3.5.0
       
   491     @static
       
   492     **/
       
   493     load: function (urls, options, callback) {
       
   494         return this._load(null, urls, options, callback);
       
   495     },
       
   496 
       
   497     // -- Protected Methods ----------------------------------------------------
       
   498 
       
   499     /**
       
   500     Triggers an automatic purge if the purge threshold has been reached.
       
   501 
       
   502     @method _autoPurge
       
   503     @param {Number} threshold Purge threshold to use, in milliseconds.
       
   504     @protected
       
   505     @since 3.5.0
       
   506     @static
       
   507     **/
       
   508     _autoPurge: function (threshold) {
       
   509         if (threshold && this._purgeNodes.length >= threshold) {
       
   510             Y.log('autopurge triggered after ' + this._purgeNodes.length + ' nodes', 'info', 'get');
       
   511             this._purge(this._purgeNodes);
       
   512         }
       
   513     },
       
   514 
       
   515     /**
       
   516     Populates the `_env` property with information about the current
       
   517     environment.
       
   518 
       
   519     @method _getEnv
       
   520     @return {Object} Environment information.
       
   521     @protected
       
   522     @since 3.5.0
       
   523     @static
       
   524     **/
       
   525     _getEnv: function () {
       
   526         var doc = Y.config.doc,
       
   527             ua  = Y.UA;
       
   528 
       
   529         // Note: some of these checks require browser sniffs since it's not
       
   530         // feasible to load test files on every pageview just to perform a
       
   531         // feature test. I'm sorry if this makes you sad.
       
   532         return (this._env = {
       
   533 
       
   534             // True if this is a browser that supports disabling async mode on
       
   535             // dynamically created script nodes. See
       
   536             // https://developer.mozilla.org/En/HTML/Element/Script#Attributes
       
   537 
       
   538             // IE10 doesn't return true for the MDN feature test, so setting it explicitly,
       
   539             // because it is async by default, and allows you to disable async by setting it to false
       
   540             async: (doc && doc.createElement('script').async === true) || (ua.ie >= 10),
       
   541 
       
   542             // True if this browser fires an event when a dynamically injected
       
   543             // link node fails to load. This is currently true for Firefox 9+
       
   544             // and WebKit 535.24+
       
   545             cssFail: ua.gecko >= 9 || ua.compareVersions(ua.webkit, 535.24) >= 0,
       
   546 
       
   547             // True if this browser fires an event when a dynamically injected
       
   548             // link node finishes loading. This is currently true for IE, Opera,
       
   549             // Firefox 9+, and WebKit 535.24+. Note that IE versions <9 fire the
       
   550             // DOM 0 "onload" event, but not "load". All versions of IE fire
       
   551             // "onload".
       
   552             // davglass: Seems that Chrome on Android needs this to be false.
       
   553             cssLoad: (
       
   554                     (!ua.gecko && !ua.webkit) || ua.gecko >= 9 ||
       
   555                     ua.compareVersions(ua.webkit, 535.24) >= 0
       
   556                 ) && !(ua.chrome && ua.chrome <= 18),
       
   557 
       
   558             // True if this browser preserves script execution order while
       
   559             // loading scripts in parallel as long as the script node's `async`
       
   560             // attribute is set to false to explicitly disable async execution.
       
   561             preservesScriptOrder: !!(ua.gecko || ua.opera || (ua.ie && ua.ie >= 10))
       
   562         });
       
   563     },
       
   564 
       
   565     _getTransaction: function (urls, options) {
       
   566         var requests = [],
       
   567             i, len, req, url;
       
   568 
       
   569         if (!Lang.isArray(urls)) {
       
   570             urls = [urls];
       
   571         }
       
   572 
       
   573         options = Y.merge(this.options, options);
       
   574 
       
   575         // Clone the attributes object so we don't end up modifying it by ref.
       
   576         options.attributes = Y.merge(this.options.attributes,
       
   577                 options.attributes);
       
   578 
       
   579         for (i = 0, len = urls.length; i < len; ++i) {
       
   580             url = urls[i];
       
   581             req = {attributes: {}};
       
   582 
       
   583             // If `url` is a string, we create a URL object for it, then mix in
       
   584             // global options and request-specific options. If it's an object
       
   585             // with a "url" property, we assume it's a request object containing
       
   586             // URL-specific options.
       
   587             if (typeof url === 'string') {
       
   588                 req.url = url;
       
   589             } else if (url.url) {
       
   590                 // URL-specific options override both global defaults and
       
   591                 // request-specific options.
       
   592                 Y.mix(req, url, false, null, 0, true);
       
   593                 url = url.url; // Make url a string so we can use it later.
       
   594             } else {
       
   595                 Y.log('URL must be a string or an object with a `url` property.', 'error', 'get');
       
   596                 continue;
       
   597             }
       
   598 
       
   599             Y.mix(req, options, false, null, 0, true);
       
   600 
       
   601             // If we didn't get an explicit type for this URL either in the
       
   602             // request options or the URL-specific options, try to determine
       
   603             // one from the file extension.
       
   604             if (!req.type) {
       
   605                 if (this.REGEX_CSS.test(url)) {
       
   606                     req.type = 'css';
       
   607                 } else {
       
   608                     if (!this.REGEX_JS.test(url)) {
       
   609                         Y.log("Can't guess file type from URL. Assuming JS: " + url, 'warn', 'get');
       
   610                     }
       
   611 
       
   612                     req.type = 'js';
       
   613                 }
       
   614             }
       
   615 
       
   616             // Mix in type-specific default options, but don't overwrite any
       
   617             // options that have already been set.
       
   618             Y.mix(req, req.type === 'js' ? this.jsOptions : this.cssOptions,
       
   619                 false, null, 0, true);
       
   620 
       
   621             // Give the node an id attribute if it doesn't already have one.
       
   622             req.attributes.id || (req.attributes.id = Y.guid());
       
   623 
       
   624             // Backcompat for <3.5.0 behavior.
       
   625             if (req.win) {
       
   626                 Y.log('The `win` option is deprecated as of 3.5.0. Use `doc` instead.', 'warn', 'get');
       
   627                 req.doc = req.win.document;
       
   628             } else {
       
   629                 req.win = req.doc.defaultView || req.doc.parentWindow;
       
   630             }
       
   631 
       
   632             if (req.charset) {
       
   633                 Y.log('The `charset` option is deprecated as of 3.5.0. Set `attributes.charset` instead.', 'warn', 'get');
       
   634                 req.attributes.charset = req.charset;
       
   635             }
       
   636 
       
   637             requests.push(req);
       
   638         }
       
   639 
       
   640         return new Transaction(requests, options);
       
   641     },
       
   642 
       
   643     _load: function (type, urls, options, callback) {
       
   644         var transaction;
       
   645 
       
   646         // Allow callback as third param.
       
   647         if (typeof options === 'function') {
       
   648             callback = options;
       
   649             options  = {};
       
   650         }
       
   651 
       
   652         options || (options = {});
       
   653         options.type = type;
       
   654 
       
   655         options._onFinish = Get._onTransactionFinish;
       
   656 
       
   657         if (!this._env) {
       
   658             this._getEnv();
       
   659         }
       
   660 
       
   661         transaction = this._getTransaction(urls, options);
       
   662 
       
   663         this._queue.push({
       
   664             callback   : callback,
       
   665             transaction: transaction
       
   666         });
       
   667 
       
   668         this._next();
       
   669 
       
   670         return transaction;
       
   671     },
       
   672 
       
   673     _onTransactionFinish : function() {
       
   674         Get._pending = null;
       
   675         Get._next();
       
   676     },
       
   677 
       
   678     _next: function () {
       
   679         var item;
       
   680 
       
   681         if (this._pending) {
       
   682             return;
       
   683         }
       
   684 
       
   685         item = this._queue.shift();
       
   686 
       
   687         if (item) {
       
   688             this._pending = item;
       
   689             item.transaction.execute(item.callback);
       
   690         }
       
   691     },
       
   692 
       
   693     _purge: function (nodes) {
       
   694         var purgeNodes    = this._purgeNodes,
       
   695             isTransaction = nodes !== purgeNodes,
       
   696             index, node;
       
   697 
       
   698         while (node = nodes.pop()) { // assignment
       
   699             // Don't purge nodes that haven't finished loading (or errored out),
       
   700             // since this can hang the transaction.
       
   701             if (!node._yuiget_finished) {
       
   702                 continue;
       
   703             }
       
   704 
       
   705             node.parentNode && node.parentNode.removeChild(node);
       
   706 
       
   707             // If this is a transaction-level purge and this node also exists in
       
   708             // the Get-level _purgeNodes array, we need to remove it from
       
   709             // _purgeNodes to avoid creating a memory leak. The indexOf lookup
       
   710             // sucks, but until we get WeakMaps, this is the least troublesome
       
   711             // way to do this (we can't just hold onto node ids because they may
       
   712             // not be in the same document).
       
   713             if (isTransaction) {
       
   714                 index = Y.Array.indexOf(purgeNodes, node);
       
   715 
       
   716                 if (index > -1) {
       
   717                     purgeNodes.splice(index, 1);
       
   718                 }
       
   719             }
       
   720         }
       
   721     }
       
   722 };
       
   723 
       
   724 /**
       
   725 Alias for `js()`.
       
   726 
       
   727 @method script
       
   728 @static
       
   729 **/
       
   730 Get.script = Get.js;
       
   731 
       
   732 /**
       
   733 Represents a Get transaction, which may contain requests for one or more JS or
       
   734 CSS files.
       
   735 
       
   736 This class should not be instantiated manually. Instances will be created and
       
   737 returned as needed by Y.Get's `css()`, `js()`, and `load()` methods.
       
   738 
       
   739 @class Get.Transaction
       
   740 @constructor
       
   741 @since 3.5.0
       
   742 **/
       
   743 Get.Transaction = Transaction = function (requests, options) {
       
   744     var self = this;
       
   745 
       
   746     self.id       = Transaction._lastId += 1;
       
   747     self.data     = options.data;
       
   748     self.errors   = [];
       
   749     self.nodes    = [];
       
   750     self.options  = options;
       
   751     self.requests = requests;
       
   752 
       
   753     self._callbacks = []; // callbacks to call after execution finishes
       
   754     self._queue     = [];
       
   755     self._reqsWaiting   = 0;
       
   756 
       
   757     // Deprecated pre-3.5.0 properties.
       
   758     self.tId = self.id; // Use `id` instead.
       
   759     self.win = options.win || Y.config.win;
       
   760 };
       
   761 
       
   762 /**
       
   763 Arbitrary data object associated with this transaction.
       
   764 
       
   765 This object comes from the options passed to `Get.css()`, `Get.js()`, or
       
   766 `Get.load()`, and will be `undefined` if no data object was specified.
       
   767 
       
   768 @property {Object} data
       
   769 **/
       
   770 
       
   771 /**
       
   772 Array of errors that have occurred during this transaction, if any.
       
   773 
       
   774 @since 3.5.0
       
   775 @property {Object[]} errors
       
   776 @property {String} errors.error Error message.
       
   777 @property {Object} errors.request Request object related to the error.
       
   778 **/
       
   779 
       
   780 /**
       
   781 Numeric id for this transaction, unique among all transactions within the same
       
   782 YUI sandbox in the current pageview.
       
   783 
       
   784 @property {Number} id
       
   785 @since 3.5.0
       
   786 **/
       
   787 
       
   788 /**
       
   789 HTMLElement nodes (native ones, not YUI Node instances) that have been inserted
       
   790 during the current transaction.
       
   791 
       
   792 @property {HTMLElement[]} nodes
       
   793 **/
       
   794 
       
   795 /**
       
   796 Options associated with this transaction.
       
   797 
       
   798 See `Get.options` for the full list of available options.
       
   799 
       
   800 @property {Object} options
       
   801 @since 3.5.0
       
   802 **/
       
   803 
       
   804 /**
       
   805 Request objects contained in this transaction. Each request object represents
       
   806 one CSS or JS URL that will be (or has been) requested and loaded into the page.
       
   807 
       
   808 @property {Object} requests
       
   809 @since 3.5.0
       
   810 **/
       
   811 
       
   812 /**
       
   813 Id of the most recent transaction.
       
   814 
       
   815 @property _lastId
       
   816 @type Number
       
   817 @protected
       
   818 @static
       
   819 **/
       
   820 Transaction._lastId = 0;
       
   821 
       
   822 Transaction.prototype = {
       
   823     // -- Public Properties ----------------------------------------------------
       
   824 
       
   825     /**
       
   826     Current state of this transaction. One of "new", "executing", or "done".
       
   827 
       
   828     @property _state
       
   829     @type String
       
   830     @protected
       
   831     **/
       
   832     _state: 'new', // "new", "executing", or "done"
       
   833 
       
   834     // -- Public Methods -------------------------------------------------------
       
   835 
       
   836     /**
       
   837     Aborts this transaction.
       
   838 
       
   839     This will cause the transaction's `onFailure` callback to be called and
       
   840     will prevent any new script and link nodes from being added to the document,
       
   841     but any resources that have already been requested will continue loading
       
   842     (there's no safe way to prevent this, unfortunately).
       
   843 
       
   844     @method abort
       
   845     @param {String} [msg="Aborted."] Optional message to use in the `errors`
       
   846         array describing why the transaction was aborted.
       
   847     **/
       
   848     abort: function (msg) {
       
   849         this._pending    = null;
       
   850         this._pendingCSS = null;
       
   851         this._pollTimer  = clearTimeout(this._pollTimer);
       
   852         this._queue      = [];
       
   853         this._reqsWaiting    = 0;
       
   854 
       
   855         this.errors.push({error: msg || 'Aborted'});
       
   856         this._finish();
       
   857     },
       
   858 
       
   859     /**
       
   860     Begins execting the transaction.
       
   861 
       
   862     There's usually no reason to call this manually, since Get will call it
       
   863     automatically when other pending transactions have finished. If you really
       
   864     want to execute your transaction before Get does, you can, but be aware that
       
   865     this transaction's scripts may end up executing before the scripts in other
       
   866     pending transactions.
       
   867 
       
   868     If the transaction is already executing, the specified callback (if any)
       
   869     will be queued and called after execution finishes. If the transaction has
       
   870     already finished, the callback will be called immediately (the transaction
       
   871     will not be executed again).
       
   872 
       
   873     @method execute
       
   874     @param {Function} callback Callback function to execute after all requests
       
   875         in the transaction are complete, or after the transaction is aborted.
       
   876     **/
       
   877     execute: function (callback) {
       
   878         var self     = this,
       
   879             requests = self.requests,
       
   880             state    = self._state,
       
   881             i, len, queue, req;
       
   882 
       
   883         if (state === 'done') {
       
   884             callback && callback(self.errors.length ? self.errors : null, self);
       
   885             return;
       
   886         } else {
       
   887             callback && self._callbacks.push(callback);
       
   888 
       
   889             if (state === 'executing') {
       
   890                 return;
       
   891             }
       
   892         }
       
   893 
       
   894         self._state = 'executing';
       
   895         self._queue = queue = [];
       
   896 
       
   897         if (self.options.timeout) {
       
   898             self._timeout = setTimeout(function () {
       
   899                 self.abort('Timeout');
       
   900             }, self.options.timeout);
       
   901         }
       
   902 
       
   903         self._reqsWaiting = requests.length;
       
   904 
       
   905         for (i = 0, len = requests.length; i < len; ++i) {
       
   906             req = requests[i];
       
   907 
       
   908             if (req.async || req.type === 'css') {
       
   909                 // No need to queue CSS or fully async JS.
       
   910                 self._insert(req);
       
   911             } else {
       
   912                 queue.push(req);
       
   913             }
       
   914         }
       
   915 
       
   916         self._next();
       
   917     },
       
   918 
       
   919     /**
       
   920     Manually purges any `<script>` or `<link>` nodes this transaction has
       
   921     created.
       
   922 
       
   923     Be careful when purging a transaction that contains CSS requests, since
       
   924     removing `<link>` nodes will also remove any styles they applied.
       
   925 
       
   926     @method purge
       
   927     **/
       
   928     purge: function () {
       
   929         Get._purge(this.nodes);
       
   930     },
       
   931 
       
   932     // -- Protected Methods ----------------------------------------------------
       
   933     _createNode: function (name, attrs, doc) {
       
   934         var node = doc.createElement(name),
       
   935             attr, testEl;
       
   936 
       
   937         if (!CUSTOM_ATTRS) {
       
   938             // IE6 and IE7 expect property names rather than attribute names for
       
   939             // certain attributes. Rather than sniffing, we do a quick feature
       
   940             // test the first time _createNode() runs to determine whether we
       
   941             // need to provide a workaround.
       
   942             testEl = doc.createElement('div');
       
   943             testEl.setAttribute('class', 'a');
       
   944 
       
   945             CUSTOM_ATTRS = testEl.className === 'a' ? {} : {
       
   946                 'for'  : 'htmlFor',
       
   947                 'class': 'className'
       
   948             };
       
   949         }
       
   950 
       
   951         for (attr in attrs) {
       
   952             if (attrs.hasOwnProperty(attr)) {
       
   953                 node.setAttribute(CUSTOM_ATTRS[attr] || attr, attrs[attr]);
       
   954             }
       
   955         }
       
   956 
       
   957         return node;
       
   958     },
       
   959 
       
   960     _finish: function () {
       
   961         var errors  = this.errors.length ? this.errors : null,
       
   962             options = this.options,
       
   963             thisObj = options.context || this,
       
   964             data, i, len;
       
   965 
       
   966         if (this._state === 'done') {
       
   967             return;
       
   968         }
       
   969 
       
   970         this._state = 'done';
       
   971 
       
   972         for (i = 0, len = this._callbacks.length; i < len; ++i) {
       
   973             this._callbacks[i].call(thisObj, errors, this);
       
   974         }
       
   975 
       
   976         data = this._getEventData();
       
   977 
       
   978         if (errors) {
       
   979             if (options.onTimeout && errors[errors.length - 1].error === 'Timeout') {
       
   980                 options.onTimeout.call(thisObj, data);
       
   981             }
       
   982 
       
   983             if (options.onFailure) {
       
   984                 options.onFailure.call(thisObj, data);
       
   985             }
       
   986         } else if (options.onSuccess) {
       
   987             options.onSuccess.call(thisObj, data);
       
   988         }
       
   989 
       
   990         if (options.onEnd) {
       
   991             options.onEnd.call(thisObj, data);
       
   992         }
       
   993 
       
   994         if (options._onFinish) {
       
   995             options._onFinish();
       
   996         }
       
   997     },
       
   998 
       
   999     _getEventData: function (req) {
       
  1000         if (req) {
       
  1001             // This merge is necessary for backcompat. I hate it.
       
  1002             return Y.merge(this, {
       
  1003                 abort  : this.abort, // have to copy these because the prototype isn't preserved
       
  1004                 purge  : this.purge,
       
  1005                 request: req,
       
  1006                 url    : req.url,
       
  1007                 win    : req.win
       
  1008             });
       
  1009         } else {
       
  1010             return this;
       
  1011         }
       
  1012     },
       
  1013 
       
  1014     _getInsertBefore: function (req) {
       
  1015         var doc = req.doc,
       
  1016             el  = req.insertBefore,
       
  1017             cache, docStamp;
       
  1018 
       
  1019         if (el) {
       
  1020             return typeof el === 'string' ? doc.getElementById(el) : el;
       
  1021         }
       
  1022 
       
  1023         cache    = Get._insertCache;
       
  1024         docStamp = Y.stamp(doc);
       
  1025 
       
  1026         if ((el = cache[docStamp])) { // assignment
       
  1027             return el;
       
  1028         }
       
  1029 
       
  1030         // Inserting before a <base> tag apparently works around an IE bug
       
  1031         // (according to a comment from pre-3.5.0 Y.Get), but I'm not sure what
       
  1032         // bug that is, exactly. Better safe than sorry?
       
  1033         if ((el = doc.getElementsByTagName('base')[0])) { // assignment
       
  1034             return (cache[docStamp] = el);
       
  1035         }
       
  1036 
       
  1037         // Look for a <head> element.
       
  1038         el = doc.head || doc.getElementsByTagName('head')[0];
       
  1039 
       
  1040         if (el) {
       
  1041             // Create a marker node at the end of <head> to use as an insertion
       
  1042             // point. Inserting before this node will ensure that all our CSS
       
  1043             // gets inserted in the correct order, to maintain style precedence.
       
  1044             el.appendChild(doc.createTextNode(''));
       
  1045             return (cache[docStamp] = el.lastChild);
       
  1046         }
       
  1047 
       
  1048         // If all else fails, just insert before the first script node on the
       
  1049         // page, which is virtually guaranteed to exist.
       
  1050         return (cache[docStamp] = doc.getElementsByTagName('script')[0]);
       
  1051     },
       
  1052 
       
  1053     _insert: function (req) {
       
  1054         var env          = Get._env,
       
  1055             insertBefore = this._getInsertBefore(req),
       
  1056             isScript     = req.type === 'js',
       
  1057             node         = req.node,
       
  1058             self         = this,
       
  1059             ua           = Y.UA,
       
  1060             cssTimeout, nodeType;
       
  1061 
       
  1062         if (!node) {
       
  1063             if (isScript) {
       
  1064                 nodeType = 'script';
       
  1065             } else if (!env.cssLoad && ua.gecko) {
       
  1066                 nodeType = 'style';
       
  1067             } else {
       
  1068                 nodeType = 'link';
       
  1069             }
       
  1070 
       
  1071             node = req.node = this._createNode(nodeType, req.attributes,
       
  1072                 req.doc);
       
  1073         }
       
  1074 
       
  1075         function onError() {
       
  1076             self._progress('Failed to load ' + req.url, req);
       
  1077         }
       
  1078 
       
  1079         function onLoad() {
       
  1080             if (cssTimeout) {
       
  1081                 clearTimeout(cssTimeout);
       
  1082             }
       
  1083 
       
  1084             self._progress(null, req);
       
  1085         }
       
  1086 
       
  1087         // Deal with script asynchronicity.
       
  1088         if (isScript) {
       
  1089             node.setAttribute('src', req.url);
       
  1090 
       
  1091             if (req.async) {
       
  1092                 // Explicitly indicate that we want the browser to execute this
       
  1093                 // script asynchronously. This is necessary for older browsers
       
  1094                 // like Firefox <4.
       
  1095                 node.async = true;
       
  1096             } else {
       
  1097                 if (env.async) {
       
  1098                     // This browser treats injected scripts as async by default
       
  1099                     // (standard HTML5 behavior) but asynchronous loading isn't
       
  1100                     // desired, so tell the browser not to mark this script as
       
  1101                     // async.
       
  1102                     node.async = false;
       
  1103                 }
       
  1104 
       
  1105                 // If this browser doesn't preserve script execution order based
       
  1106                 // on insertion order, we'll need to avoid inserting other
       
  1107                 // scripts until this one finishes loading.
       
  1108                 if (!env.preservesScriptOrder) {
       
  1109                     this._pending = req;
       
  1110                 }
       
  1111             }
       
  1112         } else {
       
  1113             if (!env.cssLoad && ua.gecko) {
       
  1114                 // In Firefox <9, we can import the requested URL into a <style>
       
  1115                 // node and poll for the existence of node.sheet.cssRules. This
       
  1116                 // gives us a reliable way to determine CSS load completion that
       
  1117                 // also works for cross-domain stylesheets.
       
  1118                 //
       
  1119                 // Props to Zach Leatherman for calling my attention to this
       
  1120                 // technique.
       
  1121                 node.innerHTML = (req.attributes.charset ?
       
  1122                     '@charset "' + req.attributes.charset + '";' : '') +
       
  1123                     '@import "' + req.url + '";';
       
  1124             } else {
       
  1125                 node.setAttribute('href', req.url);
       
  1126             }
       
  1127         }
       
  1128 
       
  1129         // Inject the node.
       
  1130         if (isScript && ua.ie && (ua.ie < 9 || (document.documentMode && document.documentMode < 9))) {
       
  1131             // Script on IE < 9, and IE 9+ when in IE 8 or older modes, including quirks mode.
       
  1132             node.onreadystatechange = function () {
       
  1133                 if (/loaded|complete/.test(node.readyState)) {
       
  1134                     node.onreadystatechange = null;
       
  1135                     onLoad();
       
  1136                 }
       
  1137             };
       
  1138         } else if (!isScript && !env.cssLoad) {
       
  1139             // CSS on Firefox <9 or WebKit.
       
  1140             this._poll(req);
       
  1141         } else {
       
  1142             // Script or CSS on everything else. Using DOM 0 events because that
       
  1143             // evens the playing field with older IEs.
       
  1144 
       
  1145             if (ua.ie >= 10) {
       
  1146 
       
  1147                 // We currently need to introduce a timeout for IE10, since it
       
  1148                 // calls onerror/onload synchronously for 304s - messing up existing
       
  1149                 // program flow.
       
  1150 
       
  1151                 // Remove this block if the following bug gets fixed by GA
       
  1152                 /*jshint maxlen: 1500 */
       
  1153                 // https://connect.microsoft.com/IE/feedback/details/763871/dynamically-loaded-scripts-with-304s-responses-interrupt-the-currently-executing-js-thread-onload
       
  1154                 node.onerror = function() { setTimeout(onError, 0); };
       
  1155                 node.onload  = function() { setTimeout(onLoad, 0); };
       
  1156             } else {
       
  1157                 node.onerror = onError;
       
  1158                 node.onload  = onLoad;
       
  1159             }
       
  1160 
       
  1161             // If this browser doesn't fire an event when CSS fails to load,
       
  1162             // fail after a timeout to avoid blocking the transaction queue.
       
  1163             if (!env.cssFail && !isScript) {
       
  1164                 cssTimeout = setTimeout(onError, req.timeout || 3000);
       
  1165             }
       
  1166         }
       
  1167 
       
  1168         this.nodes.push(node);
       
  1169         insertBefore.parentNode.insertBefore(node, insertBefore);
       
  1170     },
       
  1171 
       
  1172     _next: function () {
       
  1173         if (this._pending) {
       
  1174             return;
       
  1175         }
       
  1176 
       
  1177         // If there are requests in the queue, insert the next queued request.
       
  1178         // Otherwise, if we're waiting on already-inserted requests to finish,
       
  1179         // wait longer. If there are no queued requests and we're not waiting
       
  1180         // for anything to load, then we're done!
       
  1181         if (this._queue.length) {
       
  1182             this._insert(this._queue.shift());
       
  1183         } else if (!this._reqsWaiting) {
       
  1184             this._finish();
       
  1185         }
       
  1186     },
       
  1187 
       
  1188     _poll: function (newReq) {
       
  1189         var self       = this,
       
  1190             pendingCSS = self._pendingCSS,
       
  1191             isWebKit   = Y.UA.webkit,
       
  1192             i, hasRules, j, nodeHref, req, sheets;
       
  1193 
       
  1194         if (newReq) {
       
  1195             pendingCSS || (pendingCSS = self._pendingCSS = []);
       
  1196             pendingCSS.push(newReq);
       
  1197 
       
  1198             if (self._pollTimer) {
       
  1199                 // A poll timeout is already pending, so no need to create a
       
  1200                 // new one.
       
  1201                 return;
       
  1202             }
       
  1203         }
       
  1204 
       
  1205         self._pollTimer = null;
       
  1206 
       
  1207         // Note: in both the WebKit and Gecko hacks below, a CSS URL that 404s
       
  1208         // will still be treated as a success. There's no good workaround for
       
  1209         // this.
       
  1210 
       
  1211         for (i = 0; i < pendingCSS.length; ++i) {
       
  1212             req = pendingCSS[i];
       
  1213 
       
  1214             if (isWebKit) {
       
  1215                 // Look for a stylesheet matching the pending URL.
       
  1216                 sheets   = req.doc.styleSheets;
       
  1217                 j        = sheets.length;
       
  1218                 nodeHref = req.node.href;
       
  1219 
       
  1220                 while (--j >= 0) {
       
  1221                     if (sheets[j].href === nodeHref) {
       
  1222                         pendingCSS.splice(i, 1);
       
  1223                         i -= 1;
       
  1224                         self._progress(null, req);
       
  1225                         break;
       
  1226                     }
       
  1227                 }
       
  1228             } else {
       
  1229                 // Many thanks to Zach Leatherman for calling my attention to
       
  1230                 // the @import-based cross-domain technique used here, and to
       
  1231                 // Oleg Slobodskoi for an earlier same-domain implementation.
       
  1232                 //
       
  1233                 // See Zach's blog for more details:
       
  1234                 // http://www.zachleat.com/web/2010/07/29/load-css-dynamically/
       
  1235                 try {
       
  1236                     // We don't really need to store this value since we never
       
  1237                     // use it again, but if we don't store it, Closure Compiler
       
  1238                     // assumes the code is useless and removes it.
       
  1239                     hasRules = !!req.node.sheet.cssRules;
       
  1240 
       
  1241                     // If we get here, the stylesheet has loaded.
       
  1242                     pendingCSS.splice(i, 1);
       
  1243                     i -= 1;
       
  1244                     self._progress(null, req);
       
  1245                 } catch (ex) {
       
  1246                     // An exception means the stylesheet is still loading.
       
  1247                 }
       
  1248             }
       
  1249         }
       
  1250 
       
  1251         if (pendingCSS.length) {
       
  1252             self._pollTimer = setTimeout(function () {
       
  1253                 self._poll.call(self);
       
  1254             }, self.options.pollInterval);
       
  1255         }
       
  1256     },
       
  1257 
       
  1258     _progress: function (err, req) {
       
  1259         var options = this.options;
       
  1260 
       
  1261         if (err) {
       
  1262             req.error = err;
       
  1263 
       
  1264             this.errors.push({
       
  1265                 error  : err,
       
  1266                 request: req
       
  1267             });
       
  1268 
       
  1269             Y.log(err, 'error', 'get');
       
  1270         }
       
  1271 
       
  1272         req.node._yuiget_finished = req.finished = true;
       
  1273 
       
  1274         if (options.onProgress) {
       
  1275             options.onProgress.call(options.context || this,
       
  1276                 this._getEventData(req));
       
  1277         }
       
  1278 
       
  1279         if (req.autopurge) {
       
  1280             // Pre-3.5.0 Get always excludes the most recent node from an
       
  1281             // autopurge. I find this odd, but I'm keeping that behavior for
       
  1282             // the sake of backcompat.
       
  1283             Get._autoPurge(this.options.purgethreshold);
       
  1284             Get._purgeNodes.push(req.node);
       
  1285         }
       
  1286 
       
  1287         if (this._pending === req) {
       
  1288             this._pending = null;
       
  1289         }
       
  1290 
       
  1291         this._reqsWaiting -= 1;
       
  1292 
       
  1293         this._next();
       
  1294     }
       
  1295 };
       
  1296 
       
  1297 
       
  1298 }, '@VERSION@', {"requires": ["yui-base"]});