Fixed tree view with multi line labels
diff --git a/Gruntfile.js b/Gruntfile.js
index 7901237..24ab9df 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -27,9 +27,9 @@
 
 	  // TODO: add language versions
 	  wrap:true,
-	  include : ['app/en'],
-	  insertRequire: ['app/en'],
+	  // dir : 'public/js',
 	  name: 'lib/almond',
+	  include : ['app/en'],
 	  out: 'public/js/kalamar-<%= pkg.version %>-en.js'
 	}
       }
diff --git a/dev/demo/matchdemo.js b/dev/demo/matchdemo.js
index 56bf675..adac3c4 100644
--- a/dev/demo/matchdemo.js
+++ b/dev/demo/matchdemo.js
@@ -9,7 +9,7 @@
 // Override getMatchInfo API call
 require(['init'], function () {
 
-var snippet = "<span title=\"cnx/l:meist\">" +
+  var snippet = "<span title=\"cnx/l:meist\">" +
   "  <span title=\"cnx/p:ADV\">" +
   "    <span title=\"cnx/syn:@PREMOD\">" +
   "      <span title=\"mate/l:meist\">" +
@@ -106,6 +106,8 @@
   "</span>" +
   "<span class=\"context-right\"></span>";
 
+  var treeSnippet = "<span class=\"context-left\"><\/span><span class=\"match\">In diesem <span title=\"cnx\/c:np\">Sinne<\/span> schrieb <span title=\"cnx\/c:np\">Brunschwicg<\/span>:&quot;In <span title=\"cnx\/c:np\">Euklids<\/span> <span title=\"cnx\/c:np\">Elementen<\/span> <span title=\"cnx\/c:np\">spiegel<\/span> sich die <span title=\"cnx\/c:np\">Resultate<\/span> der <span title=\"cnx\/c:np\">Arbeit von Generationen vor Aristoteles<\/span> wider, nicht nur die <span title=\"cnx\/c:np\">technische Arbeit<\/span> der <span title=\"cnx\/c:np\">Entdecklung<\/span>, sondern auch die <span title=\"cnx\/c:np\">methodologische Arbeit<\/span> der <span title=\"cnx\/c:np\">Verbindung<\/span> und des <span title=\"cnx\/c:np\">Beweises<\/span>, die, in der <span title=\"cnx\/c:np\">Schule<\/span> des <span title=\"cnx\/c:np\">Phythagoras<\/span> begonnen, ihre <span title=\"cnx\/c:np\">Vollendung in den Schulen von Eudoxos von Cnidus<\/span> und <span title=\"cnx\/c:np\">Platon<\/span> gefunden hat&quot;(5<\/span><span class=\"context-right\"><\/span>";
+
   KorAP.API.getMatchInfo = function(match, callObj, cb) {
     if (callObj["spans"] !== undefined && callObj["spans"] === true) {
       return cb({ "snippet": treeSnippet });
@@ -114,4 +116,6 @@
       return cb({ "snippet": snippet });
     }
   };
+
+
 });
diff --git a/dev/js/src/api.js b/dev/js/src/api.js
index 82f1062..00821de 100644
--- a/dev/js/src/api.js
+++ b/dev/js/src/api.js
@@ -8,59 +8,61 @@
 
   KorAP.URL = KorAP.URL || 'http://korap.ids-mannheim.de/kalamar';
 
