** Parses a 'Str' of HTTP qvalues as per HTTP 1.1 Spec / ** [rfc2616-sec14.3]`http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.3`. Provides some ** useful accessor methods; like [#accepts(Str name)]`QualityValues.accepts` which returns 'true' only if the ** name exists AND has a qvalue greater than 0.0.**** @see `http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.3`class QualityValues {private Str:Float qvaluesprivatenew make(Str:Float qvalues){this.qvalues = qvalues}** Parses a HTTP header value into a 'name:qvalue' map.** Throws 'ParseErr' if the header Str is invalid.staticnew fromStr(Str? header := null, Bool checked := true){ qvalues := Utils.makeMap(Str#, Float#)if(header == null)return QualityValues(qvalues)try{ header.split(',').each |val| { vals := val.split(';')if(vals.size == 1){ qvalues[vals[0]] = 1.0freturn}if(vals.size == 2){ qval := vals[1]if(!qval.lower.startsWith("q="))throw ParseErr("'$qval' should start with 'q='") qnum := qval[2..-1].toFloatif(qnum < 0.0f || qnum > 1.0f)throw ParseErr("'$qnum' should be 0.0 >= q <= 1.0") qvalues[vals[0]] = qnumreturn}throw ParseErr("'$val' contains too many ';'")}return QualityValues(qvalues)}catch(ParseErr pe){if(checked)throw pereturnnull}}** Returns a joined-up Str of qvalues that may be set in a HTTP header. The names are sorted by ** qvalue. override Str toStr(){ qvalues.keys.sortr |q1, q2| { qvalues[q1] <=> qvalues[q2]}.join(", ") |q| { qvalues[q] == 1.0f ? "$q" : "$q;q=" + qvalues[q].toLocale("0.###")}}** Returns the qvalue associated with 'name'. Defaults to '0' if 'name' is not mapped.** ** 'name' is case-insensitive. @Operator Float get(Str name){ qvalues.get(name, 0f)}** Sets the given quality value. ** ** 'name' is case-insensitive. @Operator This set(Str name, Float qval){if(qval < 0.0f || qval > 1.0f)throw ArgErr("'$qval' should be 0.0 >= q <= 1.0") qvalues[name] = qvalreturnthis}** Returns 'true' if 'name' was supplied in the header Bool contains(Str name){ qvalues.containsKey(name)}** Returns 'true' if the name was supplied in the header AND has a qvalue > 0.0 Bool accepts(Str name){ get(name) > 0f}** Returns the number of values given in the header Int size(){ qvalues.size}** Returns 'size() == 0' Bool isEmpty(){ qvalues.isEmpty}** Returns a dup of the internal 'name:qvalue' map Str:Float toMap(){ qvalues.dup}}