text: /*
  Copyright (c) 2010, Yahoo! Inc. All rights reserved.
  Code licensed under the BSD License:
  http://developer.yahoo.com/yui/license.html
  version: 3.4.0
  build: nightly
  */
  YUI.add('get', function(Y) {
  
  /**
   * Provides a mechanism to fetch remote resources and
   * insert them into a document.
   * @module yui
   * @submodule get
   */
  
  /**
   * Fetches and inserts one or more script or link nodes into the document
   * @class Get
   * @static
   */
  
  var ua = Y.UA,
      L = Y.Lang,
      TYPE_JS = 'text/javascript',
      TYPE_CSS = 'text/css',
      STYLESHEET = 'stylesheet',
      SCRIPT = 'script',
      AUTOPURGE = 'autopurge',
      UTF8 = 'utf-8',
      LINK = 'link',
      ASYNC = 'async',
      ALL = true,
  
      // FireFox does not support the onload event for link nodes, so
      // there is no way to make the css requests synchronous. This means
      // that the css rules in multiple files could be applied out of order
      // in this browser if a later request returns before an earlier one.
  
      // Safari too.
  
      ONLOAD_SUPPORTED = {
          script: ALL,
          css: !(ua.webkit || ua.gecko)
      },
  
      /**
       * hash of queues to manage multiple requests
       * @property queues
       * @private
       */
      queues = {},
  
      /**
       * queue index used to generate transaction ids
       * @property qidx
       * @type int
       * @private
       */
      qidx = 0,
  
      /**
       * interal property used to prevent multiple simultaneous purge
       * processes
       * @property purging
       * @type boolean
       * @private
       */
      purging,
  
      /**
       * Clear timeout state 
       * 
       * @method _clearTimeout
       * @param {Object} q Queue data
       * @private
       */
      _clearTimeout = function(q) {
          var timer = q.timer;
          if (timer) {
              clearTimeout(timer);
              q.timer = null;
          }
      },
  
      /**
       * Generates an HTML element, this is not appended to a document
       * @method _node
       * @param {string} type the type of element.
       * @param {Object} attr the fixed set of attribute for the type.
       * @param {Object} custAttrs optional Any custom attributes provided by the user.
       * @param {Window} win optional window to create the element in.
       * @return {HTMLElement} the generated node.
       * @private
       */
      _node = function(type, attr, custAttrs, win) {
          var w = win || Y.config.win,
              d = w.document,
              n = d.createElement(type),
              i;
  
          if (custAttrs) {
              Y.mix(attr, custAttrs);
          }
  
          for (i in attr) {
              if (attr[i] && attr.hasOwnProperty(i)) {
                  n.setAttribute(i, attr[i]);
              }
          }
  
          return n;
      },
  
      /**
       * Generates a link node
       * @method _linkNode
       * @param {string} url the url for the css file.
       * @param {Window} win optional window to create the node in.
       * @param {object} attributes optional attributes collection to apply to the
       * new node.
       * @return {HTMLElement} the generated node.
       * @private
       */
      _linkNode = function(url, win, attributes) {
          return _node(LINK, {
                          id: Y.guid(),
                          type: TYPE_CSS,
                          rel: STYLESHEET,
                          href: url
                      }, attributes, win);
      },
  
      /**
       * Generates a script node
       * @method _scriptNode
       * @param {string} url the url for the script file.
       * @param {Window} win optional window to create the node in.
       * @param {object} attributes optional attributes collection to apply to the
       * new node.
       * @return {HTMLElement} the generated node.
       * @private
       */
      _scriptNode = function(url, win, attributes) {
          return _node(SCRIPT, {
                          id: Y.guid(),
                          type: TYPE_JS,
                          src: url
                      }, attributes, win);
      },
  
      /**
       * Returns the data payload for callback functions.
       * @method _returnData
       * @param {object} q the queue.
       * @param {string} msg the result message.
       * @param {string} result the status message from the request.
       * @return {object} the state data from the request.
       * @private
       */
      _returnData = function(q, msg, result) {
          return {
              tId: q.tId,
              win: q.win,
              data: q.data,
              nodes: q.nodes,
              msg: msg,
              statusText: result,
  
              purge: function() {
                  _purge(this.tId);
              }
          };
      },
  
      /**
       * The transaction is finished
       * @method _end
       * @param {string} id the id of the request.
       * @param {string} msg the result message.
       * @param {string} result the status message from the request.
       * @private
       */
      _end = function(id, msg, result) {
          var q = queues[id],
              onEnd = q && q.onEnd;
  
          q.finished = true;
  
          if (onEnd) {
              onEnd.call(q.context, _returnData(q, msg, result));
          }
      },
  
      /**
       * The request failed, execute fail handler with whatever
       * was accomplished.  There isn't a failure case at the
       * moment unless you count aborted transactions
       * @method _fail
       * @param {string} id the id of the request
       * @private
       */
      _fail = function(id, msg) {
  
          var q = queues[id],
              onFailure = q.onFailure;
  
          _clearTimeout(q);
  
          if (onFailure) {
              onFailure.call(q.context, _returnData(q, msg));
          }
  
          _end(id, msg, 'failure');
      },
  
  
      /**
       * Abort the transaction
       * 
       * @method _abort
       * @param {Object} id
       * @private
       */
      _abort = function(id) {
          _fail(id, 'transaction ' + id + ' was aborted');
      },
  
      /**
       * The request is complete, so executing the requester's callback
       * @method _complete
       * @param {string} id the id of the request.
       * @private
       */
      _complete = function(id) {
  
          var q = queues[id],
              onSuccess = q.onSuccess;
  
          _clearTimeout(q);
  
          if (q.aborted) {
              _abort(id);
          } else {
  
              if (onSuccess) {
                  onSuccess.call(q.context, _returnData(q));
              }
  
              // 3.3.0 had undefined msg for this path.
              _end(id, undefined, 'OK');
          }
      },
  
      /**
       * Get node reference, from string
       * 
       * @method _getNodeRef
       * @param {String|HTMLElement} nId The node id to find. If an HTMLElement is passed in, it will be returned.
       * @param {String} tId Queue id, used to determine document for queue
       * @private
       */
      _getNodeRef = function(nId, tId) {
          var q = queues[tId],
              n = (L.isString(nId)) ? q.win.document.getElementById(nId) : nId;
          if (!n) {
              _fail(tId, 'target node not found: ' + nId);
          }
  
          return n;
      },
  
      /**
       * Removes the nodes for the specified queue
       * @method _purge
       * @param {string} tId the transaction id.
       * @private
       */
      _purge = function(tId) {
          var nodes, doc, parent, sibling, node, attr, insertBefore,
              i, l,
              q = queues[tId];
  
          if (q) {
              nodes = q.nodes;
              l = nodes.length;
  
              // TODO: Why is node.parentNode undefined? Which forces us To Do this...
              /*
              doc = q.win.document;
              parent = doc.getElementsByTagName('head')[0];
              insertBefore = q.insertBefore || doc.getElementsByTagName('base')[0];
  
              if (insertBefore) {
                  sibling = _getNodeRef(insertBefore, tId);
                  if (sibling) {
                      parent = sibling.parentNode;
                  }
              }
              */
  
              for (i = 0; i < l; i++) {
                  node = nodes[i];
                  parent = node.parentNode;
  
                  if (node.clearAttributes) {
                      node.clearAttributes();
                  } else {
                      // This destroys parentNode ref, so we hold onto it above first.
                      for (attr in node) {
                          if (node.hasOwnProperty(attr)) {
                              delete node[attr];
                          }
                      }
                  }
  
                  parent.removeChild(node);
              }
          }
  
          q.nodes = [];
      },
  
      /**
       * Progress callback
       * 
       * @method _progress
       * @param {string} id The id of the request.
       * @param {string} The url which just completed.
       * @private
       */
      _progress = function(id, url) {
          var q = queues[id],
              onProgress = q.onProgress,
              o;
  
          if (onProgress) {
              o = _returnData(q);
              o.url = url;
              onProgress.call(q.context, o);
          }
      },
  
      /**
       * Timeout detected
       * @method _timeout
       * @param {string} id the id of the request.
       * @private
       */
      _timeout = function(id) {
  
          var q = queues[id],
              onTimeout = q.onTimeout;
  
          if (onTimeout) {
              onTimeout.call(q.context, _returnData(q));
          }
  
          _end(id, 'timeout', 'timeout');
      },
  
      /**
       * onload callback
       * @method _loaded
       * @param {string} id the id of the request.
       * @return {string} the result.
       * @private
       */
      _loaded = function(id, url) {
  
          var q = queues[id],
              sync = (q && !q.async);
  
          if (!q) {
              return;
          }
  
          if (sync) {
              _clearTimeout(q);
          }
  
          _progress(id, url);
  
          // TODO: Cleaning up flow to have a consistent end point
  
          // !q.finished check is for the async case,
          // where scripts may still be loading when we've 
          // already aborted. Ideally there should be a single path
          // for this.
  
          if (!q.finished) { 
              if (q.aborted) {
                  _abort(id);
              } else {
                  if ((--q.remaining) === 0) {
                      _complete(id);
                  } else if (sync) {
                      _next(id);
                  }
              }
          }
      },
  
      /**
       * Detects when a node has been loaded.  In the case of
       * script nodes, this does not guarantee that contained
       * script is ready to use.
       * @method _trackLoad
       * @param {string} type the type of node to track.
       * @param {HTMLElement} n the node to track.
       * @param {string} id the id of the request.
       * @param {string} url the url that is being loaded.
       * @private
       */
      _trackLoad = function(type, n, id, url) {
  
          // TODO: Can we massage this to use ONLOAD_SUPPORTED[type]?
  
          // IE supports the readystatechange event for script and css nodes
          // Opera only for script nodes.  Opera support onload for script
          // nodes, but this doesn't fire when there is a load failure.
          // The onreadystatechange appears to be a better way to respond
          // to both success and failure.
  
          if (ua.ie) {
  
              n.onreadystatechange = function() {
                  var rs = this.readyState;
                  if ('loaded' === rs || 'complete' === rs) {
                      n.onreadystatechange = null;
                      _loaded(id, url);
                  }
              };
  
          } else if (ua.webkit) {
  
              // webkit prior to 3.x is no longer supported
              if (type === SCRIPT) {
                  // Safari 3.x supports the load event for script nodes (DOM2)
                  n.addEventListener('load', function() {
                      _loaded(id, url);
                  }, false);
              }
  
          } else {
  
              // FireFox and Opera support onload (but not DOM2 in FF) handlers for
              // script nodes. Opera, but not FF, supports the onload event for link nodes.
  
              n.onload = function() {
                  _loaded(id, url);
              };
  
              n.onerror = function(e) {
                  _fail(id, e + ': ' + url);
              };
          }
      },
  
      _insertInDoc = function(node, id, win) {
  
          // Add it to the head or insert it before 'insertBefore'.  
          // Work around IE bug if there is a base tag.
          var q = queues[id],
              doc = win.document,
              insertBefore = q.insertBefore || doc.getElementsByTagName('base')[0],
              sibling;
  
          if (insertBefore) {
              sibling = _getNodeRef(insertBefore, id);
              if (sibling) {
                  sibling.parentNode.insertBefore(node, sibling);
              }
          } else {
              // 3.3.0 assumed head is always around.
              doc.getElementsByTagName('head')[0].appendChild(node);
          }
      },
  
      /**
       * Loads the next item for a given request
       * @method _next
       * @param {string} id the id of the request.
       * @return {string} the result.
       * @private
       */
      _next = function(id) {
  
          // Assigning out here for readability
          var q = queues[id],
              type = q.type,
              attrs = q.attributes,
              win = q.win,
              timeout = q.timeout,
              node,
              url;
  
          if (q.url.length > 0) {
  
              url = q.url.shift();
  
  
              // !q.timer ensures that this only happens once for async
              if (timeout && !q.timer) {
                  q.timer = setTimeout(function() {
                      _timeout(id);
                  }, timeout);
              }
  
              if (type === SCRIPT) {
                  node = _scriptNode(url, win, attrs);
              } else {
                  node = _linkNode(url, win, attrs);
              }
  
              // add the node to the queue so we can return it in the callback 
              q.nodes.push(node);
  
              _trackLoad(type, node, id, url);
              _insertInDoc(node, id, win);
      
              if (!ONLOAD_SUPPORTED[type]) {
                  _loaded(id, url);
              }
  
              if (q.async) {
                  // For sync, the _next call is chained in _loaded 
                  _next(id);
              }
          }
      },
  
      /**
       * Removes processed queues and corresponding nodes
       * @method _autoPurge
       * @private
       */
      _autoPurge = function() {
          if (purging) {
              return;
          }
          purging = true;
  
          var i, q;
  
          for (i in queues) {
              if (queues.hasOwnProperty(i)) {
                  q = queues[i];
                  if (q.autopurge && q.finished) {
                      _purge(q.tId);
                      delete queues[i];
                  }
              }
          }
  
          purging = false;
      },
  
      /**
       * Saves the state for the request and begins loading
       * the requested urls
       * @method queue
       * @param {string} type the type of node to insert.
       * @param {string} url the url to load.
       * @param {object} opts the hash of options for this request.
       * @return {object} transaction object.
       * @private
       */
      _queue = function(type, url, opts) {
  
          opts = opts || {};
  
          var id = 'q' + (qidx++),
              thresh = opts.purgethreshold || Y.Get.PURGE_THRESH, 
              q;
  
          if (qidx % thresh === 0) {
              _autoPurge();
          }
  
          // Merge to protect opts (grandfathered in).
          q = queues[id] = Y.merge(opts);
  
          // Avoid mix, merge overhead. Known set of props.
          q.tId = id;
          q.type = type;
          q.url = url;
          q.finished = false;
          q.nodes = [];
  
          q.win = q.win || Y.config.win;
          q.context = q.context || q;
          q.autopurge = (AUTOPURGE in q) ? q.autopurge : (type === SCRIPT) ? true : false;
          q.attributes = q.attributes || {};
          q.attributes.charset = opts.charset || q.attributes.charset || UTF8;
  
          if (ASYNC in q && type === SCRIPT) {
              q.attributes.async = q.async;
          }
  
          q.url = (L.isString(q.url)) ? [q.url] : q.url;
  
          // TODO: Do we really need to account for this developer error? 
          // If the url is undefined, this is probably a trailing comma problem in IE.
          if (!q.url[0]) {
              q.url.shift();
          }
  
          q.remaining = q.url.length;
  
          _next(id);
  
          return {
              tId: id
          };
      };
  
  
  Y.Get = {
  
      /**
       * The number of request required before an automatic purge.
       * Can be configured via the 'purgethreshold' config
       * @property PURGE_THRESH
       * @static
       * @type int
       * @default 20
       * @private
       */
      PURGE_THRESH: 20,
  
      /**
       * Abort a transaction
       * @method abort
       * @static
       * @param {string|object} o Either the tId or the object returned from
       * script() or css().
       */
      abort : function(o) {
          var id = (L.isString(o)) ? o : o.tId,
              q = queues[id];
  
          if (q) {
              q.aborted = true;
          }
      },
  
      /**
       * Fetches and inserts one or more script nodes into the head
       * of the current document or the document in a specified window.
       *
       * @method script
       * @static
       * @param {string|string[]} url the url or urls to the script(s).
       * @param {object} opts Options:
       * <dl>
       * <dt>onSuccess</dt>
       * <dd>
       * callback to execute when the script(s) are finished loading
       * The callback receives an object back with the following
       * data:
       * <dl>
       * <dt>win</dt>
       * <dd>the window the script(s) were inserted into</dd>
       * <dt>data</dt>
       * <dd>the data object passed in when the request was made</dd>
       * <dt>nodes</dt>
       * <dd>An array containing references to the nodes that were
       * inserted</dd>
       * <dt>purge</dt>
       * <dd>A function that, when executed, will remove the nodes
       * that were inserted</dd>
       * <dt>
       * </dl>
       * </dd>
       * <dt>onTimeout</dt>
       * <dd>
       * callback to execute when a timeout occurs.
       * The callback receives an object back with the following
       * data:
       * <dl>
       * <dt>win</dt>
       * <dd>the window the script(s) were inserted into</dd>
       * <dt>data</dt>
       * <dd>the data object passed in when the request was made</dd>
       * <dt>nodes</dt>
       * <dd>An array containing references to the nodes that were
       * inserted</dd>
       * <dt>purge</dt>
       * <dd>A function that, when executed, will remove the nodes
       * that were inserted</dd>
       * <dt>
       * </dl>
       * </dd>
       * <dt>onEnd</dt>
       * <dd>a function that executes when the transaction finishes,
       * regardless of the exit path</dd>
       * <dt>onFailure</dt>
       * <dd>
       * callback to execute when the script load operation fails
       * The callback receives an object back with the following
       * data:
       * <dl>
       * <dt>win</dt>
       * <dd>the window the script(s) were inserted into</dd>
       * <dt>data</dt>
       * <dd>the data object passed in when the request was made</dd>
       * <dt>nodes</dt>
       * <dd>An array containing references to the nodes that were
       * inserted successfully</dd>
       * <dt>purge</dt>
       * <dd>A function that, when executed, will remove any nodes
       * that were inserted</dd>
       * <dt>
       * </dl>
       * </dd>
       * <dt>onProgress</dt>
       * <dd>callback to execute when each individual file is done loading 
       * (useful when passing in an array of js files). Receives the same
       * payload as onSuccess, with the addition of a <code>url</code> 
       * property, which identifies the file which was loaded.</dd>
       * <dt>async</dt>
       * <dd>
       * <p>When passing in an array of JS files, setting this flag to true 
       * will insert them into the document in parallel, as opposed to the 
       * default behavior, which is to chain load them serially. It will also
       * set the async attribute on the script node to true.</p> 
       * <p>Setting async:true
       * will lead to optimal file download performance allowing the browser to
       * download multiple scripts in parallel, and execute them as soon as they
       * are available.</p>  
       * <p>Note that async:true does not guarantee execution order of the 
       * scripts being downloaded. They are executed in whichever order they 
       * are received.</p>
       * </dd>
       * <dt>context</dt>
       * <dd>the execution context for the callbacks</dd>
       * <dt>win</dt>
       * <dd>a window other than the one the utility occupies</dd>
       * <dt>autopurge</dt>
       * <dd>
       * setting to true will let the utilities cleanup routine purge
       * the script once loaded
       * </dd>
       * <dt>purgethreshold</dt>
       * <dd>
       * The number of transaction before autopurge should be initiated
       * </dd>
       * <dt>data</dt>
       * <dd>
       * data that is supplied to the callback when the script(s) are
       * loaded.
       * </dd>
       * <dt>insertBefore</dt>
       * <dd>node or node id that will become the new node's nextSibling.
       * If this is not specified, nodes will be inserted before a base
       * tag should it exist.  Otherwise, the nodes will be appended to the
       * end of the document head.</dd>
       * </dl>
       * <dt>charset</dt>
       * <dd>Node charset, default utf-8 (deprecated, use the attributes
       * config)</dd>
       * <dt>attributes</dt>
       * <dd>An object literal containing additional attributes to add to
       * the link tags</dd>
       * <dt>timeout</dt>
       * <dd>Number of milliseconds to wait before aborting and firing
       * the timeout event</dd>
       * <pre>
       * &nbsp; Y.Get.script(
       * &nbsp; ["http://yui.yahooapis.com/2.5.2/build/yahoo/yahoo-min.js",
       * &nbsp;  "http://yui.yahooapis.com/2.5.2/build/event/event-min.js"],
       * &nbsp; &#123;
       * &nbsp;   onSuccess: function(o) &#123;
       * &nbsp;     this.log("won't cause error because Y is the context");
       * &nbsp;                   // immediately
       * &nbsp;   &#125;,
       * &nbsp;   onFailure: function(o) &#123;
       * &nbsp;   &#125;,
       * &nbsp;   onTimeout: function(o) &#123;
       * &nbsp;   &#125;,
       * &nbsp;   data: "foo",
       * &nbsp;   timeout: 10000, // 10 second timeout
       * &nbsp;   context: Y, // make the YUI instance
       * &nbsp;   // win: otherframe // target another window/frame
       * &nbsp;   autopurge: true // allow the utility to choose when to
       * &nbsp;                   // remove the nodes
       * &nbsp;   purgetheshold: 1 // purge previous transaction before
       * &nbsp;                    // next transaction
       * &nbsp; &#125;);.
       * </pre>
       * @return {tId: string} an object containing info about the
       * transaction.
       */
      script: function(url, opts) {
          return _queue(SCRIPT, url, opts);
      },
  
      /**
       * Fetches and inserts one or more css link nodes into the
       * head of the current document or the document in a specified
       * window.
       * @method css
       * @static
       * @param {string} url the url or urls to the css file(s).
       * @param {object} opts Options:
       * <dl>
       * <dt>onSuccess</dt>
       * <dd>
       * callback to execute when the css file(s) are finished loading
       * The callback receives an object back with the following
       * data:
       * <dl>win</dl>
       * <dd>the window the link nodes(s) were inserted into</dd>
       * <dt>data</dt>
       * <dd>the data object passed in when the request was made</dd>
       * <dt>nodes</dt>
       * <dd>An array containing references to the nodes that were
       * inserted</dd>
       * <dt>purge</dt>
       * <dd>A function that, when executed, will remove the nodes
       * that were inserted</dd>
       * <dt>
       * </dl>
       * </dd>
       * <dt>onProgress</dt>
       * <dd>callback to execute when each individual file is done loading (useful when passing in an array of css files). Receives the same
       * payload as onSuccess, with the addition of a <code>url</code> property, which identifies the file which was loaded. Currently only useful for non Webkit/Gecko browsers,
       * where onload for css is detected accurately.</dd>
       * <dt>async</dt>
       * <dd>When passing in an array of css files, setting this flag to true will insert them
       * into the document in parallel, as oppposed to the default behavior, which is to chain load them (where possible). 
       * This flag is more useful for scripts currently, since for css Get only chains if not Webkit/Gecko.</dd>
       * <dt>context</dt>
       * <dd>the execution context for the callbacks</dd>
       * <dt>win</dt>
       * <dd>a window other than the one the utility occupies</dd>
       * <dt>data</dt>
       * <dd>
       * data that is supplied to the callbacks when the nodes(s) are
       * loaded.
       * </dd>
       * <dt>insertBefore</dt>
       * <dd>node or node id that will become the new node's nextSibling</dd>
       * <dt>charset</dt>
       * <dd>Node charset, default utf-8 (deprecated, use the attributes
       * config)</dd>
       * <dt>attributes</dt>
       * <dd>An object literal containing additional attributes to add to
       * the link tags</dd>
       * </dl>
       * <pre>
       * Y.Get.css("http://localhost/css/menu.css");
       * </pre>
       * <pre>
       * &nbsp; Y.Get.css(
       * &nbsp; ["http://localhost/css/menu.css",
       * &nbsp;   insertBefore: 'custom-styles' // nodes will be inserted
       * &nbsp;                                 // before the specified node
       * &nbsp; &#125;);.
       * </pre>
       * @return {tId: string} an object containing info about the
       * transaction.
       */
      css: function(url, opts) {
          return _queue('css', url, opts);
      }
  };
  
  
  }, '3.4.0' ,{requires:['yui-base']});
  