text: /**
   * @ignore
   * function utilities of lang
   * @author yiminghe@gmail.com
   *
   */
  (function (S, undefined) {
      // ios Function.prototype.bind === undefined
      function bindFn(r, fn, obj) {
          function FNOP() {
          }
  
          var slice = [].slice,
              args = slice.call(arguments, 3),
              bound = function () {
                  var inArgs = slice.call(arguments);
                  return fn.apply(
                      this instanceof FNOP ? this :
                          // fix: y.x=S.bind(fn);
                          obj || this,
                      (r ? inArgs.concat(args) : args.concat(inArgs))
                  );
              };
          FNOP.prototype = fn.prototype;
          bound.prototype = new FNOP();
          return bound;
      }
  
      S.mix(S, {
          /**
           * empty function
           * @member KISSY
           */
          noop: function () {
          },
          /**
           * Creates a new function that, when called, itself calls this function in the context of the provided this value,
           * with a given sequence of arguments preceding any provided when the new function was called.
           * refer: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind
           * @param {Function} fn internal called function
           * @param {Object} obj context in which fn runs
           * @param {*...} var_args extra arguments
           * @member KISSY
           * @return {Function} new function with context and arguments
           */
          bind: bindFn(0, bindFn, null, 0),
  
          /**
           * Creates a new function that, when called, itself calls this function in the context of the provided this value,
           * with a given sequence of arguments preceding any provided when the new function was called.
           * refer: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind
           * @param {Function} fn internal called function
           * @param {Object} obj context in which fn runs
           * @param {*...} var_args extra arguments
           * @member KISSY
           * @return {Function} new function with context and arguments
           */
          rbind: bindFn(0, bindFn, null, 1),
  
          /**
           * Executes the supplied function in the context of the supplied
           * object 'when' milliseconds later. Executes the function a
           * single time unless periodic is set to true.
           *
           * @param fn {Function|String} the function to execute or the name of the method in
           * the 'o' object to execute.
           *
           * @param [when=0] {Number} the number of milliseconds to wait until the fn is executed.
           *
           * @param {Boolean} [periodic] if true, executes continuously at supplied interval
           * until canceled.
           *
           * @param {Object} [context] the context object.
           *
           * @param [data] that is provided to the function. This accepts either a single
           * item or an array. If an array is provided, the function is executed with
           * one parameter for each array item. If you need to pass a single array
           * parameter, it needs to be wrapped in an array.
           *
           * @return {Object} a timer object. Call the cancel() method on this object to stop
           * the timer.
           *
           * @member KISSY
           */
          later: function (fn, when, periodic, context, data) {
              when = when || 0;
              var m = fn,
                  d = S.makeArray(data),
                  f,
                  r;
  
              if (typeof fn === 'string') {
                  m = context[fn];
              }
  
              if (!m) {
                  S.error('method undefined');
              }
  
              f = function () {
                  m.apply(context, d);
              };
  
              r = (periodic) ? setInterval(f, when) : setTimeout(f, when);
  
              return {
                  id: r,
                  interval: periodic,
                  cancel: function () {
                      if (this.interval) {
                          clearInterval(r);
                      } else {
                          clearTimeout(r);
                      }
                  }
              };
          },
  
  
          /**
           * Throttles a call to a method based on the time between calls.
           * @param {Function} fn The function call to throttle.
           * @param {Object} [context] context fn to run
           * @param {Number} [ms] The number of milliseconds to throttle the method call.
           * Passing a -1 will disable the throttle. Defaults to 150.
           * @return {Function} Returns a wrapped function that calls fn throttled.
           * @member KISSY
           */
          throttle: function (fn, ms, context) {
              ms = ms || 150;
  
              if (ms === -1) {
                  return function () {
                      fn.apply(context || this, arguments);
                  };
              }
  
              var last = S.now();
  
              return function () {
                  var now = S.now();
                  if (now - last > ms) {
                      last = now;
                      fn.apply(context || this, arguments);
                  }
              };
          },
  
          /**
           * buffers a call between a fixed time
           * @param {Function} fn
           * @param {Number} ms
           * @param {Object} [context]
           * @return {Function} Returns a wrapped function that calls fn buffered.
           * @member KISSY
           */
          buffer: function (fn, ms, context) {
              ms = ms || 150;
  
              if (ms === -1) {
                  return function () {
                      fn.apply(context || this, arguments);
                  };
              }
              var bufferTimer = null;
  
              function f() {
                  f.stop();
                  bufferTimer = S.later(fn, ms, 0, context || this, arguments);
              }
  
              f.stop = function () {
                  if (bufferTimer) {
                      bufferTimer.cancel();
                      bufferTimer = 0;
                  }
              };
  
              return f;
          }
      });
  })(KISSY);