derekovecs: compare collocates with reference corpus
diff --git a/templates/index.html.ep b/templates/index.html.ep
index 36a2b65..1d36ad2 100644
--- a/templates/index.html.ep
+++ b/templates/index.html.ep
@@ -312,7 +312,7 @@
            },
            "createdRow": function (row, data, rowIndex) {
              $.each($('td.collocator', row), function (colIndex) {
-               $(this).attr('title', "f("+data.word+")="+data.f2.toLocaleString("en-GB"));
+               $(this).attr('title', "f("+data.word+")="+data.f2.toLocaleString("en-GB") + " f1: "+ccResult.f1+ " total: "+ccResult.N);
              });
            },
            "sScrollY": "780px",
@@ -331,6 +331,7 @@
              { "data": "dice", render: function ( data, type, row ) {return data.toExponential(2) }},
              { "data": "ld", render: function ( data, type, row ) {return data.toFixed(2) }},
              { "data": "af", render: function ( data, type, row ) {return data.toFixed(2) }},
+             { "data": "delta", render: function ( data, type, row ) {return data.toFixed(2) }},
              { "data": "afwin", width: "auto", sClass: "dt-center mono compact", render: function ( data, type, row ) {return bitmask2window(data, row.win) }},
              { "data": "llfmd", render: function ( data, type, row ) {return data.toFixed(1) }},
              { "data": "rlfmd", render: function ( data, type, row ) {return data.toFixed(1) }},
@@ -340,14 +341,14 @@
              { "data": "word",  sClass: "collocator" }
            ],
            "columnDefs": [
-             { className: "dt-right", "targets": [0,1,2,3,4,5,6,7,9,10,11,12,13] },
-             { className: "dt-right detail", "targets": [5,9,10,11,12] },
+               { className: "dt-right", "targets": [0,1,2,3,4,5,6,7,9,10,11,12,13,14] },
+               { className: "dt-right detail", "targets": [5,10,11,12,13] },
              { "searchable": false,
                "orderable": false,
                "targets": []
              },
-             { "orderSequence": [ "desc" ], "targets": [0,1,2,3,4,5,6,7,9,10,11,12,13] },
-             { "orderSequence": [ "asc", "desc" ], "targets": [8,14] },
+               { "orderSequence": [ "desc" ], "targets": [0,1,2,3,4,5,6,7,9,10,11,12,13,14] },
+             { "orderSequence": [ "asc", "desc" ], "targets": [8,15] },
            ],
            "oLanguage": {
              "sSearch": "Filter: "
@@ -355,7 +356,6 @@
            "order": [[ 7, 'desc' ]],
          });
 
-
          $('#show-details').change(function (e) {
            var columns = classicCollocatorTable.columns(".detail");
            if(this.checked) {
@@ -526,8 +526,8 @@
             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) + ")";
+                                                                                    (d.x) + "," +
+                                                                                    (d.y) + ")";
           });
      }
 
@@ -537,8 +537,8 @@
           .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) + ")"; });
+                                                                                     ((Y[i][0]*20*ss + tx) + mapWidth/2) + "," +
+                                                                                     ((Y[i][1]*20*ss + ty) + mapHeight/2) + ")"; });
      }
 
      var svg;
@@ -855,40 +855,40 @@
                   </table>
                 </div>
               %}
-            <div id="second">
+              <div id="second">
                 <div id="embed">
                 </div>
                 <div id="cost">
                 </div>
               </div>
             </div>
-                % } elsif($word !~ /^\s*$/) {
-                <div id="wrapper">
-                  <div id="not-found-dialog" title="Not found">
-                    <p>ERROR: "<%= $word %>" not found in vocabluary.</p>
-                    <p>If you are sure you have spelled the word as intended, you can try to increase the cutoff parameter in the options menu.</p>
-                  </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");
-                         }
-                       }
-                     });
-                   });
-                  </script>
-                </div>
+          % } elsif($word !~ /^\s*$/) {
+          <div id="wrapper">
+            <div id="not-found-dialog" title="Not found">
+              <p>ERROR: "<%= $word %>" not found in vocabluary.</p>
+              <p>If you are sure you have spelled the word as intended, you can try to increase the cutoff parameter in the options menu.</p>
+            </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");
+                   }
+                 }
+               });
+             });
+            </script>
+          </div>
           % }
         </div>
         <div id="tabs-2" style="display: flex;  padding: 5px; flex-flow: row wrap;">
@@ -945,6 +945,7 @@
                     <th id="dice_tt">dice</th>
                     <th id="logdice_tt">LD</th>
                     <th id="logdiceaf_tt">LDaf</th>
+                    <th id="delta_tt" title="Difference to reference corpus.">Δ</th>
                     <th id="af_win" title="Positions around the target word that are selected by the auto-focus function are marked with ◾. Positions at which the collocate appears at least once are marked with ◽.">af-window</th>
                     <th title="PMI³ restricted to left neighbour">l-PMI³</th>
                     <th title="PMI³ restricted to right neighbour">r-PMI³</th>
diff --git a/w2v-server.pl b/w2v-server.pl
index 22d94dc..0873562 100755
--- a/w2v-server.pl
+++ b/w2v-server.pl
@@ -114,16 +114,39 @@
 
 sub getClassicCollocatorsCached {
   my ($c, $word) = @_;
+  my $s2 = "";
   if($word > $mergedEnd) {
     $word-=$mergedEnd;
   }
+
   if(!$cccache{$word}) {
     $c->app->log->info("Getting classic collocates of $word.");
     $cccache{$word} = getClassicCollocators($word);
   } else {
     $c->app->log->info("Getting classic collocates for $word from cache.");
   }
-  return $cccache{$word};
+  if($opt_p >= 5000 && $opt_p < 5600) { # German non-reference
+    $s2 = `GET http://compute:5673/getClassicCollocators?w=$word`;
+  }
+  if(length($s2) > 2000) {
+    my $d1 = decode_json($cccache{$word});
+    my $d2 = decode_json($s2);
+    my %d2ld;
+    foreach my $i (@{$d2->{collocates}}) {
+      $d2ld{$i->{word}}=$i->{ld};
+    }
+    foreach my $i (@{$d1->{collocates}}) {
+      my $w = $i->{word};
+      $i->{delta} = $i->{ld} - (defined $d2ld{$w} ? $d2ld{$w} : -5);
+    }
+    return(encode_json($d1));
+  } else {
+    my $d1 = decode_json($cccache{$word});
+    foreach my $i (@{$d1->{collocates}}) {
+      $i->{delta} = 0;
+    }
+    return(encode_json($d1));
+  }
 }
 
 sub getSimilarProfilesCached {