// Path: src/main/java/com/biasedbit/hotpotato/util/TextUtils.java
// public class TextUtils {
// 
//     // constructors ---------------------------------------------------------------------------------------------------
// 
//     private TextUtils() {
// 
//     }
// 
//     // public static methods ------------------------------------------------------------------------------------------
//     
//     /**
//      * Hash a string
//      *
//      * @param toHash String to be hashed.
//      *
//      * @return Hashed string.
//      */
//     public static String hash(Object toHash) {
//         String hashString = toHash.toString();
//         MessageDigest md;
//         try {
//             md = MessageDigest.getInstance("MD5");
//         } catch (NoSuchAlgorithmException e) {
//             return hashString;
//         }
// 
//         md.update(hashString.getBytes(), 0, hashString.length());
//         return convertToHex(md.digest());
//     }
// 
//     public static String convertToHex(byte[] data) {
//         StringBuffer buf = new StringBuffer();
//         for (byte aData : data) {
//             int halfbyte = (aData >>> 4) & 0x0F;
//             int two_halfs = 0;
//             do {
//                 if ((0 <= halfbyte) && (halfbyte <= 9)) {
//                     buf.append((char) ('0' + halfbyte));
//                 } else {
//                     buf.append((char) ('a' + (halfbyte - 10)));
//                 }
//                 halfbyte = aData & 0x0F;
//             } while (two_halfs++ < 1);
//         }
//         return buf.toString();
//     }
// 
//     /**
//      * Returns a string with a given characted repeated n times.
//      *
//      * @param str String.
//      * @param times Number of repetitions.
//      *
//      * @return String with <code>times</code> repetitions of <code>str</code>
//      */
//     public static String repeat(Object str, int times) {
//         StringBuilder builder = new StringBuilder(str.toString());
//         for (int i = 1; i < times; i++) {
//             builder.append(str);
//         }
// 
//         return builder.toString();
//     }
// }


import com.biasedbit.hotpotato.util.TextUtils;
import java.text.ParseException;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

        }
        Map<String, String> response = new HashMap<String, String>();
        response.put(SCHEME, header.substring(0, firstSpace));

        String[] params = header.substring(firstSpace + 1).split(",");
        if (params.length < 4) {
            throw new ParseException("Invalid header content: username, response, nonce & uri are required", 0);
        }
        for (String param : params) {
            param = param.trim();
            Matcher m = PROPERTY_PATTERN.matcher(param);
            if (m.find()) {
                response.put(m.group(1), m.group(3));
            }
        }
        return response;
    }

    public static DigestAuthChallengeResponse computeResponse(DigestAuthChallenge challenge, String method, String content,
                                                        String uri, String username, String password, int nonceCount)
            throws ParseException {

        String realm = challenge.getRealm();
        String nonce = challenge.getNonce();
        String cnonce = null;

        String qop = challenge.getQop();
        boolean hasQop = (qop != null) && (qop.length() > 0);
        String nc = toNonceCount(nonceCount);


// Path: src/main/java/com/biasedbit/hotpotato/util/TextUtils.java
// public class TextUtils {
// 
//     // constructors ---------------------------------------------------------------------------------------------------
// 
//     private TextUtils() {
// 
//     }
// 
//     // public static methods ------------------------------------------------------------------------------------------
//     
//     /**
//      * Hash a string
//      *
//      * @param toHash String to be hashed.
//      *
//      * @return Hashed string.
//      */
//     public static String hash(Object toHash) {
//         String hashString = toHash.toString();
//         MessageDigest md;
//         try {
//             md = MessageDigest.getInstance("MD5");
//         } catch (NoSuchAlgorithmException e) {
//             return hashString;
//         }
// 
//         md.update(hashString.getBytes(), 0, hashString.length());
//         return convertToHex(md.digest());
//     }
// 
//     public static String convertToHex(byte[] data) {
//         StringBuffer buf = new StringBuffer();
//         for (byte aData : data) {
//             int halfbyte = (aData >>> 4) & 0x0F;
//             int two_halfs = 0;
//             do {
//                 if ((0 <= halfbyte) && (halfbyte <= 9)) {
//                     buf.append((char) ('0' + halfbyte));
//                 } else {
//                     buf.append((char) ('a' + (halfbyte - 10)));
//                 }
//                 halfbyte = aData & 0x0F;
//             } while (two_halfs++ < 1);
//         }
//         return buf.toString();
//     }
// 
//     /**
//      * Returns a string with a given characted repeated n times.
//      *
//      * @param str String.
//      * @param times Number of repetitions.
//      *
//      * @return String with <code>times</code> repetitions of <code>str</code>
//      */
//     public static String repeat(Object str, int times) {
//         StringBuilder builder = new StringBuilder(str.toString());
//         for (int i = 1; i < times; i++) {
//             builder.append(str);
//         }
// 
//         return builder.toString();
//     }
// }


// Path: src/main/java/com/biasedbit/hotpotato/util/digest/DigestUtils.java
import com.biasedbit.hotpotato.util.TextUtils;
import java.text.ParseException;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

        }
        Map<String, String> response = new HashMap<String, String>();
        response.put(SCHEME, header.substring(0, firstSpace));

        String[] params = header.substring(firstSpace + 1).split(",");
        if (params.length < 4) {
            throw new ParseException("Invalid header content: username, response, nonce & uri are required", 0);
        }
        for (String param : params) {
            param = param.trim();
            Matcher m = PROPERTY_PATTERN.matcher(param);
            if (m.find()) {
                response.put(m.group(1), m.group(3));
            }
        }
        return response;
    }

    public static DigestAuthChallengeResponse computeResponse(DigestAuthChallenge challenge, String method, String content,
                                                        String uri, String username, String password, int nonceCount)
            throws ParseException {

        String realm = challenge.getRealm();
        String nonce = challenge.getNonce();
        String cnonce = null;

        String qop = challenge.getQop();
        boolean hasQop = (qop != null) && (qop.length() > 0);
        String nc = toNonceCount(nonceCount);


        String ha1 = TextUtils.hash(new StringBuilder()
