//tydeligvis nødvendig for å få det til å fungere på Internet Explorer...
if (!window.console) {console =  {log: function() {}}};

_.mixin(_.str.exports());


var make_active = function(name) {
	$("#NavnOppTilVenstre").css("color", "");

	_.each(["VerdiListeDropdown", "FrekvensTabellDropdown", "KlassedeltDropdown", "TallsystemDropdown"],function (id) {
		$("#"+id).removeClass("active");
	});

	if (name == "NavnOppTilVenstre") {
		$("#NavnOppTilVenstre").css("color", "white");
	} else if (name) {
		$("#"+name).addClass("active");
	}
}


var inputListData = " 1 1 1 2 2 3 5 5 5 ";

var outputTag = $( '#DataUt' );

var listeMode = function() {
	make_active("VerdiListeDropdown");

	$('#frekvensDataInn').hide();
	$('#tallsystemInn').hide();
	$('#klasseDataInn').hide();

	$("#nyTabell").hide();

	$("#self-promotion").hide();
	$( '#math-unit' ).show();


	$( '#DataInn' ).show();

	outputTag = $( '#DataUt' );

	
	$( '#DataInn' ).html('<form class="form-horizontal"><input id="inputList"  autocomplete="off" value="'+inputListData+'" type="text"></form>');
	$('#DataInn').keyup(_.debounce(function () {
		// her må jeg sjekke dataene også!
		inputListData = $('#inputList').val();

		inputValidator = function () {
			var elm = _.map(_.without($('#inputList').val().split(/\s+/), ""), Number);
			if(elm.length == 0) {
				return "<H2>Skriv inn tall adskilt av mellomrom</H2>";

			}
			else if(_.every(elm, 
				function (num) {return !_.isNaN(num)})) {
				return false;
		} else {

			return "<H2>Listen kan kun inneholde tall</H2>"
		}


	}

	RedrawOutData();
}, 100));


};  


var clearOutput = function() {
    $( '#DataUt' ).html('');
    $( '#frekvensDataUt' ).html('');
};
 

function frekvensHeaderRenderer(instance, td, row, col, prop, value, cellProperties) {
    Handsontable.TextCell.renderer.apply(this, arguments);


    var headers = frekvensData[0];
    var frekTab = frekvensData.slice(1);
    frekTab= _.initial(frekTab);


    // må være hvit i starten eller så beholder den fargene sine...
    $(td).css({
	    background: 'white'
		});


    if(row === 0) {
	$(td).css({
		//	    background: 'red',
		"font-size": "125%",
		    "font-weight":"bold"
		    });
    } else if((row != (frekvensData.length -1 )) && (row != 0) && (row != 1) && (frekvensData[row-1][0] >= frekvensData[row][0])) {
	$(td).css({
		background: '#F2DEDE',
		    });
	//	  $("#warnOut").html("<br/><strong>Nedre del av intervallet må være mindre enn øvre del av intervallet i rad " + (row -1) + "</Strong>");
    } else if((row != (frekvensData.length -1 )) && (row != 0) && (!_.isNumber(frekvensData[row][1]))) {
	$(td).css({
		background: '#F2DEDE',
		    });
	//	  $("#warnOut").html("<br/><strong>Nedre del av intervallet må være mindre enn øvre del av intervallet i rad " + (row -1) + "</Strong>");
    } else if(value === undefined || value === '') {
	td.style.background = '#EEE';
    }
  

}

var frekvensData = [
		    ["Verdi", "Frekvens"],
		    [1, 2],
		    [2, 5],
		    [3, 8],
		    [4, 7],
		    [5, 4],
		    [6, 1]
		    ];

var frekvensInputTable = $( '#frekvensDataInn' ).handsontable({
	data: frekvensData,
	startRows: 1,
	startCols: 2,
	minSpareRows: 1,
	contextMenu: ["row_below","remove_row"],
	onChange: _.debounce(function (changes, source) {


		// Hack som tydeligvis må til får å få tabellen til å bli tegnet på nytt...
		if(source == "loadData") {return}
		frekvensInputTable.handsontable('loadData', frekvensData);


		// her må jeg sjekke dataene også!
		if(beregn) {
		    RedrawOutData();
		}
	    }, 300),

	onBeforeChange: function (data) {

	    for (var i = data.length - 1; i >= 0; i--) {
		if (data[i][0]==0 ) {	return true; } // alt er lov i første rad
		else if (_.isNaN(Number(data[i][3])) || Number(data[i][3]) < 0) {	return false; } // disregard edit
		else {data[i][3] = Number(data[i][3]);}
	    }
	},

	onSelection: function (row, col, row2, col2) {
	    var meta = frekvensInputTable.handsontable('getCellMeta', row2, col2);
	    if (meta.isWritable == false) {
		frekvensInputTable.handsontable('updateSettings', {fillHandle: false});
	    }
	    else {
		frekvensInputTable.handsontable('updateSettings', {fillHandle: true});
	    }
	},
	cells: function (row, col, prop) {
	    var cellProperties = {};
	    if (row === 0 && col===1) {
		cellProperties.readOnly = true; //make cell read-only if it is first row or the text reads 'readOnly'
	    }
	    		
	    cellProperties.type = { renderer: frekvensHeaderRenderer }
				
	    return cellProperties;
	}
    });

	


var frekvensMode = function() {

	make_active("FrekvensTabellDropdown");

    $("#self-promotion").hide();
	$( '#math-unit' ).show();


    $( '#DataInn' ).hide();
    $('#tallsystemInn').hide();
    $('#klasseDataInn').hide();

    $('#frekvensDataInn').show();
    $( '#FrekvensDataUt' ).show();
    $("#nyTabell").show();
    outputTag = $( '#frekvensDataUt' );


	$("#nyTabell").click(function() {
		frekvensData = [
		    ["Verdi", "Frekvens"]];

		frekvensInputTable.handsontable('loadData', frekvensData);

	    RedrawOutData();


	});



    inputValidator = function () {
	var headers = frekvensData[0];
	var frekTab = frekvensData.slice(1);
	frekTab= _.initial(frekTab);

	if(frekTab.length == 0) {
	    return "<H2>Fyll inn i frekvenstabellen</H2>";

	} 

	if (! _.every(frekTab, function(value, index, array) {
		    // either it is the first element, or otherwise this element should 
		    // not be smaller than the previous element.
		    // spec requires string conversion
		    return index === 0 || array[index - 1][0] < value[0];
		})) {

	    return "<H2>Kolonnen til venstre i frekvenstabellen må være sortert fra minst til størst</H2>"
	} 

	if (! _.every(frekTab, function(value, index, array) {
		    // either it is the first element, or otherwise this element should 
		    // not be smaller than the previous element.
		    // spec requires string conversion
		    return _.isNumber(array[index][0]) && _.isNumber(array[index][1]);
		})) {

	    return "<H2>Frekvenstabellen er ikke fullstendig utfylt</H2>"
	} 
			
	return false;
			


    }


};



function klasseHeaderRenderer(instance, td, row, col, prop, value, cellProperties) {
    Handsontable.TextCell.renderer.apply(this, arguments);

    $(td).css({
	    background: 'white'
		});

    if(row === 0) {

	$(td).css({
		//	    background: 'red',
		"font-size": "125%",
		    "font-weight":"bold"
		    });
    }
    //  if(cellProperties.readOnly) {
    //   td.style.background = "yellow";
    //  }

    if((row != klasseData.length -1)  && (klasseData[row][0] >= klasseData[row][1])) {
    	console.log("Mindre enn forrige " + klasseData[row] + "---" + klasseData.length);
	$(td).css({
		background: '#F2DEDE',
		    });
	//	  $("#warnOut").html("<br/><strong>Nedre del av intervallet må være mindre enn øvre del av intervallet i rad " + (row -1) + "</Strong>");
    }


    if((row != klasseData.length -1) && (row != 0) && (row != 1) && (klasseData[row-1][0] >= klasseData[row][0])) {
    	console.log("floppa");
	$(td).css({
		background: '#F2DEDE',
		    });
	//	  $("#warnOut").html("<br/><strong>Nedre del av intervallet må være mindre enn øvre del av intervallet i rad " + (row -1) + "</Strong>");
    }

//    console.log("value: " + value);
    if((row != klasseData.length -1) &&( value === undefined || value === '' || value === null)) {
    	$(td).css({
		background: '#F2DEDE',
		    });
    }
  

}

