w2v-server-js: also show classical collocation analysis
diff --git a/templates/index.html.ep b/templates/index.html.ep
index 0050efe..38a41a0 100644
--- a/templates/index.html.ep
+++ b/templates/index.html.ep
@@ -10,9 +10,9 @@
     <script src = "https://cdn.datatables.net/plug-ins/1.10.16/sorting/scientific.js"></script>
     <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>
+      src="http://code.jquery.com/ui/1.12.1/jquery-ui.min.js"
+      integrity="sha256-VazP97ZCwtekAsvgPBSUwPFKdrwD3unUfSGVYrahUqU="
+      crossorigin="anonymous"></script>
     <script>
      var urlParams = new URLSearchParams(window.location.search);
      var currentWords = urlParams.get("word");
@@ -22,256 +22,300 @@
      $('#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;
+         }});
 
-         $( "#tabs" ).on( "tabsactivate", function( event, ui ) {
-             if (localStorage) localStorage['tab'] = ui.newTab.index();
+       $( "#tabs" ).on( "tabsactivate", function( event, ui ) {
+         if (localStorage) localStorage['tab'] = ui.newTab.index();
+       });
+
+       $(function(){
+         $("#SEARCH").click(function() {
+           window.open($(location).attr('pathname')+'?'+$('form').serialize(), "_self");
          });
+       });
 
-         $(function(){
-             $("#SEARCH").click(function() {
-                 window.open($(location).attr('pathname')+'?'+$('form').serialize(), "_self");
-             });
-         });
-
-         function changeCharColor(txt, heat, word) {
-             var newText = "";
-             for (var i=0, l=txt.length; i<l; i++) {
-                 newText += (i == 5 ? txt.charAt(i) : '<a href="http://korap.ids-mannheim.de/kalamar/?ql=cosmas2&q=' +
-                                                      CIIsearchWords + ' /' +  (i > 5? '%2B' : '-') + 'w' +
-                                                      Math.abs(i-5) + ':' +  Math.abs(i-5) + ' ' + word +
-                                                      '" target="korap"><span style="background-color:' +
-                                                      getHeatColor(heat[i]/maxHeat)+'">'+txt.charAt(i)+'</span></a>');
-             }
-             return newText;
+       function changeCharColor(txt, heat, word) {
+         var newText = "";
+         for (var i=0, l=txt.length; i<l; i++) {
+           newText += (i == 5 ? txt.charAt(i) : '<a href="http://korap.ids-mannheim.de/kalamar/?ql=cosmas2&q=' +
+                                                CIIsearchWords + ' /' +  (i > 5? '%2B' : '-') + 'w' +
+                                                Math.abs(i-5) + ':' +  Math.abs(i-5) + ' ' + word +
+                                                '" target="korap"><span style="background-color:' +
+                                                getHeatColor(heat[i]/maxHeat)+'">'+txt.charAt(i)+'</span></a>');
          }
+         return newText;
+       }
 
-         function getHeatColor(value) {
-             var hue=((1-value)*120).toString(10);
-             return ["hsl(",hue,",90%,70%)"].join("");
+       function getHeatColor(value) {
+         var hue=((1-value)*120).toString(10);
+         return ["hsl(",hue,",90%,70%)"].join("");
+       }
+
+       function bitvec2window(n, heat, word) {
+         var str = n.toString(2).padStart(10, "0")
+                    .replace(/^([0-9]{5})/, '$1x')
+                    .replace(/0/g, '·')
+                    .replace(/1/g, '+');
+         return changeCharColor(str, heat, word);
+       }
+
+       % use Mojo::ByteStream 'b';
+       var paraResults = <%= b(Mojo::JSON::to_json($lists)) %>;
+       var urlprefix =  new URLSearchParams(window.location.search);
+       if (paraResults.length > 0  && paraResults[0] != null) {
+         var nvecs = [],
+             nwords = [],
+             nranks = [],
+             nmarked = [];
+         for(var i = 0; i < paraResults.length; i++) {
+           nwords = nwords.concat(paraResults[i].map(function(a){return a.word;}));
+           nvecs = nvecs.concat(paraResults[i].map(function(a){return a.vector;}));
+           nranks = nranks.concat(paraResults[i].map(function(a){return a.rank;}));
+           nmarked = nmarked.concat(paraResults[i].map(function(a){return a.marked;}));
          }
+         showMap({target: " "+urlParams.get('word')+" ", mergedEnd: 0, words: nwords, vecs: nvecs, ranks: nranks, marked: nmarked} );
+         var t = $('#firsttable').DataTable({
+           data: paraResults[0],
+           "sScrollY": "780px",
+           "bScrollCollapse": true,
+           "bPaginate": false,
+           "bJQueryUI": true,
+           "dom": '<"top">rt<"bottom"flp><"clear">',
+           "columns": [
+             { "data": "rank", type: "allnumeric" },
+             { "data": "dist",  render: function ( data, type, row ) {return data.toFixed(3) }},
+             { "data": "word",  render: function ( data, type, row ) {urlprefix.set("word", data); return  '<a href="?' + urlprefix + '">' + data + '</a>' }}
+           ],
+           "columnDefs": [
+             { className: "dt-right", "targets": [0,1] },
+             { "searchable": false,
+               "orderable": false,
+               "targets": 0
+             },
+             { "orderSequence": [ "desc" ], "targets": [ 1 ] },
+             { "orderSequence": [ "asc", "desc" ], "targets": [ 2 ] },
+           ],
+           "oLanguage": {
+             "sSearch": "Filter: "
+           },
+           "order": [[ 1, 'desc' ]],
+         } );
 
-         function bitvec2window(n, heat, word) {
-             var str = n.toString(2).padStart(10, "0")
-                        .replace(/^([0-9]{5})/, '$1x')
-                        .replace(/0/g, '·')
-                        .replace(/1/g, '+');
-             return changeCharColor(str, heat, word);
+         t.on( 'order.dt search.dt', function () {
+           t.column(0, {order:'applied'}).nodes().each( function (cell, i) {
+             cell.innerHTML = i+1;
+           } );
+         } ).draw();
+
+         $( "#first" ).clone().prependTo( "#tabs-2" );
+
+       }
+
+
+       var collocatorData = <%= b(Mojo::JSON::to_json($collocators)) %>;
+       var maxHeat; // = Math.max.apply(Math,collocatorData.map(function(o){return o.cprob;}))
+
+       if (collocatorData != null) {
+         maxHeat = Math.max.apply(Math,collocatorData.map(function(o){return Math.max.apply(Math,o.heat);}))
+         collocatorTable = $('#secondtable').DataTable({
+           data: collocatorData,
+           "sScrollY": "780px",
+           "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, row.word) }},
+             { "data": "max",  render: function ( data, type, row ) {return data.toFixed(3) }},
+             { "data": "average", 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" },
+             { "data": "rank", type: "allnumeric" }
+           ],
+           "columnDefs": [
+             { className: "dt-right", "targets": [0,2,3,4,5,6] },
+             { className: "dt-center", "targets": [ 1] },
+             { "searchable": false,
+               "orderable": false,
+               "targets": [0, 8]
+             },
+             { "type": "scientific", targets: [2,3,4,5,6] },
+             { "orderSequence": [ "desc" ], "targets": [ 2, 3, 4, 5, 6 ] },
+             { "orderSequence": [ "asc", "desc" ], "targets": [ 1, 7 ] },
+             { "targets": [8], "visible": false }
+           ],
+           "oLanguage": {
+             "sSearch": "Filter: "
+           },
+           "order": [[ 4, 'desc' ]],
+         } );
+         $.ajaxSetup({
+           type: 'POST',
+           timeout: 30000,
+           error: function(xhr) {
+             $('#display_error')
+               .html('Error: ' + xhr.status + ' ' + xhr.statusText);
+           }
+         })
+
+         $.post('/derekovecs/getClassicCollocators',
+                JSON.stringify(paraResults[0][0].rank),
+                function(collocators, status) {
+                  collocatorTable = $('#classicoloctable').DataTable({
+                    data: collocators,
+                    "sScrollY": "780px",
+                    "bScrollCollapse": true,
+                    "bPaginate": false,
+                    "bJQueryUI": true,
+                    "dom": '<"top">rt<"bottom"flp><"clear">',
+                    "columns": [
+                      //                      { "data": "pos", width: "7%", sClass: "dt-center mono compact", render: function ( data, type, row ) {return bitvec2window(data, row.heat, row.word) }},
+                      { "data": "llr",  render: function ( data, type, row ) {return data.toFixed(3) }},
+                      { "data": "lfmd", render: function ( data, type, row ) {return data.toFixed(3) }},
+                      { "data": "fpmi", type: "scientific", render: function ( data, type, row ) {return data.toExponential(3) }  },
+                      { "data": "npmi", type: "scientific", render: function ( data, type, row ) {return data.toExponential(3) }  },
+                      { "data": "word",  sClass: "collocator" }
+                    ],
+                    "columnDefs": [
+                      { className: "dt-right", "targets": [0,1,2,3] },
+                      { "searchable": false,
+                        "orderable": false,
+                        "targets": []
+                      },
+                      { "type": "scientific", targets: [2,3] },
+                      { "orderSequence": [ "desc" ], "targets": [ 0, 1, 2, 3 ] },
+                      { "orderSequence": [ "asc", "desc" ], "targets": [ 4 ] },
+                    ],
+                    "oLanguage": {
+                      "sSearch": "Filter: "
+                    },
+                    "order": [[ 1, 'desc' ]],
+                  } );
+                }, 'json');
+
+         collocatorTable.on( 'order.dt search.dt', function () {
+           collocatorTable.column(0, {order:'applied'}).nodes().each( function (cell, i) {
+             cell.innerHTML = i+1;
+           } );
+         } ).draw();
+
+         if (localStorage && !window.location.hash) { // let's not crash if some user has IE7
+           var index = parseInt(localStorage['tab']||'0');
+           $("#tabs").tabs({ active: index });
          }
-
-         % use Mojo::ByteStream 'b';
-         var paraResults = <%= b(Mojo::JSON::to_json($lists)) %>;
-         var urlprefix =  new URLSearchParams(window.location.search);
-         if (paraResults.length > 0  && paraResults[0] != null) {
-             var nvecs = [],
-                 nwords = [],
-                 nranks = [],
-                 nmarked = [];
-             for(var i = 0; i < paraResults.length; i++) {
-                 nwords = nwords.concat(paraResults[i].map(function(a){return a.word;}));
-                 nvecs = nvecs.concat(paraResults[i].map(function(a){return a.vector;}));
-                 nranks = nranks.concat(paraResults[i].map(function(a){return a.rank;}));
-                 nmarked = nmarked.concat(paraResults[i].map(function(a){return a.marked;}));
-             }
-             showMap({target: " "+urlParams.get('word')+" ", mergedEnd: 0, words: nwords, vecs: nvecs, ranks: nranks, marked: nmarked} );
-             var t = $('#firsttable').DataTable({
-                 data: paraResults[0],
-                 "sScrollY": "780px",
-                 "bScrollCollapse": true,
-                 "bPaginate": false,
-                 "bJQueryUI": true,
-                 "dom": '<"top">rt<"bottom"flp><"clear">',
-                 "columns": [
-                     { "data": "rank", type: "allnumeric" },
-                     { "data": "dist",  render: function ( data, type, row ) {return data.toFixed(3) }},
-                     { "data": "word",  render: function ( data, type, row ) {urlprefix.set("word", data); return  '<a href="?' + urlprefix + '">' + data + '</a>' }}
-                 ],
-                 "columnDefs": [
-                     { className: "dt-right", "targets": [0,1] },
-                     { "searchable": false,
-                       "orderable": false,
-                       "targets": 0
-                     },
-                     { "orderSequence": [ "desc" ], "targets": [ 1 ] },
-                     { "orderSequence": [ "asc", "desc" ], "targets": [ 2 ] },
-                 ],
-                 "oLanguage": {
-                     "sSearch": "Filter: "
-                 },
-                 "order": [[ 1, 'desc' ]],
-             } );
-
-             t.on( 'order.dt search.dt', function () {
-                 t.column(0, {order:'applied'}).nodes().each( function (cell, i) {
-                     cell.innerHTML = i+1;
-                 } );
-             } ).draw();
-
-             $( "#first" ).clone().prependTo( "#tabs-2" );
-
-         }
-
-         var collocatorData = <%= b(Mojo::JSON::to_json($collocators)) %>;
-         var maxHeat; // = Math.max.apply(Math,collocatorData.map(function(o){return o.cprob;}))
-
-         if (collocatorData != null) {
-             maxHeat = Math.max.apply(Math,collocatorData.map(function(o){return Math.max.apply(Math,o.heat);}))
-             collocatorTable = $('#secondtable').DataTable({
-                 data: collocatorData,
-                 "sScrollY": "780px",
-                 "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, row.word) }},
-                     { "data": "max",  render: function ( data, type, row ) {return data.toFixed(3) }},
-                     { "data": "average", 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" },
-                     { "data": "rank", type: "allnumeric" }
-                 ],
-                 "columnDefs": [
-                     { className: "dt-right", "targets": [0,2,3,4,5,6] },
-                     { className: "dt-center", "targets": [ 1] },
-                     { "searchable": false,
-                       "orderable": false,
-                       "targets": [0, 8]
-                     },
-                     { "type": "scientific", targets: [2,3,4,5,6] },
-                     { "orderSequence": [ "desc" ], "targets": [ 2, 3, 4, 5, 6 ] },
-                     { "orderSequence": [ "asc", "desc" ], "targets": [ 1, 7 ] },
-                     { "targets": [8], "visible": false }
-                 ],
-                 "oLanguage": {
-                     "sSearch": "Filter: "
-                 },
-                 "order": [[ 4, 'desc' ]],
-             } );
-
-             collocatorTable.on( 'order.dt search.dt', function () {
-                 collocatorTable.column(0, {order:'applied'}).nodes().each( function (cell, i) {
-                     cell.innerHTML = i+1;
-                 } );
-             } ).draw();
-
-             if (localStorage && !window.location.hash) { // let's not crash if some user has IE7
-                 var index = parseInt(localStorage['tab']||'0');
-                 $("#tabs").tabs({ active: index });
-             }
-         }
-         $("#tabs").css("visibility", "visible"); // now we can show the tabs
+       }
+       $("#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");
-                 }
-             }
-         });
+       $("#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 " + CIIsearchWords);
-         });
+       $("td.collocator").click(function(){
+         queryKorAPCII(this.textContent + " /w5 " + CIIsearchWords);
+       });
      });
 
      $(function(){
-         $("#showoptions").click(function(){
-             $("#dropdownoptions").dialog("open");
-             var target = $(this);
-             $("#dropdownoptions").dialog("widget").position({
-                 my: 'left bottom',
-                 at: 'left bottom',
-                 of: target
-             });
+       $("#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;
+           }
+         }
+       });
      } );
 
      $( 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>
@@ -285,6 +329,15 @@
        font-size: 11pt;
      }
 
