blanket.defaultReporter = function(coverage){
    var cssSytle = "#blanket-main {margin:2px;background:#EEE;color:#333;clear:both;font-family:'Helvetica Neue Light', 'HelveticaNeue-Light', 'Helvetica Neue', Calibri, Helvetica, Arial, sans-serif; font-size:17px;} #blanket-main a {color:#333;text-decoration:none;}  #blanket-main a:hover {text-decoration:underline;} .blanket {margin:0;padding:5px;clear:both;border-bottom: 1px solid #FFFFFF;} .bl-error {color:red;}.bl-success {color:#5E7D00;} .bl-file{width:auto;} .bl-cl{float:left;} .blanket div.rs {margin-left:50px; width:150px; float:right} .bl-nb {padding-right:10px;} #blanket-main a.bl-logo {color: #EB1764;cursor: pointer;font-weight: bold;text-decoration: none} .bl-source{ overflow-x:scroll; background-color: #FFFFFF; border: 1px solid #CBCBCB; color: #363636; margin: 25px 20px; width: 80%;} .bl-source div{white-space: pre;font-family: monospace;} .bl-source > div > span:first-child{background-color: #EAEAEA;color: #949494;display: inline-block;padding: 0 10px;text-align: center;width: 30px;} .bl-source .hit{background-color:#c3e6c7} .bl-source .miss{background-color:#e6c3c7} .bl-source span.branchWarning{color:#000;background-color:yellow;} .bl-source span.branchOkay{color:#000;background-color:transparent;}",
        successRate = 60,
        head = document.head,
        fileNumber = 0,
        body = document.body,
        headerContent,
        hasBranchTracking = Object.keys(coverage.files).some(function(elem){
          return typeof coverage.files[elem].branchData !== 'undefined';
        }),
        bodyContent = "<table id='blanket-main'><tr><th class='blanket bl-title'><th class='bl-cl bl-file'><a href='http://alex-seville.github.com/blanket/' target='_blank' class='bl-logo'>Blanket.js</a> results</th><th class='bl-cl rs'>Coverage (%)</th><th class='bl-cl rs'>Covered/Total Smts.</th>"+(hasBranchTracking ? "<th class='bl-cl rs'>Covered/Total Branches</th>":"")+"<th style='clear:both;'></th></tr></table>",
        fileTemplate = "<tr><td class='blanket {{statusclass}}'><td class='bl-cl bl-file'><span class='bl-nb'>{{fileNumber}}.</span><a href='javascript:blanket_toggleSource(\"file-{{fileNumber}}\")'>{{file}}</a></td><td class='bl-cl rs'>{{percentage}} %</td><td class='bl-cl rs'>{{numberCovered}}/{{totalSmts}}</td>"+( hasBranchTracking ? "<td class='bl-cl rs'>{{passedBranches}}/{{totalBranches}}</td>" : "" )+"<td id='file-{{fileNumber}}' class='bl-source' style='display:none;'>{{source}}</td><td style='clear:both;'></td></td></tr>";
        grandTotalTemplate = "<tr><td class='blanket grand-total {{statusclass}}'><td class='bl-cl'>{{rowTitle}}</td><td class='bl-cl rs'>{{percentage}} %</td><td class='bl-cl rs'>{{numberCovered}}/{{totalSmts}}</td>"+( hasBranchTracking ? "<td class='bl-cl rs'>{{passedBranches}}/{{totalBranches}}</td>" : "" ) + "<td style='clear:both;'></td></td></tr>";

    function blanket_toggleSource(id) {
        var element = document.getElementById(id);
        if(element.style.display === 'block') {
            element.style.display = 'none';
        } else {
            element.style.display = 'block';
        }
    }


    var script = document.createElement("script");
    script.type = "text/javascript";
    script.text = blanket_toggleSource.toString().replace('function ' + blanket_toggleSource.name, 'function blanket_toggleSource');
    body.appendChild(script);

    var percentage = function(number, total) {
        return (Math.round(((number/total) * 100)*100)/100);
    };

    var appendTag = function (type, el, str) {
        var dom = document.createElement(type);
        dom.innerHTML = str;
        el.appendChild(dom);
    };

    function escapeInvalidXmlChars(str) {
        return str.replace(/\&/g, "&amp;")
            .replace(/</g, "&lt;")
            .replace(/\>/g, "&gt;")
            .replace(/\"/g, "&quot;")
            .replace(/\'/g, "&apos;")
            .replace(/`/g, "&grave;")
            .replace(/[$]/g, "&dollar;");
    }

    function isBranchFollowed(data,bool){
        var mode = bool ? 0 : 1;
        if (typeof data === 'undefined' ||
            typeof data === null ||
            typeof data[mode] === 'undefined'){
            return false;
        }
        return data[mode].length > 0;
    }

    var branchStack = [];

    function branchReport(colsIndex,src,cols,offset,lineNum){
      var newsrc="";
       var postfix="";
      if (branchStack.length > 0){
        newsrc += "<span class='" + (isBranchFollowed(branchStack[0][1],branchStack[0][1].consequent === branchStack[0][0]) ? 'branchOkay' : 'branchWarning') + "'>";
        if (branchStack[0][0].end.line === lineNum){
          newsrc += escapeInvalidXmlChars(src.slice(0,branchStack[0][0].end.column)) + "</span>";
          src = src.slice(branchStack[0][0].end.column);
          branchStack.shift();
          if (branchStack.length > 0){
            newsrc += "<span class='" + (isBranchFollowed(branchStack[0][1],false) ? 'branchOkay' : 'branchWarning') + "'>";
            if (branchStack[0][0].end.line === lineNum){
              newsrc += escapeInvalidXmlChars(src.slice(0,branchStack[0][0].end.column)) + "</span>";
              src = src.slice(branchStack[0][0].end.column);
              branchStack.shift();
              if (!cols){
                return {src: newsrc + escapeInvalidXmlChars(src) ,cols:cols};
              }
            }
            else if (!cols){
              return {src: newsrc + escapeInvalidXmlChars(src) + "</span>",cols:cols};
            }
            else{
              postfix = "</span>";
            }
          }else if (!cols){
            return {src: newsrc + escapeInvalidXmlChars(src) ,cols:cols};
          }
        }else if(!cols){
          return {src: newsrc + escapeInvalidXmlChars(src) + "</span>",cols:cols};
        }else{
          postfix = "</span>";
        }
      }
      var thisline = cols[colsIndex];
      //consequent

      var cons = thisline.consequent;
      if (cons.start.line > lineNum){
        branchStack.unshift([thisline.alternate,thisline]);
        branchStack.unshift([cons,thisline]);
        src = escapeInvalidXmlChars(src);
      }else{
        var style = "<span class='" + (isBranchFollowed(thisline,true) ? 'branchOkay' : 'branchWarning') + "'>";
        newsrc += escapeInvalidXmlChars(src.slice(0,cons.start.column-offset)) + style;

        if (cols.length > colsIndex+1 &&
          cols[colsIndex+1].consequent.start.line === lineNum &&
          cols[colsIndex+1].consequent.start.column-offset < cols[colsIndex].consequent.end.column-offset)
        {
          var res = branchReport(colsIndex+1,src.slice(cons.start.column-offset,cons.end.column-offset),cols,cons.start.column-offset,lineNum);
          newsrc += res.src;
          cols = res.cols;
          cols[colsIndex+1] = cols[colsIndex+2];
          cols.length--;
        }else{
          newsrc += escapeInvalidXmlChars(src.slice(cons.start.column-offset,cons.end.column-offset));
        }
        newsrc += "</span>";

        var alt = thisline.alternate;
        if (alt.start.line > lineNum){
          newsrc += escapeInvalidXmlChars(src.slice(cons.end.column-offset));
          branchStack.unshift([alt,thisline]);
        }else{
          newsrc += escapeInvalidXmlChars(src.slice(cons.end.column-offset,alt.start.column-offset));
          style = "<span class='" + (isBranchFollowed(thisline,false) ? 'branchOkay' : 'branchWarning') + "'>";
          newsrc +=  style;
          if (cols.length > colsIndex+1 &&
            cols[colsIndex+1].consequent.start.line === lineNum &&
            cols[colsIndex+1].consequent.start.column-offset < cols[colsIndex].alternate.end.column-offset)
          {
            var res2 = branchReport(colsIndex+1,src.slice(alt.start.column-offset,alt.end.column-offset),cols,alt.start.column-offset,lineNum);
            newsrc += res2.src;
            cols = res2.cols;
            cols[colsIndex+1] = cols[colsIndex+2];
            cols.length--;
          }else{
            newsrc += escapeInvalidXmlChars(src.slice(alt.start.column-offset,alt.end.column-offset));
          }
          newsrc += "</span>";
          newsrc += escapeInvalidXmlChars(src.slice(alt.end.column-offset));
          src = newsrc;
        }
      }
      return {src:src+postfix, cols:cols};
    }

    var isUndefined =  function(item){
            return typeof item !== 'undefined';
      };

    var files = coverage.files;
    var totals = {
      totalSmts: 0,
      numberOfFilesCovered: 0,
      passedBranches: 0,
      totalBranches: 0,
      moduleTotalStatements : {},
      moduleTotalCoveredStatements : {},
      moduleTotalBranches : {},
      moduleTotalCoveredBranches : {}
    };

    // check if a data-cover-modulepattern was provided for per-module coverage reporting
    var modulePattern = _blanket.options("modulePattern");
    var modulePatternRegex = ( modulePattern ? new RegExp(modulePattern) : null );

    for(var file in files)
    {
        if (!files.hasOwnProperty(file)) {
            continue;
        }

        fileNumber++;

        var statsForFile = files[file],
            totalSmts = 0,
            numberOfFilesCovered = 0,
            code = [],
            i;


        var end = [];
        for(i = 0; i < statsForFile.source.length; i +=1){
            var src = statsForFile.source[i];

            if (branchStack.length > 0 ||
                typeof statsForFile.branchData !== 'undefined')
            {
                if (typeof statsForFile.branchData[i+1] !== 'undefined')
                {
                  var cols = statsForFile.branchData[i+1].filter(isUndefined);
                  var colsIndex=0;


                  src = branchReport(colsIndex,src,cols,0,i+1).src;

                }else if (branchStack.length){
                  src = branchReport(0,src,null,0,i+1).src;
                }else{
                  src = escapeInvalidXmlChars(src);
                }
              }else{
                src = escapeInvalidXmlChars(src);
              }
              var lineClass="";
              if(statsForFile[i+1]) {
                numberOfFilesCovered += 1;
                totalSmts += 1;
                lineClass = 'hit';
              }else{
                if(statsForFile[i+1] === 0){
                    totalSmts++;
                    lineClass = 'miss';
                }
              }
              code[i + 1] = "<div class='"+lineClass+"'><span class=''>"+(i + 1)+"</span>"+src+"</div>";
        }
        totals.totalSmts += totalSmts;
        totals.numberOfFilesCovered += numberOfFilesCovered;
        var totalBranches=0;
        var passedBranches=0;
        if (typeof statsForFile.branchData !== 'undefined'){
          for(var j=0;j<statsForFile.branchData.length;j++){
            if (typeof statsForFile.branchData[j] !== 'undefined'){
              for(var k=0;k<statsForFile.branchData[j].length;k++){
                if (typeof statsForFile.branchData[j][k] !== 'undefined'){
                  totalBranches++;
                  if (typeof statsForFile.branchData[j][k][0] !== 'undefined' &&
                    statsForFile.branchData[j][k][0].length > 0 &&
                    typeof statsForFile.branchData[j][k][1] !== 'undefined' &&
                    statsForFile.branchData[j][k][1].length > 0){
                    passedBranches++;
                  }
                }
              }
            }
          }
        }
        totals.passedBranches += passedBranches;
        totals.totalBranches += totalBranches;

        // if "data-cover-modulepattern" was provided,
        // track totals per module name as well as globally
        if (modulePatternRegex) {
            var moduleName = file.match(modulePatternRegex)[1];

            if(!totals.moduleTotalStatements.hasOwnProperty(moduleName)) {
                totals.moduleTotalStatements[moduleName] = 0;
                totals.moduleTotalCoveredStatements[moduleName] = 0;
            }

            totals.moduleTotalStatements[moduleName] += totalSmts;
            totals.moduleTotalCoveredStatements[moduleName] += numberOfFilesCovered;

            if(!totals.moduleTotalBranches.hasOwnProperty(moduleName)) {
                totals.moduleTotalBranches[moduleName] = 0;
                totals.moduleTotalCoveredBranches[moduleName] = 0;
            }

            totals.moduleTotalBranches[moduleName] += totalBranches;
            totals.moduleTotalCoveredBranches[moduleName] += passedBranches;
        }

        var result = percentage(numberOfFilesCovered, totalSmts);

        var output = fileTemplate.replace("{{file}}", file)
                                 .replace("{{percentage}}",result)
                                 .replace("{{numberCovered}}", numberOfFilesCovered)
                                 .replace(/\{\{fileNumber\}\}/g, fileNumber)
                                 .replace("{{totalSmts}}", totalSmts)
                                 .replace("{{totalBranches}}", totalBranches)
                                 .replace("{{passedBranches}}", passedBranches)
                                 .replace("{{source}}", code.join(" "));
        if(result < successRate)
        {
            output = output.replace("{{statusclass}}", "bl-error");
        } else {
            output = output.replace("{{statusclass}}", "bl-success");
        }
        bodyContent += output;
    }

    // create temporary function for use by the global totals reporter,
    // as well as the per-module totals reporter
    var createAggregateTotal = function(numSt, numCov, numBranch, numCovBr, moduleName) {

        var totalPercent = percentage(numCov, numSt);
        var statusClass = totalPercent < successRate ? "bl-error" : "bl-success";
        var rowTitle = ( moduleName ? "Total for module: " + moduleName : "Global total" );
        var totalsOutput = grandTotalTemplate.replace("{{rowTitle}}", rowTitle)
            .replace("{{percentage}}", totalPercent)
            .replace("{{numberCovered}}", numCov)
            .replace("{{totalSmts}}", numSt)
            .replace("{{passedBranches}}", numCovBr)
            .replace("{{totalBranches}}", numBranch)
            .replace("{{statusclass}}", statusClass);

        bodyContent += totalsOutput;
    };

    // if "data-cover-modulepattern" was provided,
    // output the per-module totals alongside the global totals
    if (modulePatternRegex) {
        for (var thisModuleName in totals.moduleTotalStatements) {
            if (totals.moduleTotalStatements.hasOwnProperty(thisModuleName)) {

                var moduleTotalSt = totals.moduleTotalStatements[thisModuleName];
                var moduleTotalCovSt = totals.moduleTotalCoveredStatements[thisModuleName];

                var moduleTotalBr = totals.moduleTotalBranches[thisModuleName];
                var moduleTotalCovBr = totals.moduleTotalCoveredBranches[thisModuleName];

                createAggregateTotal(moduleTotalSt, moduleTotalCovSt, moduleTotalBr, moduleTotalCovBr, thisModuleName);
            }
        }
    }

    createAggregateTotal(totals.totalSmts, totals.numberOfFilesCovered, totals.totalBranches, totals.passedBranches, null);
    bodyContent += "</div>"; //closing main


    appendTag('style', head, cssSytle);
    //appendStyle(body, headerContent);
    if (document.getElementById("blanket-main")){
        document.getElementById("blanket-main").innerHTML=
            bodyContent.slice(23,-6);
    }else{
        appendTag('div', body, bodyContent);
    }
    //appendHtml(body, '</div>');
};
