function cfstyle() {
  var isie = /msie/i.test(navigator.userAgent)
             && !/opera/i.test(navigator.userAgent);
  var inlinetable = isie ? 'inline' : 'inline-table';
  return "table.frac { vertical-align: top; display: " + inlinetable + " }"
       + ".frac td.n { text-align:center; border-bottom: thin black solid; }"
       + ".cfd { line-height:300%; }";
}
 
function cffromfrac(f) {
  result = [];
  if (f == null) return result;
  while (f.d >= 1) {
    var p = improp(f);
    result.push(p.i);
    f = { n: p.d, d: p.n };
  }
  return result;
}

function improp(f) {
  var i = Math.floor(f.n / f.d);
  return { i: i, n: f.n - i * f.d, d: f.d }
}

function parsefrac(v) {
  var seq = v.split("/");
  if (seq.length < 1 || seq.length > 2) return null;
  if (seq.length == 2) {
    var n = parseInt(seq[0]);
    var d = parseInt(seq[1]);
    if (isNaN(n) || isNaN(d)) return null;
    return { n: n, d: d };
  }
  seq = v.split(".");
  if (seq.length > 2) return null;
  var i = parseInt(seq[0]);
  if (isNaN(i)) return null;
  if (seq.length == 1) return { n: i, d: 1 };
  var n = parseInt(seq[1]);
  if (isNaN(n)) return null;
  var d = Math.pow(10, seq[1].replace(/^\s+|\s+$/g, '').length);
  return { n: i * d + n, d: d};
}

function formatcf(c) {
  var r = "";
  for (var i = 0; i < c.length; i++) {
    if (i == c.length - 1) {
      r += c[i];
    } else {
      if (c[i] != 0) {
        r += c[i] + " + ";
      }
      r += "<table class=frac><tr><td class=n>1</td></tr>";
      if (i < c.length - 2) {
        r += "<tr><td class=cfd>";
      } else {
        r += "<tr><td>";
      }
    }
  }
  for (var i = 1; i < c.length; i++) {
    r += "</td></tr></table>";
  }
  return r;
}

function expandcf(v) {
  return formatcf(cffromfrac(parsefrac(v)));
}
