w2v-server: split perl/c and html/ep/js
diff --git a/templates/index.html.ep b/templates/index.html.ep
new file mode 100644
index 0000000..9183278
--- /dev/null
+++ b/templates/index.html.ep
@@ -0,0 +1,409 @@
+<!DOCTYPE html>
+<html>
+  <head>
+	  <title>DeReKo-Word-Vector-Distances: <%= $word %></title>
+	  <link rel="stylesheet" href="//code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css">
+	  <script src="http://code.jquery.com/jquery-latest.min.js"></script>
+    <script src="//code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
+	  <script>
+     $(function() {
+       $( document ).tooltip({
+			   content: function() {
+				   return $(this).attr('title');
+			   }}
+		   )
+	   })
+    </script>
+	  <script src="//d3js.org/d3.v3.min.js" charset="utf-8"></script>
+	  <script src="http://klinux10/word2vec/tsne.js"></script>
+	  <script src="http://klinux10/word2vec/som.js"></script>
+	  <script src="http://klinux10/word2vec/labeler.js"></script>
+    <style>
+     body, input {
+	     font-family: Arial, sans-serif;
+	     font-size: 11pt;
+     }
+     
+     .ui-tooltip-content {
+	     font-size: 9pt;
+	     color: #222222;
+     }
+     
+     svg > .ui-tooltip-content {
+	     font-size: 8pt;
+	     color: #222222;
+     }
+     
+     a.merged {
+       color: green;
+       fill: green;
+     }
+     
+     #first a {
+       text-decoration: none;
+     }
+     
+     a.marked, #first a.marked {
+       text-decoration: underline;
+     }
+     
+     a.target {
+       color: red;
+       fill: red;
+     }
+     
+     #collocators {
+       margin-bottom: 15px;
+     }
+     
+     #wrapper {
+       width: 100%;
+       //   border: 1px solid red; 
+       overflow: hidden; /* will contain if #first is longer than #second */
+     }
+     #first {
+       margin-right: 20px;
+       float: left;
+       //    border: 1px solid green;
+     }
+     #second {
+       border: 1px solid #333;
+       overflow: hidden; /* if you don't want #second to wrap below #first */
+     }
+     #som2 svg {
+       border: 1px solid #333;
+     }
+
+     #cost {
+	     font-size: 8pt;
+	     color: #222222;
+       margin-top: 4px;
+       margin-bottom: 12px;
+     }
+
+     #sominfo1, #sominfo {
+	     font-size: 8pt;
+	     color: #222222;
+       margin-top: 0px;
+     }
+
+     #somcolor1, #somcolor2, #somcolor3 {
+       display: inline-block;
+       height: 10px;
+       width: 10px;
+     }
+
+     #third {
+       border: 1px solid #333;
+     }
+
+    </style>
+    <script>
+
+     var opt = {epsilon: <%= $epsilon %>, perplexity: <%= $perplexity %>},
+		     mapWidth = 800, // width map
+		     mapHeight = 800,
+		     jitterRadius = 7;
+
+     var T = new tsnejs.tSNE(opt); // create a tSNE instance
+
+     var Y;
+
+     var data;
+     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) + ")";
+          });
+     }
+     
+     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 svg;
+     var labels = [];
+     var anchor_array = [];
+     var text;
+
+     function drawEmbedding() {
+       $("#embed").empty();
+       var div = d3.select("#embed");
+	     
+       // 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);
+	     
+       var g = svg.selectAll(".b")
+						      .data(data.words)
+						      .enter().append("g")
+						      .attr("class", "tsnet");
+	     
+       g.append("a")
+	      .attr("xlink:href", function(word) {return "/?word="+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 tx=0, ty=0;
+     var ss=1;
+     var iter_id=-1;
+
+     function zoomHandler() {
+       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");
+	     
+       // 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;
+	     });
+
+	     
+       //	 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);
+     }
+
+     var jitter_i=0;
+
+     function jitterStep() {
+       if(jitter_i++ > 100) {
+         clearInterval(iter_id);
+       } else {
+		     labeler.start2(10);
+	       applyJitter();
+       }
+     }
+
+     var last_cost=1000;
+
+     function step() {
+       var i = T.iter;
+       
+       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 {
+           last_cost = cost;
+           updateEmbedding();
+         }
+       }
+     }
+
+     function showMap(j) {
+	     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(<%= $show_som %>) {
+         makeSOM(j, <%= $no_iterations %>);
+       }
+     }
+     
+    </script>
+  </head>
+  <body>
+	  <form action="<%=url_for('/')->to_abs%>" method="GET">
+		  word(s): 
+      <input type="text" name="word" size="20"  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."> 
+		  % if($mergedEnd > 0) {
+        backw. <input type="checkbox" name="sbf" value="1" <%= ($searchBaseVocabFirst ? "checked" : "") %> title="If checkecked base vocabulary will be searched first. Otherwise merged vocabulray will be searched first.">
+      % }
+		  max. neighbours: <input type="text" size="8" name="n" value="<%= $no_nbs %>">
+		  max. iterations: <input type="text" name="N" size="8" value="<%= $no_iterations %>">
+      SOM <input type="checkbox" name="som" value="1" <%= ($show_som ? "checked" : "") %>>
+		  % if($collocators) {
+        <span>  </span>sort collocators by
+        <select name="sort">
+          <option value="0"  <%= ($sort!=1? "selected":"") %>>responsiveness</option>
+          <option value="1" <%= ($sort==1? "selected":"") %>>mean p</option>
+        </select>
+		  % }
+		  <span>  </span><input type="submit" value="Show">
+	  </form>
+	  <br>
+	  % if($lists) {
+	    <div id="wrapper">
+		    <table id="first">
+			    <tr>
+				    <th align="right">#</th><th align="right">cos</th><th align="left">paradigmatic</th>
+            % if($collocators) {
+				      <th title="Position in winodw around target word. Absolute value can be too low because of sub-sampling frequent words.">@</th><th align="right" title="&#34;Responsivenes&#34; of the collocator at the relative position @. Approximation of the probability that the combination of the target word and the collocator at the relative position @ come from the corpus.">resp.</th><th title="Probability of the collocator at window location @."align="right">p(c<sub><small>@</small></sub>)</th><th align="right">Σp(c<sub><small>@</small></sub>)/|w|</th><th align="left">syntagmatic</th>
+				    % }
+			    </tr>
+			    % my $j=0; my @words; my @vecs; my @ranks; my @marked;
+          % for my $list (@$lists) {
+			      % my $i=0; while($list) {
+              % my $item = (@$list)[$i];
+              % my $c = ($collocators? (@$collocators)[$i] : 0);
+              % last if(!$c && !$item);
+			        <tr>
+				        <td align="right">
+  				        <%= ++$i %>.
+				        </td>
+                % if($item) {
+			            % if(!grep{$_ eq $item->{word}} @words) {
+                    %   push @vecs, $item->{vector};
+			              %   push @words, $item->{word};
+			              %   push @ranks, $item->{rank};
+			              %   push @marked, ($marked->{$item->{word}}? 1 : 0);
+                  % }
+				          <td align="right">
+  				          <%= sprintf("%.3f", $item->{dist}) %>
+				          </td>
+				          <td>
+                    % my $class = ($marked->{$item->{word}}? "marked " : ""); 
+                    % my $r = $item->{rank}; 
+                    % if($r < $mergedEnd) {
+                      %   $class .= "merged";
+                      %   $r .= " (merged vocab)";
+                    % } elsif($mergedEnd!=0 && $r > $mergedEnd) {
+                    %   $r -= $mergedEnd;
+                    % }
+  				      <a class="<%= $class %>" title="freq. rank: <%= $r %>" href="/?word=<%= $item->{word} %>"><%= $item->{word} %></a>
+				          </td>
+                % } else {
+                  <td colspan="2"/>
+                % }
+                % if($c) {
+				          <td align="right">
+                    <%= $c->{pos} %>:
+				          </td>
+				          <td align="right">
+  				          <%= sprintf("%.3f", $c->{dist}) %>
+				          </td>
+				          <td align="right">
+  				          <%= sprintf("%.3e", $c->{norm}) %>
+				          </td>
+				          <td align="right">
+  				          <%= sprintf("%.3e", $c->{sum}) %>
+				          </td>
+				          <td align="left">
+  				          <a href="/?word=<%= $c->{word} %>">
+                      <%= $c->{word} %>
+				          </td>
+                % } else {
+                  <td colspan="5"/>
+                % }
+			        </tr>
+			      % }
+		      % }
+		    </table>
+		    <script>
+		     % use Mojo::ByteStream 'b';
+		     $(window).load(function() {
+			     showMap(<%= b(Mojo::JSON::to_json({target => " $word ", mergedEnd=> $mergedEnd, words => \@words, vecs => \@vecs, ranks => \@ranks, marked => \@marked})); %>);
+		     });
+        </script>
+		% }
+		<div id="second" style="width:800px; height:800px; font-family: arial;">
+			<div id="embed">
+			</div>
+		</div>
+    <div id="cost"></div>
+		% if($show_som) {
+		  <div id="som2">
+		  </div>
+      <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>
+      % if($training_args) {
+        <p>
+          Word vector model trained with <a href="https://code.google.com/p/word2vec/">word2vec</a> using the following parameters: <pre><%= $training_args %></pre>
+        </p>
+      % }
+  </body>
+</html>
diff --git a/w2v-server.pl b/w2v-server.pl
index 6f39376..b7c1f55 100755
--- a/w2v-server.pl
+++ b/w2v-server.pl
@@ -755,416 +755,4 @@
 	fclose(f);
 	return(0);
 }
