text: /**
   * @ignore
   * escape of lang
   * @author yiminghe@gmail.com
   *
   */
  (function (S, undefined) {
      // IE doesn't include non-breaking-space (0xa0) in their \s character
      // class (as required by section 7.2 of the ECMAScript spec), we explicitly
      // include it in the regexp to enforce consistent cross-browser behavior.
      var SEP = '&',
          EMPTY = '',
          EQ = '=',
          TRUE = true,
      // FALSE = false,
          HEX_BASE = 16,
      // http://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
          htmlEntities = {
              '&amp;': '&',
              '&gt;': '>',
              '&lt;': '<',
              '&#x60;': '`',
              '&#x2F;': '/',
              '&quot;': '"',
              '&#x27;': "'"
          },
          reverseEntities = {},
          escapeReg,
          unEscapeReg,
      // - # $ ^ * ( ) + [ ] { } | \ , . ?
          escapeRegExp = /[\-#$\^*()+\[\]{}|\\,.?\s]/g;
      (function () {
          for (var k in htmlEntities) {
              reverseEntities[htmlEntities[k]] = k;
          }
      })();
  
      function isValidParamValue(val) {
          var t = typeof val;
          // If the type of val is null, undefined, number, string, boolean, return TRUE.
          return val == null || (t !== 'object' && t !== 'function');
      }
  
      function getEscapeReg() {
          if (escapeReg) {
              return escapeReg
          }
          var str = EMPTY;
          S.each(htmlEntities, function (entity) {
              str += entity + '|';
          });
          str = str.slice(0, -1);
          return escapeReg = new RegExp(str, 'g');
      }
  
      function getUnEscapeReg() {
          if (unEscapeReg) {
              return unEscapeReg
          }
          var str = EMPTY;
          S.each(reverseEntities, function (entity) {
              str += entity + '|';
          });
          str += '&#(\\d{1,5});';
          return unEscapeReg = new RegExp(str, 'g');
      }
  
      S.mix(S, {
  
          /**
           * Call encodeURIComponent to encode a url component
           * @param {String} s part of url to be encoded.
           * @return {String} encoded url part string.
           * @member KISSY
           */
          urlEncode: function (s) {
              return encodeURIComponent(String(s));
          },
  
          /**
           * Call decodeURIComponent to decode a url component
           * and replace '+' with space.
           * @param {String} s part of url to be decoded.
           * @return {String} decoded url part string.
           * @member KISSY
           */
          urlDecode: function (s) {
              return decodeURIComponent(s.replace(/\+/g, ' '));
          },
  
          /**
           * frequently used in taobao cookie about nick
           * @member KISSY
           * @return {String} un-unicode string.
           */
          fromUnicode: function (str) {
              return str.replace(/\\u([a-f\d]{4})/ig, function (m, u) {
                  return  String.fromCharCode(parseInt(u, HEX_BASE));
              });
          },
          /**
           * get escaped string from html.
           * only escape
           *      & > < ` / " '
           * refer:
           *
           * [http://yiminghe.javaeye.com/blog/788929](http://yiminghe.javaeye.com/blog/788929)
           *
           * [http://wonko.com/post/html-escaping](http://wonko.com/post/html-escaping)
           * @param str {string} text2html show
           * @member KISSY
           * @return {String} escaped html
           */
          escapeHTML: function (str) {
              return (str + '').replace(getEscapeReg(), function (m) {
                  return reverseEntities[m];
              });
          },
  
          /**
           * get escaped regexp string for construct regexp.
           * @param str
           * @member KISSY
           * @return {String} escaped regexp
           */
          escapeRegExp: function (str) {
              return str.replace(escapeRegExp, '\\$&');
          },
  
          /**
           * un-escape html to string.
           * only unescape
           *      &amp; &lt; &gt; &#x60; &#x2F; &quot; &#x27; &#\d{1,5}
           * @param str {string} html2text
           * @member KISSY
           * @return {String} un-escaped html
           */
          unEscapeHTML: function (str) {
              return str.replace(getUnEscapeReg(), function (m, n) {
                  return htmlEntities[m] || String.fromCharCode(+n);
              });
          },
          /**
           * Creates a serialized string of an array or object.
           *
           * for example:
           *     @example
           *     {foo: 1, bar: 2}    // -> 'foo=1&bar=2'
           *     {foo: 1, bar: [2, 3]}    // -> 'foo=1&bar=2&bar=3'
           *     {foo: '', bar: 2}    // -> 'foo=&bar=2'
           *     {foo: undefined, bar: 2}    // -> 'foo=undefined&bar=2'
           *     {foo: TRUE, bar: 2}    // -> 'foo=TRUE&bar=2'
           *
           * @param {Object} o json data
           * @param {String} [sep='&'] separator between each pair of data
           * @param {String} [eq='='] separator between key and value of data
           * @param {Boolean} [serializeArray=true] whether add '[]' to array key of data
           * @return {String}
           * @member KISSY
           */
          param: function (o, sep, eq, serializeArray) {
              if (!S.isPlainObject(o)) {
                  return EMPTY;
              }
              sep = sep || SEP;
              eq = eq || EQ;
              if (S.isUndefined(serializeArray)) {
                  serializeArray = TRUE;
              }
              var buf = [], key, i, v, len, val,
                  encode = S.urlEncode;
              for (key in o) {
  
                  val = o[key];
                  key = encode(key);
  
                  // val is valid non-array value
                  if (isValidParamValue(val)) {
                      buf.push(key);
                      if (val !== undefined) {
                          buf.push(eq, encode(val + EMPTY));
                      }
                      buf.push(sep);
                  }
                  // val is not empty array
                  else if (S.isArray(val) && val.length) {
                      for (i = 0, len = val.length; i < len; ++i) {
                          v = val[i];
                          if (isValidParamValue(v)) {
                              buf.push(key, (serializeArray ? encode('[]') : EMPTY));
                              if (v !== undefined) {
                                  buf.push(eq, encode(v + EMPTY));
                              }
                              buf.push(sep);
                          }
                      }
                  }
                  // ignore other cases, including empty array, Function, RegExp, Date etc.
  
              }
              buf.pop();
              return buf.join(EMPTY);
          },
  
          /**
           * Parses a URI-like query string and returns an object composed of parameter/value pairs.
           *
           * for example:
           *      @example
           *      'section=blog&id=45'        // -> {section: 'blog', id: '45'}
           *      'section=blog&tag=js&tag=doc' // -> {section: 'blog', tag: ['js', 'doc']}
           *      'tag=ruby%20on%20rails'        // -> {tag: 'ruby on rails'}
           *      'id=45&raw'        // -> {id: '45', raw: ''}
           * @param {String} str param string
           * @param {String} [sep='&'] separator between each pair of data
           * @param {String} [eq='='] separator between key and value of data
           * @return {Object} json data
           * @member KISSY
           */
          unparam: function (str, sep, eq) {
              if (typeof str != 'string' || !(str = S.trim(str))) {
                  return {};
              }
              sep = sep || SEP;
              eq = eq || EQ;
              var ret = {},
                  eqIndex,
                  decode = S.urlDecode,
                  pairs = str.split(sep),
                  key, val,
                  i = 0, len = pairs.length;
  
              for (; i < len; ++i) {
                  eqIndex = pairs[i].indexOf(eq);
                  if (eqIndex == -1) {
                      key = decode(pairs[i]);
                      val = undefined;
                  } else {
                      // remember to decode key!
                      key = decode(pairs[i].substring(0, eqIndex));
                      val = pairs[i].substring(eqIndex + 1);
                      try {
                          val = decode(val);
                      } catch (e) {
                          S.log(e + 'decodeURIComponent error : ' + val, 'error');
                      }
                      if (S.endsWith(key, '[]')) {
                          key = key.substring(0, key.length - 2);
                      }
                  }
                  if (key in ret) {
                      if (S.isArray(ret[key])) {
                          ret[key].push(val);
                      } else {
                          ret[key] = [ret[key], val];
                      }
                  } else {
                      ret[key] = val;
                  }
              }
              return ret;
          }
      });
  })(KISSY);