var klasseData = [
		  ["Fra", "Til", "Frekvens"],
		  [150, 160, 28],
		  [160, 165, 18],
		  [165, 170, 43],
		  [170, 175, 35],
		  [175, 180, 48],
		  [180, 185, 23],
		  [185, 190, 15],
		  [190, 200, 8]
		     
		  ];

var klasseInputTable = $( '#klasseDataInn' ).handsontable({
	data: klasseData,
	startRows: 1,
	startCols: 3,
	minSpareRows: 1,
	contextMenu: ["row_below","remove_row"],
	onChange: _.debounce(function (data, source) {
		if(source == "loadData") {return}

		for (var i = data.length - 1; i >= 0; i--) {
		    var row = data[i][0];
		    var col = data[i][1];
		    var newVal = data[i][3];
		    //	console.log("r:"+row+"c:"+col+"nv:"+newVal+"kdl:"+klasseData.length);
		    if ((row==0) || (row==klasseData.length) || (row==1 && col==0) || (row==(klasseData.length -1)) || (row==(klasseData.length -2)&& col==1)) {
			// disse er ikke koblet sammen med en annen rute
			//console.log("HER ER JEG");
		    } 	else if (col==0) {	klasseData[row-1][1] = newVal;   } // update other value
		    else if (col==1) {  klasseData[row+1][0] = newVal;  } // update other value
		    else {console.log("")}

		    klasseInputTable.handsontable('loadData', klasseData)

		}


		// her må jeg sjekke dataene også!
		if(beregn) {
		    RedrawOutData();
		}
	    }, 300),
	onBeforeChange: function (data) {

	    for (var i = data.length - 1; i >= 0; i--) {
		if (data[i][0]==0 ) {	return true; } // alt er lov i første rad
		else if (_.isNaN(Number(data[i][3])) || Number(data[i][3]) < 0) {	return false; } // disregard edit
		else {data[i][3] = Number(data[i][3]);}
	    }
	},
	onSelection: function (row, col, row2, col2) {
	    var meta = klasseInputTable.handsontable('getCellMeta', row2, col2);
	    if (meta.isWritable == false) {
		klasseInputTable.handsontable('updateSettings', {fillHandle: false});
	    }
	    else {
		klasseInputTable.handsontable('updateSettings', {fillHandle: true});
	    }
	},
	cells: function (row, col, prop) {
	    var cellProperties = {};
	    if (row === 0) {
		cellProperties.readOnly = true; //make cell read-only if it is first row or the text reads 'readOnly'
	    }
	    		
	    cellProperties.type = { renderer: klasseHeaderRenderer }
				
	    return cellProperties;
	}
    });


$('#klasseDataInn').hide();

var klasseMode = function() {
	make_active("KlassedeltDropdown");


	$("#self-promotion").hide();
	$( '#math-unit' ).show();


	$( '#DataInn' ).hide();
	$('#tallsystemInn').hide();
	$('#frekvensDataInn').hide();
	$('#klasseDataInn').show();
	$( '#FrekvensDataUt' ).show()
	outputTag = $( '#frekvensDataUt' );

	$("#nyTabell").show();

	$("#nyTabell").click(function() {
		klasseData = [["Fra", "Til", "Frekvens"]];

		klasseInputTable.handsontable('loadData', klasseData);

		RedrawOutData();
	});


	inputValidator = function () {
		var headers = klasseData[0];
		var frekTab = klasseData.slice(1);
		frekTab= _.initial(frekTab);

		if(frekTab.length == 0) {
			return "<H2>Fyll inn i tabellen</H2>";

		} 

		if (! _.every(frekTab, function(value, index, array) {
		    // either it is the first element, or otherwise this element should 
		    // not be smaller than the previous element.
		    // spec requires string conversion
		    return index === 0 || array[index - 1][0] < value[0];
		})) {

			return "<H2>Det er overlappende intervaller i tabellen </H2>"
		} 

		if (! _.every(frekTab, function(value, index, array) {
		    // either it is the first element, or otherwise this element should 
		    // not be smaller than the previous element.
		    // spec requires string conversion
		    return array[index][0] < value[1];
		})) {

			return "<H2>Det er overlappende intervaller i tabellen </H2>"
		} 


		if (! _.every(frekTab, function(value, index, array) {
		    // either it is the first element, or otherwise this element should 
		    // not be smaller than the previous element.
		    // spec requires string conversion
		    return _.isNumber(array[index][0]) && _.isNumber(array[index][1]) && _.isNumber(array[index][2]);
		})) {

			return "<H2>Tabellen er ikke fullstendig utfylt</H2>"
		} 

		return false;



	}



};


var tallsystemMode = function() {

		make_active("TallsystemDropdown");

    $("#self-promotion").hide();
	$( '#math-unit' ).show();


    $( '#DataInn' ).hide();
    $('#frekvensDataInn').hide();
    $('#tallsystemInn').show();
    $('#klasseDataInn').hide();

    $("#nyTabell").hide();


    outputTag = $( '#DataUt' );


    $( '#tallsystemInn' ).html('<h2>Skriv inn et tall i totallsystemet (kun 0 og 1):</h2>'
			       +'<form >'
			       +'<input class="bigTextbox"  autocomplete="off" id="2to10inn" type="text" value="1010"/><br />'
			       +'</form>');
    $('#tallsystemInn').keyup(_.debounce(function () {
		// her må jeg sjekke dataene også!

		RedrawOutData();
	    }, 500));

};


function trim(stringToTrim) {
    return stringToTrim.replace(/^\s+|\s+$/g,"");
}

var ListeSnitt = function(noTitle) {


    var regnSnitt = function () {
	var sum = _.reduce(elm, function (a,b) { return a + b }, 0);
	var len =  elm.length*1.0;
	return "{S \\over N} = {" + o(sum) + " \\over " + len + "} = " +o(sum/len) ;
    };

    var elm =  _.map(trim($('#inputList').val()).split(/\s+/), Number);
    return _.template('<%= title %>' +
		      '<p>Finner summen av observasjonsverdiene: $<%= regnUtSum %>$  </p>'+ 
		      '<P>Finner antall observasjoner: $<%= visLengde %>$</P>'+
		      '<p>Gjennomsnittet er da: $<%= regnUtSnitt %>$</p>', 
{	title: noTitle?"":'<h2>Finner gjennomsnitt:</h2>',
  	regnUtSum: "S = " + _(elm).map(om).join (" + ") + " = " + o(_.reduce(elm, function (a,b) { return a + b }, 0)),
	visLengde: "N =  " + elm.length,
	regnUtSnitt: regnSnitt()});
};

var ListeTypetall = function() {

    var elm =  _.map(trim($('#inputList').val()).split(/\s+/), Number);

    //tell opp verdier
    var count = _.reduce(elm, 
			 function (memo, num) {
			     if (num in memo) {
				 memo[num]++;
			     } else {
				 memo[num]=1;
			     }
			     return memo;
			 }, {}); 

    // LAGER TABELLEN
    var sorted_elms = _.map(_.keys(count), function (e) { return [e, count[e]];})
    .sort(function(a,b){return a[0]-b[0]});

    var out = "<thead><tr><th>Verdi $x$</th><th>Frekvens $f$</th></tr></thead>";
    _.each(sorted_elms, function (e) {
	    out += "<tr><td>$"+e[0]+"$</td><td>$"+e[1]+"$</td></tr>";
	});

    // FINNER TYPETALLET

    var elms_sorted_on_count = _.map(_.keys(count), function (e) { return [e, count[e]];})
    .sort(function(a,b){return b[1]-a[1]});

    var typetall = _.reduce(elms_sorted_on_count, function (memo, e) {
	    if(e[1] == elms_sorted_on_count[0][1]) {
		memo.push(e[0]);
	    }
	    return memo;
	}, []);
    var typetallOut = typetall.join(" og ");

    return _.template('<h2>Finn typetall:</h2>'+
		      '<p>Teller opp verdiene og lager en frekvenstabell:'+
		      '<table class="table table-bordered table-striped table-condensed" style="height:0; width:0;" id="typetallVerdiTabell">'+
		      '<%= typetallVerdiTabell %>'+
		      '</table></p> '+
		      '<P>Ser i tabellen og finner de hyppigst forekommende verdiene</P>'+
		      '<p>Typetall(ene) er: <%= typetallSiste %> </p>', 
{typetallVerdiTabell: out,
	typetallSiste: typetallOut});
};

