@SuppressWarnings("AssignmentToForLoopParameter")
  public String substituteVariables(String val) {
    // If it has no references or HTML entities then no work
    // need to be done
    if (val.indexOf('$') < 0 && val.indexOf('&') < 0) {
      return val;
    }

    val = val.replace("&lt;", "<");
    val = val.replace("&gt;", ">");
    val = val.replace("&quot;", "\"");
    val = val.replace("&amp;", "&");

    StringBuilder sb = new StringBuilder(val);
    int charStart = sb.indexOf("&#");
    while (charStart > -1) {
      int charEnd = sb.indexOf(";", charStart);
      if (charEnd > -1) {
        char c = (char)Integer.parseInt(
          sb.substring(charStart + 2, charEnd));
        sb.delete(charStart, charEnd + 1);
        sb.insert(charStart, c);
        charStart = sb.indexOf("&#");
      }
      else {
        break;
      }
    }

    for (int i = 0; i < sb.length(); ) {
      // Find the next $
      for (; i < sb.length(); i++) {
        if (sb.charAt(i) == '$') {
          i++;
          break;
        }
      }
      if (i == sb.length()) break;
      // Check to see if the $ is escaped
      if (i > 1 && sb.charAt(i - 2) == '\\') {
        sb.deleteCharAt(i - 2);
        i--;
        continue;
      }
      int nameStart = i;
      int start = i - 1;
      int end;
      int nameEnd;
      char endChar = ' ';
      // Check for {} wrapped var
      if (sb.charAt(i) == '{') {
        nameStart++;
        endChar = '}';
      }
      // Find the end of the var reference
      for (; i < sb.length(); i++) {
        if (sb.charAt(i) == endChar) break;
      }
      end = i;
      nameEnd = end;
      if (endChar == '}') end++;
      // We should now have enough to extract the var name
      String varName = sb.substring(nameStart, nameEnd);
      String value = getVariableValue(varName);
      if (value == null) value = "";
      // Replace the var name with its value
      sb.replace(start, end, value);
      // Start searching for the next $ after the value
      // that was just substituted.
      i = start + value.length();
    }
    return sb.toString();
  }
@SuppressWarnings("AssignmentToForLoopParameter")
  public String substituteVariables(String val)