w2v-server: introduce position heats for collocators
diff --git a/templates/index.html.ep b/templates/index.html.ep
index 33579fd..7e5fb95 100644
--- a/templates/index.html.ep
+++ b/templates/index.html.ep
@@ -11,194 +11,211 @@
 		<link rel="stylesheet" href="https://cdn.datatables.net/1.10.16/css/jquery.dataTables.min.css">
     <script
 			src="http://code.jquery.com/ui/1.12.1/jquery-ui.min.js"
-				integrity="sha256-VazP97ZCwtekAsvgPBSUwPFKdrwD3unUfSGVYrahUqU="
-				crossorigin="anonymous"></script>
+			integrity="sha256-VazP97ZCwtekAsvgPBSUwPFKdrwD3unUfSGVYrahUqU="
+			crossorigin="anonymous"></script>
     <script>
 		 var urlParams = new URLSearchParams(window.location.search);
 
      $('#firstable').hide();
 		 $(document).ready(function() {
 
-				 $("input").bind("keydown", function(event) {
-						 // track enter key
-						 var keycode = (event.keyCode ? event.keyCode : (event.which ? event.which : event.charCode));
-						 if (keycode == 13) { // keycode for enter key
-								 // force the 'Enter Key' to implicitly click the Update button
-								 document.getElementById('SEARCH').click();
-								 return false;
-						 } else  {
-								 return true;
-						 }});
+			 $("input").bind("keydown", function(event) {
+				 // track enter key
+				 var keycode = (event.keyCode ? event.keyCode : (event.which ? event.which : event.charCode));
+				 if (keycode == 13) { // keycode for enter key
+					 // force the 'Enter Key' to implicitly click the Update button
+					 document.getElementById('SEARCH').click();
+					 return false;
+				 } else  {
+					 return true;
+				 }});
 
-				 $(".selector").tabs({ active: 1 });
+			 $(".selector").tabs({ active: 1 });
 
 
-				 $('#firsttable').DataTable({
-						 "sScrollY": "780px",
-						 "bScrollCollapse": true,
-						 "bPaginate": false,
-						 "bJQueryUI": true,
-						 "dom": '<"top">rt<"bottom"flp><"clear">',
-						 "aoColumnDefs": [
-								 { "sWidth": "10%", "aTargets": [ -1 ] }
-						 ]
+			 $('#firsttable').DataTable({
+				 "sScrollY": "780px",
+				 "bScrollCollapse": true,
+				 "bPaginate": false,
+				 "bJQueryUI": true,
+				 "dom": '<"top">rt<"bottom"flp><"clear">',
+				 "aoColumnDefs": [
+					 { "sWidth": "10%", "aTargets": [ -1 ] }
+				 ]
+			 } );
+
+       $( "#first" ).clone().prependTo( "#tabs-2" );
+
+       function changeCharColor(txt, heat) {
+         var newText = "";
+         for (var i=0, l=txt.length; i<l; i++) {
+           newText += '<span style="background-color:'+getHeatColor(heat[i]/maxHeat)+'">'+txt.charAt(i)+'</span>';
+         }
+         return newText;
+       }
+
+       function getHeatColor(value) {
+         var hue=((1-value)*120).toString(10);
+         return ["hsl(",hue,",100%,50%)"].join("");
+       }
+
+			 function bitvec2window(n, heat) {
+				 var str = n.toString(2).padStart(10, "0")
+										.replace(/^([0-9]{5})/, '$1x')
+										.replace(/0/g, '·')
+										.replace(/1/g, '+');
+			   return changeCharColor(str, heat);
+			 }
+
+			 var collocatorData = <%= b(Mojo::JSON::to_json($collocators)) %>;
+       var maxHeat; // = Math.max.apply(Math,collocatorData.map(function(o){return o.cprob;}))
+       maxHeat = Math.max.apply(Math,collocatorData.map(function(o){return Math.max.apply(Math,o.heat);}))
+
+			 if (collocatorData != null) {
+				 var t = $('#secondtable').DataTable({
+           data: collocatorData,
+					 "sScrollY": "800px",
+					 "bScrollCollapse": true,
+					 "bPaginate": false,
+					 "bJQueryUI": true,
+					 "dom": '<"top">rt<"bottom"flp><"clear">',
+					 "columns": [
+						 { "data": "rank", type: "allnumeric" },
+						 { "data": "pos", width: "7%", sClass: "dt-center mono compact", render: function ( data, type, row ) {return bitvec2window(data, row.heat) }},
+						 { "data": "max",  render: function ( data, type, row ) {return data.toFixed(3) }},
+						 { "data": "conorm", render: function ( data, type, row ) {return data.toFixed(3) }},
+						 { "data": "prob", type: "scientific", render: function ( data, type, row ) {return data.toExponential(3) }  },
+						 { "data": "cprob", type: "scientific", render: function ( data, type, row ) {return data.toExponential(3) }  },
+						 { "data": "overall", type: "scientific", render: function ( data, type, row ) {return data.toExponential(3) } },
+						 { "data": "word",  sClass: "collocator" }
+					 ],
+					 "columnDefs": [
+						 { className: "dt-right", "targets": [0,2,3,4,5,6] },
+						 { className: "dt-center", "targets": [ 1] },
+						 { "searchable": false,
+							 "orderable": false,
+							 "targets": 0
+						 },
+						 { "type": "scientific", targets: [2,3,4,5,6] },
+						 { "orderSequence": [ "desc" ], "targets": [ 2, 3, 4, 5, 6 ] },
+						 { "orderSequence": [ "asc", "desc" ], "targets": [ 1, 7 ] },
+					 ],
+					 "order": [[ 4, 'desc' ]],
 				 } );
 
-				 function bitvec2window(n) {
-						 var str = n.toString(2).padStart(10, "0")
-												.replace(/^([0-9]{5})/, '$1x')
-												.replace(/0/g, '·')
-												.replace(/1/g, '+');
-						 return str;
-				 }
-
-				 var collocatorData = <%= b(Mojo::JSON::to_json($collocators)) %>; 
-				 
-				 if (collocatorData != null) {
-						 var t = $('#secondtable').DataTable({
-                 data: collocatorData,
-								 "sScrollY": "800px",
-								 "bScrollCollapse": true,
-								 "bPaginate": false,
-								 "bJQueryUI": true,
-								 "dom": '<"top">rt<"bottom"flp><"clear">',
-								 "columns": [
-										 { "data": "rank", type: "allnumeric" },
-										 { "data": "pos", width: "7%", sClass: "dt-center mono compact", render: function ( data, type, row ) {return bitvec2window(data) }},
-										 { "data": "max",  render: function ( data, type, row ) {return data.toFixed(3) }},
-										 { "data": "conorm", render: function ( data, type, row ) {return data.toFixed(3) }},
-										 { "data": "prob", type: "scientific", render: function ( data, type, row ) {return data.toExponential(3) }  },
-										 { "data": "cprob", type: "scientific", render: function ( data, type, row ) {return data.toExponential(3) }  },
-										 { "data": "overall", type: "scientific", render: function ( data, type, row ) {return data.toExponential(3) } },
-										 { "data": "word",  sClass: "collocator" }
-								 ],
-								 "columnDefs": [
-										 { className: "dt-right", "targets": [0,2,3,4,5,6] },
-										 { className: "dt-center", "targets": [ 1] },
-										 { "searchable": false,
-											 "orderable": false,
-											 "targets": 0
-										 }, 
-										 { "type": "scientific", targets: [2,3,4,5,6] },
-										 { "orderSequence": [ "desc" ], "targets": [ 2, 3, 4, 5, 6 ] },
-										 { "orderSequence": [ "asc", "desc" ], "targets": [ 1, 7 ] },
-								 ],
-								 "order": [[ 4, 'desc' ]],
-						 } );
-
-						 t.on( 'order.dt search.dt', function () {
-								 t.column(0, {order:'applied'}).nodes().each( function (cell, i) {
-										 cell.innerHTML = i+1;
-								 } );
-						 } ).draw();
-				 }
-				 $("#tabs").css("visibility", "visible"); // now we can show the tabs
+				 t.on( 'order.dt search.dt', function () {
+					 t.column(0, {order:'applied'}).nodes().each( function (cell, i) {
+						 cell.innerHTML = i+1;
+					 } );
+				 } ).draw();
+			 }
+			 $("#tabs").css("visibility", "visible"); // now we can show the tabs
 
 		 });
 
 		 $(function(){
-				 $("#dropdownoptions").dialog({
-						 title: "Options",
-						 autoOpen: false,
-						 modal: false,
-						 draggable: false,
-						 height: "auto",
-						 width: "auto",
-						 resizable: false,
-						 buttons: {
-								 "Cancel": function() {
-										 $( this ).dialog( "close" );
-								 },
-								 "Apply": function() {
-										 window.open($(location).attr('pathname')+'?'+$('form').serialize(), "_self");
-								 }
-						 }
-				 });
-		 });
-
-		 $(function(){
-				 $("#SEARCH").click(function() {
+			 $("#dropdownoptions").dialog({
+				 title: "Options",
+				 autoOpen: false,
+				 modal: false,
+				 draggable: false,
+				 height: "auto",
+				 width: "auto",
+				 resizable: false,
+				 buttons: {
+					 "Cancel": function() {
+						 $( this ).dialog( "close" );
+					 },
+					 "Apply": function() {
 						 window.open($(location).attr('pathname')+'?'+$('form').serialize(), "_self");
-				 });
+					 }
+				 }
+			 });
 		 });
 
 		 $(function(){
-				 $("td.collocator").click(function(){
-						 queryKorAPCII(this.textContent + " /w5 " + urlParams.get('word'));
-				 });
+			 $("#SEARCH").click(function() {
+				 window.open($(location).attr('pathname')+'?'+$('form').serialize(), "_self");
+			 });
 		 });
-     
+
 		 $(function(){
-				 $("#showoptions").click(function(){
-						 $("#dropdownoptions").dialog("open");
-						 var target = $(this);
-						 $("#dropdownoptions").dialog("widget").position({
-								 my: 'left bottom',
-								 at: 'left bottom',
-								 of: target
-						 });
+			 $("td.collocator").click(function(){
+				 queryKorAPCII(this.textContent + " /w5 " + urlParams.get('word'));
+			 });
+		 });
+
+		 $(function(){
+			 $("#showoptions").click(function(){
+				 $("#dropdownoptions").dialog("open");
+				 var target = $(this);
+				 $("#dropdownoptions").dialog("widget").position({
+					 my: 'left bottom',
+					 at: 'left bottom',
+					 of: target
 				 });
+			 });
 		 });
 
 		 $( function() {
-				 $( "#no_iterations" ).spinner({
-						 spin: function( event, ui ) {
-								 if ( ui.value < 1000 ) {
-										 $( this ).spinner( "value", 1000 );
-										 return false;
-								 } else if ( ui.value > 10000 ) {
-										 $( this ).spinner( "value", 10000 );
-										 return false;
-								 }
-						 }
-				 });
+			 $( "#no_iterations" ).spinner({
+				 spin: function( event, ui ) {
+					 if ( ui.value < 1000 ) {
+						 $( this ).spinner( "value", 1000 );
+						 return false;
+					 } else if ( ui.value > 10000 ) {
+						 $( this ).spinner( "value", 10000 );
+						 return false;
+					 }
+				 }
+			 });
 		 } );
 
 		 $( function() {
-				 $( "#neighbours" ).spinner({
-						 spin: function( event, ui ) {
-								 if ( ui.value < 0 ) {
-										 $( this ).spinner( "value", 0 );
-										 return false;
-								 } else if ( ui.value > 200 ) {
-										 $( this ).spinner( "value", 200 );
-										 return false;
-								 }
-						 }
-				 });
+			 $( "#neighbours" ).spinner({
+				 spin: function( event, ui ) {
+					 if ( ui.value < 0 ) {
+						 $( this ).spinner( "value", 0 );
+						 return false;
+					 } else if ( ui.value > 200 ) {
+						 $( this ).spinner( "value", 200 );
+						 return false;
+					 }
+				 }
+			 });
 		 } );
 
 		 $( function() {
-				 $( "#cutoff" ).spinner({
-						 spin: function( event, ui ) {
-								 if ( ui.value < 100000 ) {
-										 $( this ).spinner( "value", 100000 );
-										 return false;
-								 } else if ( ui.value > 2000000 ) {
-										 $( this ).spinner( "value", 2000000 );
-										 return false;
-								 }
-						 }
-				 });
+			 $( "#cutoff" ).spinner({
+				 spin: function( event, ui ) {
+					 if ( ui.value < 100000 ) {
+						 $( this ).spinner( "value", 100000 );
+						 return false;
+					 } else if ( ui.value > 2000000 ) {
+						 $( this ).spinner( "value", 2000000 );
+						 return false;
+					 }
+				 }
+			 });
 		 } );
 
 		 var tabactivated = {}
      $( function() {
-				 $( "#tabs" ).tabs().addClass('tabs-min');
+			 $( "#tabs" ).tabs().addClass('tabs-min');
 		 } );
 
 		 $( function() {
-				 $( ".controlgroup-vertical" ).controlgroup({
-						 "direction": "vertical"
-				 });
+			 $( ".controlgroup-vertical" ).controlgroup({
+				 "direction": "vertical"
+			 });
 		 } );
 
 		 $(function() {
-				 $( document ).tooltip({
-						 content: function() {
-								 return $(this).attr('title');
-						 }}
-				 )
+			 $( document ).tooltip({
+				 content: function() {
+					 return $(this).attr('title');
+				 }}
+			 )
 		 })
 
     </script>
@@ -427,27 +444,27 @@
      var labeler;
 
      function applyJitter() {
-				 svg.selectAll('.tsnet')
-						.data(labels)
-						.transition()
-						.duration(50)
-						.attr("transform", function(d, i) {
-								T.Y[i][0] = (d.x - mapWidth/2 - tx)/ss/20;
-								T.Y[i][1] = (d.y - mapHeight/2 - ty)/ss/20;
-								return "translate(" +
-											(d.x) + "," +
-											(d.y) + ")";
-						});
+			 svg.selectAll('.tsnet')
+					.data(labels)
+					.transition()
+					.duration(50)
+					.attr("transform", function(d, i) {
+						T.Y[i][0] = (d.x - mapWidth/2 - tx)/ss/20;
+						T.Y[i][1] = (d.y - mapHeight/2 - ty)/ss/20;
+						return "translate(" +
+											  (d.x) + "," +
+											  (d.y) + ")";
+					});
      }
 
      function updateEmbedding() {
-				 var Y = T.getSolution();
-				 svg.selectAll('.tsnet')
-						.data(data.words)
-						.attr("transform", function(d, i) {
-								return "translate(" +
-											 ((Y[i][0]*20*ss + tx) + mapWidth/2) + "," +
-											 ((Y[i][1]*20*ss + ty) + mapHeight/2) + ")"; });
+			 var Y = T.getSolution();
+			 svg.selectAll('.tsnet')
+					.data(data.words)
+					.attr("transform", function(d, i) {
+						return "translate(" +
+											   ((Y[i][0]*20*ss + tx) + mapWidth/2) + "," +
+											   ((Y[i][1]*20*ss + ty) + mapHeight/2) + ")"; });
      }
 
      var svg;
@@ -456,58 +473,58 @@
      var text;
 
      function drawEmbedding() {
-				 $("#embed").empty();
-				 var div = d3.select("#embed");
+			 $("#embed").empty();
+			 var div = d3.select("#embed");
 
-				 // get min and max in each column of Y
-				 var Y = T.Y;
+			 // get min and max in each column of Y
+			 var Y = T.Y;
 
-				 svg = div.append("svg") // svg is global
-									.attr("width", mapWidth)
-									.attr("height", mapHeight);
+			 svg = div.append("svg") // svg is global
+								.attr("width", mapWidth)
+								.attr("height", mapHeight);
 
-				 var g = svg.selectAll(".b")
-										.data(data.words)
-										.enter().append("g")
-										.attr("class", "tsnet");
+			 var g = svg.selectAll(".b")
+									.data(data.words)
+									.enter().append("g")
+									.attr("class", "tsnet");
 
-				 g.append("a")
-					.attr("xlink:href", function(word) {
-							return (data.urlprefix+word);})
-					.attr("class", function(d, i) {
-							var res="";
-							if(data.marked[i]) {
-									res="marked ";
-							}
-							if(data.target.indexOf(" "+d+" ") >= 0) {
-									return res+"target";
-							} else if(data.ranks[i] < data.mergedEnd) {
-									return res+"merged";
-							} else {
-									return res;
-							}
-					})
-					.attr("title", function(d, i) {
-							if(data.mergedEnd > 0) {
-									if(data.ranks[i] >= data.mergedEnd) {	
-         							return "rank: "+i +"  "+"freq. rank: "+(data.ranks[i]).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
-									} else {
-         							return "rank: "+i +"  "+"freq. rank: "+data.ranks[i].toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") + " (merged vocab)";
-									}
-							} else {
-									return "rank: "+i +"  "+"freq. rank: "+data.ranks[i].toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
-							}
-					})
-					.append("text")
-					.attr("text-anchor", "top")
-					.attr("font-size", 12)
-					.text(function(d) { return d; });
+			 g.append("a")
+				.attr("xlink:href", function(word) {
+					return (data.urlprefix+word);})
+				.attr("class", function(d, i) {
+					var res="";
+					if(data.marked[i]) {
+						res="marked ";
+					}
+					if(data.target.indexOf(" "+d+" ") >= 0) {
+						return res+"target";
+					} else if(data.ranks[i] < data.mergedEnd) {
+						return res+"merged";
+					} else {
+						return res;
+					}
+				})
+				.attr("title", function(d, i) {
+					if(data.mergedEnd > 0) {
+						if(data.ranks[i] >= data.mergedEnd) {
+         			return "rank: "+i +"  "+"freq. rank: "+(data.ranks[i]).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
+						} else {
+         			return "rank: "+i +"  "+"freq. rank: "+data.ranks[i].toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") + " (merged vocab)";
+						}
+					} else {
+						return "rank: "+i +"  "+"freq. rank: "+data.ranks[i].toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
+					}
+				})
+				.append("text")
+				.attr("text-anchor", "top")
+				.attr("font-size", 12)
+				.text(function(d) { return d; });
 
-				 var zoomListener = d3.behavior.zoom()
-															.scaleExtent([0.1, 10])
-															.center([0,0])
-															.on("zoom", zoomHandler);
-				 zoomListener(svg);
+			 var zoomListener = d3.behavior.zoom()
+														.scaleExtent([0.1, 10])
+														.center([0,0])
+														.on("zoom", zoomHandler);
+			 zoomListener(svg);
      }
 
      var tx=0, ty=0;
@@ -515,109 +532,109 @@
      var iter_id=-1;
 
      function zoomHandler() {
-				 tx = d3.event.translate[0];
-				 ty = d3.event.translate[1];
-				 ss = d3.event.scale;
-				 updateEmbedding();
+			 tx = d3.event.translate[0];
+			 ty = d3.event.translate[1];
+			 ss = d3.event.scale;
+			 updateEmbedding();
      }
 
      var stepnum = 0;
 
      function stopStep() {
-				 clearInterval(iter_id);
-				 text = svg.selectAll("text");
+			 clearInterval(iter_id);
+			 text = svg.selectAll("text");
 
-				 // jitter function needs different data and co-ordinate representation
-				 labels = d3.range(data.words.length).map(function(i) {
-						 var x = (T.Y[i][0]*20*ss + tx) + mapWidth/2;
-						 var y = (T.Y[i][1]*20*ss + ty) + mapHeight/2;
-						 anchor_array.push({x: x, y: y, r: jitterRadius});
-						 return {
-								 x: x,
-								 y: y,
-								 name: data.words[i]
-						 };
-				 });
+			 // jitter function needs different data and co-ordinate representation
+			 labels = d3.range(data.words.length).map(function(i) {
+				 var x = (T.Y[i][0]*20*ss + tx) + mapWidth/2;
+				 var y = (T.Y[i][1]*20*ss + ty) + mapHeight/2;
+				 anchor_array.push({x: x, y: y, r: jitterRadius});
+				 return {
+					 x: x,
+					 y: y,
+					 name: data.words[i]
+				 };
+			 });
 
-				 // get the actual label bounding boxes for the jitter function
-				 var index = 0;
-				 text.each(function() {
-						 labels[index].width = this.getBBox().width;
-						 labels[index].height = this.getBBox().height;
-						 index += 1;
-				 });
+			 // get the actual label bounding boxes for the jitter function
+			 var index = 0;
+			 text.each(function() {
+				 labels[index].width = this.getBBox().width;
+				 labels[index].height = this.getBBox().height;
+				 index += 1;
+			 });
 
 
-				 //	 setTimeout(updateEmbedding, 1);
-				 //	 setTimeout(
-						 labeler =	 d3.labeler()
-													 .label(labels)
-													 .anchor(anchor_array)
-													 .width(mapWidth)
-													 .height(mapHeight)
-													 .update(applyJitter);
-				 //         .start(1000);
+			 //	 setTimeout(updateEmbedding, 1);
+			 //	 setTimeout(
+					 labeler =	 d3.labeler()
+												 .label(labels)
+												 .anchor(anchor_array)
+												 .width(mapWidth)
+												 .height(mapHeight)
+												 .update(applyJitter);
+			 //         .start(1000);
 
-				 iter_id = setInterval(jitterStep, 1);
+			 iter_id = setInterval(jitterStep, 1);
      }
 
      var jitter_i=0;
 
      function jitterStep() {
-				 if(jitter_i++ > 100) {
-						 clearInterval(iter_id);
-				 } else {
-						 labeler.start2(10);
-						 applyJitter();
-				 }
+			 if(jitter_i++ > 100) {
+				 clearInterval(iter_id);
+			 } else {
+				 labeler.start2(10);
+				 applyJitter();
+			 }
      }
 
      var last_cost=1000;
 
      function step() {
-				 var i = T.iter;
+			 var i = T.iter;
 
-				 if(i > <%= $no_iterations %>) {
-						 stopStep();
+			 if(i > <%= $no_iterations %>) {
+				 stopStep();
+			 } else {
+				 var cost = Math.round(T.step() * 100000) / 100000; // do a few steps
+				 $("#cost").html("tsne iteration " + i + ", cost: " + cost.toFixed(5));
+				 if(i % 250 == 0 && cost >= last_cost) {
+					 stopStep();
 				 } else {
-						 var cost = Math.round(T.step() * 100000) / 100000; // do a few steps
-						 $("#cost").html("tsne iteration " + i + ", cost: " + cost.toFixed(5));
-						 if(i % 250 == 0 && cost >= last_cost) {
-								 stopStep();
-						 } else {
-								 last_cost = cost;
-								 updateEmbedding();
-						 }
+					 last_cost = cost;
+					 updateEmbedding();
 				 }
+			 }
      }
 
      function showMap(j) {
-				 data=j;
-				 T.iter=0;
-				 T.initDataRaw(data.vecs); // init embedding
-				 drawEmbedding(); // draw initial embedding
+			 data=j;
+			 T.iter=0;
+			 T.initDataRaw(data.vecs); // init embedding
+			 drawEmbedding(); // draw initial embedding
 
-				 if(iter_id >= 0) {
-						 clearInterval(iter_id);
-				 }
-				 //T.debugGrad();
-				 iter_id = setInterval(step, 1);
-				 if(true) { // (<%= $show_som %>) {
-						 makeSOM(j, <%= $no_iterations %>);
-				 }
+			 if(iter_id >= 0) {
+				 clearInterval(iter_id);
+			 }
+			 //T.debugGrad();
+			 iter_id = setInterval(step, 1);
+			 if(true) { // (<%= $show_som %>) {
+				 makeSOM(j, <%= $no_iterations %>);
+			 }
      }
      var queryword;
 
      function onload() {
-         queryword = document.getElementById('word');
+       queryword = document.getElementById('word');
      }
 
      function queryKorAP() {
-         window.open('http://korap.ids-mannheim.de/kalamar/?q='+queryword.value, 'KorAP');
+       window.open('http://korap.ids-mannheim.de/kalamar/?q='+queryword.value, 'KorAP');
      }
 
      function queryKorAPCII(query) {
-         window.open('http://korap.ids-mannheim.de/kalamar/?ql=cosmas2&q='+query, 'KorAP');
+       window.open('http://korap.ids-mannheim.de/kalamar/?ql=cosmas2&q='+query, 'KorAP');
      }
     </script>
   </head>
@@ -628,7 +645,7 @@
 			</div>
 			<div id="options"  class="widget">
 				<form id="queryform">
-					<input id="word" type="text" name="word"  placeholder="Word(s) to be searched" value="<%= $word %>" 
+					<input id="word" type="text" name="word"  placeholder="Word(s) to be searched" value="<%= $word %>"
 								 title="When looking for multiple words use spaces as separators to search around the average vector and | as separator to get the neighbours for each word."/>
 					<input id="SEARCH" type="button" value="SEARCH">
 					<input type="button" id="showoptions" name="showoptions" value="Options" />
@@ -731,8 +748,8 @@
 							 % use Mojo::ByteStream 'b';
 							 % my $urlprefix = url_with->query([word=>'']);
 							 $(window).load(function() {
-									 var vecs = <%= b(Mojo::JSON::to_json($lists->[0])) %>;
-									 showMap(<%= b(Mojo::JSON::to_json({target => " $word ", mergedEnd=> $mergedEnd, words => \@words, vecs => \@vecs, ranks => \@ranks, marked => \@marked, urlprefix => $urlprefix})); %>);
+								 var vecs = <%= b(Mojo::JSON::to_json($lists->[0])) %>;
+								 showMap(<%= b(Mojo::JSON::to_json({target => " $word ", mergedEnd=> $mergedEnd, words => \@words, vecs => \@vecs, ranks => \@ranks, marked => \@marked, urlprefix => $urlprefix})); %>);
 							 });
 							</script>
             % } else {
@@ -743,22 +760,22 @@
 								</div>
 								<script>
 								 $( function() {
-										 $( "#not-found-dialog" ).dialog({
-												 autoOpen: true,
-												 modal: true,
-												 draggable: false,
-												 height: "auto",
-												 width: "auto",
-												 resizable: false,
-												 buttons: {
-														 "OK": function() {
-																 $( this ).dialog( "close" );
-														 },
-														 "Apply": function() {
-																 window.open($(location).attr('pathname')+'?'+$('form').serialize(), "_self");
-														 }
-												 }
-										 });
+									 $( "#not-found-dialog" ).dialog({
+										 autoOpen: true,
+										 modal: true,
+										 draggable: false,
+										 height: "auto",
+										 width: "auto",
+										 resizable: false,
+										 buttons: {
+											 "OK": function() {
+												 $( this ).dialog( "close" );
+											 },
+											 "Apply": function() {
+												 window.open($(location).attr('pathname')+'?'+$('form').serialize(), "_self");
+											 }
+										 }
+									 });
 								 });
 								</script>
 							</div>
@@ -798,20 +815,20 @@
 								<tr>
 									<td align="right">
 									</td>
-										<td align="right">
-										</td>
-										<td align="right">
-										</td>
-										<td align="right">
-										</td>
-										<td align="right">
-										</td>
-										<td align="right">
-										</td>
-									  <td align="right">
-										</td>
-										<td align="left">
-										</td>
+									<td align="right">
+									</td>
+									<td align="right">
+									</td>
+									<td align="right">
+									</td>
+									<td align="right">
+									</td>
+									<td align="right">
+									</td>
+									<td align="right">
+									</td>
+									<td align="left">
+									</td>
 								</tr>
 							</tbody>
 						</table>
diff --git a/w2v-server.pl b/w2v-server.pl
index 605db6c..35b0295 100755
--- a/w2v-server.pl
+++ b/w2v-server.pl
@@ -194,6 +194,7 @@
 	float activation_sum;
 	float conorm;
 	float max_activation;
+  float heat[16];
 } collocator;
 
 typedef struct {
@@ -793,6 +794,7 @@
 			best[b].conorm = 0.0;
 			best[b].probability = 0.0;
 			best[b].cprobability = syn_nbs[0]->best[b].cprobability;
+      memset(best[b].heat, 0, sizeof(float) * 16);
     }
 		
 		float best_window_sum[MAX_NEIGHBOURS];
@@ -847,6 +849,8 @@
 									word_activation_sum += syn_nbs[a]->best[b].activation;
                   if(syn_nbs[a]->best[b].activation > best[i].max_activation)
 										best[i].max_activation = syn_nbs[a]->best[b].activation;
+                  if(syn_nbs[a]->best[b].cprobability > best[i].heat[wpos])
+										best[i].heat[wpos] = syn_nbs[a]->best[b].cprobability;
 								}
 						}
 					}
@@ -939,9 +943,10 @@
 					continue;
 			}
 */