+     .info {
+       font-size: 8pt;
+       margin-top: 4px;
+       /* position: absolute;
+          bottom: 0;
+          left: 0;
+          right: 0; */
+     }
+
      h1,  h2, h3 {
        margin: 5px 10px 0 0;
        color: rgb(246,168,0);
@@ -504,27 +557,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;
@@ -533,62 +586,62 @@
      var text;
 
      function drawEmbedding() {
-         var urlprefix =  new URLSearchParams(window.location.search);
-         urlprefix.delete("word");
-         urlprefix.append("word","");
+       var urlprefix =  new URLSearchParams(window.location.search);
+       urlprefix.delete("word");
+       urlprefix.append("word","");
 
-         $("#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 "?"+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 "?"+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;
@@ -596,128 +649,128 @@
      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;
-         iter_id = -1;
-         last_cost=1000;
-         T.initDataRaw(data.vecs); // init embedding
-         drawEmbedding(); // draw initial embedding
+       data=j;
+       T.iter=0;
+       iter_id = -1;
+       last_cost=1000;
+       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 showCollocatorSOM() {
-         if (collocatorTable) {
-             var ctableData = collocatorTable.rows().data();
-             var nwords = [],
-                 nranks = [];
-             for (var i=0; i < ctableData.length && i < 100; i++) {
-                 nranks.push(ctableData[i].rank);
-                 nwords.push(ctableData[i].word);
-             }
-             $.post('/derekovecs/getVecsByRanks',
-                    JSON.stringify(nranks),
-                    function(data, status){
-                        showMap({target: " "+urlParams.get('word')+" ", mergedEnd: 0, words: nwords, vecs: data, ranks: nranks, marked: Array(100).fill(false)} );
-                    }, 'json');
+       if (collocatorTable) {
+         var ctableData = collocatorTable.rows().data();
+         var nwords = [],
+             nranks = [];
+         for (var i=0; i < ctableData.length && i < 100; i++) {
+           nranks.push(ctableData[i].rank);
+           nwords.push(ctableData[i].word);
          }
+         $.post('/derekovecs/getVecsByRanks',
+                JSON.stringify(nranks),
+                function(data, status){
+                  showMap({target: " "+urlParams.get('word')+" ", mergedEnd: 0, words: nwords, vecs: data, ranks: nranks, marked: Array(100).fill(false)} );
+                }, 'json');
+       }
      }
 
      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>
@@ -809,26 +862,26 @@
             </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>
-            % }
+             % }
         </div>
         <div id="tabs-2">
           <div id="som2" style="width: 800;">
@@ -836,9 +889,9 @@
           <div id="sominfo1"><span id="somcolor1">   </span> <span id="somword1"> </span> <span id="somcolor2">   </span> <span id="somword2"> </span> <span id="somcolor3">   </span></div>
           <div id="sominfo">SOM iteration <span id="iterations">0</span></div>
         </div>
-        <div id="tabs-3">
-          <div style="width: 800px" id="secondt">
-            <table class="display compact nowrap" id="secondtable">
+        <div id="tabs-3" style="width:1300px">
+          <div style="width: 60%; float: left;" id="secondt">
+            <table class="display compact nowrap"  id="secondtable">
               <thead>
                 <tr>
                   % if($collocators) {
@@ -871,8 +924,33 @@
               </tbody>
             </table>
           </div>
+          <div style="margin-left:20px; float:right; width: 500px">
+            <table class="display compact nowrap" id="classicoloctable">
+              <thead>
+                <tr>
+                  <th>llr</th>
+                  <th title="log-frequency biased mutual dependency">lfmd</th>
+                  <th title="frequency biased pointwise mutual information">fpmi</th>
+                  <th title="normalized mutual information">npmi</th>
+                  <th>collocator</th>
+                </tr>
+              </thead>
+              <tbody>
+                <tr>
+                  <td align="right">
+                  </td>
+                  <td align="right">
+                  </td>
+                  <td align="right">
+                  </td>
+                  <td align="right">
+                  </td>
+                </tr>
+              </tbody>
+            </table>
+          </div>
+          <div style="clear:both" ></div>
           <div style="float: right; overflow: hidden" id="extra"><button onClick="showCollocatorSOM()"> </button></div>
-          <div style="float: right; overflow: hidden" id="clock"></div>
         </div>
       </div>
     </div> <!-- topwrapper  -->