diff --git a/src/main/java/org/olat/core/commons/services/taskexecutor/model/PersistentTask.java b/src/main/java/org/olat/core/commons/services/taskexecutor/model/PersistentTask.java
index 602cd1c80e3be6b8a0465890020ea0cb35e93c45..45f8c1bdb842c3c78d1a2acdff5d80512e7ae864 100644
--- a/src/main/java/org/olat/core/commons/services/taskexecutor/model/PersistentTask.java
+++ b/src/main/java/org/olat/core/commons/services/taskexecutor/model/PersistentTask.java
@@ -65,8 +65,8 @@ public class PersistentTask implements Task, CreateInfo, ModifiedInfo, Persistab
 	private static final long serialVersionUID = 800884851125711998L;
 
 	@Id
-  @GeneratedValue(generator = "system-uuid")
-  @GenericGenerator(name = "system-uuid", strategy = "hilo")
+	@GeneratedValue(generator = "system-uuid")
+	@GenericGenerator(name = "system-uuid", strategy = "hilo")
 	@Column(name="id", nullable=false, unique=true, insertable=true, updatable=false)
 	private Long key;
 
@@ -108,7 +108,7 @@ public class PersistentTask implements Task, CreateInfo, ModifiedInfo, Persistab
 	@Column(name="e_executor_boot_id", nullable=true, insertable=true, updatable=true)
 	private String executorBootId;
 	
-	@Column(name="e_task", nullable=false, insertable=true, updatable=false)
+	@Column(name="e_task", nullable=false, insertable=true, updatable=true)
 	private String task;
 
 	@Override
