diff --git a/Kieker.WebGUI/lib/kieker-1.6-SNAPSHOT_emf.jar b/Kieker.WebGUI/lib/kieker-1.6-SNAPSHOT_emf.jar
index cc37c36997b46247562a736d8e1268d68a6a8101..2b90350faeb6f5183920c7db2904a0c67012dc01 100644
Binary files a/Kieker.WebGUI/lib/kieker-1.6-SNAPSHOT_emf.jar and b/Kieker.WebGUI/lib/kieker-1.6-SNAPSHOT_emf.jar differ
diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/view/CurrentAnalysisEditorBeanV2.java b/Kieker.WebGUI/src/main/java/kieker/webgui/beans/view/CurrentAnalysisEditorBeanV2.java
index fbd46a17020f977b28d5c3728e569ce2324713c0..38f6afeb7ee9953080c092ed53f878eea6e83ad9 100644
--- a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/view/CurrentAnalysisEditorBeanV2.java
+++ b/Kieker.WebGUI/src/main/java/kieker/webgui/beans/view/CurrentAnalysisEditorBeanV2.java
@@ -48,6 +48,7 @@ import kieker.analysis.model.analysisMetaModel.MIPlugin;
 import kieker.analysis.model.analysisMetaModel.MIPort;
 import kieker.analysis.model.analysisMetaModel.MIProject;
 import kieker.analysis.model.analysisMetaModel.MIProperty;
+import kieker.analysis.model.analysisMetaModel.MIReader;
 import kieker.analysis.model.analysisMetaModel.MIRepository;
 import kieker.analysis.model.analysisMetaModel.MIRepositoryConnector;
 import kieker.analysis.model.analysisMetaModel.impl.MAnalysisMetaModelFactory;
