docs: protected Locale getBestLocale(HttpServletRequest request, Map<String,Locale> supportedLocales) throws ServletException {
  		@SuppressWarnings("unchecked")
  		Enumeration<String> acceptLanguages = request.getHeaders("accept-language");
  		if(acceptLanguages == null) {
  			// No header, use default
  			return getDefaultLocale(request, supportedLocales);
  		}
  		// Select the best locale from the Accept-Language header(s).
  		Locale bestExact = null;
  		float bestExactQ = Float.NaN;
  		Locale bestApprox = null;
  		float bestApproxQ = Float.NaN;
  		while(acceptLanguages.hasMoreElements()) {
  			for(String pair : StringUtility.splitString(acceptLanguages.nextElement(), ',')) {
  				String acceptLanguage;
  				float q;
  				int semiPos = pair.indexOf(';');
  				if(semiPos == -1) {
  					acceptLanguage = pair.trim();
  					q = 1;
  				} else {
  					acceptLanguage = pair.substring(0, semiPos).trim();
  					try {
  						q = Float.parseFloat(pair.substring(semiPos + 1).trim());
  					} catch(NumberFormatException e) {
  						// Invalid value, use q=0 to ignore the language
  						q = 0;
  					}
  				}
  				if(
  					q > 0
  					&& (Float.isNaN(bestExactQ) || q > bestExactQ)
  					&& (Float.isNaN(bestApproxQ) || q > bestApproxQ)
  				) {
  					MatchedLocale match = getBestMatch(supportedLocales, acceptLanguage);
  					if(match != null) {
  						if(match.exact) {
  							if(Float.isNaN(bestExactQ) || q > bestExactQ) {
  								bestExact = match.locale;
  								bestExactQ = q;
  							}
  						} else {
  							if(Float.isNaN(bestApproxQ) || q > bestApproxQ) {
  								bestApprox = match.locale;
  								bestApproxQ = q;
  							}
  						}
  					}
  				}
  			}
  		}
  		// Select best exact, best approximate, then default
  		Locale selected;
  		if(bestExact != null) {
  			selected = bestExact;
  		} else if(bestApprox != null) {
  			selected = bestApprox;
  		} else {
  			selected = getDefaultLocale(request, supportedLocales);
  		}
  		return selected;
  	}