var ListeMedian = function() {

	var elm =  _.map(trim($('#inputList').val()).split(/\s+/), Number);

	var medianSorter = function() { var i=1; return _.map(elm.sort(function(a,b){return a-b}), function (e) {return e + "_{("+(i++)+")}"}).join(" \\;\\; "); }	

	var showListLength = function () {return "N =  " + elm.length};

	var medianMidtersteObservasjon = function() { 

	    var out = "";
	    out += "\\({N + 1 \\over 2} = {" + elm.length + " + 1 \\over 2} = " + (elm.length+1)/2 + " \\)";
	    if (elm.length %2 == 0) {
		out += "<br/>Fordi det er et partall antall observasjoner er medianen lik gjennomsnittet av de to verdiene som ligger på hver sin side av midtpunktet";
	    } else {
		out += "<br/>Fordi det er et oddetall antall observasjoner er medianen lik den verdien som svarer til midtpunktet.";
	    }
	    //console.log(out);
	    return out;
	}
	var medianMedian = function() { 
	    var out = "";
	    var sorted = elm.sort(function(a,b){return a-b});
	    if (elm.length % 2 == 0) {
		var elm1 = elm.length/2 -1 ;
		var elm2 = elm1 +1 ;
		out += "Medianen er gjennomsnittet av verdiene nummer "+(elm1+1)+" og "+(1+ elm2)+". \\({"+sorted[elm1]+" + "+sorted[elm2]+" \\over 2 }= "+((sorted[elm1]+sorted[elm2])/2)+"\\)";
		
	    } else {
		var elm1 = (elm.length+1)/2 
		out += "Medianen er verdi nummer "+(elm1)+". Dermed er medianen "+sorted[elm1-1]+".";
	    }
	    out = "<P>"+out+"</P>";
	    //console.log(out);
	    return out;
	}

	return _.template('<h2>Finn median:</h2>'+
			  '<p>Sorterer observasjonene: $<%= medianSorter %>$</p>'+ 
			  '<P>Finner antall observasjoner: <%= medianVisLengde %> </P>'+
			  '<p>Finner midtpunktet: <%= medianMidtersteObservasjon %>  </p>'+ 
			  '<p><%= medianMedian %></p>',
    {medianSorter: medianSorter(),	
     medianVisLengde: showListLength(),
     medianMidtersteObservasjon: medianMidtersteObservasjon(),
     medianMedian:   medianMedian()});
    };



var ListeVariasjonsbredde = function() {

    var elm =  _.map(trim($('#inputList').val()).split(/\s+/), Number);

    var min = _.min(elm);
    var max = _.max(elm);
    var variasjonsbredde = max - min;


	
    return _.template('<h2>Finn variasjonsbredden:</h2>'+
		      '<p>Finner minste verdi: $<%= minst %>$</p>'+ 
		      '<P>Finner største verdi: $<%= storst %>$</P>'+
		      '<p>Variasjonsbredden er da: største verdi - minste verdi = $<%= storst %> - <%= minst %> = <%= samlet %>$  </p>', 

{minst: min,	
	storst: max,
	samlet: max - min});
};


var ListeKvartil = function() {

	var elm =  _.map(trim($('#inputList').val()).split(/\s+/), Number);

	if (elm.length === 1) {return "Kan ikke finne kvartilbredde for kun en observasjon"};

	var sortedElm = elm.sort(function(a,b){return a-b});

	var listeMedIndex = function(liste, i) { return _.map(liste, function (e) {return e + "_{("+(i++)+")}"}).join(" \\;\\; "); }


	var nedreHalvdel = [];

	var ovreHalvdel = [];

	var medianVerdiEllerTom = "";
	var ovreStartindex;
	var Q3;
	var Q1;

	var medianTekst = "";
    if (elm.length %2 == 0) {  // partall obs
    	medianTekst = "Fordi det er et partall antall observasjoner, deler vi observasjonene i to halvdeler: øvre halvdel og nedre halvdel. Vi deler listen midt imellom onservasjon nr. " + (elm.length/2) + " og " + (elm.length/2 + 1) ;
    	nedreHalvdel = sortedElm.slice(0,(elm.length/2 ));
    	ovreHalvdel = sortedElm.slice(elm.length/2 );
    	ovreStartindex = elm.length/2 +1;

    } else { // oddetall obs
    	medianTekst = "Fordi det er et odde antall observasjoner, finner vi medianen, og deler så resten av observasjonene i to halvdeler: øvre halvdel og nedre halvdel. Vi tar ikke med medianen i noen av halvdelene. Medianen er observasjon nr. " + ((elm.length+1)/2)
	
	 	nedreHalvdel = sortedElm.slice(0,(elm.length+1) / 2 - 1 );
    	ovreHalvdel = sortedElm.slice((elm.length+1) / 2 );
    	ovreStartindex = (elm.length+1) /2;

    	medianVerdiEllerTom = sortedElm[(elm.length+1)/2 -1] + "_{(" + (elm.length+1)/2+")}"; 
	    }




	var medianMidtersteObservasjon = function(name, q, startIndex, list, onlyQuartile) {

	    var out = "";
	    if (list.length %2 == 0) {
		out += "Fordi det er et partall antall observasjoner er "+name+" lik gjennomsnittet av de to verdiene som ligger på hver sin side av midtpunktet. <BR/>";

	    if (startIndex === 0) {
		    out +=  capitaliseFirstLetter(name) + " er gjennomsnittet av observasjon nr \\({N \\over 2} = {" + list.length + " \\over 2} = " + (list.length)/2 + " \\) og \\({N \\over 2} + 1  = {" + list.length + " \\over 2} +1 = " + ((list.length)/2 +1) + " \\)<BR/>";

	    } else {
	    	out += "<P>Fordi øvre halvdel starter på observasjon nr. "+(startIndex+1)+" så legger vi til "+startIndex+" når vi finner midtpunktet </P>"
		    out +=  capitaliseFirstLetter(name) + " er gjennomsnittet av observasjon nr \\({N \\over 2} +"+startIndex+"= {" + list.length + " \\over 2} +"+startIndex+"= " + ((list.length)/2 + startIndex)+ " \\) og \\(({N \\over 2} + 1) +"+startIndex+" = ({" + list.length + " \\over 2} +1) +"+startIndex+" = " +( ((list.length)/2 +1) + startIndex)+ " \\)<BR/>";

	
	    }

		
	    var elm1 = list.length/2 -1 ;
		var elm2 = elm1 +1 ;

		out += capitaliseFirstLetter(name) + " er: $"+q+" = "+ "{"+list[elm1]+" + "+list[elm2]+" \\over 2 }= "+((list[elm1]+list[elm2])/2)+"$";

// ekkelt hack for å ta vare på verdiene og regne ut variasjonsbredden :-(

		if (onlyQuartile === true) {
			return ((list[elm1]+list[elm2])/2);
		} 



	    } else {
		out += "<br/>Fordi det er et oddetall antall observasjoner er "+name+" lik den verdien som svarer til midtpunktet. <BR/>";

	    if (startIndex === 0) {
		    out += capitaliseFirstLetter(name) + " er observasjon nr \\({N + 1 \\over 2} = {" + list.length + " + 1 \\over 2} = " + (list.length+1)/2 + " \\) <BR/>";
	    } else {
	    	out += "<P>Fordi øvre halvdel starter på observasjon nr. "+(startIndex +1)+" så legger vi til "+startIndex+" når vi finner midtpunktet </P>"


		    out += capitaliseFirstLetter(name) + " er observasjon nr \\({N + 1 \\over 2} +"+startIndex+" = {" + list.length + " + 1 \\over 2} +"+startIndex+"= " + ((list.length+1)/2 +startIndex)+ " \\) <BR/>";
	
	    }


	    var elm1 = (list.length+1)/2 

		out += capitaliseFirstLetter(name) + " er:  $"+q+" = "+ list[elm1-1]+"$.";


// ekkelt hack for å ta vare på verdiene og regne ut variasjonsbredden :-(
		if (onlyQuartile === true) {
			return list[elm1-1];
		} 


	    }
	    //console.log(out);
	    return out;
	}

	return _.template('<h2>Finner kvartilbredden:</h2>'+
			  '<p>Sorterer først observasjonene: $\\overbrace{<%= nedreHalvdel  %>}^\\text{nedre halvdel}\\;\\;<%= medianVerdiEllerTom  %>\\;\\;\\overbrace{<%= ovreHalvdel  %>}^\\text{øvre halvdel}$</p>'+ 
			  "<H3>Finner medianen</H3>"+
			  '<P>Finner antall observasjoner: $N = <%= elmLengde %>$ </P>'+
			  '<p><%= medianTekst %>  </p>'+
			  "<H3>Finner nedre kvartil, som er medianen i nedre halvdel</H3>"+
			  '<p>Nedre halvdel av observasjonene er: $<%= nedreHalvdel %>$</P>'+
			  '<p><%= finnNedreKvartil %></P>'+
			  "<H3>Finner øvre kvartil, som er medianen i øvre halvdel</H3>"+
			  '<p>Øvre halvdel av observasjonene er: $<%= ovreHalvdel %>$</P>'+
			  '<p><%= finnOvreKvartil %></P>'+
  			  "<H3>Finner kvartilbredden</H3>"+
	  			  '<p>Kvartilbredden er $Q_3 - Q_1 = <%= o(Q3)  +" - "+ o(Q1) %> = <%= Q3 - Q1 %>$</P>'

,
    {sortedElm: listeMedIndex(sortedElm,1),	
     elmLengde: elm.length,
     medianTekst: medianTekst,
     medianVerdiEllerTom: medianVerdiEllerTom,
     nedreHalvdel: listeMedIndex(nedreHalvdel, 1),
     finnNedreKvartil: medianMidtersteObservasjon("nedre kvartil", "Q_1", 0, nedreHalvdel),
     ovreHalvdel: listeMedIndex(ovreHalvdel, medianVerdiEllerTom?(ovreStartindex +1):ovreStartindex),
      finnOvreKvartil: medianMidtersteObservasjon("øvre kvartil", "Q_3", ovreStartindex -1 , ovreHalvdel),
      Q1: medianMidtersteObservasjon("nedre kvartil", "Q_1", 0, nedreHalvdel, true),
      Q3: medianMidtersteObservasjon("øvre kvartil", "Q_3", ovreStartindex -1 , ovreHalvdel, true),

      });
    };






