/**
 * querystring
 *
 * This module provides utilities for dealing with query strings.
 */
define(function() {

  function stringifyPrimitive(v) {
    switch (typeof v) {
      case 'string':
        return v;
  
      case 'boolean':
        return v ? 'true' : 'false';
  
      case 'number':
        return isFinite(v) ? v : '';
  
      default:
        return '';
    }
  }

  return {
    stringify: function(obj, sep, eq, name) {
      sep = sep || '&';
      eq = eq || '=';
      if (obj === null) {
        obj = undefined;
      }
    
      if (typeof obj === 'object') {
        return Object.keys(obj).map(function(k) {
          var ks = encodeURIComponent(stringifyPrimitive(k)) + eq;
          if (Array.isArray(obj[k])) {
            return obj[k].map(function(v) {
              return ks + encodeURIComponent(stringifyPrimitive(v));
            }).join(sep);
          } else {
            return ks + encodeURIComponent(stringifyPrimitive(obj[k]));
          }
        }).join(sep);
    
      }
    
      if (!name) return '';
      return encodeURIComponent(stringifyPrimitive(name)) + eq +
             encodeURIComponent(stringifyPrimitive(obj));
    },
  
    parse: function(qs, sep, eq, options) {
      sep = sep || '&';
      eq = eq || '=';
      var obj = {};
    
      if (typeof qs !== 'string' || qs.length === 0) {
        return obj;
      }
    
      var regexp = /\+/g;
      qs = qs.split(sep);
    
      var maxKeys = 1000;
      if (options && typeof options.maxKeys === 'number') {
        maxKeys = options.maxKeys;
      }
    
      var len = qs.length;
      // maxKeys <= 0 means that we should not limit keys count
      if (maxKeys > 0 && len > maxKeys) {
        len = maxKeys;
      }
    
      for (var i = 0; i < len; ++i) {
        var x = qs[i].replace(regexp, '%20'),
            idx = x.indexOf(eq),
            kstr, vstr, k, v;
    
        if (idx >= 0) {
          kstr = x.substr(0, idx);
          vstr = x.substr(idx + 1);
        } else {
          kstr = x;
          vstr = '';
        }
    
        k = decodeURIComponent(kstr);
        v = decodeURIComponent(vstr);
    
        if (!obj.hasOwnProperty(k)) {
          obj[k] = v;
        } else if (Array.isArray(obj[k])) {
          obj[k].push(v);
        } else {
          obj[k] = [obj[k], v];
        }
      }
    
      return obj;
    }
  };

});

@@ -386,16 +386,593 @@
 eturn %7B%0A
+    /**%0A     * Serialize an object to a query string.%0A     *%0A     * Optionally override the default separator ('&') and assignment ('=')%0A     * characters.%0A     *%0A     * Examples:%0A     *%0A     *     querystring.stringify(%7B foo: 'bar', baz: %5B'qux', 'quux'%5D, corge: '' %7D)%0A     *     // returns%0A     *     'foo=bar&baz=qux&baz=quux&corge='%0A     *%0A     *     querystring.stringify(%7Bfoo: 'bar', baz: 'qux'%7D, ';', ':')%0A     *     // returns%0A     *     'foo:bar;baz:qux'%0A     *%0A     * @param %7BObject%7D obj%0A     * @param %7BString%7D sep%0A     * @param %7BString%7D eq%0A     * @api public%0A     */%0A
     stri
@@ -1751,24 +1751,684 @@
 ;%0A    %7D,%0A  %0A
+    /**%0A     * Deserialize a query string to an object.%0A     *%0A     * Optionally override the default separator ('&') and assignment ('=')%0A     * characters.%0A     *%0A     * Options object may contain maxKeys property (equal to 1000 by default),%0A     * it'll be used to limit processed keys. Set it to 0 to remove key count%0A     * limitation.%0A     *%0A     * Examples:%0A     *%0A     *     querystring.parse('foo=bar&baz=qux&baz=quux&corge')%0A     *     // returns%0A     *     %7B foo: 'bar', baz: %5B'qux', 'quux'%5D, corge: '' %7D%0A     *%0A     * @param %7BString%7D qs%0A     * @param %7BString%7D sep%0A     * @param %7BString%7D eq%0A     * @param %7BObject%7D options%0A     * @api public%0A     */%0A
     parse: f

Document exposed functions.