-  KorAP.API = {
-    getMatchInfo : function (match, param, cb) {
-      // match is a KorAP.Match object
-      var url = KorAP.URL;
-      url += '/corpus';
-      url += '/' + match.corpusID;
-      url += '/' + match.docID + '.' + match.textID; // TODO
-      url += '/' + match.matchID;
+  KorAP.API = KorAP.API || {};
 
-      // { spans: true, layer:x, foundry : y}
-      if (param['spans'] == true) {
-	url += '?spans=true';
-	if (param['foundry'] !== undefined)
-	  url += '&foundry=' + param['foundry'];
-	if (param['layer'] !== undefined)
-	  url += '&layer=' + param['layer'];
-      }
+  KorAP.API.getMatchInfo = function (match, param, cb) {
 
-      // { spans : false, layer: [Array of KorAP.InfoLayer] }
-      else {
-	// TODO
-	url += '?spans=false';
-      }
+    // match is a KorAP.Match object
+    var url = KorAP.URL;
+    url += '/corpus';
+    url += '/' + match.corpusID;
+    url += '/' + match.docID;
+    url += '/' + match.textID;
+    url += '/' + match.matchID;
 
-      this.getJSON(url, cb);
-    },
-
-    getJSON : function (url, onload) {
-      var req = new XMLHttpRequest();
-
-      req.open("GET", url, true);
-      req.setRequestHeader("Accept", "application/json");
-      req.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); 
-      req.onreadystatechange = function () {
-	/*
-	  States:
-	  0 - unsent (prior to open)
-	  1 - opened (prior to send)
-	  2 - headers received
-	  3 - loading (responseText has partial data)
-	  4 - done
-	*/
-	if (this.readyState == 4) {
-	  if (this.status === 200)
-	    onload(JSON.parse(this.responseText));
-	  else
-	    KorAP.log(this.status, this.statusText);
-	}
-      };
-      req.ontimeout = function () {
-	KorAP.log(0, 'Request Timeout');
-      };
-      req.send();
+    // { spans: true, layer:x, foundry : y}
+    if (param['spans'] == true) {
+      url += '?spans=true';
+      if (param['foundry'] !== undefined)
+	url += '&foundry=' + param['foundry'];
+      if (param['layer'] !== undefined)
+	url += '&layer=' + param['layer'];
     }
+    
+    // { spans : false, layer: [Array of KorAP.InfoLayer] }
+    else {
+      // TODO
+      url += '?spans=false';
+    }
+
+    KorAP.API.getJSON(url, cb);
   };
+
+  KorAP.API.getJSON = function (url, onload) {
+    var req = new XMLHttpRequest();
+
+    req.open("GET", url, true);
+    req.setRequestHeader("Accept", "application/json");
+    req.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); 
+    req.onreadystatechange = function () {
+      /*
+	States:
+	0 - unsent (prior to open)
+	1 - opened (prior to send)
+	2 - headers received
+	3 - loading (responseText has partial data)
+	4 - done
+      */
+      if (this.readyState == 4) {
+	if (this.status === 200)
+	  onload(JSON.parse(this.responseText));
+	else
+	  KorAP.log(this.status, this.statusText);
+      }
+    };
+    req.ontimeout = function () {
+      KorAP.log(0, 'Request Timeout');
+    };
+    req.send();
+  }
 });
diff --git a/dev/js/src/init.js b/dev/js/src/init.js
index 5ef8dee..feab93f 100644
--- a/dev/js/src/init.js
+++ b/dev/js/src/init.js
@@ -13,7 +13,8 @@
 	     vcClass,
 	     tutClass,
 	     domReady,