/*
var ListeVarianseGammel = function(isEmbedded) {

    var elm =  _.map(trim($('#inputList').val()).split(/\s+/), Number);


    var sum = _.reduce(elm, function (a,b) { return a + b }, 0);
    var len =  elm.length*1.0;
    var snitt = sum/len;

    var diffs = _.map(elm, function(e){return (snitt-e)});

    var variansen = _.reduce(elm, function (memo,e) { return (memo + Math.pow(snitt - e, 2)) }, 0) /len;
    var varianseUtregning = "\\text{Variansen} = { (" + o(snitt) + " - " +_(elm).map(om).join (")^2 + ("+o(snitt)+"-") + ")^2 \\over " + len + "}\\\\"+
    "={ (" + _.map(diffs, o).join (")^2 + (") + ")^2 \\over " + len + "}\\\\"+
    "={ " + _(diffs).map(function(e) {return e*e}).map(om).join (" + ") + " \\over " + len + "}\\\\"+

    "= "+o(variansen); 

	
    return _.template('<%= title %>'+
		      '<H3>Finner først gjennomsnittet:</H3>'+
		      '<p><%= singleGjennomsnittUtregning %></p>'+ 
		      '<H3>Bruker gjennomsnittet for å regne ut variansen</H3>'+
		      '<p>$<%=singleVarianseUtregning %>$</p>'+ 
		      '<p>Variansen er: $  <%= singleVarianseSvar %>$</p>', 
	
{title: typeof isEmbedded === 'undefined'?'<h2>Finn variansen:</h2>':"",
	singleGjennomsnittUtregning: ListeSnitt("noTitle"),
	singleVarianseSvar: o(variansen),
	singleVarianseUtregning: varianseUtregning});
};
*/
var ListeVarianse = function(isEmbedded) {

    var elm =  _.map(trim($('#inputList').val()).split(/\s+/), Number);


    var sum = _.reduce(elm, function (a,b) { return a + b }, 0);
    var len =  elm.length*1.0;
    var snitt = sum/len;

    var diffs = _.map(elm, function(e){return (snitt-e)});

    var kvadratsum = _.reduce(elm, function (memo,e) { return (memo + Math.pow(snitt - e, 2)) }, 0);
    var variansen =  kvadratsum/len;
    var varianseUtregning = "<table style=\"height:0;width:0;\" class='table table-bordered table-striped table-condensed'><thead><tr><th>Verdi&nbsp;$x$</th><th>$(x-g)^2$</th></tr></thead><tbody>" +
    						(_(elm).map(function(e) {
    							        return "<tr><td>$"+o(e)+"$</td>"+
    								               "<td>$("+o(e)+"-"+o(snitt)+")^2 = " + om(e-snitt)+"^2 = " + o(Math.pow(e-snitt,2)) + "$</td></tr>"})).join("") +
    						"<tr><td>&nbsp;</td><td>$A= "+o(kvadratsum) + "$</td></tr>"+
    						"</tbody></table>"; 

	
    return _.template('<%= title %>'+
		      '<H3>Finner først gjennomsnittet:</H3>'+
		      '<p><%= singleGjennomsnittUtregning %></p>'+ 
		      '<H3>Bruker gjennomsnittet for å regne ut variansen</H3>'+
		      '<p><%=singleVarianseUtregning %></p>'+ 
		      '<p>Variansen er: $  <%= singleVarianseSvar %>$</p>', 
	
{title: typeof isEmbedded === 'undefined'?'<h2>Finn variansen:</h2>':"",
	singleGjennomsnittUtregning: ListeSnitt("noTitle"),
	singleVarianseSvar: fr("A","N")+"="+fr(o(kvadratsum),len)+"="+o(variansen),
	singleVarianseUtregning: varianseUtregning});
};


var ListeStandardavvik = function() {

    var elm =  _.map(trim($('#inputList').val()).split(/\s+/), Number);


    var sum = _.reduce(elm, function (a,b) { return a + b }, 0);
    var len =  elm.length*1.0;
    var snitt = sum/len;

    var variansen = _.reduce(elm, function (memo,e) { return (memo + Math.pow(snitt - e, 2)) }, 0) /len;
    var varianseUtregning = "\sigma^2 = { (" + snitt + " - " +elm.join (")^2 + ("+snitt+"-") + ")^2 \\over " + len + "} =" +variansen; 

	
    return _.template('<h2 >Finn standardavvik:</h2>'+
		      '<%= finnVariansen %>'+
		      '<H3>Bruker variansen for å regne ut standardavvik</H3>'+
		      '<p>Standardavviket er: $ \\sqrt{\\text{Variansen}} = \\sqrt{<%= variansen %>} = <%= standardavvik %>$</p>', 
	
{finnVariansen: ListeVarianse("inEmbedded"),
	variansen: o(variansen),
	standardavvik: o(Math.sqrt(variansen))});
};


var ListeStolpe = function() {

    var elm =  _.map(trim($('#inputList').val()).split(/\s+/), Number);

    //	$( '#DataUt' ).css({width:"80%", height:"80%"}); 						

    //tell opp verdier
    var count = _.reduce(elm, 
			 function (memo, num) {
			     if (num in memo) {
				 memo[num]++;
			     } else {
				 memo[num]=1;
			     }
			     return memo;
			 }, {}); 

    // LAGER TABELLEN
    var sorted_elms = _.map(_.keys(count), function (e) { return [e, count[e] ]})
    .sort(function(a,b){return a[0]-b[0]});






    outputTag.append("<h2>Søylediagram:</h2>");


    var margin = {top: 20, right: 20, bottom: 60, left: 40},
    width = 700 - margin.left - margin.right,
    height = 400 - margin.top - margin.bottom;

    //		var formatPercent = d3.format(".0%");

    var x = d3.scale.ordinal()
    .rangeRoundBands([0, width], .1);

    var y = d3.scale.linear()
    .range([height, 0]);

    var xAxis = d3.svg.axis()
    .scale(x)
    .orient("bottom");

    var yAxis = d3.svg.axis()
    .scale(y)
    .orient("left");
    //		    .tickFormat(formatPercent);

    var svg = d3.select("#DataUt").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
    .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

		
    var data = sorted_elms;

    x.domain(data.map(function(d) { return d[0]; }));
    y.domain([0, d3.max(data, function(d) { return d[1]; })]);

    svg.append("g")
    .attr("class", "x axis")
    .attr("transform", "translate(0," + height + ")")
    .call(xAxis);
  		     
    svg.append("g")
    .attr("class", "y axis")
    .call(yAxis)
    .append("text")
    .attr("transform", "rotate(-90)")
    .attr("y", 6)
    .attr("dy", ".51em")
    .style("text-anchor", "end")
    .text("Frekvens");

    svg.selectAll(".bar")
    .data(data)
    .enter().append("rect")
    .attr("class", "bar")
    .attr("x", function(d) { return x(d[0]); })
    .attr("width", x.rangeBand())
    .attr("y", function(d) { return y(d[1]); })
    .attr("height", function(d) { return height - y(d[1]); });


    svg.append("text")
    .attr("class", "x label")
    .attr("text-anchor", "end")
    .attr("x", width/2 )
    .attr("y", height + 40)
    .text("Verdier");


    return "";


};

