docs: private JobVertex createSingleInputVertex(SingleInputPlanNode node) throws CompilerException {
  		final String taskName = node.getNodeName();
  		final DriverStrategy ds = node.getDriverStrategy();
  		
  		// check, whether chaining is possible
  		boolean chaining;
  		{
  			Channel inConn = node.getInput();
  			PlanNode pred = inConn.getSource();
  			chaining = ds.getPushChainDriverClass() != null &&
  					!(pred instanceof NAryUnionPlanNode) &&	// first op after union is stand-alone, because union is merged
  					!(pred instanceof BulkPartialSolutionPlanNode) &&	// partial solution merges anyways
  					!(pred instanceof WorksetPlanNode) &&	// workset merges anyways
  					!(pred instanceof IterationPlanNode) && // cannot chain with iteration heads currently
  					inConn.getShipStrategy() == ShipStrategyType.FORWARD &&
  					inConn.getLocalStrategy() == LocalStrategy.NONE &&
  					pred.getOutgoingChannels().size() == 1 &&
  					node.getParallelism() == pred.getParallelism() &&
  					node.getBroadcastInputs().isEmpty();
  			
  			// cannot chain the nodes that produce the next workset or the next solution set, if they are not the
  			// in a tail 
  			if (this.currentIteration instanceof WorksetIterationPlanNode && node.getOutgoingChannels().size() > 0)
  			{
  				WorksetIterationPlanNode wspn = (WorksetIterationPlanNode) this.currentIteration;
  				if (wspn.getSolutionSetDeltaPlanNode() == pred || wspn.getNextWorkSetPlanNode() == pred) {
  					chaining = false;
  				}
  			}
  			// cannot chain the nodes that produce the next workset in a bulk iteration if a termination criterion follows
  			if (this.currentIteration instanceof BulkIterationPlanNode)
  			{
  				BulkIterationPlanNode wspn = (BulkIterationPlanNode) this.currentIteration;
  				if (node == wspn.getRootOfTerminationCriterion() && wspn.getRootOfStepFunction() == pred){
  					chaining = false;
  				}else if(node.getOutgoingChannels().size() > 0 &&(wspn.getRootOfStepFunction() == pred ||
  						wspn.getRootOfTerminationCriterion() == pred)) {
  					chaining = false;
  				}
  			}
  		}
  		
  		final JobVertex vertex;
  		final TaskConfig config;
  		
  		if (chaining) {
  			vertex = null;
  			config = new TaskConfig(new Configuration());
  			this.chainedTasks.put(node, new TaskInChain(node, ds.getPushChainDriverClass(), config, taskName));
  		} else {
  			// create task vertex
  			vertex = new JobVertex(taskName);
  			vertex.setResources(node.getMinResources(), node.getPreferredResources());
  			vertex.setInvokableClass((this.currentIteration != null && node.isOnDynamicPath()) ? IterationIntermediateTask.class : BatchTask.class);
  			
  			config = new TaskConfig(vertex.getConfiguration());
  			config.setDriver(ds.getDriverClass());
  		}
  		
  		// set user code
  		config.setStubWrapper(node.getProgramOperator().getUserCodeWrapper());
  		config.setStubParameters(node.getProgramOperator().getParameters());
  		
  		// set the driver strategy
  		config.setDriverStrategy(ds);
  		for (int i = 0; i < ds.getNumRequiredComparators(); i++) {
  			config.setDriverComparator(node.getComparator(i), i);
  		}
  		// assign memory, file-handles, etc.
  		assignDriverResources(node, config);
  		return vertex;
  	}