diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..57bc88a15a0ee8266c259b2667e64608d3f7e292
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,202 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
diff --git a/README.md b/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/benchmark-collector/src/it4i/fiji/benchmark_extractor/Extractor.java b/benchmark-collector/src/it4i/fiji/benchmark_extractor/Extractor.java
index 2354ccec7a66c5a046427ce058ff326c350d9d96..55c3c4739c4c5ad4d15cfae8a5c3d08b5d43c2bb 100644
--- a/benchmark-collector/src/it4i/fiji/benchmark_extractor/Extractor.java
+++ b/benchmark-collector/src/it4i/fiji/benchmark_extractor/Extractor.java
@@ -7,8 +7,6 @@ import java.io.PrintWriter;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.time.Duration;
-import java.time.LocalTime;
-import java.time.format.DateTimeFormatter;
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
@@ -29,7 +27,8 @@ public class Extractor {
 
 	private Map<String, String> valueWithTypes;
 
-	public Extractor(Path inputFile, Set<String> valuesToExport, Map<String, String> valuesWithTypes, OutputStream out) {
+	public Extractor(Path inputFile, Set<String> valuesToExport, Map<String, String> valuesWithTypes,
+			OutputStream out) {
 		this.inputFile = inputFile;
 		this.valuesToExport = valuesToExport;
 		this.valueWithTypes = valuesWithTypes;
@@ -61,7 +60,7 @@ public class Extractor {
 					}
 				}
 			}
-			if(valueCollector != null) {
+			if (valueCollector != null) {
 				write(pw, collector, valueCollector);
 			}
 		} catch (IOException e) {
@@ -102,12 +101,12 @@ public class Extractor {
 			out.printf("jobs #;%d\n", ids.size());
 			out.printf("job ids;%s\n", String.join(";", ids));
 			for (String key : valuesToExport) {
-				out.printf("%s;%s\n", key, String.join(";", convert(key,values4Job.get(key))));
+				out.printf("%s;%s\n", key, String.join(";", convert(key, values4Job.get(key))));
 			}
 		}
 
 		private List<String> convert(String key, List<String> list) {
-			if(!valueWithTypes.containsKey(key)) {
+			if (!valueWithTypes.containsKey(key)) {
 				return list;
 			}
 			Function<String, String> conversion = getConversion(valueWithTypes.get(key));
@@ -122,7 +121,13 @@ public class Extractor {
 				//return str->nf.format(Double.parseDouble(str.replace("kb", ""))/1024.);
 				return str -> "" + Double.parseDouble(str.replace("kb", ""))/1024.;
 			case "tm":
-				return str-> Duration.between(LocalTime.of(0, 0, 0), LocalTime.parse(str, DateTimeFormatter.ofPattern("H:m:s"))).getSeconds() + "";
+				
+				return str->  {
+					String []tokens = str.split(":");
+					return Duration.ofHours(Integer.parseInt(tokens[0]))
+							       .plusMinutes(Integer.parseInt(tokens[1]))
+							       .plusSeconds(Integer.parseInt(tokens[2])).getSeconds() + "";
+				};
 			}
 			
 			return str->str;
diff --git a/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/Job.java b/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/Job.java
index 555b1742666d9791de536e8219ca6154c3808a30..41c3b33f1f3677d357a08acef27d6f5cc847696a 100644
--- a/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/Job.java
+++ b/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/Job.java
@@ -19,6 +19,7 @@ import org.slf4j.LoggerFactory;
 
 import cz.it4i.fiji.haas.JobManager.JobManager4Job;
 import cz.it4i.fiji.haas.JobManager.JobSynchronizableFile;
+import cz.it4i.fiji.haas_java_client.DummyProgressNotifier;
 import cz.it4i.fiji.haas_java_client.HaaSClient;
 import cz.it4i.fiji.haas_java_client.HaaSClient.UploadingFile;
 import cz.it4i.fiji.haas_java_client.HaaSFileTransfer;
@@ -55,7 +56,7 @@ public class Job {
 
 	public Job(JobManager4Job jobManager, String name, Path basePath, Supplier<HaaSClient> haasClientSupplier) throws IOException {
 		this(jobManager,haasClientSupplier);
-		HaaSClient client = this.haasClientSupplier.get();
+		HaaSClient client = getHaaSClient();
 		long id = client.createJob(name, Collections.emptyList());
 		jobDir = basePath.resolve("" + id);
 		propertyHolder = new PropertyHolder(jobDir.resolve(JOB_INFO_FILE));
@@ -75,7 +76,7 @@ public class Job {
 	}
 
 	public void uploadFiles(Iterable<UploadingFile> files, Progress notifier) {
-		HaaSClient client = this.haasClientSupplier.get();
+		HaaSClient client = getHaaSClient();
 		try(HaaSFileTransfer transfer = client.startFileTransfer(getId(), new P_ProgressNotifierAdapter(notifier))){
 			transfer.upload(files);
 		}
@@ -88,7 +89,7 @@ public class Job {
 	}
 
 	public void submit() {
-		HaaSClient client = this.haasClientSupplier.get();
+		HaaSClient client = getHaaSClient();
 		client.submitJob(jobId);
 	}
 
@@ -119,8 +120,8 @@ public class Job {
 	}
 
 	synchronized public void download(Predicate<String> predicate, Progress notifier) {
-		try (HaaSFileTransfer fileTransfer = haasClientSupplier.get().startFileTransfer(jobId, new P_ProgressNotifierAdapter(notifier))) {
-			fileTransfer.download(haasClientSupplier.get().getChangedFiles(jobId).stream().filter(predicate).collect(Collectors.toList()), jobDir);
+		try (HaaSFileTransfer fileTransfer = getHaaSClient().startFileTransfer(jobId, new P_ProgressNotifierAdapter(notifier))) {
+			fileTransfer.download(getHaaSClient().getChangedFiles(jobId).stream().filter(predicate).collect(Collectors.toList()), jobDir);
 		}
 	}
 
@@ -144,7 +145,7 @@ public class Job {
 		HaaSClient.SynchronizableFiles taskFileOffset = new HaaSClient.SynchronizableFiles();
 		long taskId = (Long) getJobInfo().getTasks().toArray()[0];
 		output.forEach(file -> taskFileOffset.addFile(taskId, file.getType(), file.getOffset()));
-		return haasClientSupplier.get().downloadPartsOfJobFiles(jobId, taskFileOffset).stream().map(f -> f.getContent())
+		return getHaaSClient().downloadPartsOfJobFiles(jobId, taskFileOffset).stream().map(f -> f.getContent())
 				.collect(Collectors.toList());
 	}
 
@@ -185,6 +186,10 @@ public class Job {
 		return result;
 	}
 	
+	private HaaSClient getHaaSClient() {
+		return this.haasClientSupplier.get();
+	}
+
 	private JobInfo getJobInfo() {
 		if (jobInfo == null) {
 			updateJobInfo();
@@ -193,7 +198,7 @@ public class Job {
 	}
 
 	private void updateJobInfo() {
-		jobInfo = haasClientSupplier.get().obtainJobInfo(getId());
+		jobInfo = getHaaSClient().obtainJobInfo(getId());
 	}
 
 	private static boolean isValidPath(Path path) {
@@ -244,11 +249,24 @@ public class Job {
 	}
 
 	public Collection<String> getChangedFiles() {
-		return haasClientSupplier.get().getChangedFiles(getId());
+		return getHaaSClient().getChangedFiles(getId());
 	}
 
 	public void cancelJob() {
-		haasClientSupplier.get().cancelJob(jobId);
+		getHaaSClient().cancelJob(jobId);
+	}
+
+	public List<Long> getFileSizes(List<String> names) {
+		
+		try (HaaSFileTransfer transfer = getHaaSClient().startFileTransfer(getId(), new DummyProgressNotifier())) {
+			return transfer.obtainSize(names);
+		}
+	}
+
+	public List<String> getFileContents(List<String> logs) {
+		try (HaaSFileTransfer transfer = getHaaSClient().startFileTransfer(getId(), new DummyProgressNotifier())) {
+			return transfer.getContent(logs);
+		}
 	}
 
 	
diff --git a/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/ui/FXFrame.java b/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/ui/FXFrame.java
index 7b981a33910a5fdea3348929595ae54d5d544f3b..23dda8e8dc97ad23bd3788559e814c3528e21897 100644
--- a/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/ui/FXFrame.java
+++ b/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/ui/FXFrame.java
@@ -30,18 +30,17 @@ public abstract class FXFrame<T extends Parent&CloseableControl> extends JDialog
 	public FXFrame(Window parent, Supplier<T> fxSupplier) {
 		super(parent, ModalityType.MODELESS);
 		fxPanel = new JFXPanel<>(fxSupplier);
+		init();
 		if (fxPanel.getControl() instanceof InitiableControl) {
 			InitiableControl control = (InitiableControl) fxPanel.getControl();
 			control.init(this);
 		}
-		init();
 	}
 
 	private void init() {
 		addWindowListener(new WindowAdapter() {
 			@Override
-			public void windowClosed(WindowEvent e) {
-				super.windowClosed(e);
+			public void windowClosing(WindowEvent e) {
 				getFxPanel().getControl().close();
 			}
 		});
diff --git a/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/ui/JavaFXRoutines.java b/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/ui/JavaFXRoutines.java
index 59ae9b7c86a5c374991c1d6f0ffe9e410b62bed0..c33528cde87f4dad3d174482c44b0698620a7924 100644
--- a/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/ui/JavaFXRoutines.java
+++ b/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/ui/JavaFXRoutines.java
@@ -6,6 +6,7 @@ import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.Executor;
 import java.util.function.Consumer;
 import java.util.function.Function;
+import java.util.function.Predicate;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -135,5 +136,13 @@ public interface JavaFXRoutines {
 			}
 		});
 	}
+	
+	public static <T> boolean notNullValue(ObservableValue<T> j, Predicate<T> pred) {
+		if (j == null || j.getValue() == null) {
+			return false;
+		} else {
+			return pred.test(j.getValue());
+		}
+	}
 
 }
diff --git a/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/ui/ObservableValueRegistry.java b/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/ui/ObservableValueRegistry.java
index 355ab32036a370e82100599234f44316e57fbe9b..b47f0739cd6a60e14d2649f977a18334101d68a2 100644
--- a/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/ui/ObservableValueRegistry.java
+++ b/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/ui/ObservableValueRegistry.java
@@ -1,7 +1,7 @@
 package cz.it4i.fiji.haas.ui;
 
 import java.util.Collection;
-import java.util.HashMap;
+import java.util.LinkedHashMap;
 import java.util.LinkedList;
 import java.util.Map;
 import java.util.function.Consumer;
@@ -29,7 +29,7 @@ public class ObservableValueRegistry<T> {
 		
 	}
 
-	private Map<T,UpdatableObservableValue<T>> map = new HashMap<>(); 
+	private Map<T,UpdatableObservableValue<T>> map = new LinkedHashMap<>(); 
 	
 	public  ObservableValue<T> addIfAbsent(T value) {
 		UpdatableObservableValue<T> uov = map.computeIfAbsent(value, v-> new UpdatableObservableValue<T>(v, updateFunction, stateProvider));
diff --git a/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/ui/ProgressDialog.java b/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/ui/ProgressDialog.java
index 93ad84c8caeaf3a21849ad29d8b5a489ac80af6a..c86acb066ac80fa35b9db30573361a743a3e55ba 100644
--- a/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/ui/ProgressDialog.java
+++ b/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/ui/ProgressDialog.java
@@ -27,14 +27,13 @@ import net.imagej.updater.util.Progress;
 import net.imagej.updater.util.UpdateCanceledException;
 
 /**
- * TODO
  * 
  * @author Johannes Schindelin
  */
 @SuppressWarnings("serial")
 public class ProgressDialog extends JDialog implements Progress {
 	@SuppressWarnings("unused")
-	private static Logger log = LoggerFactory.getLogger(cz.it4i.fiji.haas.ui.ProgressDialog.class);
+	public final static Logger log = LoggerFactory.getLogger(cz.it4i.fiji.haas.ui.ProgressDialog.class);
 
 	JProgressBar progress;
 	JButton detailsToggle;
@@ -110,7 +109,6 @@ public class ProgressDialog extends JDialog implements Progress {
 		if (title != null)
 			setTitle(title);
 		pack();
-
 		if (owner != null) {
 			final Dimension o = owner.getSize();
 			final Dimension size = getSize();
@@ -119,6 +117,8 @@ public class ProgressDialog extends JDialog implements Progress {
 				setSize(size);
 			}
 			setLocation(owner.getX() + (o.width - size.width) / 2, owner.getY() + (o.height - size.height) / 2);
+		} else { 
+			setLocationRelativeTo(owner);
 		}
 
 		final KeyAdapter keyAdapter = new KeyAdapter() {
@@ -133,7 +133,6 @@ public class ProgressDialog extends JDialog implements Progress {
 		detailsToggle.addKeyListener(keyAdapter);
 		cancel.addKeyListener(keyAdapter);
 
-		setLocationRelativeTo(null);
 		if (title != null)
 			setVisible(true);
 	}
@@ -293,7 +292,7 @@ public class ProgressDialog extends JDialog implements Progress {
 		return false;
 	}
 
-	public static void main(final String[] args) {
+	private static void main(final String[] args) {
 		final ProgressDialog dialog = new ProgressDialog(null, "Hello");
 		dialog.addItem("Bello");
 		dialog.setVisible(true);
diff --git a/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/ui/TableViewContextMenu.java b/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/ui/TableViewContextMenu.java
index ed828856dc41ca8c3f311de33f0fc5849d26a362..0789e95c66f6a7124e5398cecb10e6a107a67923 100644
--- a/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/ui/TableViewContextMenu.java
+++ b/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/ui/TableViewContextMenu.java
@@ -2,6 +2,8 @@ package cz.it4i.fiji.haas.ui;
 
 import java.util.Collection;
 import java.util.LinkedList;
+import java.util.function.BiConsumer;
+import java.util.function.BiPredicate;
 import java.util.function.Consumer;
 import java.util.function.Predicate;
 
@@ -11,42 +13,73 @@ import org.slf4j.LoggerFactory;
 import javafx.event.EventHandler;
 import javafx.scene.control.ContextMenu;
 import javafx.scene.control.MenuItem;
+import javafx.scene.control.TableColumn;
 import javafx.scene.control.TableView;
 import javafx.scene.input.ContextMenuEvent;
 
 public class TableViewContextMenu<T> {
-	@SuppressWarnings("unused")
-	private static Logger log = LoggerFactory.getLogger(cz.it4i.fiji.haas.ui.TableViewContextMenu.class);
-	private Collection<P_MenuItem> items = new LinkedList<TableViewContextMenu<T>.P_MenuItem>();
-	private ContextMenu cm;
+
+	public final static Logger log = LoggerFactory.getLogger(cz.it4i.fiji.haas.ui.TableViewContextMenu.class);
+
+	private final Collection<P_MenuItem> items = new LinkedList<>();
+	private final Collection<P_MenuItemWithColumnIndex> itemsWithColumnIndex = new LinkedList<>();
+
 	private TableView<T> tableView;
 
+	private int columnIndex = -1;
+
 	public TableViewContextMenu(TableView<T> tableView) {
-		this.cm = new ContextMenu();
 		this.tableView = tableView;
-		tableView.setContextMenu(cm);
-		tableView.setOnContextMenuRequested(new EventHandler<ContextMenuEvent>() {
-			@Override
-			public void handle(ContextMenuEvent event) {
-				T selected = getSelectedItem();
-				
-				for (P_MenuItem item : items) {
-					item.updateEnable(selected);
-				}
-			}
-		});
 	}
 
 	public void addItem(String text, Consumer<T> eventHandler, Predicate<T> enableHandler) {
 		items.add(new P_MenuItem(text, eventHandler, enableHandler));
 	}
 
-	private T getSelectedItem() {
-		T result = null;
-		if (tableView.getSelectionModel().getSelectedCells().size() >= 0) {
-			result = tableView.getSelectionModel().getSelectedItem();
+	public void addItem(String text, BiConsumer<T, Integer> eventHandler, BiPredicate<T, Integer> enableHandler) {
+		itemsWithColumnIndex.add(new P_MenuItemWithColumnIndex(text, eventHandler, enableHandler));
+	}
+
+	private T getRequestedItem() {
+		return tableView.getFocusModel().getFocusedItem();
+	}
+
+	private int getRequestedColumn() {
+		return columnIndex;
+	}
+
+	private ContextMenu getOrCreateContextMenu() {
+		ContextMenu cm = tableView.getContextMenu();
+		if (cm == null) {
+			cm = new ContextMenu();
+			tableView.setContextMenu(cm);
+			tableView.setOnContextMenuRequested(new EventHandler<ContextMenuEvent>() {
+				@Override
+				public void handle(ContextMenuEvent event) {
+					T requestedItem = getRequestedItem();
+					updateColumnIndex(event.getSceneX());
+					int column = getRequestedColumn();
+					items.forEach(item -> item.updateEnable(requestedItem));
+					itemsWithColumnIndex.forEach(item -> item.updateEnable(requestedItem, column));
+				}
+
+				private void updateColumnIndex(double sceneX) {
+					double last = 0;
+					columnIndex = tableView.getColumns().size();
+					int index = 0;
+					for (TableColumn<?, ?> column : tableView.getColumns()) {
+						last += column.getWidth();
+						if (last > sceneX) {
+							columnIndex = index;
+							break;
+						}
+						index++;
+					}
+				}
+			});
+
 		}
-		return result;
+		return cm;
 	}
 
 	private class P_MenuItem {
@@ -57,8 +90,8 @@ public class TableViewContextMenu<T> {
 		public P_MenuItem(String text, Consumer<T> eventHandler, Predicate<T> enableHandler) {
 			this.enableHandler = enableHandler;
 			item = new MenuItem(text);
-			item.setOnAction(e -> eventHandler.accept(getSelectedItem()));
-			cm.getItems().add(item);
+			item.setOnAction(e -> eventHandler.accept(getRequestedItem()));
+			getOrCreateContextMenu().getItems().add(item);
 		}
 
 		public void updateEnable(T selected) {
@@ -67,4 +100,23 @@ public class TableViewContextMenu<T> {
 
 	}
 
+	private class P_MenuItemWithColumnIndex {
+
+		private MenuItem item;
+		private BiPredicate<T, Integer> enableHandler;
+
+		public P_MenuItemWithColumnIndex(String text, BiConsumer<T, Integer> eventHandler,
+				BiPredicate<T, Integer> enableHandler) {
+			this.enableHandler = enableHandler;
+			item = new MenuItem(text);
+			item.setOnAction(e -> eventHandler.accept(getRequestedItem(), getRequestedColumn()));
+			getOrCreateContextMenu().getItems().add(item);
+		}
+
+		public void updateEnable(T selected, int column) {
+			item.setDisable(!enableHandler.test(selected, column));
+		}
+
+	}
+
 }
diff --git a/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/ui/UpdatableObservableValue.java b/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/ui/UpdatableObservableValue.java
index a4c41a15cfa241aa801cfcf6a7b5a5d33e906d30..4116da697e01d538211eee84d879f538e4160b26 100644
--- a/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/ui/UpdatableObservableValue.java
+++ b/haas-imagej-client/src/main/java/cz/it4i/fiji/haas/ui/UpdatableObservableValue.java
@@ -2,10 +2,16 @@ package cz.it4i.fiji.haas.ui;
 
 import java.util.function.Function;
 
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 import javafx.beans.value.ObservableValueBase;
 
 public class UpdatableObservableValue<T> extends ObservableValueBase<T> {
 
+	@SuppressWarnings("unused")
+	private static Logger log = LoggerFactory.getLogger(cz.it4i.fiji.haas.ui.UpdatableObservableValue.class);
+	
 	public enum UpdateStatus {
 		Deleted, Updated, NotUpdated
 	}
diff --git a/haas-imagej-client/src/test/java/cz/it4i/fiji/haas/TableProof.fxml b/haas-imagej-client/src/test/java/cz/it4i/fiji/haas/TableProof.fxml
new file mode 100644
index 0000000000000000000000000000000000000000..ac481ad65cac5d34e5ac0e3dff9b362fb1b0b7a1
--- /dev/null
+++ b/haas-imagej-client/src/test/java/cz/it4i/fiji/haas/TableProof.fxml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<?import javafx.scene.layout.BorderPane?>
+<?import javafx.scene.layout.HBox?>
+<?import javafx.scene.control.TableView?>
+<?import javafx.scene.control.TableColumn?>
+<?import javafx.geometry.Insets?>
+
+
+<fx:root type="BorderPane" xmlns="http://javafx.com/javafx/8.0.65"
+	xmlns:fx="http://javafx.com/fxml/1" fx:controller="cz.it4i.fiji.haas.TableProofControl">
+	<center>
+
+		<HBox>
+			<children>
+
+				<TableView fx:id="table" HBox.hgrow="ALWAYS">
+					<columns>
+						<TableColumn prefWidth="75.0" text="Job Id" />
+						<TableColumn prefWidth="149.0" text="Status" />
+						<TableColumn prefWidth="230.0" text="Creation time" />
+						<TableColumn prefWidth="230.0" text="Start time" />
+						<TableColumn prefWidth="230.0" text="End Time" />
+					</columns>
+				</TableView>
+			</children>
+			<padding>
+				<Insets bottom="1.0" left="1.0" right="1.0" top="1.0" />
+			</padding>
+		</HBox>
+	</center>
+
+</fx:root>
+
diff --git a/haas-imagej-client/src/test/java/cz/it4i/fiji/haas/TableProofControl.java b/haas-imagej-client/src/test/java/cz/it4i/fiji/haas/TableProofControl.java
new file mode 100644
index 0000000000000000000000000000000000000000..7c03872a9866460fd4111019b725900cf76effc7
--- /dev/null
+++ b/haas-imagej-client/src/test/java/cz/it4i/fiji/haas/TableProofControl.java
@@ -0,0 +1,97 @@
+package cz.it4i.fiji.haas;
+
+import java.awt.Window;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+
+import javax.swing.WindowConstants;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import cz.it4i.fiji.haas.ui.CloseableControl;
+import cz.it4i.fiji.haas.ui.FXFrame;
+import cz.it4i.fiji.haas.ui.InitiableControl;
+import cz.it4i.fiji.haas.ui.JavaFXRoutines;
+import cz.it4i.fiji.haas.ui.TableViewContextMenu;
+import javafx.beans.value.ObservableValue;
+import javafx.beans.value.ObservableValueBase;
+import javafx.fxml.FXML;
+import javafx.scene.control.TableView;
+import javafx.scene.layout.BorderPane;
+
+public class TableProofControl extends BorderPane implements CloseableControl, InitiableControl {
+
+	@SuppressWarnings("unused")
+	private static Logger log = LoggerFactory.getLogger(cz.it4i.fiji.haas.TableProofControl.class);
+
+	@FXML
+	private TableView<ObservableValue<String[]>> table;
+	private TableViewContextMenu<ObservableValue<String[]>> menu;
+
+	public TableProofControl() {
+		JavaFXRoutines.initRootAndController("TableProof.fxml", this);
+		menu = new TableViewContextMenu<>(table);
+		for (int i = 0; i < 4; i++) {
+			final int index = i;
+			JavaFXRoutines.setCellValueFactory(table, index, vals -> vals[index]);
+		}
+		menu.addItem("Proof", (val, index) -> proof(index), (val, index) -> index < 4);
+		addItem();
+		addItem();
+		addItem();
+		addItem();
+	}
+
+	private void addItem() {
+		String[] values = new String[] { "0", "1", "2", "3" };
+		class Values extends ObservableValueBase<String[]> {
+
+			@Override
+			public String[] getValue() {
+				return values;
+			}
+		}
+		table.getItems().add(new Values());
+	}
+
+	private void proof(int index) {
+		System.out.println(index);
+	}
+
+	@Override
+	public void init(Window parameter) {
+		// TODO Auto-generated method stub
+
+	}
+
+	@Override
+	public void close() {
+		// TODO Auto-generated method stub
+
+	}
+
+	public static void main(String[] args) {
+		class Window extends FXFrame<TableProofControl> {
+
+			public Window() {
+				super(() -> new TableProofControl());
+			}
+
+			/**
+			 * 
+			 */
+			private static final long serialVersionUID = 1L;
+		}
+		
+		Window w = new Window();
+		w.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
+		w.setVisible(true);
+		w.addWindowListener(new WindowAdapter() {
+			@Override
+			public void windowClosing(WindowEvent e) {
+				System.exit(0);
+			}
+		});
+	}
+}
diff --git a/haas-java-client/src/main/java/cz/it4i/fiji/haas_java_client/DummyProgressNotifier.java b/haas-java-client/src/main/java/cz/it4i/fiji/haas_java_client/DummyProgressNotifier.java
new file mode 100644
index 0000000000000000000000000000000000000000..927d4c048226546d76acd64d99fb3953b886ce70
--- /dev/null
+++ b/haas-java-client/src/main/java/cz/it4i/fiji/haas_java_client/DummyProgressNotifier.java
@@ -0,0 +1,29 @@
+package cz.it4i.fiji.haas_java_client;
+
+public class DummyProgressNotifier implements ProgressNotifier {
+
+	@Override
+	public void setCount(int count, int total) {
+	}
+
+	@Override
+	public void addItem(Object item) {
+	}
+
+	@Override
+	public void setItemCount(int count, int total) {
+
+	}
+
+	@Override
+	public void itemDone(Object item) {
+	}
+
+	@Override
+	public void done() {
+	}
+
+	@Override
+	public void setTitle(String title) {
+	}
+}
diff --git a/haas-java-client/src/main/java/cz/it4i/fiji/haas_java_client/HaaSClient.java b/haas-java-client/src/main/java/cz/it4i/fiji/haas_java_client/HaaSClient.java
index dac7e14f777a0eaf8532726a8acd5326a2fe2275..c2aa23c2afad67cbec975cf18d453a7c4bdff3f0 100644
--- a/haas-java-client/src/main/java/cz/it4i/fiji/haas_java_client/HaaSClient.java
+++ b/haas-java-client/src/main/java/cz/it4i/fiji/haas_java_client/HaaSClient.java
@@ -163,6 +163,8 @@ public class HaaSClient {
 
 	private String projectId;
 
+	private Map<Long, P_FileTransferPool> filetransferPoolMap = new HashMap<>();
+
 	public static ProgressNotifier DUMMY_NOTIFIER = new ProgressNotifier() {
 
 		@Override
@@ -246,8 +248,7 @@ public class HaaSClient {
 
 	public HaaSFileTransfer startFileTransfer(long jobId, ProgressNotifier notifier) {
 		try {
-			FileTransferMethodExt ft = getFileTransfer().getFileTransferMethod(jobId, getSessionID());
-			return new HaaSFileTransferImp(ft, getSessionID(), jobId, getFileTransfer(), getScpClient(ft), notifier);
+			return getFileTransferMethod(jobId, notifier);
 		} catch (RemoteException | ServiceException | UnsupportedEncodingException | JSchException e) {
 			throw new HaaSClientException(e);
 		}
@@ -304,7 +305,7 @@ public class HaaSClient {
 			throw new HaaSClientException(e);
 		}
 	}
-	
+
 	public Collection<String> getChangedFiles(long jobId) {
 		try {
 			return Arrays.asList(getFileTransfer().listChangedFilesForJob(jobId, getSessionID()));
@@ -312,8 +313,7 @@ public class HaaSClient {
 			throw new HaaSClientException(e);
 		}
 	}
-	
-	
+
 	public void cancelJob(Long jobId) {
 		try {
 			getJobManagement().cancelJob(jobId, getSessionID());
@@ -322,6 +322,27 @@ public class HaaSClient {
 		}
 	}
 
+	private HaaSFileTransferImp getFileTransferMethod(long jobId, ProgressNotifier notifier)
+			throws RemoteException, UnsupportedEncodingException, ServiceException, JSchException {
+		P_FileTransferPool pool = filetransferPoolMap.computeIfAbsent(jobId, id -> new P_FileTransferPool(id));
+		FileTransferMethodExt ft = pool.obtain();
+		try {
+			return new HaaSFileTransferImp(ft, getScpClient(ft), notifier) {
+				public void close() {
+					super.close();
+					try {
+						pool.release();
+					} catch (RemoteException | ServiceException e) {
+						throw new HaaSClientException(e);
+					}
+				};
+			};
+		} catch (UnsupportedEncodingException | JSchException e) {
+			pool.release();
+			throw e;
+		}
+	}
+
 	private void doSubmitJob(long jobId) throws RemoteException, ServiceException {
 		getJobManagement().submitJob(jobId, getSessionID());
 	}
@@ -469,4 +490,43 @@ public class HaaSClient {
 		}
 	}
 
+	private interface P_Supplier<T> {
+
+		T get() throws RemoteException, ServiceException;
+	}
+
+	private interface P_Consumer<T> {
+
+		void accept(T val) throws RemoteException, ServiceException;
+	}
+
+	private class P_FileTransferPool {
+		private FileTransferMethodExt holded;
+		private int counter;
+		private final P_Supplier<FileTransferMethodExt> factory;
+		private final P_Consumer<FileTransferMethodExt> destroyer;
+
+		public P_FileTransferPool(long jobId) {
+			this.factory = () -> getFileTransfer().getFileTransferMethod(jobId, getSessionID());
+			this.destroyer = val -> getFileTransfer().endFileTransfer(jobId, val, sessionID);
+			;
+		}
+
+		public synchronized FileTransferMethodExt obtain() throws RemoteException, ServiceException {
+			if (holded == null) {
+				holded = factory.get();
+			}
+			counter++;
+			return holded;
+		}
+
+		public synchronized void release() throws RemoteException, ServiceException {
+			if (--counter == 0) {
+				destroyer.accept(holded);
+				holded = null;
+			}
+		}
+
+	}
+
 }
diff --git a/haas-java-client/src/main/java/cz/it4i/fiji/haas_java_client/HaaSFileTransfer.java b/haas-java-client/src/main/java/cz/it4i/fiji/haas_java_client/HaaSFileTransfer.java
index e3b427f2a1cdbdfbaef67fbfa10b3a5d9bc789a8..c6c8a4b9b31142c0b5041b1ccf1882bae1a82b4d 100644
--- a/haas-java-client/src/main/java/cz/it4i/fiji/haas_java_client/HaaSFileTransfer.java
+++ b/haas-java-client/src/main/java/cz/it4i/fiji/haas_java_client/HaaSFileTransfer.java
@@ -18,4 +18,5 @@ public interface HaaSFileTransfer extends Closeable {
 
 	List<Long> obtainSize(List<String> files);
 
+	List<String> getContent(List<String> logs);
 }
diff --git a/haas-java-client/src/main/java/cz/it4i/fiji/haas_java_client/HaaSFileTransferImp.java b/haas-java-client/src/main/java/cz/it4i/fiji/haas_java_client/HaaSFileTransferImp.java
index 6d59b42f6240640ab78a8f692f43d17e00e39bad..5cbaf90c68a5b762795ae6b58365bcfdf7948ab1 100644
--- a/haas-java-client/src/main/java/cz/it4i/fiji/haas_java_client/HaaSFileTransferImp.java
+++ b/haas-java-client/src/main/java/cz/it4i/fiji/haas_java_client/HaaSFileTransferImp.java
@@ -1,9 +1,10 @@
 package cz.it4i.fiji.haas_java_client;
 
+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.nio.file.Path;
-import java.rmi.RemoteException;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.stream.Collectors;
 import java.util.stream.StreamSupport;
@@ -16,39 +17,26 @@ import com.jcraft.jsch.JSchException;
 import cz.it4i.fiji.haas_java_client.HaaSClient.P_ProgressNotifierDecorator4Size;
 import cz.it4i.fiji.haas_java_client.HaaSClient.UploadingFile;
 import cz.it4i.fiji.haas_java_client.proxy.FileTransferMethodExt;
-import cz.it4i.fiji.haas_java_client.proxy.FileTransferWsSoap;
 import cz.it4i.fiji.scpclient.ScpClient;
 
 class HaaSFileTransferImp implements HaaSFileTransfer {
 
+	@SuppressWarnings("unused")
 	private static Logger log = LoggerFactory.getLogger(cz.it4i.fiji.haas_java_client.HaaSFileTransferImp.class);
 
 	private FileTransferMethodExt ft;
 	private ScpClient scpClient;
-	private FileTransferWsSoap fileTransfer;
-	private String sessionId;
-	private long jobId;
 	private ProgressNotifier notifier;
 
-	public HaaSFileTransferImp(FileTransferMethodExt ft, String sessionId, long jobId, FileTransferWsSoap fileTransfer,
-			ScpClient scpClient, ProgressNotifier notifier) {
+	public HaaSFileTransferImp(FileTransferMethodExt ft, ScpClient scpClient, ProgressNotifier notifier) {
 		this.ft = ft;
 		this.scpClient = scpClient;
-		this.fileTransfer = fileTransfer;
-		this.sessionId = sessionId;
-		this.jobId = jobId;
 		this.notifier = notifier;
 	}
 
 	@Override
 	public void close() {
 		scpClient.close();
-		try {
-			fileTransfer.endFileTransfer(jobId, ft, sessionId);
-		} catch (RemoteException e) {
-			throw new HaaSClientException(e);
-		}
-
 	}
 
 	@Override
@@ -108,11 +96,52 @@ class HaaSFileTransferImp implements HaaSFileTransfer {
 	public List<Long> obtainSize(List<String> files) {
 		try {
 			return HaaSClient.getSizes(files.stream()
-					.map(filename -> "'" + ft.getSharedBasepath() + "/" + filename + "'").collect(Collectors.toList()), scpClient, notifier);
+					.map(filename -> "'" + ft.getSharedBasepath() + "/" + filename + "'").collect(Collectors.toList()),
+					scpClient, notifier);
+		} catch (JSchException | IOException e) {
+			throw new HaaSClientException(e);
+		}
+
+	}
+
+	// FIXME: merge with download - stream provider for file, consumer for stream
+	@Override
+	public List<String> getContent(List<String> files) {
+		List<String> result = new LinkedList<>();
+		List<Long> fileSizes;
+		try {
+			fileSizes = HaaSClient.getSizes(StreamSupport.stream(files.spliterator(), false)
+					.map(filename -> "'" + ft.getSharedBasepath() + "/" + filename + "'").collect(Collectors.toList()),
+					scpClient, new P_ProgressNotifierDecorator4Size(notifier));
+
+			final long totalFileSize = fileSizes.stream().mapToLong(i -> i.longValue()).sum();
+			TransferFileProgressForHaaSClient progress = new TransferFileProgressForHaaSClient(totalFileSize, notifier);
+			int idx = 0;
+			for (String fileName : files) {
+				fileName = replaceIfFirstFirst(fileName, "/", "");
+				try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
+					String fileToDownload = "'" + ft.getSharedBasepath() + "/" + fileName + "'";
+					String item;
+					progress.addItem(item = fileName);
+					progress.startNewFile(fileSizes.get(idx));
+					scpClient.download(fileToDownload, os, progress);
+					os.flush();
+					progress.itemDone(item);
+					idx++;
+					result.add(os.toString());
+				}
+			}
 		} catch (JSchException | IOException e) {
 			throw new HaaSClientException(e);
 		}
+		return result;
+	}
 
+	private String replaceIfFirstFirst(String fileName, String string, String string2) {
+		if (fileName.length() < 0 && fileName.charAt(0) == '/') {
+			fileName = fileName.substring(1);
+		}
+		return fileName;
 	}
 
 }
diff --git a/haas-java-client/src/test/java/cz/it4i/fiji/haas_java_client/TestConcurentAccessToHaaSFileTransfer.java b/haas-java-client/src/test/java/cz/it4i/fiji/haas_java_client/TestConcurentAccessToHaaSFileTransfer.java
new file mode 100644
index 0000000000000000000000000000000000000000..cdeedef7f7bcb4a58bdd249520d82c5dfa6eae2b
--- /dev/null
+++ b/haas-java-client/src/test/java/cz/it4i/fiji/haas_java_client/TestConcurentAccessToHaaSFileTransfer.java
@@ -0,0 +1,26 @@
+package cz.it4i.fiji.haas_java_client;
+
+import java.io.IOException;
+import java.util.Arrays;
+
+import javax.xml.rpc.ServiceException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class TestConcurentAccessToHaaSFileTransfer {
+
+	private static Logger log = LoggerFactory.getLogger(cz.it4i.fiji.haas_java_client.TestConcurentAccessToHaaSFileTransfer.class);
+
+	public static void main(String[] args) throws ServiceException, IOException {
+		HaaSClient client = new HaaSClient(TestingConstants.getSettings(1l, 600, 7l, "OPEN-12-20"));
+		HaaSFileTransfer tr1 = client.startFileTransfer(250, new DummyProgressNotifier());
+		HaaSFileTransfer tr2 = client.startFileTransfer(249, new DummyProgressNotifier());
+		log.info("config.yaml - size:" + tr1.obtainSize(Arrays.asList("config.yaml")));
+		tr1.close();
+		log.info("config.yaml - size:" + tr2.obtainSize(Arrays.asList("config.yaml")));
+		tr2.close();
+	}
+
+	
+}
diff --git a/haas-spim-benchmark/pom.xml b/haas-spim-benchmark/pom.xml
index 92859dc556c15ffd153120c062eef63adf87d9ea..10057406c4c5b478647fc61aae0ee12efb56925d 100644
--- a/haas-spim-benchmark/pom.xml
+++ b/haas-spim-benchmark/pom.xml
@@ -78,6 +78,14 @@
 			<artifactId>haas-imagej-client</artifactId>
 			<version>0.0.1-SNAPSHOT</version>
 		</dependency>
+		
+		<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
+		<dependency>
+		    <groupId>commons-io</groupId>
+		    <artifactId>commons-io</artifactId>
+		    <version>2.6</version>
+		</dependency>
+				
 		<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
 		<dependency>
 			<groupId>org.slf4j</groupId>
diff --git a/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/commands/ManageSPIMBenchmark.java b/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/commands/ManageSPIMBenchmark.java
index 4f54ce6bbb8c77cca64905f994a716c7a75ec6ab..f7e6b93d1c66fd775eaa7c88fadb1633d19a753d 100644
--- a/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/commands/ManageSPIMBenchmark.java
+++ b/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/commands/ManageSPIMBenchmark.java
@@ -17,6 +17,7 @@ import org.scijava.widget.TextWidget;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import cz.it4i.fiji.haas_spim_benchmark.core.Constants;
 import cz.it4i.fiji.haas_spim_benchmark.ui.BenchmarkSPIMWindow;
 import net.imagej.ImageJ;
 
@@ -43,8 +44,6 @@ public class ManageSPIMBenchmark implements Command {
 	@Parameter(style = TextWidget.PASSWORD_STYLE)
 	private String password;
 	
-	@Parameter(style = TextWidget.FIELD_STYLE)
-	private String phone;
 	
 	@Parameter(style = TextWidget.FIELD_STYLE)
 	private String email;
@@ -56,7 +55,7 @@ public class ManageSPIMBenchmark implements Command {
 	public void run() {
 		try {
 			JDialog dialog = 
-					new BenchmarkSPIMWindow(null, new BenchmarkSPIMParametersImpl(userName, password, phone,
+					new BenchmarkSPIMWindow(null, new BenchmarkSPIMParametersImpl(userName, password, Constants.PHONE,
 							email, Paths.get(workingDirectory.getPath())));
 			dialog.setTitle("SPIM workflow computation manager");
 			dialog.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
diff --git a/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/core/BenchmarkJobManager.java b/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/core/BenchmarkJobManager.java
index fb63795c97bda42a976575902ed0661956867192..1a90371e33e179e9c2f474d733d5c9cd94d3adcb 100644
--- a/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/core/BenchmarkJobManager.java
+++ b/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/core/BenchmarkJobManager.java
@@ -65,7 +65,7 @@ public class BenchmarkJobManager {
 		private JobState verifiedState;
 		private boolean verifiedStateProcessed;
 		private CompletableFuture<JobState> running;
-	
+
 		public BenchmarkJob(Job job) {
 			this.job = job;
 			tasks = new LinkedList<Task>();
@@ -85,14 +85,18 @@ public class BenchmarkJobManager {
 		}
 
 		public JobState getState() {
-			return getStateAsync(r->r.run()).getNow(JobState.Unknown);
+			return getStateAsync(r -> r.run()).getNow(JobState.Unknown);
 		}
-		
+
 		public synchronized CompletableFuture<JobState> getStateAsync(Executor executor) {
-			if(running != null) {
+			if (running != null) {
 				return running;
 			}
-			return running = doGetStateAsync(executor);
+			CompletableFuture<JobState> result = doGetStateAsync(executor);
+			if (!result.isCancelled() && !result.isCompletedExceptionally() && !result.isDone()) {
+				running = result;
+			}
+			return result;
 		}
 
 		private synchronized CompletableFuture<JobState> doGetStateAsync(Executor executor) {
@@ -103,28 +107,27 @@ public class BenchmarkJobManager {
 				return CompletableFuture.completedFuture(verifiedState);
 			}
 			verifiedStateProcessed = true;
-			return CompletableFuture.supplyAsync(()->{
+			return CompletableFuture.supplyAsync(() -> {
 				try {
-					verifiedState = Stream
-							.concat(Arrays.asList(state).stream(), getTasks().stream()
+					verifiedState = 
+							Stream.concat(Arrays.asList(state).stream(), getTasks().stream().filter(task->!task.getDescription().equals(Constants.DONE_TASK))
 									.flatMap(task -> task.getComputations().stream()).map(tc -> tc.getState()))
-							.max(new JobStateComparator()).get();
-
+									.max(new JobStateComparator()).get();
 					if (verifiedState != JobState.Finished && verifiedState != JobState.Canceled) {
 						verifiedState = JobState.Failed;
 					}
-					synchronized(BenchmarkJob.this) {
-						//test whether job was restarted - it sets running to null
-						if(!verifiedStateProcessed) {
+					synchronized (BenchmarkJob.this) {
+						// test whether job was restarted - it sets running to null
+						if (!verifiedStateProcessed) {
 							verifiedState = null;
-							return doGetStateAsync(r->r.run()).getNow(null);
-						} 
+							return doGetStateAsync(r -> r.run()).getNow(null);
+						}
 						running = null;
 						return verifiedState;
 					}
 				} finally {
-					synchronized(BenchmarkJob.this) {
-						if(running != null) {
+					synchronized (BenchmarkJob.this) {
+						if (running != null) {
 							running = null;
 						}
 					}
@@ -233,7 +236,7 @@ public class BenchmarkJobManager {
 		public List<String> getActualOutput(List<SynchronizableFileType> content) {
 			return computationAccessor.getActualOutput(content);
 		}
-		
+
 		@Override
 		public String toString() {
 			return "" + getId();
@@ -365,6 +368,16 @@ public class BenchmarkJobManager {
 
 				public java.util.Collection<String> getChangedFiles() {
 					return job.getChangedFiles();
+				}
+
+				@Override
+				public List<Long> getFileSizes(List<String> names) {
+					return job.getFileSizes(names);
+				}
+
+				@Override
+				public List<String> getFileContents(List<String> logs) {
+					return job.getFileContents(logs);
 				};
 			};
 
diff --git a/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/core/Constants.java b/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/core/Constants.java
index fb92a8c287a4ba3e15ef253ccce02e5f6561d3e1..dd3ce0507d0be10acf7170cce0f1360630e85b94 100644
--- a/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/core/Constants.java
+++ b/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/core/Constants.java
@@ -4,6 +4,7 @@ import java.util.LinkedHashMap;
 import java.util.Map;
 
 public interface Constants {
+	String PHONE = "123456789";
 	int HAAS_UPDATE_TIMEOUT = 30000;
 	short UI_TO_HAAS_FREQUENCY_UPDATE_RATIO = 10;
 	String HAAS_JOB_NAME = "HaaSSPIMBenchmark";
@@ -37,7 +38,7 @@ public interface Constants {
 			put("define_output", "Define output");
 			put("hdf5_xml_output", "Define hdf5 output");
 			put("resave_hdf5_output", "Resave output to hdf5");
-			put("done", "Done");
+			put(DONE_TASK, "Done");
 		}};
 	
 	String STATISTICS_TASK_NAME = "Task name";
@@ -50,4 +51,6 @@ public interface Constants {
 	
 	String STATISTICS_SUMMARY_FILENAME = "summary.csv";
 	String SUMMARY_FILE_HEADER = "Task;AvgMemoryUsage;AvgWallTime;MaxWallTime;TotalTime;JobCount";
+	String DONE_TASK = "done";
+	
 }
diff --git a/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/core/JobStateComparator.java b/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/core/JobStateComparator.java
index 09a568863ac634140c85fbc810d56e0b73e11d1e..6b312cb88b6761acec362c04c476de2049906b48 100644
--- a/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/core/JobStateComparator.java
+++ b/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/core/JobStateComparator.java
@@ -14,7 +14,7 @@ public class JobStateComparator implements Comparator<JobState>{
 		priorities.put(state, priorities.size());
 	}
 	
-	{
+	static {
 		Arrays.asList(JobState.Finished,JobState.Queued, JobState.Running, JobState.Canceled, JobState.Failed).forEach(state->add(state));
 	}
 	@Override
diff --git a/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/core/ResultFileTask.java b/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/core/ResultFileTask.java
index 7cb8b1ceca95e7588b676eec1d3b83f032e2c3eb..4f0bed3365cb2dc1fd08a856588365c88eb69df8 100644
--- a/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/core/ResultFileTask.java
+++ b/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/core/ResultFileTask.java
@@ -41,7 +41,9 @@ public class ResultFileTask {
 				.appendOptional(DateTimeFormatter.ofPattern("EEE MMM dd kk:mm:ss z yyyy"))
 				.appendOptional(DateTimeFormatter.ofPattern("EEE MMM dd kk:mm:ss yyyy")).toFormatter();
 		Collection<Double> startTimeValues = retrieveValues(Constants.STATISTICS_RESOURCES_START_TIME)
-				.map(s -> (double) LocalDateTime.parse(s, formatter).toEpochSecond(ZoneOffset.UTC))
+				.map(s -> s != null && !s.equals("null")
+						? (double) LocalDateTime.parse(s, formatter).toEpochSecond(ZoneOffset.UTC)
+						: Double.NaN)
 				.collect(Collectors.toList());
 		Collection<Double> wallTimeValues = retrieveValues(Constants.STATISTICS_RESOURCES_WALL_TIME)
 				.map(s -> Double.parseDouble(s)).collect(Collectors.toList());
diff --git a/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/core/SPIMComputationAccessor.java b/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/core/SPIMComputationAccessor.java
index d0283db80c1ae69815923886723074ecf57bf31b..3b1a6a9bbd69528d4eabc6c1c9ec41dec980e383 100644
--- a/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/core/SPIMComputationAccessor.java
+++ b/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/core/SPIMComputationAccessor.java
@@ -1,6 +1,7 @@
 package cz.it4i.fiji.haas_spim_benchmark.core;
 
 import java.util.Collection;
+import java.util.List;
 
 import cz.it4i.fiji.haas.HaaSOutputHolder;
 
@@ -11,6 +12,9 @@ public interface SPIMComputationAccessor extends HaaSOutputHolder {
 	default boolean fileExists(String fileName) {
 		return getChangedFiles().contains(FILE_SEPARATOR_UNIX + fileName);
 	}
-	
 	Collection<String> getChangedFiles();
+
+	List<Long> getFileSizes(List<String> names);
+	
+	List<String> getFileContents(List<String> logs);
 }
diff --git a/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/core/SPIMComputationAccessorDecoratorWithTimeout.java b/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/core/SPIMComputationAccessorDecoratorWithTimeout.java
index d308d8a4d015622e98f970d678eb789d2317d205..3f9b2ce48d1a6a3a2832d13241891cdf8613d3af 100644
--- a/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/core/SPIMComputationAccessorDecoratorWithTimeout.java
+++ b/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/core/SPIMComputationAccessorDecoratorWithTimeout.java
@@ -18,10 +18,12 @@ public class SPIMComputationAccessorDecoratorWithTimeout implements SPIMComputat
 	private final P_ResultCacheHolder<Set<String>> changedFilesCache;
 	private final Map<SynchronizableFileType, Integer> allowedTypesIndices = new HashMap<>();
 	private final List<SynchronizableFileType> allowedTypes = new LinkedList<>();
+	private SPIMComputationAccessor decorated;
 
 	public SPIMComputationAccessorDecoratorWithTimeout(SPIMComputationAccessor decorated,
 			Set<SynchronizableFileType> allowedTypes, long intervalForQueryInMs) {
 		this.intervalForQueryInMs = intervalForQueryInMs;
+		this.decorated = decorated;
 		initAllowedTypes(allowedTypes);
 		outputCache = new P_ResultCacheHolder<List<String>>(x -> decorated.getActualOutput(this.allowedTypes));
 		changedFilesCache = new P_ResultCacheHolder<>(set -> {
@@ -49,6 +51,16 @@ public class SPIMComputationAccessorDecoratorWithTimeout implements SPIMComputat
 		return changedFilesCache.getResult();
 	}
 
+	@Override
+	public List<Long> getFileSizes(List<String> names) {
+		return decorated.getFileSizes(names);
+	}
+	
+	@Override
+	public List<String> getFileContents(List<String> logs) {
+		return decorated.getFileContents(logs);
+	}
+
 	private void initAllowedTypes(Set<SynchronizableFileType> allowedTypes) {
 		for (SynchronizableFileType type : allowedTypes) {
 			this.allowedTypes.add(type);
diff --git a/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/core/TaskComputation.java b/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/core/TaskComputation.java
index 15f1664cf52147f976726e3c78ec1c5a3652df09..4aacf63016dd8d92ee92a6c8fcbbd9dd09ae74e1 100644
--- a/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/core/TaskComputation.java
+++ b/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/core/TaskComputation.java
@@ -2,15 +2,81 @@ package cz.it4i.fiji.haas_spim_benchmark.core;
 
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Map;
 import java.util.Scanner;
+import java.util.stream.Collectors;
+
+import org.apache.commons.math3.util.Pair;
+
+import com.google.common.collect.Streams;
 
 import cz.it4i.fiji.haas_java_client.JobState;
 import cz.it4i.fiji.haas_java_client.SynchronizableFileType;
 
+//FIXME: TaskComputation 'done' should be Finished not Queued
 public class TaskComputation {
 
+	public static class Log {
+		final private String name;
+		final private String content;
+
+		public Log(String name, String content) {
+			this.name = name;
+			this.content = content;
+		}
+
+		public String getName() {
+			return name;
+		}
+
+		public String getContent() {
+			return content;
+		}
+
+		@Override
+		public boolean equals(Object obj) {
+			if (this == obj)
+				return true;
+			if (obj == null)
+				return false;
+			if (getClass() != obj.getClass())
+				return false;
+			Log other = (Log) obj;
+			if (content == null) {
+				if (other.content != null)
+					return false;
+			} else if (!content.equals(other.content))
+				return false;
+			if (name == null) {
+				if (other.name != null)
+					return false;
+			} else if (!name.equals(other.name))
+				return false;
+			return true;
+		}
+	}
+
+	public static class File {
+		final private String name;
+		final private long size;
+
+		public File(String name, long size) {
+			this.name = name;
+			this.size = size;
+		}
+
+		public String getName() {
+			return name;
+		}
+
+		public long getSize() {
+			return size;
+		}
+	}
+
 	private final SPIMComputationAccessor computationAccessor;
 	private final String taskDescription;
 	private final int timepoint;
@@ -19,13 +85,12 @@ public class TaskComputation {
 	private int positionInOutput;
 
 	private Collection<String> inputs;
-	@SuppressWarnings("unused")
-	private Collection<String> outputs;
-	private Collection<String> logs;
+	private Collection<String> outputs = Collections.emptyList();
+	private Collection<String> logs = Collections.emptyList();
 	private Long id;
 
 	private final List<BenchmarkError> errors;
-	
+
 	/**
 	 * Creates a TaskComputation object. At the time of creation, the job parameters
 	 * are not populated
@@ -61,11 +126,10 @@ public class TaskComputation {
 		return id;
 	}
 
-	// TODO: Method stub
 	public void update() {
 
 	}
-	
+
 	/**
 	 * @return computations errors
 	 */
@@ -73,6 +137,13 @@ public class TaskComputation {
 		return errors;
 	}
 
+	public Collection<Log> getLogs() {
+		List<String> logNames = new LinkedList<>(logs);
+		List<String> contents = computationAccessor.getFileContents(logNames);
+		return Streams.<String, String, Log>zip(logNames.stream(), contents.stream(),
+				(name, content) -> new Log(name, content)).collect(Collectors.toList());
+	}
+
 	/**
 	 * Populates parameters of the current object by searching the output
 	 * 
@@ -99,6 +170,17 @@ public class TaskComputation {
 		return true;
 	}
 
+	public Collection<String> getOutputs() {
+		return outputs;
+	}
+
+	public Map<String, Long> getOutFileSizes() {
+		List<String> names = new LinkedList<>(outputs);
+		List<Long> sizes = computationAccessor.getFileSizes(names);
+		return Streams.zip(names.stream(), sizes.stream(), (name, size) -> new Pair<>(name, size))
+				.collect(Collectors.toMap(p -> p.getFirst(), p -> p.getSecond()));
+	}
+
 	private void updateState() {
 
 		// Should the state be queued, try to find out whether a log file exists
diff --git a/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/BenchmarkSPIMController.java b/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/BenchmarkSPIMController.java
index 14a0ffddbee390b5e2453f3446d0b1ec4b0443eb..2dd990dff6715ed43d07a51a4025464dcca57d4e 100644
--- a/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/BenchmarkSPIMController.java
+++ b/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/BenchmarkSPIMController.java
@@ -3,9 +3,10 @@ package cz.it4i.fiji.haas_spim_benchmark.ui;
 import java.awt.Desktop;
 import java.awt.Window;
 import java.io.IOException;
-import java.util.Collection;
 import java.util.EnumSet;
 import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
 import java.util.Set;
 import java.util.Timer;
 import java.util.TimerTask;
@@ -15,7 +16,6 @@ import java.util.concurrent.Executor;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.function.Function;
-import java.util.function.Predicate;
 
 import javax.swing.WindowConstants;
 
@@ -30,7 +30,6 @@ import cz.it4i.fiji.haas.ui.ModalDialogs;
 import cz.it4i.fiji.haas.ui.ProgressDialog;
 import cz.it4i.fiji.haas.ui.TableViewContextMenu;
 import cz.it4i.fiji.haas_java_client.JobState;
-import cz.it4i.fiji.haas_java_client.SynchronizableFileType;
 import cz.it4i.fiji.haas_spim_benchmark.core.BenchmarkJobManager;
 import cz.it4i.fiji.haas_spim_benchmark.core.BenchmarkJobManager.BenchmarkJob;
 import cz.it4i.fiji.haas_spim_benchmark.core.Constants;
@@ -42,16 +41,9 @@ import javafx.scene.control.TableView;
 import javafx.scene.layout.BorderPane;
 import net.imagej.updater.util.Progress;
 
+//FIXME: fix Exception during context menu request on task with N/A state
 public class BenchmarkSPIMController extends BorderPane implements CloseableControl, InitiableControl {
 
-	private static boolean notNullValue(ObservableValue<BenchmarkJob> j, Predicate<BenchmarkJob> pred) {
-		if (j == null || j.getValue() == null) {
-			return false;
-		} else {
-			return pred.test(j.getValue());
-		}
-	}
-
 	@FXML
 	private TableView<ObservableValue<BenchmarkJob>> jobs;
 
@@ -89,8 +81,7 @@ public class BenchmarkSPIMController extends BorderPane implements CloseableCont
 		}, Constants.HAAS_UPDATE_TIMEOUT, Constants.HAAS_UPDATE_TIMEOUT);
 		initTable();
 		initMenu();
-		updateJobs();
-
+		executorServiceFX.execute(this::updateJobs);
 	}
 
 	private void initMenu() {
@@ -99,46 +90,37 @@ public class BenchmarkSPIMController extends BorderPane implements CloseableCont
 		menu.addItem("Start job", job -> executeWSCallAsync("Starting job", p -> {
 			job.getValue().startJob(p);
 			registry.get(job.getValue()).update();
-		}), job -> notNullValue(job, j -> j.getState() == JobState.Configuring || j.getState() == JobState.Finished
-				|| j.getState() == JobState.Failed));
+		}), job -> JavaFXRoutines.notNullValue(job, j -> j.getState() == JobState.Configuring
+				|| j.getState() == JobState.Finished || j.getState() == JobState.Failed));
 
 		menu.addItem("Cancel job", job -> executeWSCallAsync("Canceling job", p -> {
 			job.getValue().cancelJob();
 			registry.get(job.getValue()).update();
-		}), job -> notNullValue(job, j -> j.getState() == JobState.Running));
+		}), job -> JavaFXRoutines.notNullValue(job, j -> j.getState() == JobState.Running));
 
-		menu.addItem("Show details", job -> {
+		menu.addItem("Execution details", job -> {
 			try {
 				new JobDetailWindow(root, job.getValue()).setVisible(true);
 			} catch (IOException e) {
-				// TODO Auto-generated catch block
 				log.error(e.getMessage(), e);
 			}
-		}, job -> notNullValue(job, j -> j.getState() == JobState.Running || j.getState() == JobState.Finished
-				|| j.getState() == JobState.Failed || j.getState() == JobState.Canceled));
+		}, job -> JavaFXRoutines.notNullValue(job,
+				j -> j.getState() == JobState.Running || j.getState() == JobState.Finished
+						|| j.getState() == JobState.Failed || j.getState() == JobState.Canceled));
 
 		menu.addItem("Download result",
 				job -> executeWSCallAsync("Downloading data", p -> job.getValue().downloadData(p)),
-				job -> notNullValue(job,
+				job -> JavaFXRoutines.notNullValue(job,
 						j -> EnumSet.of(JobState.Failed, JobState.Finished, JobState.Canceled).contains(j.getState())
 								&& !j.downloaded()));
 		menu.addItem("Download statistics",
 				job -> executeWSCallAsync("Downloading data", p -> job.getValue().downloadStatistics(p)),
-				job -> notNullValue(job, j -> j.getState() == JobState.Finished));
+				job -> JavaFXRoutines.notNullValue(job, j -> j.getState() == JobState.Finished));
 
 		menu.addItem("Explore errors", job -> job.getValue().exploreErrors(),
-				job -> notNullValue(job, j -> j.getState().equals(JobState.Failed)));
-
-		menu.addItem("Show output", j -> {
-			new JobOutputView(root, executorServiceUI, j.getValue(), SynchronizableFileType.StandardErrorFile,
-					job -> job.getSnakemakeOutput(), Constants.HAAS_UPDATE_TIMEOUT);
-			new JobOutputView(root, executorServiceUI, j.getValue(), SynchronizableFileType.StandardOutputFile,
-					job -> job.getAnotherOutput(), Constants.HAAS_UPDATE_TIMEOUT);
-		}, job -> notNullValue(job, j -> EnumSet
-				.of(JobState.Failed, JobState.Finished, JobState.Running, JobState.Canceled).contains(j.getState())));
-		menu.addItem("Open working directory", j -> open(j.getValue()), x -> notNullValue(x, j -> true));
-		menu.addItem("Update table", job -> updateJobs(), j -> true);
+				job -> JavaFXRoutines.notNullValue(job, j -> j.getState().equals(JobState.Failed)));
 
+		menu.addItem("Open working directory", j -> open(j.getValue()), x -> JavaFXRoutines.notNullValue(x, j -> true));
 	}
 
 	private void open(BenchmarkJob j) {
@@ -180,15 +162,15 @@ public class BenchmarkSPIMController extends BorderPane implements CloseableCont
 		if (manager == null) {
 			return;
 		}
+		Progress progress = showProgress
+				? ModalDialogs.doModal(new ProgressDialog(root, "Updating jobs"), WindowConstants.DO_NOTHING_ON_CLOSE)
+				: new DummyProgress();
+
 		executorServiceWS.execute(() -> {
-			Progress progress = showProgress
-					? ModalDialogs.doModal(new ProgressDialog(root, "Updating jobs"),
-							WindowConstants.DO_NOTHING_ON_CLOSE)
-					: new DummyProgress();
 
 			try {
-				Collection<BenchmarkJob> jobs = manager.getJobs();
-				//jobs.forEach(bj->bj.getStateAsync(executorServiceJobState));
+				List<BenchmarkJob> jobs = new LinkedList<>(manager.getJobs());
+				jobs.sort((bj1, bj2) -> (int) (bj1.getId() - bj2.getId()));
 				Set<ObservableValue<BenchmarkJob>> actual = new HashSet<>(this.jobs.getItems());
 				for (BenchmarkJob bj : jobs) {
 					registry.addIfAbsent(bj);
@@ -210,13 +192,13 @@ public class BenchmarkSPIMController extends BorderPane implements CloseableCont
 	}
 
 	private void initTable() {
-		registry = new ObservableBenchmarkJobRegistry(bj -> remove(bj),executorServiceJobState);
+		registry = new ObservableBenchmarkJobRegistry(bj -> remove(bj), executorServiceJobState);
 		setCellValueFactory(0, j -> j.getId() + "");
-		setCellValueFactoryCompletable(1,
-				j -> j.getStateAsync(executorServiceJobState).thenApply(state -> "" + state));
+		setCellValueFactoryCompletable(1, j -> j.getStateAsync(executorServiceJobState).thenApply(state -> "" + state));
 		setCellValueFactory(2, j -> j.getCreationTime().toString());
 		setCellValueFactory(3, j -> j.getStartTime().toString());
 		setCellValueFactory(4, j -> j.getEndTime().toString());
+		// jobs.getSortOrder().add(jobs.getColumns().get(0));
 	}
 
 	private void remove(BenchmarkJob bj) {
diff --git a/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/RemoteFileInfo.java b/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/RemoteFileInfo.java
new file mode 100644
index 0000000000000000000000000000000000000000..60d2855437c4df3f77eeb1fbbef26c17ada17c8c
--- /dev/null
+++ b/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/RemoteFileInfo.java
@@ -0,0 +1,12 @@
+package cz.it4i.fiji.haas_spim_benchmark.ui;
+
+public interface RemoteFileInfo {
+	
+	/**
+	 * 
+	 * @return size of file or -1 in case of absence
+	 */
+	Long getSize();
+	
+	String getName();
+}
diff --git a/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/RemoteFilesInfo.fxml b/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/RemoteFilesInfo.fxml
new file mode 100644
index 0000000000000000000000000000000000000000..d16c28005d7c4d5544e947867934119c805b160a
--- /dev/null
+++ b/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/RemoteFilesInfo.fxml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<?import javafx.geometry.Insets?>
+<?import javafx.scene.control.TableColumn?>
+<?import javafx.scene.control.TableView?>
+<?import javafx.scene.layout.BorderPane?>
+<?import javafx.scene.layout.HBox?>
+
+<fx:root type="BorderPane" xmlns="http://javafx.com/javafx/8.0.65" xmlns:fx="http://javafx.com/fxml/1" fx:controller="cz.it4i.fiji.haas_spim_benchmark.ui.RemoteFilesInfoControl">
+	<center>
+
+		<HBox>
+			<children>
+
+				<TableView fx:id="files" HBox.hgrow="ALWAYS">
+					<columns>
+						<TableColumn prefWidth="450.0" text="File name" />
+						<TableColumn minWidth="150.0" prefWidth="0.0" text="Size of file" />
+					</columns>
+				</TableView>
+			</children>
+			<padding>
+				<Insets bottom="1.0" left="1.0" right="1.0" top="1.0" />
+			</padding>
+		</HBox>
+	</center>
+
+</fx:root>
diff --git a/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/RemoteFilesInfoControl.java b/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/RemoteFilesInfoControl.java
new file mode 100644
index 0000000000000000000000000000000000000000..3b2f64db03ace0d8c2ca91a1833ac7e3931c2755
--- /dev/null
+++ b/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/RemoteFilesInfoControl.java
@@ -0,0 +1,62 @@
+package cz.it4i.fiji.haas_spim_benchmark.ui;
+
+import java.awt.Window;
+import java.util.List;
+import java.util.function.Function;
+
+import org.apache.commons.io.FileUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import cz.it4i.fiji.haas.ui.CloseableControl;
+import cz.it4i.fiji.haas.ui.InitiableControl;
+import cz.it4i.fiji.haas.ui.JavaFXRoutines;
+import javafx.beans.value.ObservableValue;
+import javafx.fxml.FXML;
+import javafx.scene.control.TableView;
+import javafx.scene.layout.BorderPane;
+
+public class RemoteFilesInfoControl extends BorderPane implements CloseableControl, InitiableControl {
+
+	@SuppressWarnings("unused")
+	private static Logger log = LoggerFactory
+			.getLogger(cz.it4i.fiji.haas_spim_benchmark.ui.RemoteFilesInfoControl.class);
+
+	@SuppressWarnings("unused")
+	private Window root;
+
+	@FXML
+	private TableView<ObservableValue<RemoteFileInfo>> files;
+
+	public RemoteFilesInfoControl() {
+		JavaFXRoutines.initRootAndController("RemoteFilesInfo.fxml", this);
+	}
+
+	public void setFiles(List<ObservableValue<RemoteFileInfo>> files) {
+		files.forEach(file -> this.files.getItems().add(file));
+	}
+
+	@Override
+	public void init(Window parameter) {
+		this.root = parameter;
+		initTable();
+	}
+
+	@Override
+	public void close() {
+
+	}
+
+	private void initTable() {
+		JavaFXRoutines.setCellValueFactory(files, 0, file -> file.getName());
+		JavaFXRoutines.setCellValueFactory(files, 1,
+				(Function<RemoteFileInfo, String>) file -> file.getSize() >= 0 ? formatSize(file.getSize())
+						: "Not exists");
+
+	}
+
+	private String formatSize(long size) {
+		return FileUtils.byteCountToDisplaySize(size);
+	}
+
+}
diff --git a/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/SPIMPipelineProgressView.fxml b/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/SPIMPipelineProgressView.fxml
index 294e40a69f10160d5ed436a4855a311c3d5c9a02..b765d90ce6c58696ac1be866c03b90ac93635eb3 100644
--- a/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/SPIMPipelineProgressView.fxml
+++ b/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/SPIMPipelineProgressView.fxml
@@ -1,22 +1,20 @@
 <?xml version="1.0" encoding="UTF-8"?>
 
+<?import javafx.geometry.Insets?>
 <?import javafx.scene.control.TableColumn?>
 <?import javafx.scene.control.TableView?>
 <?import javafx.scene.layout.BorderPane?>
 <?import javafx.scene.layout.HBox?>
-<?import javafx.geometry.Insets?>
 
-<fx:root type="BorderPane" xmlns="http://javafx.com/javafx/8.0.65"
-	xmlns:fx="http://javafx.com/fxml/1"
-	fx:controller="cz.it4i.fiji.haas_spim_benchmark.ui.SPIMPipelineProgressViewController">
+<fx:root type="BorderPane" xmlns="http://javafx.com/javafx/8.0.65" xmlns:fx="http://javafx.com/fxml/1" fx:controller="cz.it4i.fiji.haas_spim_benchmark.ui.SPIMPipelineProgressViewController">
 	<center>
 
 		<HBox>
 			<children>
 
-				<TableView fx:id="tasks"  HBox.hgrow="ALWAYS">
+				<TableView fx:id="tasks" stylesheets="@style.css" HBox.hgrow="ALWAYS">
 					<columns>
-						<TableColumn prefWidth="101.0" text="Task name" />
+						<TableColumn prefWidth="179.0" text="Task name" />
 					</columns>
 				</TableView>
 
diff --git a/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/SPIMPipelineProgressViewController.java b/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/SPIMPipelineProgressViewController.java
index 282ecd41623affc6ea6d6afeefe9e3f2df3bafcc..2b3de110b2065a43dbcf1581996bd65bd2bd797e 100644
--- a/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/SPIMPipelineProgressViewController.java
+++ b/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/SPIMPipelineProgressViewController.java
@@ -1,5 +1,7 @@
 package cz.it4i.fiji.haas_spim_benchmark.ui;
 
+import java.awt.Window;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -12,8 +14,16 @@ import java.util.concurrent.Executors;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 
+import javax.swing.WindowConstants;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 import cz.it4i.fiji.haas.ui.CloseableControl;
+import cz.it4i.fiji.haas.ui.InitiableControl;
 import cz.it4i.fiji.haas.ui.JavaFXRoutines;
+import cz.it4i.fiji.haas.ui.ModalDialogs;
+import cz.it4i.fiji.haas.ui.TableViewContextMenu;
 import cz.it4i.fiji.haas_java_client.JobState;
 import cz.it4i.fiji.haas_spim_benchmark.core.BenchmarkJobManager.BenchmarkJob;
 import cz.it4i.fiji.haas_spim_benchmark.core.Constants;
@@ -21,29 +31,28 @@ import cz.it4i.fiji.haas_spim_benchmark.core.FXFrameExecutorService;
 import cz.it4i.fiji.haas_spim_benchmark.core.Task;
 import cz.it4i.fiji.haas_spim_benchmark.core.TaskComputation;
 import javafx.beans.value.ObservableValue;
+import javafx.beans.value.ObservableValueBase;
 import javafx.fxml.FXML;
 import javafx.scene.control.TableColumn;
 import javafx.scene.control.TableView;
 import javafx.scene.layout.BorderPane;
 import javafx.scene.paint.Color;
 
-public class SPIMPipelineProgressViewController extends BorderPane implements CloseableControl {
+public class SPIMPipelineProgressViewController extends BorderPane implements CloseableControl, InitiableControl {
 
+	public final static Logger log = LoggerFactory
+			.getLogger(cz.it4i.fiji.haas_spim_benchmark.ui.SPIMPipelineProgressViewController.class);
+	
 	private static final String EMPTY_VALUE = "\u2007\u2007\u2007";
 
 	private static final int PREFERRED_WIDTH = 900;
 
-	protected static final String RUNNING_STATE_COMPUTATION = Color.YELLOW.toString();
-
-	protected static final String FINISHED_STATE_COMPUTATION = null;
-
-	protected static final String UNKNOWN_STATE_COMPUTATION = Color.GRAY.toString();
-
 	private static final Map<JobState, Color> taskExecutionState2Color = new HashMap<>();
 	static {
-		taskExecutionState2Color.put(JobState.Running, Color.YELLOW);
-		taskExecutionState2Color.put(JobState.Finished, Color.GREEN);
-		taskExecutionState2Color.put(JobState.Failed, Color.RED);
+		taskExecutionState2Color.put(JobState.Running, Color.rgb(0xF2, 0xD5, 0x39));
+		taskExecutionState2Color.put(JobState.Finished, Color.rgb(0x41, 0xB2, 0x80));
+		taskExecutionState2Color.put(JobState.Failed, Color.rgb(0xFF, 0x51, 0x3D));
+		taskExecutionState2Color.put(JobState.Queued, Color.rgb(0x30, 0xA2, 0xCC));
 		taskExecutionState2Color.put(JobState.Unknown, Color.GRAY);
 	}
 
@@ -70,11 +79,11 @@ public class SPIMPipelineProgressViewController extends BorderPane implements Cl
 	private ObservableTaskRegistry registry;
 	private ExecutorService executorServiceWS;
 	private Executor executorFx = new FXFrameExecutorService();
+	private Window root;
 
 	public SPIMPipelineProgressViewController() {
 		executorServiceWS = Executors.newSingleThreadExecutor();
 		init();
-
 	}
 
 	public SPIMPipelineProgressViewController(BenchmarkJob job) {
@@ -98,12 +107,54 @@ public class SPIMPipelineProgressViewController extends BorderPane implements Cl
 		executorServiceWS.shutdown();
 	}
 
+	@Override
+	public void init(Window parameter) {
+		this.root = parameter;
+	}
+
 	private void init() {
 		JavaFXRoutines.initRootAndController("SPIMPipelineProgressView.fxml", this);
 		tasks.setPrefWidth(PREFERRED_WIDTH);
 		timer = new Timer();
 		registry = new ObservableTaskRegistry(task -> tasks.getItems().remove(registry.get(task)));
+		TableViewContextMenu<ObservableValue<Task>> menu = new TableViewContextMenu<ObservableValue<Task>>(this.tasks);
+		menu.addItem("Open view", (task, columnIndex) -> proof(task, columnIndex),
+				(x, columnIndex) -> check(x, columnIndex));
+	}
+
+	private boolean check(ObservableValue<Task> x, Integer columnIndex) {
+		boolean result = x != null && 0 < columnIndex &&columnIndex - 1 < x.getValue().getComputations().size();
+		return result;
+	}
+
+	private void proof(ObservableValue<Task> task, int columnIndex) {
+		ModalDialogs.doModal(new TaskComputationWindow(root, task.getValue().getComputations().get(columnIndex - 1)),
+				WindowConstants.DISPOSE_ON_CLOSE);
+	}
+
+	static void add(Collection<ObservableValue<RemoteFileInfo>> files, String name, long size) {
+		RemoteFileInfo file = new RemoteFileInfo() {
+
+			@Override
+			public Long getSize() {
+				return size;
+			}
+
+			@Override
+			public String getName() {
+				return name;
+			}
+
+		};
+		ObservableValue<RemoteFileInfo> value = new ObservableValueBase<RemoteFileInfo>() {
+
+			@Override
+			public RemoteFileInfo getValue() {
+				return file;
+			}
+		};
 
+		files.add(value);
 	}
 
 	private void fillTable() {
@@ -162,6 +213,7 @@ public class SPIMPipelineProgressViewController extends BorderPane implements Cl
 						cell.setStyle("");
 					} else {
 						cell.setText(EMPTY_VALUE);
+						cell.getStyleClass().add("bordered-class");
 						cell.setStyle("-fx-background-color: " + getColorTaskExecState(val.getState()));
 					}
 				}));
diff --git a/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/TaskComputationAdapter.java b/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/TaskComputationAdapter.java
new file mode 100644
index 0000000000000000000000000000000000000000..40c7fa85d825b3ffe1f06f9f96ea20156bcfea8e
--- /dev/null
+++ b/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/TaskComputationAdapter.java
@@ -0,0 +1,170 @@
+package cz.it4i.fiji.haas_spim_benchmark.ui;
+
+import java.io.Closeable;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.stream.Collectors;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import cz.it4i.fiji.haas_spim_benchmark.core.Constants;
+import cz.it4i.fiji.haas_spim_benchmark.core.TaskComputation;
+import cz.it4i.fiji.haas_spim_benchmark.core.TaskComputation.Log;
+import javafx.beans.value.ObservableValue;
+import javafx.beans.value.ObservableValueBase;
+
+public class TaskComputationAdapter implements Closeable {
+
+	public final static Logger log = LoggerFactory
+			.getLogger(cz.it4i.fiji.haas_spim_benchmark.ui.TaskComputationAdapter.class);
+
+	private final TaskComputation computation;
+
+	private final List<ObservableValue<RemoteFileInfo>> outputs = new LinkedList<>();
+
+	private final List<ObservableLog> logs = new LinkedList<>();
+
+	private Timer timer;
+
+	public TaskComputationAdapter(TaskComputation computation) {
+		this.computation = computation;
+		timer = new Timer();
+	}
+
+	public void init() {
+		Map<String, Long> sizes = computation.getOutFileSizes();
+		computation.getOutputs().forEach(outputFile -> addOutputFile(outputFile, sizes.get(outputFile)));
+		computation.getLogs().forEach(log -> logs.add(new ObservableLog(log)));
+		synchronized (this) {
+			if(timer != null) {
+				timer.schedule(new P_TimerTask(), Constants.HAAS_TIMEOUT, Constants.HAAS_TIMEOUT);
+			}
+		}
+		
+	}
+
+	@Override
+	public synchronized void close() {
+		timer.cancel();
+		timer = null;
+	}
+
+	public List<ObservableValue<RemoteFileInfo>> getOutputs() {
+		return outputs;
+	}
+	
+	public List<ObservableLog> getLogs() {
+		return logs;
+	}
+
+	private void addOutputFile(String outputFile, Long size) {
+		outputs.add(new ObservableOutputFile(outputFile, size));
+	}
+
+	public static class ObservableLog  {
+	
+		private final String name;
+		
+		private  final P_ObservableString value;
+	
+		public ObservableLog(Log content) {
+			this.value = new P_ObservableString(content.getContent());
+			this.name = content.getName();
+		}
+	
+		public String getName() {
+			return name;
+		}
+		
+		public ObservableValue<String> getContent() {
+			return value;
+		}
+	
+		public void setContentValue(Log log) {
+			if (!getName().equals(log.getName())) {
+				throw new IllegalArgumentException(
+						"this.name=" + getName() + ", log.name=" + log.getName());
+			}
+			value.setValue(log.getContent());
+		}
+	
+		private class P_ObservableString extends ObservableValueBase<String> {
+	
+			private String value;
+	
+			public P_ObservableString(String value) {
+				this.value = value;
+			}
+	
+			@Override
+			public String getValue() {
+				return value;
+			}
+			
+			public void setValue(String value) {
+				if(this.value != null && !this.value.equals(value) ||
+					value != null && !value.equals(this.value)) {
+					this.value = value;
+					fireValueChangedEvent();
+				}
+			}
+		}
+		
+	}
+
+	private class ObservableOutputFile extends ObservableValueBase<RemoteFileInfo> {
+
+		private final String name;
+
+		private Long size;
+
+		private final RemoteFileInfo value = new RemoteFileInfo() {
+
+			@Override
+			public Long getSize() {
+				return size;
+			}
+
+			@Override
+			public String getName() {
+				return name;
+			}
+		};
+
+		public ObservableOutputFile(String name, Long size) {
+			this.name = name;
+			this.size = size;
+		}
+
+		@Override
+		public RemoteFileInfo getValue() {
+			return value;
+		}
+
+		public void setSize(Long newValue) {
+			Long oldValue = size;
+			size = newValue;
+			if (oldValue != newValue && oldValue != null && !oldValue.equals(newValue)) {
+				fireValueChangedEvent();
+			}
+		}
+	}
+
+	private class P_TimerTask extends TimerTask {
+
+		@Override
+		public void run() {
+			Map<String, Long> sizes = computation.getOutFileSizes();
+			Map<String, Log> logs = computation.getLogs().stream()
+					.collect(Collectors.<Log, String, Log>toMap((Log log) -> log.getName(), (Log log) -> log));
+			TaskComputationAdapter.this.logs
+					.forEach(log -> ((ObservableLog) log).setContentValue(logs.get(log.getName())));
+			outputs.forEach(value -> ((ObservableOutputFile) value).setSize(sizes.get(value.getValue().getName())));
+		}
+
+	}
+}
diff --git a/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/TaskComputationControl.java b/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/TaskComputationControl.java
new file mode 100644
index 0000000000000000000000000000000000000000..c354adf04b1badb986ea9aa9d159c1fa0bc0e27a
--- /dev/null
+++ b/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/TaskComputationControl.java
@@ -0,0 +1,87 @@
+package cz.it4i.fiji.haas_spim_benchmark.ui;
+
+import java.awt.Window;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.concurrent.Executor;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import javax.swing.WindowConstants;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import cz.it4i.fiji.haas.ui.CloseableControl;
+import cz.it4i.fiji.haas.ui.InitiableControl;
+import cz.it4i.fiji.haas.ui.JavaFXRoutines;
+import cz.it4i.fiji.haas.ui.ModalDialogs;
+import cz.it4i.fiji.haas.ui.ProgressDialog;
+import cz.it4i.fiji.haas_spim_benchmark.core.FXFrameExecutorService;
+import cz.it4i.fiji.haas_spim_benchmark.core.TaskComputation;
+import cz.it4i.fiji.haas_spim_benchmark.ui.TaskComputationAdapter.ObservableLog;
+import javafx.fxml.FXML;
+import javafx.scene.Node;
+import javafx.scene.control.Tab;
+import javafx.scene.control.TabPane;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.Priority;
+public class TaskComputationControl extends TabPane implements CloseableControl, InitiableControl {
+	public final static Logger log = LoggerFactory.getLogger(cz.it4i.fiji.haas_spim_benchmark.ui.TaskComputationControl.class);
+
+	private TaskComputationAdapter adapter;
+	
+	private Executor uiExecutor = new FXFrameExecutorService();
+	
+	private ExecutorService wsExecutorService = Executors.newSingleThreadExecutor();
+	@FXML
+	private RemoteFilesInfoControl remoteFilesInfo;
+
+	private TaskComputation computation;
+	
+	
+	public TaskComputationControl(TaskComputation computation) {
+		JavaFXRoutines.initRootAndController("TaskComputationView.fxml", this);
+		this.computation = computation;
+	}
+	
+	@Override
+	public void init(Window parameter) {
+		wsExecutorService.execute(() -> {
+			ProgressDialog dialog = ModalDialogs.doModal(new ProgressDialog(parameter, "Updating infos..."),
+					WindowConstants.DO_NOTHING_ON_CLOSE);
+			try {
+				adapter = new TaskComputationAdapter(computation);
+				adapter.init();
+			} finally {
+				dialog.done();
+			}
+			remoteFilesInfo.setFiles(adapter.getOutputs());
+			remoteFilesInfo.init(parameter);
+			Collection<Runnable> runs = new LinkedList<>();
+			for (ObservableLog log : adapter.getLogs()) {
+				LogViewControl logViewControl = new LogViewControl();
+				logViewControl.setObservable(log.getContent());
+				runs.add(() -> addTab(log.getName(), logViewControl));
+			}
+			uiExecutor.execute(() -> runs.forEach(r -> r.run()));
+		});
+	}
+
+	private void addTab(String title, Node control) {
+		Tab t = new Tab(title);
+		t.setClosable(false);
+		HBox hbox = new HBox();
+		HBox.setHgrow(control, Priority.ALWAYS);
+		hbox.getChildren().add(control);
+		t.setContent(hbox);
+		getTabs().add(t);
+	}
+	@Override
+	public void close() {
+		adapter.close();
+		wsExecutorService.shutdown();
+	}
+
+	
+}
diff --git a/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/TaskComputationView.fxml b/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/TaskComputationView.fxml
new file mode 100644
index 0000000000000000000000000000000000000000..6964bc2e111b00a7c2324beab046ac8ddc933f34
--- /dev/null
+++ b/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/TaskComputationView.fxml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<?import cz.it4i.fiji.haas_spim_benchmark.ui.RemoteFilesInfoControl?>
+<?import javafx.scene.control.Tab?>
+<?import javafx.scene.control.TabPane?>
+<?import javafx.scene.layout.AnchorPane?>
+<?import javafx.scene.layout.HBox?>
+
+
+<fx:root type="TabPane" xmlns:fx="http://javafx.com/fxml/1"
+	xmlns="http://javafx.com/javafx/8.0.65" fx:controller="cz.it4i.fiji.haas_spim_benchmark.ui.TaskComputationControl">
+	<Tab closable="false" text="Output files">
+			<content>
+				<HBox>
+					<RemoteFilesInfoControl fx:id="remoteFilesInfo"
+						HBox.hgrow="ALWAYS" />
+
+				</HBox>
+			</content>
+		</Tab>
+</fx:root>
diff --git a/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/TaskComputationWindow.java b/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/TaskComputationWindow.java
new file mode 100644
index 0000000000000000000000000000000000000000..98f8f2aed4ea8afcefc63d18b253940befd16961
--- /dev/null
+++ b/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/TaskComputationWindow.java
@@ -0,0 +1,18 @@
+package cz.it4i.fiji.haas_spim_benchmark.ui;
+
+import java.awt.Window;
+
+import cz.it4i.fiji.haas.ui.FXFrame;
+import cz.it4i.fiji.haas_spim_benchmark.core.TaskComputation;
+
+public class TaskComputationWindow extends FXFrame<TaskComputationControl> {
+
+	private static final long serialVersionUID = 1L;
+
+	public TaskComputationWindow(Window applicationFrame,TaskComputation computation) {
+		super(applicationFrame,()->new TaskComputationControl(computation));
+		
+	}
+
+	
+}
diff --git a/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/style.css b/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/style.css
new file mode 100644
index 0000000000000000000000000000000000000000..e5bc5bca424e96c7f7182f288beafcf16f52ce8a
--- /dev/null
+++ b/haas-spim-benchmark/src/main/java/cz/it4i/fiji/haas_spim_benchmark/ui/style.css
@@ -0,0 +1,7 @@
+.table-row-cell {
+	-fx-table-cell-border-color: #909090;
+}
+
+.bordered-class {
+	-fx-background-insets:1 1 1 1;
+}
\ No newline at end of file
diff --git a/haas-spim-benchmark/src/test/java/cz/it4i/fiji/haas/RunRemoteFilesView.java b/haas-spim-benchmark/src/test/java/cz/it4i/fiji/haas/RunRemoteFilesView.java
new file mode 100644
index 0000000000000000000000000000000000000000..fc6190b4024ab749e97c2a70152725f8970bf29a
--- /dev/null
+++ b/haas-spim-benchmark/src/test/java/cz/it4i/fiji/haas/RunRemoteFilesView.java
@@ -0,0 +1,54 @@
+package cz.it4i.fiji.haas;
+
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+
+import cz.it4i.fiji.haas_spim_benchmark.ui.RemoteFileInfo;
+import cz.it4i.fiji.haas_spim_benchmark.ui.RemoteFilesInfoControl;
+import javafx.beans.value.ObservableValue;
+import javafx.beans.value.ObservableValueBase;
+
+public class RunRemoteFilesView {
+
+	
+	public static void main(String[] args) {
+		List<ObservableValue<RemoteFileInfo>> files = new LinkedList<>();
+		add(files, "Some file.txt", 100025456);
+		
+		@SuppressWarnings("serial")
+		class Window extends cz.it4i.fiji.haas.ui.FXFrame<RemoteFilesInfoControl>{
+			public Window() {
+				super(()-> new RemoteFilesInfoControl());
+			}
+		}
+		
+		new Window().setVisible(true);
+	}
+	
+	static void add(Collection<ObservableValue<RemoteFileInfo>> files, String name, long size) {
+		RemoteFileInfo file = new RemoteFileInfo() {
+			
+			@Override
+			public Long getSize() {
+				return size;
+			}
+			
+			@Override
+			public String getName() {
+				return name;
+			}
+			
+		};
+		ObservableValue<RemoteFileInfo> value = new ObservableValueBase<RemoteFileInfo>() {
+
+			@Override
+			public RemoteFileInfo getValue() {
+				return file;
+			}
+		};
+		
+		files.add(value);
+	}
+
+}
diff --git a/haas-spim-benchmark/src/test/java/cz/it4i/fiji/haas/RunSPIMPipelineView.java b/haas-spim-benchmark/src/test/java/cz/it4i/fiji/haas/RunSPIMPipelineView.java
deleted file mode 100644
index c73535a5e9bfa4958469dfce131be4a0ab0295e0..0000000000000000000000000000000000000000
--- a/haas-spim-benchmark/src/test/java/cz/it4i/fiji/haas/RunSPIMPipelineView.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package cz.it4i.fiji.haas;
-
-import cz.it4i.fiji.haas.ui.FXFrameNative;
-
-public class RunSPIMPipelineView {
-
-	
-	public static void main(String[] args) {
-		class Window extends FXFrameNative<SPIMPipelineProgressViewController>{
-	
-			public Window() {
-				super(()-> new SPIMPipelineProgressViewController());
-				
-			}
-			
-		}
-		
-		new Window().setVisible(true);
-	}
-
-}
diff --git a/haas-spim-benchmark/src/test/java/cz/it4i/fiji/haas/SPIMPipelineProgressViewController.java b/haas-spim-benchmark/src/test/java/cz/it4i/fiji/haas/SPIMPipelineProgressViewController.java
deleted file mode 100644
index d3bc5de9384b8a5594ac8470049a4c738a3f5732..0000000000000000000000000000000000000000
--- a/haas-spim-benchmark/src/test/java/cz/it4i/fiji/haas/SPIMPipelineProgressViewController.java
+++ /dev/null
@@ -1,115 +0,0 @@
-package cz.it4i.fiji.haas;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.function.Function;
-
-import cz.it4i.fiji.haas.ui.CloseableControl;
-import cz.it4i.fiji.haas.ui.JavaFXRoutines;
-import cz.it4i.fiji.haas.ui.ResizeableControl;
-import cz.it4i.fiji.haas_java_client.JobState;
-import javafx.beans.value.ObservableValue;
-import javafx.beans.value.ObservableValueBase;
-import javafx.fxml.FXML;
-import javafx.scene.control.TableCell;
-import javafx.scene.control.TableColumn;
-import javafx.scene.control.TableView;
-import javafx.scene.layout.BorderPane;
-import javafx.scene.paint.Color;
-
-public class SPIMPipelineProgressViewController extends BorderPane implements CloseableControl, ResizeableControl {
-
-	protected static final String RUNNING_STATE_COMPUTATION = Color.YELLOW.toString();
-
-	protected static final String FINISHED_STATE_COMPUTATION = null;
-
-	protected static final String UNKNOWN_STATE_COMPUTATION = Color.GRAY.toString();
-
-	private final Map<JobState, Color> taskExecutionState2Color = new HashMap<>();
-	{
-		taskExecutionState2Color.put(JobState.Running, Color.YELLOW);
-		taskExecutionState2Color.put(JobState.Finished, Color.GREEN);
-		taskExecutionState2Color.put(JobState.Failed, Color.RED);
-		taskExecutionState2Color.put(JobState.Unknown, Color.GRAY);
-	}
-
-	private String getColorTaskExecState(JobState jobState) {
-		Color result = null;
-		if (jobState == null) {
-			result = Color.GRAY;
-		} else {
-			result = taskExecutionState2Color.get(jobState);
-		}
-		return toCss(result != null ? result : Color.ORANGE);
-	}
-
-	private static String toCss(Color color) {
-		return "rgb(" + Math.round(color.getRed() * 255.0) + "," + Math.round(color.getGreen() * 255.0) + ","
-				+ Math.round(color.getBlue() * 255.0) + ")";
-	}
-
-	@FXML
-	public TableView<ObservableValue<String>> tasks;
-
-	public SPIMPipelineProgressViewController() {
-		init();
-	}
-
-	public void close() {
-
-	}
-	
-	@Override
-	public void setSize(double width, double height) {
-		tasks.setPrefSize(width, height);
-	}
-
-	private void init() {
-		JavaFXRoutines.initRootAndController("SPIMPipelineProgressView.fxml", this);
-		fillTable();
-
-	}
-
-	private void fillTable() {
-
-		JavaFXRoutines.setCellValueFactory(this.tasks, 0, (Function<String, String>) v -> v);
-		for (int i = 1; i <= 91; i++) {
-			this.tasks.getColumns().add(new TableColumn<>(i + ""));
-			constructCellFactory(i);
-		}
-		for (int i = 0; i < 10; i++) {
-			tasks.getItems().add(new ObservableValueBase<String>() {
-
-				@Override
-				public String getValue() {
-					return "Value";
-				}
-
-			});
-		}
-		
-	}
-
-	@SuppressWarnings("unchecked")
-	private void constructCellFactory(int index) {
-		JavaFXRoutines.setCellValueFactory(this.tasks, index, (Function<String, String>) v -> {
-			return v;
-		});
-		((TableColumn<ObservableValue<String>, String>) this.tasks.getColumns().get(index)).setCellFactory(column -> {
-			TableCell<ObservableValue<String>, String> result = new TableCell<ObservableValue<String>, String>() {
-
-				@Override
-				protected void updateItem(String computation, boolean empty) {
-					if (computation == null || empty) {
-						setText(null);
-						setStyle("");
-					} else {
-						setText("\u2007\u2007\u2007");
-						setStyle("-fx-background-color: " + getColorTaskExecState(JobState.Finished));
-					}
-				}
-			};
-			return result;
-		});
-	}
-}
diff --git a/java-scpclient/src/main/java/cz/it4i/fiji/scpclient/ScpClient.java b/java-scpclient/src/main/java/cz/it4i/fiji/scpclient/ScpClient.java
index 49247986b3fd2a1234021e7647ea23366173ad1c..a25697caf0d88cfb3c9daa69c7429fc79710fb06 100644
--- a/java-scpclient/src/main/java/cz/it4i/fiji/scpclient/ScpClient.java
+++ b/java-scpclient/src/main/java/cz/it4i/fiji/scpclient/ScpClient.java
@@ -23,6 +23,7 @@ import com.jcraft.jsch.SftpException;
 import com.jcraft.jsch.UserInfo;
 
 public class ScpClient implements Closeable {
+	
 	private String hostName;
 	private String username;
 	private JSch jsch = new JSch();
@@ -314,6 +315,15 @@ public class ScpClient implements Closeable {
 		return null;
 	}
 
+	@Override
+	public void close() {
+		if (session != null && session.isConnected()) {
+			//log.info("disconnect");
+			session.disconnect();
+			session = null;
+		}
+	}
+
 	private int getBufferSize() {
 		return 1024 * 1024;
 	}
@@ -327,6 +337,7 @@ public class ScpClient implements Closeable {
 			session.setUserInfo(ui);
 		}
 		if (!session.isConnected()) {
+			//log.info("connect");
 			session.connect();
 		}
 		return session;
@@ -392,12 +403,4 @@ public class ScpClient implements Closeable {
 		}
 		return b;
 	}
-
-	@Override
-	public void close() {
-		if (session != null && session.isConnected()) {
-			session.disconnect();
-			session = null;
-		}
-	}
 }