-	     hintArray) {
+	     hintArray,
+	     alertifyClass) {
   domReady(function (event) {
     var obj = {};
 
@@ -130,7 +131,8 @@
     };
 
     // Initialize queries for document
-    obj.tutorial.initQueries(document);
+    if (obj.tutorial)
+      obj.tutorial.initQueries(document);
 
     /**
      * Init hint helper
@@ -148,10 +150,10 @@
     KorAP.log = function (type, msg) {
 
       // Use alertify to log errors
-      alertify.log(
+      alertifyClass.log(
 	(type === 0 ? '' : type + ': ') +
 	  msg,
-	'warn',
+	'error',
 	5000
       );
     };
diff --git a/dev/js/src/match/tree.js b/dev/js/src/match/tree.js
index 9722f94..e45d05f 100644
--- a/dev/js/src/match/tree.js
+++ b/dev/js/src/match/tree.js
@@ -9,7 +9,7 @@
   var _TermRE = new RegExp("^(?:([^\/]+?)\/)?([^:]+?):(.+?)$");
 
   // Node size
-  var WIDTH  = 55, HEIGHT = 20;
+  var WIDTH  = 55, HEIGHT = 20, LINEHEIGHT = 14;
 
   // Create path for node connections 
   function _line (src, target) {
@@ -179,8 +179,7 @@
       var canvas = document.createElementNS(svgXmlns, 'svg');
       this._element = canvas;
 
-      canvas.setAttribute('height', g.graph().height);
-      canvas.setAttribute('width', g.graph().width);
+      var height = g.graph().height;
 
       // Create edges
       g.edges().forEach(
@@ -218,22 +217,52 @@
 	  // Add label
 	  if (v.label !== undefined) {
 	    var text = group.appendChild(document.createElementNS(svgXmlns, 'text'));
-	    text.setAttribute('x', v.x - v.width / 2);
-	    text.setAttribute('y', v.y - v.height / 2);
+	    var y = v.y - v.height / 2;
+	    text.setAttribute('y', y);
 	    text.setAttribute(
 	      'transform',
 	      'translate(' + v.width/2 + ',' + ((v.height / 2) + 5) + ')'
 	    );
 
-	    var tspan = document.createElementNS(svgXmlns, 'tspan');
-	    tspan.appendChild(document.createTextNode(v.label));
-	    text.appendChild(tspan);
-	  };
+	    if (v.class === "leaf") {
+	      text.setAttribute('title', v.label);
 
+	      var labelPart = v.label.split(" ");
+	      var n = 0;
+	      for (var i = 0; i < labelPart.length; i++) {
+		if (labelPart[i].length === 0)
+		  continue;
+
+		var tspan = document.createElementNS(svgXmlns, 'tspan');
+		tspan.appendChild(document.createTextNode(labelPart[i]));
+		if (n !== 0)
+		  tspan.setAttribute('dy', LINEHEIGHT + 'pt');
+		else
+		  n = 1;
+		tspan.setAttribute('x', v.x - v.width / 2);
+		y += LINEHEIGHT;
+		text.appendChild(tspan);
+	      };
+
+	      y += LINEHEIGHT;
+
+	      // The text is below the canvas - readjust the height!
+	      if (y > height)
+		height = y;
+	    }
+	    else {
+	      var tspan = document.createElementNS(svgXmlns, 'tspan');
+	      tspan.appendChild(document.createTextNode(v.label));
+	      tspan.setAttribute('x', v.x - v.width / 2);
+	      text.appendChild(tspan);
+	    };
+	  };
 	  canvas.appendChild(group);
 	}
       );
 
+      canvas.setAttribute('width', g.graph().width);
+      canvas.setAttribute('height', height);
       return this._element;
     }
   };
diff --git a/dev/js/src/vc/doc.js b/dev/js/src/vc/doc.js
index f04b445..a19430a 100644
--- a/dev/js/src/vc/doc.js
+++ b/dev/js/src/vc/doc.js
@@ -489,6 +489,9 @@
     _changed : function () {
       this.__changed = true;
       
+      if (this._parent) {
+      };
+
       if (this._rewrites === undefined)
 	return;
 
diff --git a/dev/js/src/vc/docgroup.js b/dev/js/src/vc/docgroup.js
index 0db4b4c..da1f6ab 100644
--- a/dev/js/src/vc/docgroup.js
+++ b/dev/js/src/vc/docgroup.js
@@ -1,6 +1,9 @@
 /**
  * Document group criterion
  */
+/*
+ * TODO: Let the UPDATE event bubble up through parents!
+ */
 define([
   'vc/jsonld',
   'vc/unspecified',
diff --git a/dev/scss/header/header.scss b/dev/scss/header/header.scss
index 8b4e0a5..c9d2c3d 100644
--- a/dev/scss/header/header.scss
+++ b/dev/scss/header/header.scss
@@ -69,7 +69,7 @@
       top: 0;
       right: 0;
       margin-right: 0;
-      width: 22px;
+      width: ($standard-margin / 2);
       background-color: $dark-green;
       text-align: center;
       height: 100%;
diff --git a/dev/scss/main/kwic.scss b/dev/scss/main/kwic.scss
index f04cf9b..3676663 100644
--- a/dev/scss/main/kwic.scss
+++ b/dev/scss/main/kwic.scss
@@ -90,12 +90,7 @@
 	  > * {
 	    background-color: transparent;
 	  }
-	  padding: {
-	    top: 0;
-	    right: 0;
-	    bottom: 5pt;
-	    left: 5pt;
-	  };
+	  padding: 2pt 0 5pt 5pt;
 	  margin: {
 	    top: 0;
 	    right: $right-match-distance; // 3em;
diff --git a/dev/scss/main/main.scss b/dev/scss/main/main.scss
index 9cadd4b..8f23bbd 100644
--- a/dev/scss/main/main.scss
+++ b/dev/scss/main/main.scss
@@ -18,7 +18,7 @@
 main {
   margin: {
     left: $standard-margin; 
-    right: $standard-margin; // Todo: -16px
+    right: ($standard-margin / 2);
   }
   padding-bottom: 20pt;
   &.embedded {
diff --git a/dev/scss/main/sidebar.scss b/dev/scss/main/sidebar.scss
index b454055..5d9d4df 100644
--- a/dev/scss/main/sidebar.scss
+++ b/dev/scss/main/sidebar.scss
@@ -33,7 +33,7 @@
     position: absolute;
     right: 0;
     bottom: 0;
-    margin-right: -30px;
+    margin-right: -1 * ($standard-margin / 2);
     background-color: $dark-green;
     font-family: FontAwesome;
     content: $fa-bars;
@@ -135,7 +135,7 @@
 
 
 aside:not(:focus):not(.active) {
-  margin-left: -1 * ($logo-left-distance - 15px);
+  margin-left: -1 * ($logo-left-distance - ($standard-margin / 2));
 //  box-shadow: none;
 /*
   overflow-y: hidden;
diff --git a/dev/scss/util.scss b/dev/scss/util.scss
index 7f5f723..a349bd4 100644
--- a/dev/scss/util.scss
+++ b/dev/scss/util.scss
@@ -90,9 +90,9 @@
 /**
  * Margins
  */
-$standard-margin: 30px;
-$right-distance: 30px;
-$right-match-distance: 20px;
+$standard-margin: 40px;
+$right-distance: 40px;
+$right-match-distance: $standard-margin / 2;
 $logo-left-distance: 230px;
 
 
diff --git a/lib/Kalamar.pm b/lib/Kalamar.pm
index d1d0049..aea95f5 100644
--- a/lib/Kalamar.pm
+++ b/lib/Kalamar.pm
@@ -23,6 +23,9 @@
     $self->secrets([
       b($secret)->slurp->split("\n")
     ]);
+  }
+  else {
+    $self->log->warn('Please create a kalamar.secret file');
   };
 
   # Load plugins
diff --git a/lib/Kalamar/API.pm b/lib/Kalamar/API.pm
index 9b8a529..fb06a7e 100644
--- a/lib/Kalamar/API.pm
+++ b/lib/Kalamar/API.pm
@@ -455,7 +455,7 @@
 
   # Legacy: In old versions the text_id was part of the doc_id
   unless ($x->{textID}) {
-    ($x->{docID}, $x->{textID}) = split '.', $x->{docID};
+    ($x->{docID}, $x->{textID}) = split '\.', $x->{docID};
   };
   $x;
 };
diff --git a/package.json b/package.json
index d3bbea4..215d81e 100755
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "kalamar",
-  "version": "0.14.2",
+  "version": "0.14.3",
   "description": "User Frontend for KorAP",
   "devDependencies": {
     "grunt": "~0.4.5",
diff --git a/templates/match.html.ep b/templates/match.html.ep
index d6e3794..c9c95e6 100644
--- a/templates/match.html.ep
+++ b/templates/match.html.ep
@@ -1,11 +1,12 @@
 % my $match = stash('match') || {}; 
-% my $id = $match->{corpusID} . '-' . $match->{docID} . '-' . $match->{ID};
+% my $id = $match->{corpusID} . '-' . $match->{docID} . '.' . $match->{textID} . '#' . $match->{ID};
 <li data-corpus-id="<%= $match->{corpusID} %>"
     data-doc-id="<%= $match->{docID} %>"
     data-text-id="<%= $match->{textID} %>"
     data-match-id="<%= $match->{ID} %>"
     %# TODO: This needs to be retrieved per match 
-    data-available-info="base/s=spans corenlp/c=spans corenlp/ne=tokens corenlp/p=tokens corenlp/s=spans glemm/l=tokens mate/l=tokens mate/m=tokens mate/p=tokens opennlp/p=tokens opennlp/s=spans tt/l=tokens tt/p=tokens tt/s=spans xip/c=spans"
+%#    data-available-info="base/s=spans corenlp/c=spans corenlp/ne=tokens corenlp/p=tokens corenlp/s=spans glemm/l=tokens mate/l=tokens mate/m=tokens mate/p=tokens opennlp/p=tokens opennlp/s=spans tt/l=tokens tt/p=tokens tt/s=spans xip/c=spans"
+    data-available-info="cnx/c=spans corenlp/ne=tokens corenlp/p=tokens mate/l=tokens mate/m=tokens mate/p=tokens opennlp/p=tokens tt/l=tokens tt/p=tokens xip/c=spans"
     id="<%= $id %>"\
 <% if (current_route eq 'match') { %> class="active"<% } =%>>
   <div>