var ListeKake = function() {

    var elm =  _.map(trim($('#inputList').val()).split(/\s+/), Number);
	 					

    //tell opp verdier
    var count = _.reduce(elm, 
			 function (memo, num) {
			     if (num in memo) {
				 memo[num]++;
			     } else {
				 memo[num]=1;
			     }
			     return memo;
			 }, {}); 

    // LAGER TABELLEN
    var sorted_elms = _.map(_.keys(count), function (e) { return {"label": e, "value":count[e]};})
    .sort(function(a,b){return a["label"]-b["label"]});



    outputTag.append("<h2>Kakediagram:</h2>");


    var width = 500,
    height = 400,
    radius = Math.min(width, height) / 2;

    var color = d3.scale.ordinal()
//    .range(["Red", "Green", "Blue", "Magenta", "Cyan", "Yellow", "Gray", "Maroon", "Navy", "Purple"]);

    .range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00", "Red", "Green", "Blue", "Magenta", "Cyan", "Yellow", "Gray", "Maroon", "Navy", "Purple"]);

    var arc = d3.svg.arc()
    .outerRadius(radius - 10)
    .innerRadius(0);

    var pie = d3.layout.pie()
    .sort(null)
    .value(function(d) { return d["value"]; });

    var svg = d3.select("#DataUt").append("svg")
    .attr("width", width)
    .attr("height", height)
    .append("g")
    .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");


    var data = sorted_elms;

    data.forEach(function(d) {
	    d[1] = +d[1];
	});

    var g = svg.selectAll(".arc")
    .data(pie(data))
    .enter().append("g")
    .attr("class", "arc");

    g.append("path")
    .attr("d", arc)
    .style("fill", function(d) { return color(d.data["label"]); });

    g.append("text")
    .attr("transform", function(d) { return "translate(" + arc.centroid(d) + ")"; })
    .attr("dy", ".35em")
    .style("text-anchor", "middle")
    .style("font-size", "20px")
    .style("color", "white")      
    .text(function(d) { return d.data["label"]; });

    return "";
};

var Tallsystem2til10 =function () {


    var bin_str = $('#2to10inn').val();
    // foreta en sanity check på input

	bin_str =    bin_str.trim();

    if (! _.every(_.chars(bin_str), function (val){
    	return val === "0" || val === "1";	
    })) { return "<H2>Kun 0 og 1 er gyldig input</H2>"};
	    
    var bin_siff = _.map(bin_str.split(""), Number);
    var base = 2;
    bin_siff = bin_siff.reverse();
    var toThe1 = 0;
    var toThe2 = 0;
    var toThe3 = 0;
    var out = 
    eq(eqnl(add(_.map(bin_siff, function (s) {
			return x(red(s), pwr(base,toThe1++)); 
		    }).reverse()),
	    add(_.map(bin_siff, function (s) {
			return s*Math.pow(base,toThe2++); 
		    }).reverse())),
	red(uu(subs(_.reduce(_.map(bin_siff, function (s) {
				return s*Math.pow(base,toThe3++); 
			    }).reverse(),
			function (col, val) {
			    return col + val;
			}
			
			),"(10)")) ));


    return _.template('<h2 >Konverterer $<%= input %>$ til 10-tallsystemet:</h2>'+
		      '$<%= out %>$',
{input: bin_str+"_{(2)}",
	out: out});

};

var  FrekvensSnitt = function (utenTittel) {
    var headers = frekvensData[0];
    var frekTab = frekvensData.slice(1);
    frekTab= _.initial(frekTab);

    var t = $( '<table>');
    t.addClass("table table-bordered table-striped table-condensed");
    t.css({ width: 0,
		height: 0});
    t.append("<thead><tr><th>Verdi&nbsp;$x$</th><th>Frekvens&nbsp;$f$</th><th>$f \\cdot x$</th></tr></thead>");
    var N = 0;
    var S = 0;
    _.each(frekTab, function(row) {
	    N = N + parseInt(row[1]);
	    S = S + (parseInt(row[0])*parseInt(row[1]));
	    t.append("<tr><td>$"+row[0]+"$</td><td>$"+row[1]+"$</td><td>$"+(row[0]*row[1])+"$</td></tr>");

	});

    t.append("<tr><td>&nbsp;</td><td>$N="+N+"$</td><td>$S="+S+"$</td></tr>");

    var out = _.template('<%= table %>'+
			 'Gjennomsnittet er: $ g = \\frac{S}{N} = <%= snitt %>$',
{table: t.wrap('<div></div>').parent().html(),
 snitt: eq(fr(S,N),o(S/N))});
    out = (utenTittel?"":'<h2>Finner gjennomsnittet:</h2>') + out;
    return out;
};

var  FrekvensTypetall = function () {
    var headers = frekvensData[0];
    var frekTab = frekvensData.slice(1);
    frekTab= _.initial(frekTab);

    var t = $( '<table>');
    t.addClass("table table-bordered table-striped table-condensed");
    t.css({ width: 0,
		height: 0});
    t.append("<thead><tr><th>Verdi&nbsp;$x$</th><th>Frekvens&nbsp;$f$</th></thead>");
    var N = 0;
    var maxRow = frekTab[0];
    //var maxRowIndex = 0;
    var maxRowList = [maxRow];

    _.each(frekTab.slice(1), function(row, index) {
	    if (Number(maxRow[1]) < Number(row[1])) {
		maxRow = row;
		maxRowList = [maxRow];
		//		maxRowIndex = index;
	    } else if (maxRow[1] == row[1]) {
		maxRowList.push(row);
	    }
	});
    //	console.log("maxRowIndex " + maxRowIndex)
    var highlight = "";
    _.each(frekTab, function(row, index) {
	    N = N + parseInt(row[1],10);

	    if (row[1] == maxRow[1]) {
		highlight = 'class="info"';
	    } else {

		highlight = "";
	    }

	    currTD = t.append('<tr '+highlight+'><td>$'+row[0]+"$</td><td>$"+row[1]+"$</td></tr>");
	});

    t.append("<tr><td>&nbsp;</td><td>$N="+N+"$</td></tr>");

    var out = _.template('<h2>Finner typetallet:</h2><%= table %>'+
			 'Typetallet er <%= typetall %>',
{table: t.wrap('<div></div>').parent().html(),
 typetall:  _.toSentence(_.pluck(maxRowList, 0), ", ", " og ")});

    return out;
}

    function repeatArray(arr, count) {
	var ln = arr.length;
	var b = new Array();
	for(i=0; i<count; i++) {
	    b.push(arr[i%ln]);
	}

	return b;
    }

