function indent(code, indentString) {
  if (!indentString) {
    indentString = "   ";
  }
    
  var newCode = "";
  var indentLevel = 0;
  var indentDuration = 0;   // used for temporary indents like 1-line ifs
  var newLines = [];
  var inMultiLineComment = false;
    
  var lines = code.split(/[\r]?\n/gi);
  for (var i = 0; i < lines.length; i++) {
    var line = trim(lines[i]);
    var lineForMatching = line.replace(/\/\/.*/, "");

    // ignore stuff in comments
        
    var lbrackets = lineForMatching.replace(/[^\{]+/gi, "");
    var rbrackets = lineForMatching.replace(/[^\}]+/gi, "");
    var lbracket1 = lineForMatching.indexOf("{");
    var rbracket1 = lineForMatching.indexOf("}");
    var lbracketN = lineForMatching.lastIndexOf("{");
    var rbracketN = lineForMatching.lastIndexOf("}");

    var increaseIndentBefore = false;
    var decreaseIndentBefore = false;
    var increaseIndentAfter = false;
    var decreaseIndentAfter = false;
        
    if (lbrackets.length > rbrackets.length ||
      lbracketN >= 0 && lbracketN > rbracketN) {
      // opening brace(s) on this line; indent subsequent lines
      increaseIndentAfter = true;
    }
    if (rbrackets.length > lbrackets.length ||
      rbracket1 >= 0 && rbracket1 < lbracket1) {
      // closing brace(s) on this line; decrease this line and subseqent lines
      decreaseIndentBefore = true;
    }
        
    // closing bracket; decrease indent
    // indentLevel = Math.max(0, indentLevel - 1);

    // check for a prior temporary indent (unbracketed if/else)
    // and get rid of it if so
    if (indentDuration > 0) {
      // if (lbrackets.length != rbrackets.length ||
      // (!lineForMatching.match(/(if |for |while )[ \t]*([^)]*)/) && !lineForMatching.match(/else /))) {
      indentDuration--;
      if (indentDuration == 0) {
        // indentLevel = Math.max(0, indent - 1);
        decreaseIndentAfter = true;
      }
      // }
    }
        
    // check for a new temporary indent (unbracketed if/else)
    // on this line and increase subsequent indent temporarily if so
    // side note: f**k unbracketed if/elses for making me write this code
    if (
    (
    (lbrackets.length < rbrackets.length || rbracketN > lbracketN) ||
      (lbrackets.length == 0 && rbrackets.length == 0)
  )
      &&
      (
    (lineForMatching.match(/(if |while )[ \t]*([^)]*)/) && !lineForMatching.match(/;/)) ||
      (lineForMatching.match(/(for )[ \t]*([^)]*)/)) ||
      (lineForMatching.match(/else/) && 
      (
      !lineForMatching.match(/else[ ]+if/) &&
      // !lineForMatching.match(/ /)
    (lbrackets.length == 0 || lbrackets.length > rbrackets.length)
  )
  )
  )
  ) {
      increaseIndentAfter = true;
      indentDuration = 1;
    }
        
    // pre-print indentation adjustments
    if (increaseIndentBefore) {
      indentLevel++;
    } else if (decreaseIndentBefore) {
      indentLevel = Math.max(0, indentLevel - 1);
    }
        
    // store this line, indented (hopefully) properly
    for (var tabs = 0; tabs < indentLevel; tabs++) {
      line = indentString + line;
    }
    newLines.push(line);

    // post-print indentation adjustments
    if (increaseIndentAfter) {
      indentLevel++;
    } else if (decreaseIndentAfter) {
      indentLevel = Math.max(0, indentLevel - 1);
    }
  }
    
  // put the newly indented lines into the text area on the page
  newCode = newLines.join("\n");
  return newCode;
}


function padL(text, length) {
  while (text.length < length) {
    text = " " + text;
  }
  return text;
}

function padR(text, length) {
  while (text.length < length) {
    text = text + " ";
  }
  return text;
}

function htmlDecode(text, skipNbsp) {
  text = text.replace(/&lt;/g, "<");
  text = text.replace(/&gt;/g, ">");
  text = text.replace(/&quot;/g, "\"");
  if (!skipNbsp) {
    text = text.replace(/&nbsp;/g, " ");
  }
  text = text.replace(/&amp;/g, "&");
  return text;
}

function htmlEncode(text, skipNbsp) {
  text = text.replace(/&/g, "&amp;");
  text = text.replace(/</g, "&lt;");
  text = text.replace(/>/g, "&gt;");
  text = text.replace(/"/g, "&quot;");
  if (!skipNbsp) {
    text = text.replace(/ /g, "&nbsp;");
  }
  return text;
}

function ltrim(str) { 
  for (var k = 0; k < str.length && str.charAt(k) <= " "; k++);
  return str.substring(k, str.length);
}

function rtrim(str) {
  for (var j = str.length - 1; j >= 0 && str.charAt(j) <= " "; j--);
  return str.substring(0, j+1);
}

function trim(str) {
  return ltrim(rtrim(str));
}