-__DATA__
-
-@@ index.html.ep
-<!DOCTYPE html>
-<html>
-<head>
-	<title>DeReKo-Word-Vector-Distances</title>
-	<link rel="stylesheet" href="//code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css">
-	<script src="http://code.jquery.com/jquery-latest.min.js"></script>
-  <script src="//code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
-	<script>
- $(function() {
-    $( document ).tooltip({
-			content: function() {
-				return $(this).attr('title');
-			}}
-		)
-	 })
-  </script>
-	<script src="//d3js.org/d3.v3.min.js" charset="utf-8"></script>
-	<script src="http://klinux10/word2vec/tsne.js"></script>
-	<script src="http://klinux10/word2vec/som.js"></script>
-	<script src="http://klinux10/word2vec/labeler.js"></script>
-<style>
-body, input {
-	font-family: Arial, sans-serif;
-	font-size: 11pt;
-}
-
-.ui-tooltip-content {
-	font-size: 9pt;
-	color: #222222;
-}
-
-svg > .ui-tooltip-content {
-	font-size: 8pt;
-	color: #222222;
-}
-
-a.merged {
-  color: green;
-  fill: green;
-}
-
-#first a {
-  text-decoration: none;
-}
-
-a.marked, #first a.marked {
-  text-decoration: underline;
-}
-
-a.target {
-  color: red;
-  fill: red;
-}
-
-#collocators {
-    margin-bottom: 15px;
-}
-  
-#wrapper {
-    width: 100%;
-//   border: 1px solid red; 
-    overflow: hidden; /* will contain if #first is longer than #second */
-}
-#first {
-    margin-right: 20px;
-    float: left;
- //    border: 1px solid green;
-}
-#second {
-    border: 1px solid #333;
-    overflow: hidden; /* if you don't want #second to wrap below #first */
-}
-#som2 svg {
-    border: 1px solid #333;
-}
-
-#cost {
-	  font-size: 8pt;
-	  color: #222222;
-    margin-top: 4px;
-    margin-bottom: 12px;
-}
-
-#sominfo1, #sominfo {
-	  font-size: 8pt;
-	  color: #222222;
-    margin-top: 0px;
-}
-
-#somcolor1, #somcolor2, #somcolor3 {
-  display: inline-block;
-  height: 10px;
-  width: 10px;
-}
-
-#third {
-  border: 1px solid #333;
-}
-
-</style>
-<script>
-
-var opt = {epsilon: <%= $epsilon %>, perplexity: <%= $perplexity %>},
-		mapWidth = 800, // width map
-		mapHeight = 800,
-		jitterRadius = 7;
-
-var T = new tsnejs.tSNE(opt); // create a tSNE instance
-
-var Y;
-
-var data;
-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) + ")";
-    });
-}
-    
-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 svg;
-var labels = [];
-var anchor_array = [];
-var text;
-
-function drawEmbedding() {
-  $("#embed").empty();
-  var div = d3.select("#embed");
-	
-  // 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);
-	
-  var g = svg.selectAll(".b")
-						 .data(data.words)
-						 .enter().append("g")
-						 .attr("class", "tsnet");
-	
-  g.append("a")
-	 .attr("xlink:href", function(word) {return "/?word="+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 tx=0, ty=0;
-var ss=1;
-var iter_id=-1;
-
-function zoomHandler() {
-  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");
-	
-  // 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;
-	});
-
-	 
-//	 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);
-}
-
-var jitter_i=0;
-
-function jitterStep() {
-  if(jitter_i++ > 100) {
-    clearInterval(iter_id);
-  } else {
-		labeler.start2(10);
-	  applyJitter();
-  }
-}
-
-var last_cost=1000;
-
-function step() {
-  var i = T.iter;
-  
-  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 {
-      last_cost = cost;
-      updateEmbedding();
-    }
-  }
-}
-
-function showMap(j) {
-	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(<%= $show_som %>) {
-    makeSOM(j, <%= $no_iterations %>);
-  }
-}
- 
-</script>
-</head>
-<body>
-	<form action="<%=url_for('/')->to_abs%>" method="GET">
-		word(s): 
-    <input type="text" name="word" size="20"  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."> 
-		% if($mergedEnd > 0) {
-     backw. <input type="checkbox" name="sbf" value="1" <%= ($searchBaseVocabFirst ? "checked" : "") %> title="If checkecked base vocabulary will be searched first. Otherwise merged vocabulray will be searched first.">
-    % }
-		max. neighbours: <input type="text" size="8" name="n" value="<%= $no_nbs %>">
-		max. iterations: <input type="text" name="N" size="8" value="<%= $no_iterations %>">
-    SOM <input type="checkbox" name="som" value="1" <%= ($show_som ? "checked" : "") %>>
-		% if($collocators) {
-    <span>  </span>sort collocators by
-    <select name="sort">
-      <option value="0"  <%= ($sort!=1? "selected":"") %>>responsiveness</option>
-      <option value="1" <%= ($sort==1? "selected":"") %>>mean p</option>
-    </select>
-		% }
-		<span>  </span><input type="submit" value="Show">
-	</form>
-	<br>
-	% if($lists) {
-	<div id="wrapper">
-		<table id="first">
-			<tr>
-				<th align="right">#</th><th align="right">cos</th><th align="left">paradigmatic</th>
-        % if($collocators) {
-				<th title="Position in winodw around target word. Absolute value can be too low because of sub-sampling frequent words.">@</th><th align="right" title="&#34;Responsivenes&#34; of the collocator at the relative position @. Approximation of the probability that the combination of the target word and the collocator at the relative position @ come from the corpus.">resp.</th><th title="Probability of the collocator at window location @."align="right">p(c<sub><small>@</small></sub>)</th><th align="right">Σp(c<sub><small>@</small></sub>)/|w|</th><th align="left">syntagmatic</th>
-				% }
-			</tr>
-			% my $j=0; my @words; my @vecs; my @ranks; my @marked; for my $list (@$lists) {
-			% my $i=0; while($list) {
-      % my $item = (@$list)[$i];
-      % my $c = ($collocators? (@$collocators)[$i] : 0);
-      % last if(!$c && !$item);
-			<tr>
-				<td align="right">
-  				<%= ++$i %>.
-				</td>
-        % if($item) {
-			  % if(!grep{$_ eq $item->{word}} @words) {
-        %   push @vecs, $item->{vector};
-			  %   push @words, $item->{word};
-			  %   push @ranks, $item->{rank};
-			  %   push @marked, ($marked->{$item->{word}}? 1 : 0);
-        % }
-				<td align="right">
-  				<%= sprintf("%.3f", $item->{dist}) %>
-				</td>
-				<td>
-          % my $class = ($marked->{$item->{word}}? "marked " : ""); 
-          % my $r = $item->{rank}; 
-          % if($r < $mergedEnd) {
-          %   $class .= "merged";
-          %   $r .= " (merged vocab)";
-          % } elsif($mergedEnd!=0 && $r > $mergedEnd) {
-          %   $r -= $mergedEnd;
-          % }
-  				<a class="<%= $class %>" title="freq. rank: <%= $r %>" href="/?word=<%= $item->{word} %>"><%= $item->{word} %></a>
-				</td>
-        % } else {
-          <td colspan="2"/>
-        % }
-        % if($c) {
-				<td align="right">
-          <%= $c->{pos} %>:
-				</td>
-				<td align="right">
-  				<%= sprintf("%.3f", $c->{dist}) %>
-				</td>
-				<td align="right">
-  				<%= sprintf("%.3e", $c->{norm}) %>
-				</td>
-				<td align="right">
-  				<%= sprintf("%.3e", $c->{sum}) %>
-				</td>
-				<td align="left">
-  				<a href="/?word=<%= $c->{word} %>">
-            <%= $c->{word} %>
-				</td>
-        % } else {
-        <td colspan="5"/>
-        % }
-			</tr>
-			% }
-			% }
-		</table>
-		<script>
-		 % use Mojo::ByteStream 'b';
-		 $(window).load(function() {
-			 showMap(<%= b(Mojo::JSON::to_json({target => " $word ", mergedEnd=> $mergedEnd, words => \@words, vecs => \@vecs, ranks => \@ranks, marked => \@marked})); %>);
-		 });
-    </script>
-		% }
-		<div id="second" style="width:800px; height:800px; font-family: arial;">
-			<div id="embed">
-			</div>
-		</div>
-    <div id="cost"></div>
-		% if($show_som) {
-		<div id="som2">
-		</div>
-    <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>
-  % if($training_args) {
-    <p>
-      Word vector model trained with <a href="https://code.google.com/p/word2vec/">word2vec</a> using the following parameters: <pre><%= $training_args %></pre>
-    </p>
-  % }
-  </body>
-</html>