var  FrekvensMedian = function () {
    var headers = frekvensData[0];
    var frekTab = frekvensData.slice(1);
    frekTab= _.initial(frekTab);

// Må dessverre sjekke at ikke frekvensene er for høye fordi da kræsjer programmet...

	if (! _.every(frekTab, function(row) {
		return row[1] < 1000000;
	})){
		return "Kalkulatoren kan for tiden dessverre ikke finne medianen av tabeller med så høye frekvenser. Beklager."
	}



    var t = $( '<table>');
    t.addClass("table table-bordered table-striped table-condensed");
    t.css({ width: 0,
		height: 0});
    t.append("<thead><tr><th>Verdi&nbsp;$x$</th><th>Frekvens&nbsp;$f$</th><th>Kumulativ&nbsp;frekvens</th></tr></thead>");


    // må dessverre finne antall obs. først for å kunne bruke den i neste loop
    var NumObs = 0;
    _.each(frekTab, function(row,index) {
	    NumObs = NumObs + parseInt(row[1]);
	});

    var N = 0;

    var listVals = [""]; // må legge til en nullverdi for at tellingen skal bli enklere senere...
	
    _.each(frekTab, function(row,index) {
	    listVals = listVals.concat(repeatArray([parseInt(row[0])],row[1]));

	    var oldN = N;

	    N = N + parseInt(row[1]);
	    var utregn = index===0?N:eq(pl(oldN,row[1]),N);

	    //gjær grønn hvis den er median
	    var makeGreen = "";
	    if (NumObs%2==0) { // partall
		var v1 = (NumObs/2);
		var v2 = v1 + 1;
		if ((v1 > oldN && v1<= N ) || (v2 > oldN && v2<= N )) {
		    makeGreen = ' class="info" ' ;
		} else {
		    makeGreen = "";	
		}
	    } else { // oddetall
		var v = ((NumObs +1)/2);
		if (v > oldN && v<= N ) {
		    makeGreen = ' class="info" ' ;
		} else {
		    makeGreen = "";	
		}
	    }



	    t.append("<tr"+makeGreen+"><td>$"+row[0]+"$</td><td>$"+row[1]+"$</td><td>$"+utregn+"$</td></tr>");

	});
    //	console.log(listVals);
    var medUtr = "";
    var type = "";
    var median = "";
    var nr = "";
    if (N%2==0) { // partall
	type = "partall";
	medUtr = "Dette er et partall. <br/> Medianen er derfor snittet av observasjon nummer $" + [fr("N", "2"),
												    fr(N , "2"),
												    (N)/2].join(" = ") + "$ og den neste observasjonen, som er observasjon nummer $" + (N/2 +1) + "$";

	nr = "Observasjon nr $" + (N/2) + "$ er $" + listVals[N/2] + "$<br>"+
	    "Observasjon nr $" + (N/2 +1) + "$ er $" + listVals[N/2 + 1] + "$<br>";


	median = "$" + fr(listVals[N/2] + " + " + listVals[N/2 + 1], "2") + 
	    " = " + fr(listVals[N/2] + listVals[N/2 + 1], "2") + 
	    " = " +  (listVals[N/2] + listVals[N/2 + 1])/2 +
	    "$";



    } else { // oddetall

	type = "oddetall";

	nr = "Observasjon nr $" + ((N + 1)/2) + "$ er $" + listVals[(N+1)/2] + "$<br>";


	medUtr = "Det er et oddetall. <br/>" + 
	"Medianen er da observasjon nummer $" + [fr("N +1", "2"),
						 fr(N + "+ 1", "2"),
						 fr(N+1,"2"),
						 (N+1)/2].join(" = ") + "$";
	median = "$" + listVals[(N+1)/2] + "$";
    }

    t.append("<tr><td>&nbsp;</td><td>$N="+N+"$</td><td>&nbsp;</td></tr>");

    var out = _.template('<h2>Finner medianen:</h2><%= table %>'+
			 'Vi har her $<%= N %>$ observasjoner. ' + 
			 '<%= medUtr %><br/>'+
			 "<%= ObsNr%>" +
			 'Medianen er dermed: <%= median %>',
{table: t.wrap('<div></div>').parent().html(),
 N: N,
 ObsNr: nr,
 medUtr: medUtr,
 median: median});

    return out;
};


var  FrekvensVarianse = function (utenTittel) {
    var headers = frekvensData[0];
    var frekTab = frekvensData.slice(1);
    frekTab= _.initial(frekTab);

    // Finner snittet
    var NN = 0;
    var SS = 0;
    _.each(frekTab, function(row) {
	    NN = NN + parseInt(row[1]);
	    SS = SS + (parseInt(row[0])*parseInt(row[1]));
	});

    var Snittet = SS/NN;


    var t = $( '<table>');
    t.addClass("table table-bordered table-striped table-condensed");
    t.css({ width: 0, height: 0});
    t.append("<thead><tr><th>Verdi&nbsp;$x$</th><th>Frekvens&nbsp;$f$</th><th>$f \\cdot x$</th><th>$f \\cdot (x - g)^2$</th></tr></thead>");
    var N = 0;
    var S = 0;
    var A = 0;
    _.each(frekTab, function(row) {
	    N = N + parseInt(row[1]);
	    S = S + (parseInt(row[0])*parseInt(row[1]));
	    var radVar = row[1] *Math.pow(row[0]-Snittet,2);
	    A = A + radVar;
	    t.append("<tr><td>$"+row[0]+"$</td><td>$"+row[1]+"$</td><td>$"+(row[0]*row[1])+"$</td><td>$"+
		     x(row[1], sups(par(row[0]+"-"+o(Snittet)), 2))+" ="+o(radVar)+"$</td></tr>");

	});

    t.append("<tr><td>&nbsp;</td><td>$N="+N+"$</td><td>$S="+S+"$</td><td>$A="+o(A)+"$</td></tr>");

    var out = _.template((utenTittel?"":'<h2>Finner variansen:</h2>')+
			 '<h3>Må først finne gjennomsnittet:</h3>'+
			 '<%= gjSnitt %>'+
			 '<h3>Bruker gjennomsnittet til å finne variansen:</h3>'+
			 '<%= table %>'+
			 'Summen av kvadratene av avvikene er $ A = <%= A %>$<br>'+
			 'Variansen er: $<%= varUtr %>$',
{gjSnitt: FrekvensSnitt("Uten tittel"),
 table: t.wrap('<div></div>').parent().html(),
 A: o(A),
 varUtr: fr("A","N")+"="+fr(o(A),N) + "=" + o(A/N)});

    return out;
};



var  FrekvensStandardavvik = function (utenTittel) {
    var headers = frekvensData[0];
    var frekTab = frekvensData.slice(1);
    frekTab= _.initial(frekTab);

    // Finner snittet
    var NN = 0;
    var SS = 0;
    _.each(frekTab, function(row) {
	    NN = NN + parseInt(row[1]);
	    SS = SS + (parseInt(row[0])*parseInt(row[1]));
	});

    var Snittet = SS/NN;


    var N = 0;
    var S = 0;
    var A = 0;
    _.each(frekTab, function(row) {
	    N = N + parseInt(row[1]);
	    S = S + (parseInt(row[0])*parseInt(row[1]));
	    var radVar = row[1] *Math.pow(row[0]-Snittet,2);
	    A = A + radVar;
	});

    var Variansen = A/N;
    var out = _.template(utenTittel?"":'<h2>Finner standardavviket:</h2>'+
			 '<%= varUtr %>'+
			 '<H3>Bruker variansen til å finne standardavviket:</h3>'+
			 'Standardavviket er: $<%= stdUtr %>$',
{varUtr: FrekvensVarianse("Uten tittel"),
 stdUtr:  sq(o(A/N))+ "=" + o(Math.sqrt(A/N))});
    // variant med litt mer utregning under...
    // stdUtr: sq(fr("A","N"))+"="+sq(fr(A,N)) + "=" + sq(o(A/N))+ "=" + o(Math.sqrt(A/N))});

    return out;
};


var  FrekvensVariasjonsbredde = function () {
    var headers = frekvensData[0];
    var frekTab = frekvensData.slice(1);
    frekTab= _.initial(frekTab);

    var maxVer= parseInt(_.max(frekTab, function(elm){ return elm[0]; })[0]);
    var minVer= parseInt(_.min(frekTab, function(elm){ return elm[0]; })[0]);


    var out = _.template('<h2>Finner Variasjonsbredden:</h2>'+
			 'Den minste verdien er <%= minVer %><br/>'+
			 'Den største verdien er <%= maxVer %><br/>'+

			 'Variasjonsbredden er største verdi minus minste verdi = $<%= varbredd %>$',
{minVer:minVer,
 maxVer:maxVer,
 varbredd:  maxVer + "-" + minVer +"="+(maxVer - minVer)});

    return out;
};


