code: public String canonicalize(String url) {
  
          if (url == null || url.length() <= 0) {
              return url;
          }
  
          // hang on, we're about to get aggressive:
          url = url.toLowerCase();
          StringBuilder sb = new StringBuilder(url);
          boolean changed = false;
  		for(int i=0; i<choosers.length; i++) {
  			if(sb.indexOf(choosers[i]) != -1) {
  				changed |= doStripRegexMatch(sb,strippers[i].matcher(sb));
  			}
  		}
  		if(changed) {
  			url = sb.toString();
  		}
          
          int index = url.lastIndexOf('?');
          if (index > 0) {
              if (index == (url.length() - 1)) {
                  // '?' is last char in url.  Strip it.
                  url = url.substring(0, url.length() - 1);
              } else if (url.charAt(index + 1) == '&') {
                  // Next char is '&'. Strip it.
                  if (url.length() == (index + 2)) {
                      // Then url ends with '?&'.  Strip them.
                      url = url.substring(0, url.length() - 2);
                  } else {
                      // The '&' is redundant.  Strip it.
                      url = url.substring(0, index + 1) + 
                      	url.substring(index + 2);
                  }
              } else if (url.charAt(url.length() - 1) == '&') {
                  // If we have a lone '&' on end of query str,
                  // strip it.
                  url = url.substring(0, url.length() - 1);
              }
          }
          return url;
  	}
docs: Idempotent operation that will determine the 'fuzziest'
  form of the url argument. This operation is done prior to adding records
  to the ResourceIndex, and prior to lookup. Current version is exactly
  the default found in Heritrix. When the configuration system for
  Heritrix stabilizes, hopefully this can use the system directly within
  Heritrix.
  
  @param url to be canonicalized.
  @return canonicalized version of url argument.