-			chosen[i++]=&vocab[c * max_w];
+			chosen[i++]=c;
       HV* hash = newHV();
       SV* word = newSVpvf(&vocab[best[a].wordi * max_w], 0);
+      AV* heat = newAV();
       if(latin_enc == 0) SvUTF8_on(word);
       hv_store(hash, "word", strlen("word"), word , 0);
       hv_store(hash, "rank", strlen("rank"), newSVuv(best[a].wordi), 0);
@@ -951,6 +956,9 @@
       hv_store(hash, "max", strlen("max"), newSVnv(best[a].max_activation), 0); // newSVnv(target_sums[best[a].wordi]), 0);
       hv_store(hash, "overall", strlen("overall"), newSVnv(best[a].activation_sum/total_activation), 0); // newSVnv(target_sums[best[a].wordi]), 0);
       hv_store(hash, "pos", strlen("pos"), newSVnv(best[a].position), 0);
+      best[a].heat[5]=0;
+      for(i=10; i >= 0; i--) av_push(heat, newSVnv(best[a].heat[i]));
+      hv_store(hash, "heat", strlen("heat"), newRV_noinc((SV*)heat), 0);
       av_push(array, newRV_noinc((SV*)hash));
     }
     hv_store(result, "syntagmatic", strlen("syntagmatic"), newRV_noinc((SV*)array), 0);