var FrekvensStolpe = function() {
    console.log("FrekvensStolpe er blit kallet");
    var headers = frekvensData[0];
    var frekTab = frekvensData.slice(1);
    frekTab= _.initial(frekTab);


    outputTag.append("<h2>Søylediagram:</h2>");


    var margin = {top: 20, right: 20, bottom: 60, left: 65},
    width = 700 - margin.left - margin.right,
    height = 400 - margin.top - margin.bottom;

    //		var formatPercent = d3.format(".0%");

    var x = d3.scale.ordinal()
    .rangeRoundBands([0, width], .1);

    var y = d3.scale.linear()
    .range([height, 0]);

    var xAxis = d3.svg.axis()
    .scale(x)
    .orient("bottom");

    var yAxis = d3.svg.axis()
    .scale(y)
    .orient("left");
    //		    .tickFormat(formatPercent);

    var svg = d3.select("#frekvensDataUt").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
    .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

		
    var data = frekTab;

    x.domain(data.map(function(d) { return d[0]; }));
    y.domain([0, d3.max(data, function(d) { return d[1]; })]);

    svg.append("g")
    .attr("class", "x axis")
    .attr("transform", "translate(0," + height + ")")
    .call(xAxis);
  		     
    svg.append("g")
    .attr("class", "y axis")
    .call(yAxis)
    .append("text")
    .attr("transform", "rotate(-90)")
    .attr("y", 6)
    .attr("dy", ".51em")
    .style("text-anchor", "end")
    .text("Frekvens");

    svg.selectAll(".bar")
    .data(data)
    .enter().append("rect")
    .attr("class", "bar")
    .attr("x", function(d) { return x(d[0]); })
    .attr("width", x.rangeBand())
    .attr("y", function(d) { return y(d[1]); })
    .attr("height", function(d) { return height - y(d[1]); });


    svg.append("text")
    .attr("class", "x label")
    .attr("text-anchor", "end")
    .attr("x", width/2 )
    .attr("y", height + 40)
    .text(headers[0]);


    return "";
}


    var FrekvensKake = function() {

	var headers = frekvensData[0];
	var frekTab = frekvensData.slice(1);
	frekTab= _.initial(frekTab);


	outputTag.append("<h2>Kakediagram:</h2>");


	var width = 500,
	height = 400,
	radius = Math.min(width, height) / 2;

	var color = d3.scale.ordinal()
	.range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);

	var arc = d3.svg.arc()
	.outerRadius(radius - 10)
	.innerRadius(0);

	var pie = d3.layout.pie()
	.sort(null)
	.value(function(d) { return d[1]; });

	var svg = d3.select("#frekvensDataUt").append("svg")
	.attr("width", width)
	.attr("height", height)
	.append("g")
	.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");


	var data = frekTab;

	data.forEach(function(d) {
		d[1] = +d[1];
	    });

	var g = svg.selectAll(".arc")
	.data(pie(data))
	.enter().append("g")
	.attr("class", "arc");

	g.append("path")
	.attr("d", arc)
	.style("fill", function(d) { return color(d.data[0]); });

	g.append("text")
	.attr("transform", function(d) { return "translate(" + arc.centroid(d) + ")"; })
	.attr("dy", ".35em")
	.style("text-anchor", "middle")
	.style("font-size", "20px")
	.style("color", "white")      
	.text(function(d) { return d.data[0]; });


    };

var  KlasseSnitt = function (utenTittel) {
    var headers = klasseData[0];
    var frekTab = klasseData.slice(1);
    frekTab= _.initial(frekTab);

    var t = $( '<table>');
    t.addClass("table table-bordered table-striped table-condensed");
    t.css({ width: 0,
		height: 0});
    t.append("<thead><tr><th>Klasse&nbsp;$[a, b \\rangle $</th><th>Klassemidtpunkt&nbsp;$x_m$</th><th>Frekvens&nbsp;$f$</th><th>Klassesum&nbsp;$f \\cdot x_m$</th></tr></thead>");
    var N = 0;
    var S = 0;
    _.each(frekTab, function(row) {
	    row = _.map(row,Number);
	    N = N + row[2];
	    var klmidt = (row[1]+row[0])/2;
	    var klsum = (klmidt*row[2]);
	    S = S + klsum;
	    t.append("<tr><td>$["+row[0]+" , "+ row[1]+"\\rangle $</td><td>$"+klmidt+"$</td><td>$"+row[2]+"$</td><td>$"+klsum+"$</td></tr>");

	});

    t.append("<tr><td>&nbsp;</td><td>&nbsp;</td><td>$N="+N+"$</td><td>$S="+S+"$</td></tr>");

    var out = _.template('<%= table %>'+
			 'Gjennomsnittet er omtrent: $ g = \\frac{S}{N} = <%= snitt %>$',
{table: t.wrap('<div></div>').parent().html(),
 snitt: eq(fr(S,N),o(S/N))});
    out = (utenTittel?"":'<h2>Finner gjennomsnittet:</h2>') + out;
    return out;
};


var  KlasseMedian = function () {
    var headers = klasseData[0];
    var frekTab = klasseData.slice(1);
    frekTab= _.initial(frekTab);


    // Må dessverre sjekke at ikke frekvensene er for høye fordi da kræsjer programmet...

	if (! _.every(frekTab, function(row) {
		return row[2] < 1000000;
	})){
		return "Kalkulatoren kan for tiden dessverre ikke finne medianen av tabeller med så høye frekvenser. Beklager."
	}


    var t = $( '<table>');
    t.addClass("table table-bordered table-striped table-condensed");
    t.css({ width: 0,
		height: 0});
    t.append("<thead><tr><th>Klasse&nbsp;$[a, b \\rangle $</th><th>Frekvens&nbsp;$f$</th><th>Kumulativ&nbsp;frekvens</th></tr></thead>");


    // må dessverre finne antall obs. først for å kunne bruke den i neste loop
    var NumObs = 0;
    _.each(frekTab, function(row,index) {
	    row = _.map(row,Number);

	    NumObs = NumObs + row[2];
	});

    var N = 0;

    var listVals = [""]; // må legge til en nullverdi for at tellingen skal bli enklere senere...
	
    _.each(frekTab, function(row,index) {
	    row = _.map(row,Number);


	    var oldN = N;


	    N = N + parseInt(row[2]);


	    listVals = listVals.concat(repeatArray([[row[0], row[1],oldN,N,row[2]]],row[2]));


	    var utregn = index===0?N:eq(pl(oldN,row[2]),N);

	    //gjær grønn hvis den er median
	    var makeGreen = "";
	    if (NumObs%2==0) { // partall
		var v1 = (NumObs/2);
		var v2 = v1 + 1;
		if ((v1 > oldN && v1<= N ) || (v2 > oldN && v2<= N )) {
		    makeGreen = ' class="info" ' ;
		} else {
		    makeGreen = "";	
		}
	    } else { // oddetall
		var v = ((NumObs +1)/2);
		if (v > oldN && v<= N ) {
		    makeGreen = ' class="info" ' ;
		} else {
		    makeGreen = "";	
		}
	    }



	    t.append("<tr"+makeGreen+"><td>$["+row[0]+" , "+ row[1]+"\\rangle $</td><td>$"+row[2]+"$</td><td>$"+utregn+"$</td></tr>");

	});
    //	console.log(listVals);
    var medUtr = "";
    var type = "";
    var median = "";
    var nr = "";
    var med1 = "";
    var medianVerdi; 
    if (N%2==0) { // partall
	type = "partall";
	medUtr = "Dette er et partall. <br/> Fordi vi ikke kan finne nøyaktig median i klassedelt materiale sier vi at medianen er observasjon nummer $" + 
	    [fr("N", "2"), fr(N , "2"), (N)/2].join(" = ") + "$";

	med1 = listVals[N/2];

	nr = "Observasjon nr $" + (N/2) + "$ er i intervallet $" + interval(med1) + "$<br>"+

	    "Ettersom det er "+ med1[2] +" observasjoner som er lavere enn "+ med1[0]+ " er observasjonen nummer $"+(N/2)+"-"+med1[2]+"="+((N/2)-med1[2])+"$ i intervallet $"+interval(med1)+"$<br/>";
			

	median = "$"+med1[0]+ "+"+ x(fr(((N/2)-med1[2]), med1[4]),med1[1]-med1[0])+ "=" + uu(o(med1[0] + (((N/2)-med1[2])/med1[4])*(med1[1]-med1[0])))+ "$<br>";




    } else { // oddetall

	type = "oddetall";
	medianVerdi = (N+1)/2;

	medUtr = "Det er et oddetall. <br/>" + 
	"Medianen er da observasjon nummer $" + [fr("N +1", "2"),
						 fr(N + "+ 1", "2"),
						 fr(N+1,"2"),
						 (N+1)/2].join(" = ") + "$";



	med1 = listVals[medianVerdi];


	nr = "Observasjon nr $" + medianVerdi + "$ er i intervallet $" + interval(med1) + "$<br>"+

	"Ettersom det er "+ med1[2] +" observasjoner som er lavere enn "+ med1[0]+ " er observasjonen nummer $"+medianVerdi+"-"+med1[2]+"="+(medianVerdi-med1[2])+"$ i intervallet $"+interval(med1)+"$<br/>";

	median = "$"+med1[0]+ "+"+ x(fr(((medianVerdi-med1[2])), med1[4]),med1[1]-med1[0])+ "=" + uu(o(med1[0] + ((medianVerdi-med1[2])/med1[4])*(med1[1]-med1[0])))+ "$<br>";

		
    }

    t.append("<tr><td>&nbsp;</td><td>$N="+N+"$</td><td>&nbsp;</td></tr>");

    var out = _.template('<h2>Finner medianen:</h2><%= table %>'+
			 'Vi har her $<%= N %>$ observasjoner. ' + 
			 '<%= medUtr %><br/>'+
			 "<%= ObsNr%>" +
			 'Medianen er dermed omtrent: <%= median %>',
{table: t.wrap('<div></div>').parent().html(),
 N: N,
 ObsNr: nr,
 medUtr: medUtr,
 median: median});

    return out;
};