diff --git a/src/main/java/org/olat/course/assessment/bulk/BulkAssessment_2_DatasStep.java b/src/main/java/org/olat/course/assessment/bulk/BulkAssessment_2_DatasStep.java
index 8537bf944398d13daba269df3d62b8360e2b2f62..6f312cdc08deea2b2479b6cea30122a23723b18f 100644
--- a/src/main/java/org/olat/course/assessment/bulk/BulkAssessment_2_DatasStep.java
+++ b/src/main/java/org/olat/course/assessment/bulk/BulkAssessment_2_DatasStep.java
@@ -39,7 +39,7 @@ import org.olat.course.nodes.AssessableCourseNode;
 public class BulkAssessment_2_DatasStep extends BasicStep {
 	
 	private final Task task;
-	private final BulkAssessmentDatas datas;
+	private final BulkAssessmentDatas savedDatas;
 	private final AssessableCourseNode courseNode;
 	private boolean hasPreviousStep = true;
 
@@ -58,13 +58,18 @@ public class BulkAssessment_2_DatasStep extends BasicStep {
 	 * @param datas
 	 */
 	public BulkAssessment_2_DatasStep(UserRequest ureq, AssessableCourseNode courseNode,
-			BulkAssessmentDatas datas, Task task) {
+			BulkAssessmentDatas savedDatas, Task task) {
 		super(ureq);
 		this.task = task;
-		this.datas = datas;
+		this.savedDatas = savedDatas;
 		this.courseNode = courseNode;
 		setI18nTitleAndDescr("data.title", "data.title");
-		setNextStep(new BulkAssessment_3_ValidationStep(ureq));
+		if(savedDatas == null) {
+			setNextStep(new BulkAssessment_2b_ChooseColumnsStep(ureq));
+		} else {
+			setNextStep(new BulkAssessment_2b_ChooseColumnsStep(ureq, savedDatas.getColumnsSettings()));
+		}
+		
 		hasPreviousStep = (courseNode == null ? false : true);
 	}
 
@@ -84,9 +89,8 @@ public class BulkAssessment_2_DatasStep extends BasicStep {
 		}
 		
 		DataStepForm ctrl;
-		if(datas != null) {
-			context.put("datas", datas);
-			ctrl = new DataStepForm(ureq, wControl, courseNode, datas, context, form);
+		if(savedDatas != null) {
+			ctrl = new DataStepForm(ureq, wControl, courseNode, savedDatas, context, form);
 		} else {
 			ctrl = new DataStepForm(ureq, wControl, context, form);
 		}
diff --git a/src/main/java/org/olat/course/assessment/bulk/BulkAssessment_2b_ChooseColumnsStep.java b/src/main/java/org/olat/course/assessment/bulk/BulkAssessment_2b_ChooseColumnsStep.java
new file mode 100644
index 0000000000000000000000000000000000000000..60b37cebabcc1d4c31c1d64956bc85e93871df0d
--- /dev/null
+++ b/src/main/java/org/olat/course/assessment/bulk/BulkAssessment_2b_ChooseColumnsStep.java
@@ -0,0 +1,74 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.course.assessment.bulk;
+
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.form.flexible.impl.Form;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.gui.control.generic.wizard.BasicStep;
+import org.olat.core.gui.control.generic.wizard.PrevNextFinishConfig;
+import org.olat.core.gui.control.generic.wizard.StepFormController;
+import org.olat.core.gui.control.generic.wizard.StepsRunContext;
+import org.olat.course.assessment.model.BulkAssessmentColumnSettings;
+
+/**
+ * 
+ * Initial date: 9.1.2014<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class BulkAssessment_2b_ChooseColumnsStep extends BasicStep {
+	
+	private final BulkAssessmentColumnSettings savedColumnsSettings;
+	
+	/**
+	 * This constructor start the edit the bulk update.
+	 * @param ureq
+	 * @param courseNode
+	 * @param datas
+	 */
+	public BulkAssessment_2b_ChooseColumnsStep(UserRequest ureq) {
+		this(ureq, null);
+	}
+
+	/**
+	 * This constructor start the edit the bulk update.
+	 * @param ureq
+	 * @param courseNode
+	 * @param datas
+	 */
+	public BulkAssessment_2b_ChooseColumnsStep(UserRequest ureq, BulkAssessmentColumnSettings savedColumnsSettings) {
+		super(ureq);
+		this.savedColumnsSettings = savedColumnsSettings;
+		setI18nTitleAndDescr("chooseColumns.title", "chooseColumns.title");
+		setNextStep(new BulkAssessment_3_ValidationStep(ureq));
+	}
+
+	@Override
+	public PrevNextFinishConfig getInitialPrevNextFinishConfig() {
+		return new PrevNextFinishConfig(true, true, false);
+	}
+
+	@Override
+	public StepFormController getStepController(UserRequest ureq, WindowControl wControl, StepsRunContext context, Form form) {
+		ChooseColumnsStepForm ctrl = new ChooseColumnsStepForm(ureq, wControl, savedColumnsSettings, context, form);
+		return ctrl;
+	}
+}
diff --git a/src/main/java/org/olat/course/assessment/bulk/ChooseColumnsStepForm.java b/src/main/java/org/olat/course/assessment/bulk/ChooseColumnsStepForm.java
new file mode 100644
index 0000000000000000000000000000000000000000..97f8251f8dedf0483ecfb461cb0a58f1fcc16c23
--- /dev/null
+++ b/src/main/java/org/olat/course/assessment/bulk/ChooseColumnsStepForm.java
@@ -0,0 +1,316 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.course.assessment.bulk;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.form.flexible.FormItemContainer;
+import org.olat.core.gui.components.form.flexible.elements.SingleSelection;
+import org.olat.core.gui.components.form.flexible.impl.Form;
+import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiColumnModel;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModel;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory;
+import org.olat.core.gui.components.table.DefaultTableDataModel;
+import org.olat.core.gui.control.Controller;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.gui.control.generic.wizard.StepFormBasicController;
+import org.olat.core.gui.control.generic.wizard.StepsEvent;
+import org.olat.core.gui.control.generic.wizard.StepsRunContext;
+import org.olat.core.util.StringHelper;
+import org.olat.course.assessment.model.BulkAssessmentDatas;
+import org.olat.course.assessment.model.BulkAssessmentRow;
+import org.olat.course.assessment.model.BulkAssessmentColumnSettings;
+import org.olat.course.assessment.model.BulkAssessmentSettings;
+import org.olat.course.nodes.AssessableCourseNode;
+
+/**
+ * 
+ * Initial date: 9.1.2014<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class ChooseColumnsStepForm extends StepFormBasicController {
+
+	private int numOfColumns;
+	private SingleSelection userNameColumnEl, scoreColumnEl, passedColumnEl, commentColumnEl;
+	private final OverviewDataModel overviewDataModel;
+	private final BulkAssessmentColumnSettings columnsSettings;
+
+	public ChooseColumnsStepForm(UserRequest ureq, WindowControl wControl, BulkAssessmentColumnSettings columnsSettings,
+			StepsRunContext runContext, Form rootForm) {
+		super(ureq, wControl, rootForm, runContext, LAYOUT_VERTICAL, null);
+		setTranslator(new HeaderColumnTranslator(getTranslator()));
+		this.columnsSettings = columnsSettings;
+		
+		@SuppressWarnings("unchecked")
+		List<String[]> splittedRows = (List<String[]>)getFromRunContext("splittedRows");
+		if(splittedRows.size() > 0) {
+			numOfColumns = splittedRows.get(0).length;
+		}
+
+		overviewDataModel = new OverviewDataModel(splittedRows);
+		initForm(ureq);
+	}
+	
+	@Override
+	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		setFormTitle("chooseColumns.title");
+		setFormDescription("chooseColumns.description");
+
+		AssessableCourseNode courseNode = (AssessableCourseNode)getFromRunContext("courseNode");
+		BulkAssessmentSettings settings = new BulkAssessmentSettings(courseNode);
+
+		String[] theKeys = new String[numOfColumns];
+		String[] theValues = new String[numOfColumns];
+		for(int i=0; i<numOfColumns; i++) {
+			theKeys[i] = "col" + i;
+			theValues[i] = translate("column",  Integer.toString(i + 1));
+		}
+		
+		FormLayoutContainer choosersCont = FormLayoutContainer.createDefaultFormLayout("choosers", getTranslator());
+		choosersCont.setRootForm(mainForm);
+		formLayout.add(choosersCont);
+
+		int pos = 0;
+		userNameColumnEl = uifactory.addDropdownSingleselect("table.header.identifier", choosersCont, theKeys, theValues, null);
+		if(columnsSettings != null && columnsSettings.getUsernameColumn() < theKeys.length) {
+			userNameColumnEl.select(getSelectedKey(pos++, columnsSettings.getUsernameColumn(), theKeys), true);
+		} else {
+			userNameColumnEl.select(theKeys[pos++], true);
+		}
+		if(settings.isHasScore()) {
+			scoreColumnEl = uifactory.addDropdownSingleselect("table.header.score", choosersCont, theKeys, theValues, null);
+			if(columnsSettings != null && columnsSettings.getScoreColumn() < theKeys.length) {
+				scoreColumnEl.select(getSelectedKey(pos++, columnsSettings.getScoreColumn(), theKeys), true);
+			} else {
+				scoreColumnEl.select(theKeys[pos++], true);
+			}
+		}
+		if(settings.isHasPassed() && settings.getCut() == null) {
+			passedColumnEl = uifactory.addDropdownSingleselect("table.header.passed", choosersCont, theKeys, theValues, null);
+			if(columnsSettings != null && columnsSettings.getPassedColumn() < theKeys.length) {
+				passedColumnEl.select(getSelectedKey(pos++, columnsSettings.getPassedColumn(), theKeys), true);
+			} else {
+				passedColumnEl.select(theKeys[pos++], true);
+			}
+		}
+		if(settings.isHasUserComment()) {
+			commentColumnEl = uifactory.addDropdownSingleselect("table.header.comment", choosersCont, theKeys, theValues, null);
+			if(columnsSettings != null && columnsSettings.getCommentColumn() < theKeys.length) {
+				commentColumnEl.select(getSelectedKey(pos++, columnsSettings.getCommentColumn(), theKeys), true);
+			} else {
+				commentColumnEl.select(theKeys[pos++], true);
+			}
+		}
+
+		FlexiTableColumnModel tableColumnModel = FlexiTableDataModelFactory.createFlexiTableColumnModel();
+		for(int i=0; i<numOfColumns; i++) {
+			DefaultFlexiColumnModel colModel = new DefaultFlexiColumnModel("ccc" + (i+1), i);
+			tableColumnModel.addFlexiColumnModel(colModel);
+		}
+		
+		overviewDataModel.setTableColumnModel(tableColumnModel);
+		uifactory.addTableElement(ureq, getWindowControl(), "overviewList", overviewDataModel, formLayout);
+	}
+	
+	private String getSelectedKey(int pos, int settings, String[] theKeys) {
+		int selectionPos = pos;
+		if(settings >= 0 && settings < theKeys.length) {
+			selectionPos = settings;
+		}
+		return theKeys[selectionPos];
+	}
+
+	@Override
+	protected void doDispose() {
+		//
+	}
+
+	@Override
+	protected void formOK(UserRequest ureq) {
+		BulkAssessmentDatas datas = (BulkAssessmentDatas)getFromRunContext("datas");
+		List<BulkAssessmentRow> rows = datas.getRows();
+		Map<String, BulkAssessmentRow> assessedIdToRow = new HashMap<>();
+		for(BulkAssessmentRow row:rows) {
+			assessedIdToRow.put(row.getAssessedId(), row);
+		}
+		
+		BulkAssessmentColumnSettings settings = datas.getColumnsSettings();
+		if(settings == null) {
+			settings = new BulkAssessmentColumnSettings();
+			datas.setColumnsSettings(settings);
+		}
+		settings.setUsernameColumn(getColumnPosition(userNameColumnEl));
+		settings.setScoreColumn(getColumnPosition(scoreColumnEl));
+		settings.setPassedColumn(getColumnPosition(passedColumnEl));
+		settings.setCommentColumn(getColumnPosition(commentColumnEl));
+
+		List<String[]> splittedRows = overviewDataModel.getObjects();
+		for(String[] values:splittedRows) {
+			createRow(values, settings, rows, assessedIdToRow);
+		}
+
+		fireEvent(ureq, StepsEvent.ACTIVATE_NEXT);
+	}
+	
+	private int getColumnPosition(SingleSelection el) {
+		if(el == null) return 9999;
+		String selectedKey = el.getSelectedKey();
+		if(selectedKey == null || selectedKey.length() < 4) return 9999;
+		String pos = selectedKey.substring(3);
+		if(StringHelper.isLong(pos)) {
+			return Integer.parseInt(pos);
+		}
+		return 9999;
+	}
+	
+	
+	/**
+	 * Create a row object from an array of strings. The array
+	 * is assessed identity identifier, score, status, comment.
+	 * @param values
+	 * @return
+	 */
+	private void createRow(String[] values, BulkAssessmentColumnSettings settings,
+			List<BulkAssessmentRow> rows, Map<String, BulkAssessmentRow> assessedIdToRow) {
+		int valuesLength = values.length;
+		if(valuesLength <= 0 || valuesLength <= settings.getUsernameColumn()) {
+			return;
+		}
+
+		String identifyer = values[settings.getUsernameColumn()];
+		identifyer.trim();
+		if (!StringHelper.containsNonWhitespace(identifyer)) {
+			identifyer = "-";
+		}
+
+		BulkAssessmentRow row;
+		if(assessedIdToRow.containsKey(identifyer)) {
+			row = assessedIdToRow.get(identifyer);
+		} else {
+			row = new BulkAssessmentRow();
+			row.setAssessedId(identifyer);
+			rows.add(row);
+		}
+
+		if(valuesLength > settings.getScoreColumn()) {
+			String scoreStr = values[settings.getScoreColumn()];
+			scoreStr= scoreStr.trim();
+			Float score;
+			if (StringHelper.containsNonWhitespace(scoreStr)) {
+				try {
+					// accept writing with , or .
+					score = Float.parseFloat(scoreStr.replace(',', '.'));
+				} catch (NumberFormatException e) {
+					score = null;
+				}
+			} else {
+				// only set new numbers, ignore everything else
+				score = null;
+			}
+			row.setScore(score);
+		}
+
+		if(valuesLength > settings.getPassedColumn()) {
+			String passedStr = values[settings.getPassedColumn()];
+			passedStr= passedStr.trim();
+			Boolean passed;
+			if ("y".equalsIgnoreCase(passedStr)
+					|| "yes".equalsIgnoreCase(passedStr)
+					|| "passed".equalsIgnoreCase(passedStr)
+					|| "true".equalsIgnoreCase(passedStr)
+					|| "1".equalsIgnoreCase(passedStr)) {
+				passed = Boolean.TRUE;
+			} else if ("n".equalsIgnoreCase(passedStr)
+					|| "no".equalsIgnoreCase(passedStr)
+					|| "false".equalsIgnoreCase(passedStr)
+					|| "failed".equalsIgnoreCase(passedStr)
+					|| "0".equalsIgnoreCase(passedStr)) {
+				passed = Boolean.FALSE;
+			} else {
+				// only set defined values, ignore everything else
+				passed = null;
+			}
+			row.setPassed(passed);
+		}
+		
+		if(valuesLength > settings.getCommentColumn()) {
+			String commentStr = values[settings.getCommentColumn()];
+			// add any additional comment which probably is just a comma in a escaped string
+			if (valuesLength > 4) {
+				for (int i = 4; i < valuesLength; i++) {
+					commentStr += "," + values[i];					
+				}				
+			}			
+			commentStr= commentStr.trim();
+			
+			if(commentStr.isEmpty()) {
+				// ignore empty values
+				row.setComment(null);
+			} else if("\"\"".equals(commentStr) || "''".equals(commentStr)) {
+				row.setComment("");
+			} else {
+				row.setComment(commentStr);
+			} 
+		}
+	}
+	
+	private static class OverviewDataModel extends DefaultTableDataModel<String[]> implements FlexiTableDataModel<String[]> {
+		private FlexiTableColumnModel columnModel;
+		
+		public OverviewDataModel(List<String[]> nodes) {
+			super(nodes);
+		}
+
+		@Override
+		public FlexiTableColumnModel getTableColumnModel() {
+			return columnModel;
+		}
+
+		@Override
+		public int getRowCount() {
+			return Math.min(3, super.getRowCount());
+		}
+
+		@Override
+		public void setTableColumnModel(FlexiTableColumnModel tableColumnModel) {
+			this.columnModel = tableColumnModel;
+		}
+
+		@Override
+		public int getColumnCount() {
+			return columnModel.getColumnCount();
+		}
+
+		@Override
+		public Object getValueAt(int row, int col) {
+			String[] data = getObject(row);
+			if(data != null && col >= 0 && col < data.length) {
+				return data[col];
+			}
+			return null;
+		}
+	}
+}
diff --git a/src/main/java/org/olat/course/assessment/bulk/DataStepForm.java b/src/main/java/org/olat/course/assessment/bulk/DataStepForm.java
index a4cd38c02c4fed5e1c9c2b5023454e3d825f52ca..206d695692f3376e01e6eff4d466d0fe91e4891f 100644
--- a/src/main/java/org/olat/course/assessment/bulk/DataStepForm.java
+++ b/src/main/java/org/olat/course/assessment/bulk/DataStepForm.java
@@ -77,7 +77,8 @@ public class DataStepForm extends StepFormBasicController {
 	private FileElement returnFileEl;
 	private SingleSelection delimiter;
 
-	private BulkAssessmentDatas datas;
+	private OlatRootFileImpl targetArchive;
+	private BulkAssessmentDatas savedDatas;
 	private final AssessableCourseNode courseNode;
 	private OlatRootFolderImpl bulkAssessmentTmpDir;
 	
@@ -89,11 +90,11 @@ public class DataStepForm extends StepFormBasicController {
 		initForm(ureq);
 	}
 	
-	public DataStepForm(UserRequest ureq, WindowControl wControl, AssessableCourseNode courseNode, BulkAssessmentDatas datas, 
+	public DataStepForm(UserRequest ureq, WindowControl wControl, AssessableCourseNode courseNode, BulkAssessmentDatas savedDatas, 
 			StepsRunContext runContext, Form rootForm) {
 		super(ureq, wControl, rootForm, runContext, LAYOUT_VERTICAL, null);
 		
-		this.datas = datas;
+		this.savedDatas = savedDatas;
 		this.courseNode = courseNode;
 		addToRunContext("courseNode", courseNode);
 		initForm(ureq);
@@ -112,8 +113,8 @@ public class DataStepForm extends StepFormBasicController {
 		setFormContextHelp("org.olat.course.assessment.bulk", "bulkassessment_data.html","help.hover.bulkassessment_data");
 		
 		String dataVal = "";
-		if(datas != null && StringHelper.containsNonWhitespace(datas.getDataBackupFile())) {
-			OlatRootFileImpl file = new OlatRootFileImpl(datas.getDataBackupFile(), null);
+		if(savedDatas != null && StringHelper.containsNonWhitespace(savedDatas.getDataBackupFile())) {
+			OlatRootFileImpl file = new OlatRootFileImpl(savedDatas.getDataBackupFile(), null);
 			InputStream in = file.getInputStream();
 			try {
 				dataVal = IOUtils.toString(in);
@@ -150,8 +151,8 @@ public class DataStepForm extends StepFormBasicController {
 			Set<String> mimes = new HashSet<String>();
 			mimes.add(WebappHelper.getMimeType("file.zip"));
 			returnFileEl.limitToMimeType(mimes, "return.mime", null);
-			if(datas != null && StringHelper.containsNonWhitespace(datas.getReturnFiles())) {
-				targetArchive = new OlatRootFileImpl(datas.getReturnFiles(), null);
+			if(savedDatas != null && StringHelper.containsNonWhitespace(savedDatas.getReturnFiles())) {
+				targetArchive = new OlatRootFileImpl(savedDatas.getReturnFiles(), null);
 				if(targetArchive.exists()) {
 					returnFileEl.setInitialFile(targetArchive.getBasefile());
 				}
@@ -173,7 +174,10 @@ public class DataStepForm extends StepFormBasicController {
 			return;
 		}
 		setFormWarning(null); // reset error
-		BulkAssessmentDatas datas = new BulkAssessmentDatas();
+		BulkAssessmentDatas datas = (BulkAssessmentDatas)getFromRunContext("datas");
+		if(datas == null) {
+			datas = new BulkAssessmentDatas();
+		}
 		
 		if(bulkAssessmentTmpDir == null) {
 			OlatRootFolderImpl bulkAssessmentDir = new OlatRootFolderImpl("/bulkassessment/", null);
@@ -181,7 +185,9 @@ public class DataStepForm extends StepFormBasicController {
 		}
 
 		backupInputDatas(val, datas, bulkAssessmentTmpDir);
-		List<BulkAssessmentRow> rows = processInputData(val);
+		List<String[]> splittedRows = splitRawData(val);
+		addToRunContext("splittedRows", splittedRows);
+		List<BulkAssessmentRow> rows = new ArrayList<>(100);
 		if(returnFileEl != null) {
 			processReturnFiles(datas, rows, bulkAssessmentTmpDir);
 		}
@@ -190,14 +196,43 @@ public class DataStepForm extends StepFormBasicController {
 		fireEvent(ureq, StepsEvent.ACTIVATE_NEXT);
 	}
 	
+	private List<String[]> splitRawData(String idata) {
+		String[] lines = idata.split("\r?\n");
+		int numOfLines = lines.length;
+		
+		List<String[]> rows = new ArrayList<String[]>(numOfLines);
+		
+		String d;
+		if (delimiter.getSelectedKey().startsWith("t")) {
+			d = "\t";
+		} else {
+			d = ",";
+		}
+		
+		for (int i = 0; i < numOfLines; i++) {
+			String line = lines[i];
+			if(StringHelper.containsNonWhitespace(line)){
+				String[] values = line.split(d,-1);
+				rows.add(values);
+			}
+		}
+		return rows;
+	}
+	
 	/**
 	 * Backup the input field for later editing purpose
 	 * @param val
 	 * @param datas
 	 */
 	private void backupInputDatas(String val, BulkAssessmentDatas datas, OlatRootFolderImpl tmpDir) {
-		String inputFilename = UUID.randomUUID().toString() + ".csv";
-		OlatRootFileImpl inputFile = tmpDir.createChildLeaf(inputFilename);
+		OlatRootFileImpl inputFile = null;
+		if(StringHelper.containsNonWhitespace(datas.getDataBackupFile())) {
+			inputFile = new OlatRootFileImpl(datas.getDataBackupFile(), null);
+		}
+		if(inputFile == null) {
+			String inputFilename = UUID.randomUUID().toString() + ".csv";
+			inputFile = tmpDir.createChildLeaf(inputFilename);
+		}
 		OutputStream out = inputFile.getOutputStream(false);
 		
 		try {
@@ -210,8 +245,6 @@ public class DataStepForm extends StepFormBasicController {
 		}
 	}
 	
-	private OlatRootFileImpl targetArchive;
-	
 	private void processReturnFiles(BulkAssessmentDatas datas, List<BulkAssessmentRow> rows, OlatRootFolderImpl tmpDir) {
 		File uploadedFile = returnFileEl.getUploadFile();
 		if(uploadedFile == null) {
@@ -317,115 +350,4 @@ public class DataStepForm extends StepFormBasicController {
 			}
 		}
 	}
-	
-	private List<BulkAssessmentRow> processInputData(String idata) {
-		String[] lines = idata.split("\r?\n");
-		int numOfLines = lines.length;
-		
-		List<BulkAssessmentRow> rows = new ArrayList<BulkAssessmentRow>(numOfLines);
-		
-		String d;
-		if (delimiter.getSelectedKey().startsWith("t")) {
-			d = "\t";
-		} else {
-			d = ",";
-		}
-		
-		for (int i = 0; i < numOfLines; i++) {
-			String line = lines[i];
-
-			if(StringHelper.containsNonWhitespace(line)){
-				String[] values = line.split(d,-1);
-				BulkAssessmentRow row = createRow(values);
-				if(row != null) {
-					rows.add(row);
-				}
-			}
-		}
-		return rows;
-	}
-	
-	/**
-	 * Create a row object from an array of strings. The array
-	 * is assessed identity identifier, score, status, comment.
-	 * @param values
-	 * @return
-	 */
-	private BulkAssessmentRow createRow(String[] values) {
-		int valuesLength = values.length;
-		if(valuesLength <= 0) {
-			return null;
-		}
-
-		BulkAssessmentRow row = new BulkAssessmentRow();
-		String identifyer = values[0];
-		identifyer.trim();
-		if (!StringHelper.containsNonWhitespace(identifyer)) {
-			identifyer = "-";
-		}
-		row.setAssessedId(identifyer);
-
-		if(valuesLength > 1) {
-			String scoreStr = values[1];
-			scoreStr= scoreStr.trim();
-			Float score;
-			if (StringHelper.containsNonWhitespace(scoreStr)) {
-				try {
-					// accept writing with , or .
-					score = Float.parseFloat(scoreStr.replace(',', '.'));
-				} catch (NumberFormatException e) {
-					score = null;
-				}
-			} else {
-				// only set new numbers, ignore everything else
-				score = null;
-			}
-			row.setScore(score);
-		}
-
-		if(valuesLength > 2) {
-			String passedStr = values[2];
-			passedStr= passedStr.trim();
-			Boolean passed;
-			if ("y".equalsIgnoreCase(passedStr)
-					|| "yes".equalsIgnoreCase(passedStr)
-					|| "passed".equalsIgnoreCase(passedStr)
-					|| "true".equalsIgnoreCase(passedStr)
-					|| "1".equalsIgnoreCase(passedStr)) {
-				passed = Boolean.TRUE;
-			} else if ("n".equalsIgnoreCase(passedStr)
-					|| "no".equalsIgnoreCase(passedStr)
-					|| "false".equalsIgnoreCase(passedStr)
-					|| "failed".equalsIgnoreCase(passedStr)
-					|| "0".equalsIgnoreCase(passedStr)) {
-				passed = Boolean.FALSE;
-			} else {
-				// only set defined values, ignore everything else
-				passed = null;
-			}
-			row.setPassed(passed);
-		}
-		
-		if(valuesLength > 3) {
-			String commentStr = values[3];
-			// add any additional comment which probably is just a comma in a escaped string
-			if (valuesLength > 4) {
-				for (int i = 4; i < valuesLength; i++) {
-					commentStr += "," + values[i];					
-				}				
-			}			
-			commentStr= commentStr.trim();
-			
-			if(commentStr.isEmpty()) {
-				// ignore empty values
-				row.setComment(null);
-			} else if("\"\"".equals(commentStr) || "''".equals(commentStr)) {
-				row.setComment("");
-			} else {
-				row.setComment(commentStr);
-			} 
-		}
-		
-		return row;
-	}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/course/assessment/bulk/HeaderColumnTranslator.java b/src/main/java/org/olat/course/assessment/bulk/HeaderColumnTranslator.java
new file mode 100644
index 0000000000000000000000000000000000000000..e703eb3e820f84dfc1b6926f6c216193ed1c8354
--- /dev/null
+++ b/src/main/java/org/olat/course/assessment/bulk/HeaderColumnTranslator.java
@@ -0,0 +1,89 @@
+/**
+* OLAT - Online Learning and Training<br>
+* http://www.olat.org
+* <p>
+* Licensed under the Apache License, Version 2.0 (the "License"); <br>
+* you may not use this file except in compliance with the License.<br>
+* You may obtain a copy of the License at
+* <p>
+* http://www.apache.org/licenses/LICENSE-2.0
+* <p>
+* Unless required by applicable law or agreed to in writing,<br>
+* software distributed under the License is distributed on an "AS IS" BASIS, <br>
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+* See the License for the specific language governing permissions and <br>
+* limitations under the License.
+* <p>
+* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br>
+* University of Zurich, Switzerland.
+* <hr>
+* <a href="http://www.openolat.org">
+* OpenOLAT - Online Learning and Training</a><br>
+* This file has been modified by the OpenOLAT community. Changes are licensed
+* under the Apache 2.0 license as the original file.  
+* <p>
+*/ 
+
+package org.olat.course.assessment.bulk;
+
+import java.util.Locale;
+
+import org.apache.log4j.Level;
+import org.olat.core.gui.translator.Translator;
+/**
+ * 
+ * Description:<br>
+ * Proxy for the column numbering
+ * 
+ * <P>
+ * Initial Date:  19.12.2005 <br>
+ *
+ * @author Alexander Schneider
+ */
+public class HeaderColumnTranslator implements Translator {
+	private Translator origTranslator;
+	
+	public HeaderColumnTranslator(Translator origTranslator){
+		this.origTranslator = origTranslator;
+	}
+
+	public String translate(String key) {
+		return translate(key, null);
+	}
+
+	@Override
+	public String translate(String key, String[] args) {
+		return translate(key, args, Level.WARN);
+	}
+	
+	@Override
+	public String translate(String key, String[] args, Level missingTranslationLogLevel) {
+		String val;
+		if(key.startsWith("ccc")){
+			String t = key.substring(3);
+			val = origTranslator.translate("column", new String[]{t});
+		}else if (key.startsWith("hhh")){
+			val = key.substring(3);
+		}else{
+			val = origTranslator.translate(key, args, missingTranslationLogLevel);
+		}
+		return val;
+	}
+	
+	/**
+	 * @see org.olat.core.gui.translator.Translator#translate(java.lang.String,
+	 *      java.lang.String[], boolean)
+	 */
+	public String translate(String key, String[] args, boolean fallBackToDefaultLocale) {
+		// no fall back to default locale
+		return translate(key, args);
+	}
+
+	public Locale getLocale() {
+		return origTranslator.getLocale();
+	}
+
+	public void setLocale(Locale locale) {
+		origTranslator.setLocale(locale);
+	}
+}
diff --git a/src/main/java/org/olat/course/assessment/bulk/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/assessment/bulk/_i18n/LocalStrings_de.properties
index 601a82cf4afd23a52734ab2585aaedd77e7ddd32..3902d0de67d697743d2934faaeacc8edb9b2f839 100644
--- a/src/main/java/org/olat/course/assessment/bulk/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/course/assessment/bulk/_i18n/LocalStrings_de.properties
@@ -64,6 +64,9 @@ chelp.bulkassessment_schedule.intro=Eine Massenbewertung kann entweder sofort od
 chelp.bulkassessment_schedule.title=Massenbewertung\: Planung
 choose.node.desc=W\u00E4hlen Sie einen bewertbaren Baustein aus diesem Kurs f\u00FCr den eine Massenbewertung durchgef\u00FChrt werden soll. 
 choose.node.title=Kursbaustein ausw\u00E4hlen
+column=Spalte {0}
+chooseColumns.title=Bestimmen der zu interpretierenden Spalte
+chooseColumns.description=W\u00E4hlen Sie aus, welche Spalte OLAT als was interpretieren soll.
 confirmation.mail.body=Ihre Massenbewertung des Kursbausteins {1} im Kurs {0} wurde wie geplant f\u00FCr {3} Benutzer am {4} ausgef\u00FChrt.\n\n{2}
 confirmation.mail.subject=Geplante Massenbewertung {0} {1} ausgef\u00FChrt
 data=Daten
diff --git a/src/main/java/org/olat/course/assessment/model/BulkAssessmentColumnSettings.java b/src/main/java/org/olat/course/assessment/model/BulkAssessmentColumnSettings.java
new file mode 100644
index 0000000000000000000000000000000000000000..cd106d7695751b1fb80c045dde5e13b605aeb724
--- /dev/null
+++ b/src/main/java/org/olat/course/assessment/model/BulkAssessmentColumnSettings.java
@@ -0,0 +1,70 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.course.assessment.model;
+
+import java.io.Serializable;
+
+/**
+ * 
+ * Initial date: 09.01.2014<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class BulkAssessmentColumnSettings implements Serializable {
+
+	private static final long serialVersionUID = -8726013806107035722L;
+	
+	private int usernameColumn;
+	private int scoreColumn;
+	private int passedColumn;
+	private int commentColumn;
+	
+	public int getUsernameColumn() {
+		return usernameColumn;
+	}
+	
+	public void setUsernameColumn(int usernameColumn) {
+		this.usernameColumn = usernameColumn;
+	}
+	
+	public int getScoreColumn() {
+		return scoreColumn;
+	}
+	
+	public void setScoreColumn(int scoreColumn) {
+		this.scoreColumn = scoreColumn;
+	}
+	
+	public int getPassedColumn() {
+		return passedColumn;
+	}
+	
+	public void setPassedColumn(int passedColumn) {
+		this.passedColumn = passedColumn;
+	}
+	
+	public int getCommentColumn() {
+		return commentColumn;
+	}
+	
+	public void setCommentColumn(int commentColumn) {
+		this.commentColumn = commentColumn;
+	}
+}
diff --git a/src/main/java/org/olat/course/assessment/model/BulkAssessmentDatas.java b/src/main/java/org/olat/course/assessment/model/BulkAssessmentDatas.java
index d2e07fa6ed48d3529f83195dfb07634be634706f..d0225276893cd89db58f00e3f8a8443cb71b274d 100644
--- a/src/main/java/org/olat/course/assessment/model/BulkAssessmentDatas.java
+++ b/src/main/java/org/olat/course/assessment/model/BulkAssessmentDatas.java
@@ -34,6 +34,15 @@ public class BulkAssessmentDatas implements Serializable {
 	private List<BulkAssessmentRow> rows;
 	private String returnFiles;
 	private String dataBackupFile;
+	private BulkAssessmentColumnSettings columnsSettings;
+
+	public BulkAssessmentColumnSettings getColumnsSettings() {
+		return columnsSettings;
+	}
+
+	public void setColumnsSettings(BulkAssessmentColumnSettings columnsSettings) {
+		this.columnsSettings = columnsSettings;
+	}
 
 	public int getRowsSize() {
 		return rows == null ? 0 : rows.size();
diff --git a/src/test/java/org/olat/core/commons/services/taskexecutor/PersistentTaskDAOTest.java b/src/test/java/org/olat/core/commons/services/taskexecutor/PersistentTaskDAOTest.java
index 6b0c4ab8e316b8a6e8ffdb2303c40937448c5b97..bcabb8960fdabb45db29e5cc5882f6f1f61fba03 100644
--- a/src/test/java/org/olat/core/commons/services/taskexecutor/PersistentTaskDAOTest.java
+++ b/src/test/java/org/olat/core/commons/services/taskexecutor/PersistentTaskDAOTest.java
@@ -33,6 +33,8 @@ import org.olat.core.commons.persistence.DB;
 import org.olat.core.commons.services.taskexecutor.manager.PersistentTaskDAO;
 import org.olat.core.commons.services.taskexecutor.model.PersistentTask;
 import org.olat.core.id.Identity;
+import org.olat.core.logging.OLog;
+import org.olat.core.logging.Tracing;
 import org.olat.core.util.WebappHelper;
 import org.olat.core.util.xml.XStreamHelper;
 import org.olat.repository.RepositoryEntry;
@@ -48,12 +50,13 @@ import org.springframework.beans.factory.annotation.Autowired;
  */
 public class PersistentTaskDAOTest extends OlatTestCase  {
 	
+	private static final OLog log = Tracing.createLoggerFor(PersistentTaskDAOTest.class);
+	
 	@Autowired
 	private DB dbInstance;
 	@Autowired
 	private PersistentTaskDAO persistentTaskDao;
 	
-	
 	@Test
 	public void createTask() {
 		String name = "Task 0";
@@ -118,6 +121,30 @@ public class PersistentTaskDAOTest extends OlatTestCase  {
 		Assert.assertEquals(TaskStatus.inWork, todo.getStatus());
 	}
 	
+	@Test
+	public void updateTask() {
+		//create
+		String name = "Task to update";
+		PersistentTask task = persistentTaskDao.createTask(name, new DummyTask());
+		dbInstance.commitAndCloseSession();
+		
+		//update
+		PersistentTask todo = persistentTaskDao.pickTaskForRun(task.getKey());
+		DummyTask taskToUpdate = new DummyTask();
+		taskToUpdate.setMarkerValue("new marker");
+		persistentTaskDao.updateTask(todo, taskToUpdate, null, null);
+		dbInstance.commitAndCloseSession();
+		
+		//reload and check
+		PersistentTask loadedTask = persistentTaskDao.loadTaskById(task.getKey());
+		Runnable runnable = persistentTaskDao.deserializeTask(loadedTask);
+
+		Assert.assertNotNull(runnable);
+		Assert.assertTrue(runnable instanceof DummyTask);
+		DummyTask dummyRunnable = (DummyTask)runnable;
+		Assert.assertEquals("new marker", dummyRunnable.getMarkerValue());
+	}
+	
 	@Test
 	public void todo() {
 		String name = UUID.randomUUID().toString();
@@ -471,10 +498,26 @@ public class PersistentTaskDAOTest extends OlatTestCase  {
 	
 	public static class DummyTask implements Runnable, Serializable {
 		private static final long serialVersionUID = 5193785402425324970L;
+		
+		private String markerValue;
+		
+		public DummyTask() {
+			this.markerValue = UUID.randomUUID().toString();
+		}
+
+		public String getMarkerValue() {
+			return markerValue;
+		}
+
+		public void setMarkerValue(String markerValue) {
+			this.markerValue = markerValue;
+		}
+
+
 
 		@Override
 		public void run() {
-			//
+			log.info("Run: " + markerValue);
 		}
 	}
 }