docs: function parse(arg)
  {
    try{
      var url = urllib.parse(arg, true);
    }catch(E){
      return false;
    }
  
    // paths is always an array
    if(!url.query.paths) url.query.paths = [];
    if(!Array.isArray(url.query.paths)) url.query.paths = [url.query.paths];
    
    // parse any paths
    url.paths = [];
    url.query.paths.forEach(function(epath){
      try{
        var path = JSON.parse(hashname.base32.decode(epath));
        if(typeof path == 'object' && typeof path.type == 'string') url.paths.push(path);
      }catch(E){};
    });
  
    // parse any csid keys
    url.keys = {};
    Object.keys(url.query).forEach(function(id){
      if(id.length != 4 || id.substr(0,2) != 'cs') return;
      url.keys[id.substr(2)] = url.query[id];
    });
    
    // parse any fragment
    if(url.hash) url.fragment = hashname.base32.decode(url.hash.substr(1));
    
    // add formatting wrapper
    url.encode = function()
    {
      // delete these to force lib to make new
      delete url.search;
      delete url.href;
      if(url.query.paths.length == 0) delete url.query.paths; // dumb node bug
      return urllib.format(url);
    }
    
    return url;
  }