@@ -98,9 +99,37 @@ public final class CurrentAnalysisEditorBeanV2 {
 	 */
 	private static final String JS_CMD_INIT_GRAPH = "var graph = GraphFlow(); graph.initGraph(null);";
 	/**
-	 * This is the javascript command to add a node to the graph.
+	 * This is the javascript command for a node object.
 	 */
-	private static final String JS_CMD_ADD_NODE = "graph.addNode(%d, %d, \"%s\", [%s], [%s]);";
+	private static final String JS_CMD_NODE = "{\"id\":\"%s\", \"name\":\"%s\", \"nodeClass\":\"%s\", \"tooltip\":\"%s\"}";
+	/**
+	 * This is the javascript command for a port object.
+	 */
+	private static final String JS_CMD_PORT = "{\"name\":\"%s\",\"id\":\"%s\", \"tooltip\":\"%s\"}";
+	/**
+	 * This is the javascript type name for a repository port.
+	 */
+	private static final String JS_CMD_PORT_TYPE_REPOSITORY = "repoPort";
+	/**
+	 * This is the javascript type name for an input port.
+	 */
+	private static final String JS_CMD_PORT_TYPE_INPUT = "inputPort";
+	/**
+	 * This is the javascript type name for an output port.
+	 */
+	private static final String JS_CMD_PORT_TYPE_OUTPUT = "outputPort";
+	/**
+	 * This is the javascript command to add a filter to the graph.
+	 */
+	private static final String JS_CMD_ADD_FILTER = "graph.addFilter(%d, %d, %s,[%s],[%s],[%s]);";
+	/**
+	 * This is the javascript command to add a reader to the graph.
+	 */
+	private static final String JS_CMD_ADD_READER = "graph.addReader(%d, %d, %s,[%s],[%s]);";
+	/**
+	 * This is the javascript command to add a repository to the graph.
+	 */
+	private static final String JS_CMD_ADD_REPOSITORY = "graph.addRepository(%d, %d, %s,%s);";
 	/**
 	 * This is the javascript command to add an edge to the graph.
 	 */
@@ -621,7 +650,7 @@ public final class CurrentAnalysisEditorBeanV2 {
 	}
 
 	/**
-	 * This method initializes the modified jit-grpah by delivering the necessary javascript commands to paint the repository components.
+	 * This method initializes the modified jit-graph by delivering the necessary javascript commands to paint the repository components.
 	 */
 	private void initializeGraphRepositories() {
 		final RequestContext context = RequestContext.getCurrentInstance();
@@ -629,22 +658,26 @@ public final class CurrentAnalysisEditorBeanV2 {
 		int posCounter = 0;
 		for (final MIRepository repository : this.project.getRepositories()) {
 			final int pos = (posCounter * 100) - 250;
-			context.execute(String.format(CurrentAnalysisEditorBeanV2.JS_CMD_ADD_NODE, 0, pos, this.assembleGraphString(repository), "\"ip\"", ""));
+			final String repoPort = String.format(CurrentAnalysisEditorBeanV2.JS_CMD_PORT, CurrentAnalysisEditorBeanV2.JS_CMD_PORT_TYPE_INPUT, "ip1", "N/A");
+			context.execute(String.format(CurrentAnalysisEditorBeanV2.JS_CMD_ADD_REPOSITORY, 0, pos, this.assembleGraphString(repository), repoPort));
 			posCounter++;
 		}
 	}
 
 	/**
-	 * This method initializes the modified jit-grpah by delivering the necessary javascript commands to paint the plugin components.
+	 * This method initializes the modified jit-graph by delivering the necessary javascript commands to paint the plugin components.
 	 */
 	private void initializeGraphPlugins() {
 		final RequestContext context = RequestContext.getCurrentInstance();
 
 		int posCounter = 0;
 		for (final MIPlugin plugin : this.project.getPlugins()) {
-			final int pos = (posCounter * 100) - 250;
-			context.execute(String.format(CurrentAnalysisEditorBeanV2.JS_CMD_ADD_NODE, -250, pos, this.assembleGraphString(plugin),
-					this.assembleInputPortsGraphString(plugin), this.assembleOutputPortsGraphString(plugin)));
+			final int pos = posCounter * 100;
+			if (plugin instanceof MIReader) {
+				context.execute(String.format(CurrentAnalysisEditorBeanV2.JS_CMD_ADD_READER, pos, pos, this.assembleGraphString(plugin), "", ""));
+			} else {
+				context.execute(String.format(CurrentAnalysisEditorBeanV2.JS_CMD_ADD_FILTER, pos, pos, this.assembleGraphString(plugin), "", "", ""));
+			}
 			posCounter++;
 		}
 	}
@@ -659,7 +692,7 @@ public final class CurrentAnalysisEditorBeanV2 {
 	 * @return The ID for the port within the graph
 	 */
 	private String assembleGraphPortID(final MIPlugin plugin, final MIPort port) {
-		return this.assembleGraphString(plugin) + "_" + this.portMap.get(port);
+		return this.pluginMap.get(plugin) + "_" + this.portMap.get(port);
 	}
 
 	/**
@@ -718,7 +751,7 @@ public final class CurrentAnalysisEditorBeanV2 {
 	 * @return A human readable ID.
 	 */
 	private String assembleGraphString(final MIRepository repository) {
-		return "Repository" + this.repositoryMap.get(repository) + "(" + repository.getName() + ")";
+		return String.format(CurrentAnalysisEditorBeanV2.JS_CMD_NODE, this.repositoryMap.get(repository), repository.getName(), repository.getClassname(), "N/A");
 	}
 
 	/**
@@ -729,7 +762,7 @@ public final class CurrentAnalysisEditorBeanV2 {
 	 * @return A human readable ID.
 	 */
 	private String assembleGraphString(final MIPlugin plugin) {
-		return "Plugin" + this.pluginMap.get(plugin) + "(" + plugin.getName() + ")";
+		return String.format(CurrentAnalysisEditorBeanV2.JS_CMD_NODE, this.pluginMap.get(plugin), plugin.getName(), plugin.getClassname(), "N/A");
 	}
 
 	/**
diff --git a/Kieker.WebGUI/src/main/webapp/AnalysisEditor.xhtml b/Kieker.WebGUI/src/main/webapp/AnalysisEditor.xhtml
index 4796358c757fd1b522ead048995d309301047b2d..81c83b3452508fa1034d2c7da4d4a2b905588958 100644
--- a/Kieker.WebGUI/src/main/webapp/AnalysisEditor.xhtml
+++ b/Kieker.WebGUI/src/main/webapp/AnalysisEditor.xhtml
@@ -198,7 +198,7 @@
                             <ui:repeat value="#{currentAnalysisEditorBean.availableRepositories}" var="repository">
                                 <p:commandLink id="repositoryLink" value="#{repository.simpleName}" action="#{currentAnalysisEditorBean.addRepository(repository)}" update=":centerForm :messages"/><br/>
                                 <p:tooltip for="repositoryLink">
-                                    <b><h:outputText value="#{repository.simpleName} repositoryfilter.name})"/></b>
+                                    <b><h:outputText value="#{repository.simpleName} (#{repository.name})"/></b>
                                     <br/>
                                     <h:outputText value="#{currentAnalysisEditorBean.getDescription(repository)}"/>
                                 </p:tooltip>  
diff --git a/Kieker.WebGUI/src/main/webapp/AnalysisEditor_V2.xhtml b/Kieker.WebGUI/src/main/webapp/AnalysisEditor_V2.xhtml
index 0e42c7eb972b1aac35b9d466062fa6a834d97325..6761853592a4ca0db3092348c18f593d2ddf4953 100644
--- a/Kieker.WebGUI/src/main/webapp/AnalysisEditor_V2.xhtml
+++ b/Kieker.WebGUI/src/main/webapp/AnalysisEditor_V2.xhtml
@@ -15,10 +15,10 @@
     <h:head>
         <title>Kieker.WebGUI</title>
 
-        <link type="text/css" href="css/base.css" rel="stylesheet" />
-        <link type="text/css" href="css/FlowEditor.css" rel="stylesheet" />
-        <link rel="stylesheet" type="text/css" href="../css/Common.css" />
-        <link rel="stylesheet" type="text/css" href="../css/AnalysisEditor.css" />
+        <link rel="stylesheet" type="text/css" href="css/base.css"  />
+        <link rel="stylesheet" type="text/css" href="css/FlowEditor.css"  />
+        <link rel="stylesheet" type="text/css" href="css/Common.css" />
+        <link rel="stylesheet" type="text/css" href="css/AnalysisEditor.css" />
 
         <script language="javascript" type="text/javascript" src="js/jit.js"></script>
         <script language="javascript" type="text/javascript" src="js/flowEditor.js"></script>
diff --git a/Kieker.WebGUI/src/main/webapp/css/base.css b/Kieker.WebGUI/src/main/webapp/css/base.css
index 398da055806ed1f71f2912dd84867a6e79812fef..4e05001708d0c99e615008a16c7b683c63144370 100644
--- a/Kieker.WebGUI/src/main/webapp/css/base.css
+++ b/Kieker.WebGUI/src/main/webapp/css/base.css
@@ -14,3 +14,18 @@
     overflow:hidden;
 }
 
+.tip {
+    color: #111;
+    width: 139px;
+    background-color: white;
+    border:1px solid #ccc;
+    -moz-box-shadow:#555 2px 2px 8px;
+    -webkit-box-shadow:#555 2px 2px 8px;
+    -o-box-shadow:#555 2px 2px 8px;
+    box-shadow:#555 2px 2px 8px;
+    opacity:0.9;
+    filter:alpha(opacity=90);
+    font-size:10px;
+    font-family:Verdana, Geneva, Arial, Helvetica, sans-serif;
+    padding:7px;
+}
\ No newline at end of file
diff --git a/Kieker.WebGUI/src/main/webapp/js/flowEditor.js b/Kieker.WebGUI/src/main/webapp/js/flowEditor.js
index 3bfde4fb7451db64921a3037a0b7275e2abf2fc9..b411673eb0ca53b8c2d6e20bb1ff189efe263c76 100644
--- a/Kieker.WebGUI/src/main/webapp/js/flowEditor.js
+++ b/Kieker.WebGUI/src/main/webapp/js/flowEditor.js
@@ -44,18 +44,26 @@ function GraphFlow(){
 	
 	//var that = this;
 	
-	/** edge properties */
-	var edgeColor 		= "#114270",
-		edgeColorFocus 	= "#FF00FF";
-
-	/** node properties */
-	var vertexLabelSize 	= 12,		// this value modifies the text size and with it the node size
-		nodeColor			= "#909090",
-		nodeColorFocus		= "#FF00FF";
-		//vertexLabelColor 	= "#0F0F0F",
-		//vertexSelectColor	= "#B2E5F2";
-
-	var longestEdge = 0;
+	/** Color Palettes */
+	var nodeFillColor = [];
+		nodeFillColor['Filter'] 	 	= "#DEDEDE";
+		nodeFillColor['Repository']  	= "#EFAC6A";
+		nodeFillColor['Reader'] 	 	= "#6AEF73";
+	
+	var nodeStrokeColor = [];
+		nodeStrokeColor['Filter'] 	   	  = "#4D4D4D";
+		nodeStrokeColor['Repository']  	  = "#735332";
+		nodeStrokeColor['Reader'] 	      = "#327337";
+		nodeStrokeColor['inputPort']   	  = "#AA0000";
+		nodeStrokeColor['outputPort']	  = "#AA0000";
+		nodeStrokeColor['repositoryPort'] = "#AA0000";
+		
+	var nodeColorFocus	  = "#0098BE",
+		edgeColor 		  = "#114270",
+		edgeColorFocus 	  = "#0098BE";
+		
+	/** Overall size modifier: the width of node labels in pixels */
+	var vertexLabelSize 	= 12;
 
 	/** FlowGraph Object */
 	var fd;
@@ -64,7 +72,7 @@ function GraphFlow(){
 	var hover = null;
 
 	/** This array stores all Nodes and is initialized with a dummy,
-		used for beautiful edge dragging.
+		used for drawing edges between a node and the mousepointer.
 		*/
 	var json = [ {
 			  "adjacencies": [], 
@@ -130,6 +138,11 @@ function GraphFlow(){
 			onDragMove,
 			onDragCancel,
 			onDragEnd
+		Or one of these events:
+			onCreateEdge(sourceNodeID, targetNodeID, sourcePortID, targetPortID),
+			onCreateNode(nodeID),
+			onRemoveEdge(sourceNodeID, targetNodeID, sourcePortID, targetPortID),
+			onRemoveNode(nodeID)
 		When altering the graph, do not forget to refresh() it at the
 		end!
 		@param event - the name of the mouse event ( see list above)
@@ -147,21 +160,111 @@ function GraphFlow(){
 		listener[event].push(listenerFunction);
 	}
 	
+	/**
+	Adds a listener that forbids edge creation if...
+		... an edge with the same source and target exists.
+		...	the target node is the source node.
+		... the source and target node are of the same port type.
+		... a repository node is not connected to a repository and
+			vice versa.
+	*/
+	this.addEdgeConstraints = function(){
+		addListener("onCreateEdge", 
+		function(sourceFamilyID, targetFamilyID, sourcePortID, targetPortID){
+		
+			// remove Edge if it leads to itself
+			if( sourcePortID == targetPortID){
+				removeEdge(sourcePortID, targetPortID);
+				return;
+			}
+		
+			var	sourcePort = getNode(sourcePortID),
+				targetPort = getNode(targetPortID);
+			
+			// remove Edge if the connected nodes share the same type
+			if(sourcePort.data.$type == targetPort.data.$type){
+				removeEdge(sourcePortID, targetPortID);
+				return;
+			}
+			
+			var target = getNode(targetFamilyID),
+				goesToRepo = (target.data.$nodeType == "Repository"),
+				isRepoPort = (sourcePort.data.$type == "repositoryPort");
+			
+			// remove Edge if it is falsely connected to repository ports
+			if(goesToRepo != isRepoPort){
+				removeEdge(sourcePortID, targetPortID);
+				return;
+			}
+			
+			// remove duplicate Edge
+			var adja = sourcePort.adjacencies,
+				duplicate = false;
+			for(var a=0; a < adja.length; a++){
+				if(adja[a].nodeTo == targetPortID){
+					if(duplicate){
+						removeEdge(sourcePortID, targetPortID);
+						return;
+					}
+					else{
+						duplicate = true;
+					}
+				}
+			}
+		});
+	}
+	
+	/**
+	Changes all colors of the graph. Colors that should not be changed are given null as argument.
+	*/
+	/*
+	this.setColors = function(nodeFocus, edgeFocus, edge, filterFill, filterStroke, readerFill, readerStroke, repoFill, repoSroke){
+		
+		var nodeFillColor = [];
+		nodeFillColor['Filter'] 	 	= "#DEDEDE";
+		nodeFillColor['Repository']  	= "#EFAC6A";
+		nodeFillColor['Reader'] 	 	= "#6AEF73";
+	
+	var nodeStrokeColor = [];
+		nodeStrokeColor['Filter'] 	   	  = "#4D4D4D";
+		nodeStrokeColor['Repository']  	  = "#735332";
+		nodeStrokeColor['Reader'] 	      = "#327337";
+		nodeStrokeColor['inputPort']   	  = "#AA0000";
+		nodeStrokeColor['outputPort']	  = "#AA0000";
+		nodeStrokeColor['repositoryPort'] = "#AA0000";
+		
+	var nodeColorFocus	  = "#0098BE",
+		edgeColor 		  = "#114270",
+		edgeColorFocus 	  = "#0098BE";
+		
+	}*/
+	
 	/**
 		Calls all listener that are registered under the eventName.
 		@param eventName - see 'addListener()'
-		@param node - the node which was clicked
-		@param eventInfo - an object containing useful methods like *getPos* to get the mouse position relative to the canvas
-		@param e - the grabbed event (should return the native event in a cross-browser manner)
+		@param arguments - an array of arguments. For mouseEvents it is [node, eventInfo, e],
+						   for nodeEvents it is [nodeID], 
+						   and for edgeEvents it is [sourceNodeID, targetNodeID, sourcePortID, targetPortID]
 	*/
-	this.callListener = function(eventName, node, eventInfo, e){
+	function callListener(eventName, arguments){
+		//Log.write("call "+eventName+" "+arguments.length + " ("+Math.random()+")");
 		var lArr = listener[eventName];
 		if(lArr == undefined){
 			return;
 		}
 		// iterate through all listener this event concerns
-		for(var l=0; l < lArr.length; l++){
-			lArr[l](node, eventInfo, e);
+		if(arguments.length == 3){
+			for(var l=0; l < lArr.length; l++){
+				lArr[l](arguments[0], arguments[1], arguments[2]);
+			}
+		}else if(arguments.length == 1){
+			for(var l=0; l < lArr.length; l++){
+				lArr[l](arguments[0]);
+			}
+		}else if(arguments.length == 4){
+			for(var l=0; l < lArr.length; l++){
+				lArr[l](arguments[0], arguments[1], arguments[2], arguments[3]);
+			}
 		}
 	}
 	
@@ -179,133 +282,185 @@ function GraphFlow(){
 		}
 	}
 	
+	/**
+	Adds a repository node to the graph.
+	@param nodeFamily - describes some properties of the node: (id, name, nodeClass, tooltip)
+	@param outputPort - properties of the single output port(id, name, tooltip)
+	*/
+	this.addRepository = function(xPosition, yPosition, nodeFamily, inputPort){
+		addNode(xPosition, yPosition, nodeFamily, null, [inputPort], null, "Repository");
+	}
+	
+	/**
+	Adds a reader node to the graph.
+	@param nodeFamily - describes some properties of the node: (id, name, nodeClass, tooltip)
+	@param repositoryPorts - an array of properties for the repository ports (id, name, tooltip)
+	@param outputPorts - an array of properties for the output ports (id, name, tooltip)
+	*/
+	this.addReader = function(xPosition, yPosition, nodeFamily, repositoryPorts, outputPorts){
+		addNode(xPosition, yPosition, nodeFamily, repositoryPorts, null, outputPorts, "Reader");
+	}
+	
+	/**
+	Adds a filter node to the graph.
+	@param nodeFamily - describes some properties of the node: (id, name, nodeClass, tooltip)
+	@param outputPort - properties of the single output port(id, name, tooltip)
+	@param repositoryPorts - an array of properties for the repository ports (id, name, tooltip)
+	@param inputPorts - an array of properties for the input ports (id, name, tooltip)
+	@param outputPorts - an array of properties for the output ports (id, name, tooltip)
+	*/
+	this.addFilter = function(xPosition, yPosition, nodeFamily, repositoryPorts, inputPorts, outputPorts){
+		addNode(xPosition, yPosition, nodeFamily, repositoryPorts, inputPorts, outputPorts, "Filter");
+	}
+	
 	/**
 	 Adds a Node to the graph.
-	 @param familyID - the ID and displayname of the node
-	 @param inputPortIDs - an array of IDs for the input ports
-	 @param outputPortIDs - an array of IDs for the output ports
+	 @param nodeFamily - describes some properties of the node: (id, name, nodeClass, tooltip)
+	 @param inputPortIDs - an array of properties for the input ports (id, name, tooltip)
+	 @param outputPortIDs - an array of properties for the output ports (id, name, tooltip)
 	 */
-	this.addNode = function(xPosition, yPosition, familyID, inputPortIDs, outputPortIDs){
+	function addNode(xPosition, yPosition, nodeFamily, repositoryPorts, inputPorts, outputPorts, nodeType){
 	
-	var inputPorts = [],
-		outputPorts = [],
-		maxPorts = Math.max(inputPortIDs.length, outputPortIDs.length),
-		size = vertexLabelSize*2;
+	var countRepo = 0,
+		countInput = 0,
+		countOutput = 0;
 		
-	var width = (familyID.length+4)*vertexLabelSize,
-		height = 1*size + 
-			Math.max( 2*size, size/2 + maxPorts * size);
-		
-	// for fast position computation, calculate the relative position
-	// of the first port to the nodeFamily-box
-	var ipRelativeX = -width/2,
-		ipRelativeY = (size - inputPortIDs.length * size)/2,
-		opRelativeX = width/2,
-		opRelativeY = (size - outputPortIDs.length * size)/2;
-	
-	// set position of the ports in world coordinates
-	var x = xPosition+ ipRelativeX,
-		y = yPosition+ ipRelativeY;
-	
-	// define inputPorts
-	for(var p=0; p < inputPortIDs.length; p++){
-		var inputPort =
-			{
-			  "adjacencies": [], 
-			  "data": {
-				"$dim": size,					
-				"$type": "inputPort",
-				"$xPos": x,
-				"$yPos": y,
-				"$color": "#AA0000",
-				"$unfocusColor" : "#AA0000"
-			}, 
-			  "id": familyID+"_"+inputPortIDs[p], 
-			  "name": inputPortIDs[p],
-		};
-		
-		inputPorts.push(inputPort);
-		y += size;
+	if(repositoryPorts != null){
+		countRepo= repositoryPorts.length;
 	}
-	
-	if(inputPorts.length != 0){
-		inputPorts[0].data.$relativeX= ipRelativeX;
-		inputPorts[0].data.$relativeY= ipRelativeY;
+	if(inputPorts != null){
+		countInput= inputPorts.length;
+	}
+	if(outputPorts != null){
+		countOutput= outputPorts.length;
 	}
 	
-	// set position of the ports in world coordinates
-	x = xPosition+ opRelativeX,
-	y = yPosition+ opRelativeY;
-	
-	// define outputPorts
-	for(var p=0; p < outputPortIDs.length; p++){
-		var outputPort =
-			{
-			  "adjacencies": [], 
-			  "data": {
-				"$dim": size,					
-				"$type": "outputPort",
-				"$xPos": x,
-				"$yPos": y,
-				"$color": "#0000AA",
-				"$unfocusColor" : "#0000AA"
-			}, 
-			  "id": familyID+"_"+outputPortIDs[p], 
-			  "name": outputPortIDs[p],
-		};
+	var maxPorts = Math.max(countInput, countRepo+countOutput),
+		size = vertexLabelSize*2;
 		
-		outputPorts.push(outputPort);
-		y += size;
+	if(maxPorts >= countInput && countRepo > 0 && countInput > 0){
+		maxPorts++;
 	}
-	if(outputPorts.length != 0){
-		outputPorts[0].data.$relativeX= opRelativeX;
-		outputPorts[0].data.$relativeY= opRelativeY;
+		
+	var width = (nodeFamily.name.length+4)*vertexLabelSize,
+		height = 1*size + 
+			Math.max( 2*size, size/2 + maxPorts * size);
+	
+	// the classname may be longer than the diplayed name
+	if( nodeFamily.nodeClass != undefined){
+		width = Math.max(width,  (nodeFamily.nodeClass.length+6)*(vertexLabelSize-2));
 	}
-	var nodeFamily =
-		{
-		  //"adjacencies": [], 
+	
+	// add big node box
+	// change node color, depending on its type
+	var nodeColor = nodeFillColor[nodeType],
+		strokeColor = nodeStrokeColor[nodeType];
+	var newNode = {
 		  "data": {
 			"$dim": size,					
 			"$type": "nodeFamily",
 			"$jsonIndex": json.length,
-			"$portCount": inputPortIDs.length+ outputPortIDs.length,
+			"$portCount": countRepo+countInput+countOutput,
 			"$width": width,
 			"$height": height,
-			"$color": "#909090",
-			"$unfocusColor" : "#909090",
-			"$fillColor": "#F0F0F0",
+			"$color": strokeColor,
+			"$fillColor": nodeColor,
+			"$nodeClass": nodeFamily.nodeClass,
+			"$nodeType": nodeType,
 			"$xPos": xPosition,
-			"$yPos": yPosition
+			"$yPos": yPosition,
+			"$tooltip": nodeFamily.tooltip
 		  }, 
-		  "id": familyID, 
-		  "name": familyID,
-		};
-		
-	// set position of the close button in world coordinates
-	x = xPosition+ width/2,
-	y = yPosition- height/2;
+		  "id": nodeFamily.id, 
+		  "name": nodeFamily.name
+	};
+	json.push(newNode);
 	
-	var closeButton =
-		{
+	// add closeButton
+	var closeButton ={
 		  "adjacencies": [], 
 		  "data": {
 			"$dim": size,					
 			"$type": "crossBox",
-			"$family": nodeFamily,
-			"$xPos": x,
-			"$yPos": y,
-			"$color": "#CC0909",
-			"$unfocusColor" : "#CC0909",
+			"$family": newNode,
+			"$xPos": xPosition+ width/2,
+			"$yPos": yPosition- height/2,
+			"$color": strokeColor,
+			"$fillColor": nodeColor,
 		   }, 
-		  "id": familyID+"_close", 
-		  "name": "x",
-		};
-
-	// add all components
-	json.push(nodeFamily);
+		  "id": nodeFamily.id+"_close", 
+		  "name": "x"
+	};
 	json.push(closeButton);
-	json= json.concat(inputPorts);
-	json= json.concat(outputPorts);
+	
+	// Loop Info: 
+	// This loop adds all port types to the temporary port array.
+	// For fast position computation, the relative position
+	// of the first port to the nodeFamily-box is computed for each port type
+	// it is stored in relativeX, relativeY
+	
+	for(var portType = 0; portType < 3; portType++){
+		var x, y, relativeX, relativeY,
+			loopPorts, loopType;
+		switch(portType){
+			case 0: // repository ports
+				var repoSpace = 0;
+				if(countInput == 0){
+					repoSpace = 1;
+				}
+				relativeX = width/2,
+				relativeY = ((0.5+repoSpace-countOutput-countRepo) * size)/2,
+				loopPorts = repositoryPorts;
+				loopType = "repositoryPort";
+				break;
+				
+			case 1: // input ports
+				relativeX = -width/2,
+				relativeY = ( (1.5-countInput)*size)/2,
+				loopPorts = inputPorts;
+				loopType = "inputPort";
+				break;
+				
+			case 2: // output ports
+				relativeX = width/2,
+				relativeY = ((1.5 + countRepo - countOutput) * size)/2;
+				loopPorts = outputPorts;
+				loopType = "outputPort";
+				break;
+		}
+		
+		// continue only if ports exist
+		if(loopPorts != null && loopPorts.length > 0){
+		
+			x = xPosition+ relativeX;
+			y = yPosition+ relativeY;
+			
+			for(var p=0; p < loopPorts.length; p++){
+				var port = loopPorts[p];
+				var newPort ={
+					  "adjacencies": [], 
+					  "data": {
+						"$dim": size,					
+						"$type": loopType,
+						"$xPos": x,
+						"$yPos": y,
+						"$color": nodeStrokeColor[loopType],
+						"$tooltip": port.tooltip}, 
+					  "id": nodeFamily.id+"_"+port.id, 
+					  "name": port.name};
+					  
+				if(p == 0){
+					newPort.data.$relativeX= relativeX;
+					newPort.data.$relativeY= relativeY;
+				}
+				json.push(newPort);
+				y += size;
+			}
+		}
+	}
+	
+	// call listener
+	callListener("onCreateNode", [nodeFamily.id]);
 	}
 
 	/**
@@ -315,7 +470,8 @@ function GraphFlow(){
 	this.removeNode =  function(nodeFamily){
 		
 		var deleteFrom = nodeFamily.data.$jsonIndex, 
-			deleteUntil = deleteFrom+ nodeFamily.data.$portCount+1;
+			deleteUntil = deleteFrom+ nodeFamily.data.$portCount+1,
+			familyID = nodeFamily.id;
 		
 		// delete nodeFamily and closeButton
 		delete json[deleteFrom];
@@ -329,7 +485,7 @@ function GraphFlow(){
 			for(var e = 0;  e < json.length;  e++){
 				var incNode = json[e];
 				if(incNode != undefined){
-					removeEdge(incNode, portID);	
+					removeEdge(incNode.id, portID);	
 				}
 			}
 			
@@ -348,7 +504,10 @@ function GraphFlow(){
 				json[n].data.$jsonIndex = n;
 			}
 		}
-			
+		
+		// call listener
+		callListener("onRemoveNode", [familyID]);
+		
 		return;
 	 }
 	 
@@ -378,35 +537,18 @@ function GraphFlow(){
 		json[moveFrom].data.$xPos = nodeX;
 		json[moveFrom].data.$yPos = nodeY;
 		moveFrom++;
-			
-		// set pos of inputs		
-		nodeX = x+ json[moveFrom].data.$relativeX;
-		nodeY = y+ json[moveFrom].data.$relativeY;
 		
+		// set pos of ports
 		for(var i= moveFrom; i<= moveUntil; i++){
 			node = fd.graph.getNode(json[i].id);
-			if(node.data.$type == "inputPort"){
-				node.pos.setc(nodeX,nodeY);
-				json[i].data.$xPos = nodeX;
-				json[i].data.$yPos = nodeY;
-				nodeY+= dim;
-			}
-			else{
-				moveFrom = i;
-				break;
+			
+			if(node.data.$relativeX != undefined){
+				nodeX = x+ node.data.$relativeX;
+				nodeY = y+ node.data.$relativeY;
 			}
-		}
-		
-		// set pos of outputs
-		nodeX = x+ json[moveFrom].data.$relativeX;
-		nodeY = y+ json[moveFrom].data.$relativeY;
-		
-		for(var o= moveFrom; o <= moveUntil; o++){
-			node = fd.graph.getNode(json[o].id);
 			node.pos.setc(nodeX,nodeY);
-			json[o].data.$xPos = nodeX;
-			json[o].data.$yPos = nodeY;
-			
+			json[i].data.$xPos = nodeX;
+			json[i].data.$yPos = nodeY;
 			nodeY+= dim;
 		}
 	 }
@@ -419,40 +561,46 @@ function GraphFlow(){
    *  @return true if the edge was successfully added
    */
 	this.addEdge = function(sourceID, targetID){
-		// edge from node to itself?
-		if(sourceID == targetID){
-			Log.write("Error: Cannot connect Node to itself!");
-			return false;
-		}
 		
-		// look up the source node
-		var source = getNodeFromJSON(sourceID),
-			adja = source.adjacencies;
+		// look up the source node and the nodeFamilys of both nodes
+		var source, sourceFamilyID, targetFamilyID, lastFamilyID;
+		for(var n=0; n< json.length; n++){
+			var loopNode = json[n];
+			if(loopNode.data.$type == "nodeFamily"){
+				lastFamilyID = loopNode.id
+			}
+			else if(loopNode.id == sourceID){
+				source = loopNode;
+				sourceFamilyID = lastFamilyID;
+			}
+			else if(loopNode.id == targetID){
+				targetFamilyID = lastFamilyID;
+			}
+		}
 		
+		var adja = source.adjacencies;
 		// source node does not exist?
 		if(adja == undefined){
 			Log.write("Error: "+sourceID+" does not exist!");
 			return false;
 		}
 	
-		for(var a=0; a < adja.length; a++){
-			// does the edge exist already?
-			if(adja[a].nodeTo == targetID){
-				Log.write("Error: Edge("+ adja[a].nodeFrom+", "+adja[a].nodeTo+") exists already!" );
-				return false;
-			}
-		}
 		var edge ={
 				  "nodeTo": targetID, 
 				  "nodeFrom": sourceID,
 				  "data": {"$direction" : [ sourceID, targetID ] }
 				  };
 				  
+		adja.push(edge);
+		
 		if(sourceID == mouseNode.id || targetID == mouseNode.id){
 			edge.data.$type = "mouseArrow";
+			return true;
 		}
 		
-		adja.push(edge);
+		// call listener (only if the edge is not connected to the dummy node!)
+		callListener("onCreateEdge", [sourceFamilyID, targetFamilyID, sourceID, targetID]);
+		
 		return true;
 	}
   
@@ -461,13 +609,32 @@ function GraphFlow(){
 	@param source the source Node
 	@param targetID the id of the target Node
 	*/
-  this.removeEdge = function(source, targetID){
-	var adja = source.adjacencies;
+  this.removeEdge = function(sourceID, targetID){
+	var source = getNode(sourceID),
+		adja = source.adjacencies;
 	
 	// nothing to delete?
 	if(adja == undefined){
 		return;
 	}
+	
+	// look up nodeFamily IDs
+	var sourceFamilyID, targetFamilyID, lastFamilyID;
+		for(var n=0; n< json.length; n++){
+			var loopNode = json[n];
+			if(loopNode != undefined){ // <- this happens on Node Deletion
+				if(loopNode.data.$type == "nodeFamily"){
+					lastFamilyID = loopNode.id
+				}
+				else if(loopNode.id == sourceID){
+					sourceFamilyID = lastFamilyID;
+				}
+				else if(loopNode.id == targetID){
+					targetFamilyID = lastFamilyID;
+				}
+			}
+		}
+	
 	for(var a=0; a< adja.length; a++){
 		if(adja[a].nodeTo == targetID){
 			delete adja[a];
@@ -475,6 +642,11 @@ function GraphFlow(){
 			break;
 		}
 	}
+	
+	// call listener
+	if(sourceID != mouseNode.id && targetID != mouseNode.id){
+		callListener("onRemoveEdge", [sourceFamilyID, targetFamilyID, sourceID, targetID]);
+	}
   }
   
   /**
@@ -505,7 +677,7 @@ function GraphFlow(){
 	@param y - y-position of the node
 	*/
   function saveNodePosition(nodeID, x, y){
-	var node =getNodeFromJSON(nodeID);
+	var node = getNode(nodeID);
 	node.data.$xPos = x;
 	node.data.$yPos = y;
   }
@@ -514,9 +686,10 @@ function GraphFlow(){
   returns a jsonNode by id
   @param nodeID the id of the desired node
   */
-  function getNodeFromJSON(nodeID){
+  this.getNode = function(nodeID){
 	for(var n=0; n< json.length; n++){
-		if(json[n].id == nodeID){
+		var node = json[n];
+		if(node != undefined && node.id == nodeID){
 			return json[n];
 		}
 	}
@@ -541,7 +714,16 @@ function GraphFlow(){
 				hover.setData('color', edgeColor, 'end');
 			}
 			else{
-				hover.setData('color', hover.data.$unfocusColor, 'end');
+				var type = hover.data.$type;
+				if(type == "nodeFamily"){
+					hover.setData('color', nodeStrokeColor[hover.data.$nodeType], 'end');
+				}
+				else if(type == "crossBox"){
+					hover.setData('color', nodeStrokeColor[hover.data.$family.data.$nodeType], 'end');
+				}
+				else{
+					hover.setData('color', nodeStrokeColor[type], 'end');
+				}
 			}
 			hover = null;
 		}
@@ -601,7 +783,7 @@ function GraphFlow(){
 		// JSON structure.
 		Node: {
 		  overridable: true,
-		  color: nodeColor,
+		  //color: "#FFFFFF",
 		  CanvasStyles: {  
 			  lineWidth: 2  
 			}  
@@ -616,10 +798,27 @@ function GraphFlow(){
 		},
 		//Native canvas text styling  
 		Label: {  
-			type: "HTML", //Native or HTML  
+			type: 'HTML', //Native or HTML  
 			size: 10,  
 			style: 'bold'  
-		},  
+		}, 
+		//Add Tips  
+		  Tips: {  
+			enable: true,  
+			type: 'Native',
+			onShow: function(tip, node) {  
+			  var message = node.data.$tooltip;
+			  
+			  // do not show a tooltip if it is undefined
+			  if(message == undefined){
+				tip.style.visibility = "hidden";
+			  }
+			  else{
+				tip.innerHTML = "<div class=\"tip-text\">" + message + "</div>";  
+				tip.style.visibility = "visible";
+			  }
+			}  
+		 },  
 		// Add node events
 		Events: {
 		  enable: true,
@@ -630,21 +829,21 @@ function GraphFlow(){
 		   *	EVENT:	OnRightClick
 		   */
 		  onRightClick: function(node, eventInfo, e) {
-			callListener("onRightClick", node, eventInfo, e);
+			callListener("onRightClick", [node, eventInfo, e]);
 		  },
 		  
 		  /**
 		   *	EVENT:	OnDragEnd
 		   */
 		  onDragEnd: function(node, eventInfo, e) {
-			callListener("onDragEnd", node, eventInfo, e);
+			callListener("onDragEnd", [node, eventInfo, e]);
 		  },
 		  
 		  /**
 		   *	EVENT:	OnDragCancel
 		   */
 		  onDragCancel: function(node, eventInfo, e) {
-			callListener("onDragCancel", node, eventInfo, e);
+			callListener("onDragCancel", [node, eventInfo, e]);
 		  },
 		  
 		  /**
@@ -657,7 +856,9 @@ function GraphFlow(){
 			
 			// ignore some highlights if we are dragging an edge
 			if(selectedNode != null && 
-				(node.data.$type != "inputPort" && node.data.$type != "outputPort" )){
+				(node.data.$type != "inputPort" 
+				&& node.data.$type != "outputPort" 
+				&& node.data.$type != "repositoryPort")){
 				return;
 			}
 			
@@ -672,7 +873,7 @@ function GraphFlow(){
 			}else{
 				fd.canvas.getElement().style.cursor = 'pointer';
 			}
-			callListener("onMouseEnter", node, eventInfo, e);
+			callListener("onMouseEnter", [node, eventInfo, e]);
 		  },
 		  
 		  /**
@@ -685,7 +886,7 @@ function GraphFlow(){
 				mouseNode.pos.setc(pos.x, pos.y-2);
 				fd.plot();
 			}
-			callListener("onMouseMove", node, eventInfo, e);
+			callListener("onMouseMove", [node, eventInfo, e]);
 		  },
 		  
 		  /**
@@ -697,7 +898,7 @@ function GraphFlow(){
 			mouseOverEdge = false;
 			
 			setHighlight(null);
-			callListener("onMouseLeave", node, eventInfo, e);
+			callListener("onMouseLeave", [node, eventInfo, e]);
 		  },
 		  
 		  /**
@@ -716,7 +917,7 @@ function GraphFlow(){
 				
 			mouseNode.data.$dragX = nodePos.x - mousePos.x;
 			mouseNode.data.$dragY = nodePos.y - mousePos.y;
-			callListener("onDragStart", node, eventInfo, e);
+			callListener("onDragStart", [node, eventInfo, e]);
 		  },
 		  
 		  /**
@@ -732,7 +933,7 @@ function GraphFlow(){
 			moveNode(node, 
 						   pos.x+mouseNode.data.$dragX,
 							pos.y+mouseNode.data.$dragY);
-			callListener("onDragMove", node, eventInfo, e);
+			callListener("onDragMove", [node, eventInfo, e]);
 			fd.plot();
 			
 		  },
@@ -758,49 +959,37 @@ function GraphFlow(){
 					removeNode(node.data.$family);
 					refresh();
 					break;
+					
 				case "nodeFamily":
 					break;
+					
 				case "outputPort":
+				case "inputPort":
+				case "repositoryPort":
 					// no selection yet
 					if(selectedNode == null){
-						selectedNode = {"id": node.id, "from": "outputPort"};
+						selectedNode = {"id": node.id, "from": node.data.$type};
 						
 						// add edge to mouseNode
-						addEdge(node.id, mouseNode.id);
-						refresh();
-						return;
-					}
-					// click outside the edge drag box
-					else{
-						// add Edge if the selectedNode differs from the clickedNode
-						if(selectedNode.from == "outputPort"){
-							Log.write("Error: Cannot connect two ports of the same type!");
-							break;
+						if(selectedNode.from == "inputPort"){
+							addEdge(mouseNode.id, node.id);
 						}
-						var newEdgeAdded = addEdge(node.id, selectedNode.id);
-						if(newEdgeAdded){
-							refresh();
+						else{
+							addEdge(node.id, mouseNode.id);
 						}
-					}
-					break;
-				case "inputPort":
-					// no selection yet
-					if(selectedNode == null){
-						selectedNode = {"id": node.id, "from": "inputPort"};
-						
-						// add edge to mouseNode
-						addEdge(mouseNode.id, node.id);
 						refresh();
 						return;
 					}
 					// click outside the edge drag box
 					else{
 						// add Edge if the selectedNode differs from the clickedNode
+						var newEdgeAdded;
 						if(selectedNode.from == "inputPort"){
-							Log.write("Error: Cannot connect two ports of the same type!");
-							break;
+							newEdgeAdded = addEdge(node.id, selectedNode.id);
+						}
+						else{
+							newEdgeAdded = addEdge(selectedNode.id, node.id);
 						}
-						var newEdgeAdded = addEdge(selectedNode.id,node.id);
 						if(newEdgeAdded){
 							refresh();
 						}
@@ -814,11 +1003,8 @@ function GraphFlow(){
 				if(selectedNode == null){
 					selectedNode = {"id":node.data.$direction[0], "from":"outputPort"};//nodeTo
 					
-					var selectedNodeJson = getNodeFromJSON(selectedNode.id);
-					
-					Log.write(selectedNode.id+"->"+node.data.$direction[1]);
 					// remove selectedEdge
-					removeEdge(selectedNodeJson, node.data.$direction[1]);
+					removeEdge(selectedNode.id, node.data.$direction[1]);
 					
 					// add edge to mouseNode
 					addEdge(selectedNode.id, mouseNode.id);
@@ -830,23 +1016,22 @@ function GraphFlow(){
 		  // remove selection and mouse-edge upon clicking anywhere
 		  if(selectedNode != null){
 		  
-			if(selectedNode.from == "outputPort"){
-				var selectedNodeJson = getNodeFromJSON(selectedNode.id);
-				removeEdge(selectedNodeJson, mouseNode.id);
+			if(selectedNode.from == "inputPort"){
+				removeEdge(mouseNode.id, selectedNode.id);
 			}else{
-				removeEdge(json[0], selectedNode.id);
+				removeEdge(selectedNode.id, mouseNode.id);
 			}
 			
 			selectedNode = null;
 			refresh();
 		  }
-		  callListener("onClick", node, eventInfo, e);
+		  callListener("onClick", [node, eventInfo, e]);
 		  }
 		},
 		//Number of iterations for the FD algorithm
-		iterations: 200,
+		iterations: 0,
 		//Edge length
-		levelDistance: (longestEdge+2)*vertexLabelSize,
+		levelDistance: 2*vertexLabelSize,
 		// This method is only triggered
 		// on label creation and only for DOM labels (not native canvas ones).
 		onCreateLabel: function(domElement, node){
@@ -864,32 +1049,46 @@ function GraphFlow(){
 			saveNodePosition(node.id, node.pos.x, node.pos.y);
 			
 			domElement.innerHTML = node.name;  
+			
+			// set style for name
 			var style = domElement.style;  
-			/*var nameContainer = document.createElement('span'),
-				  styleName = nameContainer.style;
-				  
-			  nameContainer.className = 'fTitle';
-			  nameContainer.innerHTML = node.name;
-			  setLabelUnselectable(nameContainer);
-			  domElement.appendChild(nameContainer);*/
-			// style for nameContainer
-			style.fontSize = 1.65*vertexLabelSize+"px";
-			style.left = 0.2*vertexLabelSize+"px";
-			style.color = node.data.$color;
-		 
+			style.fontSize = 1.65* fd.canvas.scaleOffsetX* vertexLabelSize+"px";
+			style.left = 0.2*vertexLabelSize-domElement.offsetWidth/2+"px";
+			setLabelUnselectable(domElement);
 		},
 		
 		// Change node styles when DOM labels are placed
 		// or moved.
 		onPlaceLabel: function(domElement, node){
+		  if(node.data.$type != "nodeFamily"){
+			return;
+		  }
+		  
 		  var style = domElement.style;
 		  var left = parseInt(style.left);
 		  var top = parseInt(style.top);
-		  var w = domElement.offsetWidth;
-		  var h = domElement.offsetHeight;
-		  style.left = (left - w / 2) + 'px';
-		  style.top = (top - h / 2) + 'px';
+		  var scale = fd.canvas.scaleOffsetX;
+		  var w = scale*vertexLabelSize* node.name.length;//domElement.offsetWidth;
+		  var h = scale*vertexLabelSize*1.65;//domElement.offsetHeight;
+		  
+		  // TODO: store more calculations inside a nodefamily!
+		  var classWidth =  scale*(vertexLabelSize-2)* (node.data.$nodeClass.length+2);
+		  if(classWidth > w){
+			w = classWidth;
+		  }
+		  
+		  style.fontSize = scale* 1.65 * vertexLabelSize+"px";
+		  style.fontFamily = "Lucida Console";
+		  style.left = (left - w/ 2) + 'px';
+		  style.top = (top - h ) + 'px';
+		  style.color = node.data.$color;
 		  style.display = '';
+		  // add class name
+			if(node.data.$nodeClass != undefined){
+				domElement.innerHTML = node.name;  
+				var fontSize= scale*1.65*(vertexLabelSize-2);
+				domElement.innerHTML += "<div style=\"font-size:"+fontSize+"px\"> &lt"+node.data.$nodeClass+"&gt";
+			}
 		}
 	  });
 	  
@@ -908,15 +1107,59 @@ function GraphFlow(){
 function init(){
 	var addNodeCounter = 0;
 	var graph = GraphFlow();
+	// add a new listener: 
 	graph.addListener("onRightClick", function(node,info,e){
-										graph.addNode(info.getPos().x, info.getPos().y, "lol"+addNodeCounter, ["ip1"], ["op1"]); 
+										var newNode = {"id":"nuNode"+addNodeCounter, 
+														"name":"i am node #"+addNodeCounter, 
+														"nodeClass":"someClassAgain",
+														"tooltip":"i am new and shiny!"};
+										graph.addFilter(info.getPos().x, info.getPos().y, newNode, null,
+													  [{"name":"inputPort","id":"ip1"}], 
+													  [{"name":"outputPort", "id":"op1"}]); 
 										graph.refresh();
 										addNodeCounter++;
 					  });
+					  
+	// adds a listener that removes invalid Edges
+	graph.addEdgeConstraints();
+	
+	graph.addListener("onRemoveNode", function(nodeID){alert("bye bye, "+ nodeID+".");});
 	
-	graph.addNode(0, -100, "superNode1", ["ip1","ip2","ip3","ip4","ip5","ip6"], ["op1"]);
-	graph.addNode(0, 100, "superNode2", ["ip1"], ["op1","op2"]);
+	// define graph by adding nodes
+	var node1 = {"id":"superNode1", 
+					  "name":"i am node", 
+					  "nodeClass":"someClass",
+					  "tooltip":"look at me, i'm a node!"};
+	
+	graph.addFilter(0, -100, node1,[{"name":"repoPort", "id":"rp1", "tooltip":"repo"},
+									{"name":"repoPort", "id":"rp2", "tooltip":"repo"},
+									{"name":"repoPort", "id":"rp3", "tooltip":"repo"}],
+	
+								   [{"name":"inputPort","id":"ip1", "tooltip":"input goes here"}, 
+									{"name":"inputPort","id":"ip2", "tooltip":"input goes here"}, 
+								    {"name":"inputPort","id":"ip3", "tooltip":"input goes here"}, 
+								    {"name":"inputPort","id":"ip4"}, 
+								    {"name":"inputPort","id":"ip5", "tooltip":"input goes here"},
+								    {"name":"inputPort","id":"ip6"}],
+									
+								   [{"name":"outputPort", "id":"op1"}]);
+
+	// create graph
 	graph.initGraph(null);
-	graph.addNode(100, 0, "superNode3", ["ip1"], ["op1","op2"]);
+	
+	// add nodes after graph creation
+	var node2 = {"id":"superNode2", 
+					  "name":"i am node", 
+					  "nodeType":"Filter",
+					  "nodeClass":"someOtherClass",
+					  "tooltip":"look at me, i'm another node!"};
+	graph.addRepository(100, 0, node2,{"name":"outputPort", "id":"op1"});
+	var node3 = {"id":"superNode3", 
+					  "name":"i am reader", 
+					  "nodeType":"Reader",
+					  "nodeClass":"someOtherClass",
+					  "tooltip":"look at me, i'm another node!"};
+	graph.addReader(0, 100, node3,[{"name":"repoPort", "id":"rp1"}], [{"name":"outputPort", "id":"op1"}]);
+	// refresh graph to show the new nodes
 	graph.refresh();
 }
diff --git a/Kieker.WebGUI/src/main/webapp/js/jit.js b/Kieker.WebGUI/src/main/webapp/js/jit.js
index eca35c3efa20c52b391c6aca144349e5b9618f0b..ccb742b49bf747caf95c1e04b80f55a9147d3eec 100644
--- a/Kieker.WebGUI/src/main/webapp/js/jit.js
+++ b/Kieker.WebGUI/src/main/webapp/js/jit.js
@@ -17672,7 +17672,7 @@ $jit.FlowGraph.$extend = true;
 						pe2 = 2*pe,
 						pe4 = 4*pe;
 					
-					ctx.fillStyle = "#FFFFFF";
+					ctx.fillStyle = node.getData('fillColor');
 					
 					ctx.beginPath();
 					ctx.moveTo(bx-pe4, yTop);
@@ -17699,6 +17699,64 @@ $jit.FlowGraph.$extend = true;
 	        }
 	},
 	
+	/**
+		The port is a 2x1 square. The node.pos marks the position of the top-middle of the rectangle.
+	*/
+	'repositoryPort': {
+	    	  'render': function(node, canvas){
+					
+	    	        var pos = node.pos.getc(true), 
+	    	            size = node.getData('dim'),
+						bx = pos.x,
+						by = pos.y,
+	    	            ctx = canvas.getCtx();
+					
+					// draw close-button area
+					this.nodeHelper.rectangle.render('fill', {x: bx, y: by+size/4}, size, size/2, canvas);
+					
+					var grid = size/8,
+						i = by + 2*grid,
+						b = by + grid,
+						h = grid/2,
+						j = h + grid,
+						k = by + 3*grid + h,
+						xh = bx + h,
+						xmh = bx - h;
+						
+					// draw R
+					ctx.fillStyle = "#FFFFFF";
+					ctx.beginPath();
+					ctx.moveTo(bx - j	, by + h);
+					ctx.lineTo(xh		, by + h);
+					ctx.lineTo(bx + j	, b);
+					ctx.lineTo(bx + grid, i);
+					ctx.lineTo(xh		, i);
+					ctx.lineTo(bx + j	, k);
+					ctx.lineTo(xh		, k);
+					ctx.lineTo(xmh		, i);
+					ctx.lineTo(xmh		, k);
+					ctx.lineTo(bx - j	, k);
+					ctx.closePath();
+					ctx.fill();
+					
+					ctx.fillStyle = node.getData('color');
+					ctx.beginPath();
+					ctx.moveTo(xmh	   , b);
+					ctx.lineTo(xh + h/2, b);
+					ctx.lineTo(xh	   , by + j);
+					ctx.lineTo(xmh	   , by + j);
+					ctx.closePath();
+					ctx.fill();
+					
+	    	      },
+	    	      'contains': function(node, pos){
+				  
+	    	        var npos = node.pos.getc(true), 
+	    	            size = node.getData('dim')/2;
+	    	        return Math.abs(pos.x - npos.x) <= size && Math.abs(pos.y - npos.y-size) <= size;
+	        }
+	},
+	
 	/**
 		The port is a 2x1 square. The node.pos marks the position of the top-middle of the rectangle.
 	*/