var KlasseHist = function() {
    var headers = klasseData[0];
    var frekTab = klasseData.slice(1);
    frekTab= _.initial(frekTab);


    outputTag.append("<h2>Histogram:</h2>");


    var margin = {top: 10, right: 20, bottom: 70, left: 60},
    width = 700 - margin.left - margin.right,
    height = 500 - margin.top - margin.bottom;


    var svg = d3.select("#frekvensDataUt").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
    .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    var x = d3.scale.linear()
    .range([0, width]);

    var y = d3.scale.linear()
    .range([height, 0]);


    var bins = frekTab;

    // Coerce types.
    bins.forEach(function(bin) {
	    bin = _.map(bin, Number);
	});

    // Normalize each bin to so that height = quantity/width;
    // see http://en.wikipedia.org/wiki/Histogram#Examples
    for (var i = 0, n = bins.length, bin; i < n; i++) {
	bin = bins[i];
	bin.offset = bin[0];
	bin.width = bin[1] - bin[0];
	bin.height = bin[2] / bin.width;
    }

    // Drop the first bin, since it's incorporated into the next.
    //bins.shift();

    //  console.log([d3.min(bins.map(function(d) { return d[0] })), d3.max(bins.map(function(d) { return d[1] }))]);

    console.log(bins.map(function(d) { return d[1]; }));
    // Set the scale domain.
    x.domain([d3.min(bins.map(function(d) { return d[0] })), d3.max(bins.map(function(d) { return d[1] }))]);
    y.domain([0, d3.max(bins.map(function(d) { return d.height; }))]);

    //  console.log("***" + x(5) + "++++"+ x(190));
    // Add the bins.
    svg.selectAll(".bin")
    .data(bins)
    .enter().append("rect")
    .attr("class", "bin")
    .attr("x", function(d) { return x(d.offset); })
    .attr("width", function(d) { console.log("!!!"+ d.width); return x(d[1]) -x(d[0]) - 1; })
    .attr("y", function(d) { return y(d.height); })
    .attr("height", function(d) { return height - y(d.height); });

    svg.append("g")
    .attr("class", "hist x axis")
    .attr("transform", "translate(0," + height + ")")
    .call(d3.svg.axis()
	  .scale(x)
	  .orient("bottom"));

    svg.append("g")
    .attr("class", "y axis")
    .call(d3.svg.axis()
	  .scale(y)
	  .orient("left"))

    .append("text")
    .attr("transform", "rotate(-90)")
    .attr("y", 6)
    .attr("dy", ".51em")
    .style("text-anchor", "end")
    .text("Histogramhøyde");


}

    var beregn = undefined;
var inputValidator = function () {return false};

var RedrawOutData = function() {
    clearOutput();
    if (beregn) {
	var res = inputValidator() || beregn();


	if (res) {
	    outputTag.html(res).show();
	} else {
	    // da antar vi at vi er i en av graftegnevariantene...
	    outputTag.show();
 									
	}

 							
	MathJax.Hub.Queue(["Typeset",MathJax.Hub]);

							
    } else {
	console.log("beregn er " + beregn);
	$( '#DataUt' ).html('Du må velge en funksjon i menyen øverst').show();
    }
};	

$( document ).ready(function() {

	// set up handlers for everything...
	$( '#ListeSnitt' ).click(function( event ) { 
		listeMode();
		clearOutput();
		beregn = ListeSnitt;
		beregn();
		RedrawOutData();
	    });
	$( '#ListeTypetall' ).click(function( event ) { 
		listeMode();
		clearOutput();
		beregn = ListeTypetall;
		beregn();
		RedrawOutData();
	    });
	$( '#ListeMedian' ).click(function( event ) { 
		listeMode();
		clearOutput();
		beregn = ListeMedian;
		beregn();
		RedrawOutData();
	    });

	$( '#ListeVarianse' ).click(function( event ) { 
		listeMode();
		clearOutput();
		beregn = ListeVarianse;
		beregn();
		RedrawOutData();
	    });
	$( '#ListeKvartil' ).click(function( event ) { 
		listeMode();
		clearOutput();
		beregn = ListeKvartil;
		beregn();
		RedrawOutData();
	    });
	$( '#ListeStandardavvik' ).click(function( event ) { 
		listeMode();
		clearOutput();
		beregn = ListeStandardavvik;
		beregn();
		RedrawOutData();
	    });
	$( '#ListeVariasjonsbredde' ).click(function( event ) { 
		listeMode();
		clearOutput();
		beregn = ListeVariasjonsbredde;
		RedrawOutData();
	    });
	$( '#ListeStolpe' ).click(function( event ) { 
		listeMode();
		clearOutput();
		beregn = ListeStolpe;
		RedrawOutData();
	    });

	$( '#ListeKake' ).click(function( event ) { 
		listeMode();
		clearOutput();
		beregn = ListeKake;
		RedrawOutData();
	    });

	$( '#FrekvensSnitt' ).click(function( event ) { 
		frekvensMode();
		clearOutput();
		beregn = FrekvensSnitt;
		//console.log("klikket på greia"+beregn);
		RedrawOutData();
	    });

	$( '#FrekvensTypetall' ).click(function( event ) { 
		frekvensMode();
		clearOutput();
		beregn = FrekvensTypetall;
		//console.log("klikket på greia"+beregn);
		RedrawOutData();
	    });	 
	$( '#FrekvensMedian' ).click(function( event ) { 
		frekvensMode();
		clearOutput();
		beregn = FrekvensMedian;
		//console.log("klikket på greia"+beregn);
		RedrawOutData();
	    });	
	$( '#FrekvensVarianse' ).click(function( event ) { 
		frekvensMode();
		clearOutput();
		beregn = FrekvensVarianse;
		//console.log("klikket på greia"+beregn);
		RedrawOutData();
	    });	
	$( '#FrekvensKvartil' ).click(function( event ) { 
		listeMode();
		clearOutput();
		beregn = FrekvensKvartil;
		beregn();
		RedrawOutData();
	    });
	$( '#FrekvensStandardavvik' ).click(function( event ) { 
		frekvensMode();
		clearOutput();
		beregn = FrekvensStandardavvik;
		//console.log("klikket på greia"+beregn);
		RedrawOutData();
	    });	
	$( '#FrekvensVariasjonsbredde' ).click(function( event ) { 
		console.log("$( '#FrekvensVariasjonsbredde' ).click(function( event ) { ");
		frekvensMode();
		clearOutput();
		beregn = FrekvensVariasjonsbredde;
		//console.log("klikket på greia"+beregn);
		RedrawOutData();
	    });	

	$( '#FrekvensStolpe' ).click(function( event ) { 
		console.log("$( '#FrekvensStolpe' ).click(function( event ) { ");
		frekvensMode();
		clearOutput();
		beregn = FrekvensStolpe;
		//console.log("klikket på greia"+beregn);
		RedrawOutData();
	    });	
	$( '#FrekvensKake' ).click(function( event ) { 
		frekvensMode();
		clearOutput();
		beregn = FrekvensKake;
		//console.log("klikket på greia"+beregn);
		RedrawOutData();
	    });	


	$( '#KlasseSnitt' ).click(function( event ) { 
		klasseMode();
		clearOutput();
		beregn = KlasseSnitt;
		//console.log("klikket på greia"+beregn);
		RedrawOutData();
	    });

	$( '#KlasseMedian' ).click(function( event ) { 
		klasseMode();
		clearOutput();
		beregn = KlasseMedian;
		//console.log("klikket på greia"+beregn);
		RedrawOutData();
	    });

	$( '#KlasseHist' ).click(function( event ) { 
		klasseMode();
		clearOutput();
		beregn = KlasseHist;
		//console.log("klikket på greia"+beregn);
		RedrawOutData();
	    });

	$( '#Tallsystem2til10' ).click(function( event ) { 
		tallsystemMode();
		clearOutput();
		beregn = Tallsystem2til10;
		RedrawOutData();
	});


	$( '#regnUtKnapp' ).click(function (event){
		event.preventDefault();
		RedrawOutData();
	});

	$( '.brand' ).click(function (event){
		event.preventDefault();

		make_active("NavnOppTilVenstre");

		$("#self-promotion").show();
		$( '#math-unit' ).hide();
		
	});




	make_active("NavnOppTilVenstre");

		$( '#math-unit' ).hide();

		$('#frekvensDataInn').hide();

		$("#nyTabell").hide();



    });

