Skip to content
Snippets Groups Projects
Commit 62d4ac40 authored by Petr Bainar's avatar Petr Bainar
Browse files

jobInfoRemoval: removing JobInfo class, renaming Job to BenchmarkJob

parent edd37bcf
Branches
No related tags found
1 merge request!4Job info removal
...@@ -116,6 +116,7 @@ public class Job { ...@@ -116,6 +116,7 @@ public class Job {
} }
public JobState getState() { public JobState getState() {
updateJobInfo();
return getJobInfo().getState(); return getJobInfo().getState();
} }
......
package cz.it4i.fiji.haas; package cz.it4i.fiji.haas;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Calendar;
import java.util.Collection; import java.util.Collection;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.slf4j.Logger; import org.slf4j.Logger;
...@@ -20,7 +16,6 @@ import cz.it4i.fiji.haas_java_client.HaaSClient.UploadingFile; ...@@ -20,7 +16,6 @@ import cz.it4i.fiji.haas_java_client.HaaSClient.UploadingFile;
import cz.it4i.fiji.haas_java_client.JobState; import cz.it4i.fiji.haas_java_client.JobState;
import cz.it4i.fiji.haas_java_client.Settings; import cz.it4i.fiji.haas_java_client.Settings;
import cz.it4i.fiji.haas_java_client.SynchronizableFileType; import cz.it4i.fiji.haas_java_client.SynchronizableFileType;
import javafx.beans.value.ObservableValueBase;
import net.imagej.updater.util.Progress; import net.imagej.updater.util.Progress;
public class JobManager { public class JobManager {
...@@ -41,29 +36,23 @@ public class JobManager { ...@@ -41,29 +36,23 @@ public class JobManager {
this.settings = settings; this.settings = settings;
} }
public JobInfo createJob() throws IOException { public Job createJob() throws IOException {
Job job; Job job;
if (jobs == null) { if (jobs == null) {
jobs = new LinkedList<>(); jobs = new LinkedList<>();
} }
jobs.add(job = new Job(settings.getJobName(), workDirectory, this::getHaasClient)); jobs.add(job = new Job(settings.getJobName(), workDirectory, this::getHaasClient));
return new JobInfo(job) { return job;
@Override
public JobState getState() {
job.updateInfo();
return super.getState();
}
};
} }
public JobInfo startJob(Iterable<UploadingFile> files, Progress notifier) throws IOException { public Job startJob(Iterable<UploadingFile> files, Progress notifier) throws IOException {
JobInfo result = createJob(); Job result = createJob();
result.uploadFiles(files, notifier); result.uploadFiles(files, notifier);
result.submit(); result.submit();
return result; return result;
} }
public Collection<JobInfo> getJobs() { public Collection<Job> getJobs() {
if (jobs == null) { if (jobs == null) {
jobs = new LinkedList<>(); jobs = new LinkedList<>();
try { try {
...@@ -75,7 +64,7 @@ public class JobManager { ...@@ -75,7 +64,7 @@ public class JobManager {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
return jobs.stream().map(j -> new JobInfo(j)).collect(Collectors.toList()); return jobs.stream().collect(Collectors.toList());
} }
public void downloadJob(Long id, Progress notifier) { public void downloadJob(Long id, Progress notifier) {
...@@ -114,100 +103,4 @@ public class JobManager { ...@@ -114,100 +103,4 @@ public class JobManager {
return offset; return offset;
} }
} }
public static class JobInfo extends ObservableValueBase<JobInfo> {
private Job job;
public JobInfo(Job job) {
this.job = job;
}
public void uploadFiles(Iterable<UploadingFile> files, Progress notifier) {
job.uploadFiles(files,notifier);
}
public void uploadFilesByName(Iterable<String> files, Progress notifier) {
job.uploadFilesByName(files, notifier);
}
public void submit() {
job.submit();
}
public Long getId() {
return job.getJobId();
}
public JobState getState() {
return job.getState();
}
public String getCreationTime() {
return getStringFromTimeSafely(job.getCreationTime());
}
public String getStartTime() {
return getStringFromTimeSafely(job.getStartTime());
}
public String getEndTime() {
return getStringFromTimeSafely(job.getEndTime());
}
public void downloadData(Progress notifier) {
downloadData(x -> true, notifier);
}
public void downloadData(Predicate<String> predicate, Progress notifier) {
job.download(predicate, notifier);
fireValueChangedEvent();
}
public void waitForStart() {
// TODO Auto-generated method stub
}
public void updateInfo() {
job.updateInfo();
}
@Override
public JobInfo getValue() {
return this;
}
public Path storeDataInWorkdirectory(UploadingFile uploadingFile) throws IOException {
return job.storeDataInWorkdirectory(uploadingFile);
}
public List<String> getOutput(Iterable<JobSynchronizableFile> files) {
return job.getOutput(files);
}
private String getStringFromTimeSafely(Calendar time) {
return time != null ? time.getTime().toString() : "N/A";
}
public InputStream openLocalFile(String name) throws IOException {
return job.openLocalFile(name);
}
public void setProperty(String name, String value) {
job.setProperty(name, value);
}
public String getProperty(String name) {
return job.getProperty(name);
}
public Path getDirectory() {
return job.getDirectory();
}
}
} }
...@@ -10,6 +10,7 @@ import java.nio.file.InvalidPathException; ...@@ -10,6 +10,7 @@ import java.nio.file.InvalidPathException;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.Arrays; import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection; import java.util.Collection;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
...@@ -21,8 +22,8 @@ import org.slf4j.Logger; ...@@ -21,8 +22,8 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.Yaml;
import cz.it4i.fiji.haas.Job;
import cz.it4i.fiji.haas.JobManager; import cz.it4i.fiji.haas.JobManager;
import cz.it4i.fiji.haas.JobManager.JobInfo;
import cz.it4i.fiji.haas.JobManager.JobSynchronizableFile; import cz.it4i.fiji.haas.JobManager.JobSynchronizableFile;
import cz.it4i.fiji.haas.UploadingFileFromResource; import cz.it4i.fiji.haas.UploadingFileFromResource;
import cz.it4i.fiji.haas_java_client.HaaSClient; import cz.it4i.fiji.haas_java_client.HaaSClient;
...@@ -38,90 +39,93 @@ public class BenchmarkJobManager { ...@@ -38,90 +39,93 @@ public class BenchmarkJobManager {
private static Logger log = LoggerFactory private static Logger log = LoggerFactory
.getLogger(cz.it4i.fiji.haas_spim_benchmark.core.BenchmarkJobManager.class); .getLogger(cz.it4i.fiji.haas_spim_benchmark.core.BenchmarkJobManager.class);
public final class Job extends ObservableValueBase<Job> { public final class BenchmarkJob extends ObservableValueBase<BenchmarkJob> {
private JobInfo jobInfo;
private Job job;
private JobState oldState; private JobState oldState;
public Job(JobInfo ji) { public BenchmarkJob(Job job) {
super(); super();
this.jobInfo = ji; this.job = job;
} }
public void startJob(Progress progress) throws IOException { public void startJob(Progress progress) throws IOException {
jobInfo.uploadFilesByName(Arrays.asList(Constants.CONFIG_YAML), progress); job.uploadFilesByName(Arrays.asList(Constants.CONFIG_YAML), progress);
String outputName = getOutputName(jobInfo.openLocalFile(Constants.CONFIG_YAML)); String outputName = getOutputName(job.openLocalFile(Constants.CONFIG_YAML));
jobInfo.submit(); job.submit();
jobInfo.setProperty(Constants.SPIM_OUTPUT_FILENAME_PATTERN, outputName); job.setProperty(Constants.SPIM_OUTPUT_FILENAME_PATTERN, outputName);
setDownloaded(false); setDownloaded(false);
} }
public JobState getState() { public JobState getState() {
return oldState = jobInfo.getState(); job.updateInfo();
return oldState = job.getState();
} }
public void downloadData(Progress progress) throws IOException { public void downloadData(Progress progress) throws IOException {
JobInfo ji = jobInfo; if (this.job.getState() == JobState.Finished) {
if (ji.getState() == JobState.Finished) { String filePattern = this.job.getProperty(Constants.SPIM_OUTPUT_FILENAME_PATTERN);
String filePattern = ji.getProperty(Constants.SPIM_OUTPUT_FILENAME_PATTERN); this.job.download(downloadFinishedData(filePattern), progress);
ji.downloadData(downloadFinishedData(filePattern), progress); } else if (this.job.getState() == JobState.Failed) {
} else if (ji.getState() == JobState.Failed) { this.job.download(downloadFailedData(), progress);
ji.downloadData(downloadFailedData(), progress);
} }
fireValueChangedEvent();
setDownloaded(true); setDownloaded(true);
} }
public void downloadStatistics(Progress progress) throws IOException { public void downloadStatistics(Progress progress) throws IOException {
JobInfo ji = jobInfo; this.job.download(BenchmarkJobManager.downloadStatistics(), progress);
ji.downloadData(BenchmarkJobManager.downloadStatistics(), progress); fireValueChangedEvent();
Path resultFile = ji.getDirectory().resolve(Constants.BENCHMARK_RESULT_FILE); Path resultFile = this.job.getDirectory().resolve(Constants.BENCHMARK_RESULT_FILE);
if (resultFile != null) if (resultFile != null)
BenchmarkJobManager.formatResultFile(resultFile); BenchmarkJobManager.formatResultFile(resultFile);
} }
public List<String> getOutput(List<JobSynchronizableFile> files) { public List<String> getOutput(List<JobSynchronizableFile> files) {
return jobInfo.getOutput(files); return this.job.getOutput(files);
} }
public long getId() { public long getId() {
return jobInfo.getId(); return this.job.getJobId();
} }
public String getCreationTime() { public String getCreationTime() {
return jobInfo.getCreationTime(); return getStringFromTimeSafely(this.job.getCreationTime());
} }
public String getStartTime() { public String getStartTime() {
return jobInfo.getStartTime(); return getStringFromTimeSafely(this.job.getStartTime());
} }
public String getEndTime() { public String getEndTime() {
return jobInfo.getEndTime(); return getStringFromTimeSafely(this.job.getEndTime());
}
private String getStringFromTimeSafely(Calendar time) {
return time != null ? time.getTime().toString() : "N/A";
} }
@Override @Override
public Job getValue() { public BenchmarkJob getValue() {
return this; return this;
} }
@Override @Override
public int hashCode() { public int hashCode() {
return jobInfo.getId().hashCode(); return Long.hashCode(this.job.getJobId());
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (obj instanceof Job) { if (obj instanceof BenchmarkJob) {
Job job = (Job) obj; BenchmarkJob job = (BenchmarkJob) obj;
return job.getId() == getId(); return job.getId() == getId();
} }
return false; return false;
} }
public void update(Job job) { public void update(BenchmarkJob benchmarkJob) {
jobInfo = job.jobInfo; if (benchmarkJob.job.getState() != oldState) {
if (jobInfo.getState() != oldState) {
fireValueChangedEvent(); fireValueChangedEvent();
} }
} }
...@@ -130,22 +134,22 @@ public class BenchmarkJobManager { ...@@ -130,22 +134,22 @@ public class BenchmarkJobManager {
return getDownloaded(); return getDownloaded();
} }
public Job update() { public BenchmarkJob update() {
jobInfo.updateInfo(); this.job.updateInfo();
return this; return this;
} }
public Path getDirectory() { public Path getDirectory() {
return jobInfo.getDirectory(); return this.job.getDirectory();
} }
private void setDownloaded(boolean b) { private void setDownloaded(boolean b) {
jobInfo.setProperty(JOB_HAS_DATA_TO_DOWNLOAD_PROPERTY, b + ""); this.job.setProperty(JOB_HAS_DATA_TO_DOWNLOAD_PROPERTY, b + "");
} }
private boolean getDownloaded() { private boolean getDownloaded() {
String downloadedStr = jobInfo.getProperty(JOB_HAS_DATA_TO_DOWNLOAD_PROPERTY); String downloadedStr = this.job.getProperty(JOB_HAS_DATA_TO_DOWNLOAD_PROPERTY);
return downloadedStr != null && Boolean.parseBoolean(downloadedStr); return downloadedStr != null && Boolean.parseBoolean(downloadedStr);
} }
} }
...@@ -156,13 +160,13 @@ public class BenchmarkJobManager { ...@@ -156,13 +160,13 @@ public class BenchmarkJobManager {
jobManager = new JobManager(params.workingDirectory(), constructSettingsFromParams(params)); jobManager = new JobManager(params.workingDirectory(), constructSettingsFromParams(params));
} }
public Job createJob() throws IOException { public BenchmarkJob createJob() throws IOException {
JobInfo jobInfo = jobManager.createJob(); Job job = jobManager.createJob();
jobInfo.storeDataInWorkdirectory(getUploadingFile()); job.storeDataInWorkdirectory(getUploadingFile());
return convertJob(jobInfo); return convertJob(job);
} }
public Collection<Job> getJobs() throws IOException { public Collection<BenchmarkJob> getJobs() throws IOException {
return jobManager.getJobs().stream().map(this::convertJob).collect(Collectors.toList()); return jobManager.getJobs().stream().map(this::convertJob).collect(Collectors.toList());
} }
...@@ -171,8 +175,8 @@ public class BenchmarkJobManager { ...@@ -171,8 +175,8 @@ public class BenchmarkJobManager {
return new UploadingFileFromResource("", Constants.CONFIG_YAML); return new UploadingFileFromResource("", Constants.CONFIG_YAML);
} }
private Job convertJob(JobInfo jobInfo) { private BenchmarkJob convertJob(Job job) {
return new Job(jobInfo); return new BenchmarkJob(job);
} }
private String getOutputName(InputStream openLocalFile) throws IOException { private String getOutputName(InputStream openLocalFile) throws IOException {
......
...@@ -33,7 +33,7 @@ import cz.it4i.fiji.haas.ui.ProgressDialog; ...@@ -33,7 +33,7 @@ import cz.it4i.fiji.haas.ui.ProgressDialog;
import cz.it4i.fiji.haas.ui.TableViewContextMenu; import cz.it4i.fiji.haas.ui.TableViewContextMenu;
import cz.it4i.fiji.haas_java_client.JobState; import cz.it4i.fiji.haas_java_client.JobState;
import cz.it4i.fiji.haas_spim_benchmark.core.BenchmarkJobManager; import cz.it4i.fiji.haas_spim_benchmark.core.BenchmarkJobManager;
import cz.it4i.fiji.haas_spim_benchmark.core.BenchmarkJobManager.Job; import cz.it4i.fiji.haas_spim_benchmark.core.BenchmarkJobManager.BenchmarkJob;
import cz.it4i.fiji.haas_spim_benchmark.core.Constants; import cz.it4i.fiji.haas_spim_benchmark.core.Constants;
import cz.it4i.fiji.haas_spim_benchmark.core.FXFrameExecutorService; import cz.it4i.fiji.haas_spim_benchmark.core.FXFrameExecutorService;
import javafx.fxml.FXML; import javafx.fxml.FXML;
...@@ -43,7 +43,7 @@ import net.imagej.updater.util.Progress; ...@@ -43,7 +43,7 @@ import net.imagej.updater.util.Progress;
public class BenchmarkSPIMController implements FXFrame.Controller { public class BenchmarkSPIMController implements FXFrame.Controller {
private static boolean notNullValue(Job j, Predicate<Job> pred) { private static boolean notNullValue(BenchmarkJob j, Predicate<BenchmarkJob> pred) {
if (j == null) { if (j == null) {
return false; return false;
} else { } else {
...@@ -52,7 +52,7 @@ public class BenchmarkSPIMController implements FXFrame.Controller { ...@@ -52,7 +52,7 @@ public class BenchmarkSPIMController implements FXFrame.Controller {
} }
@FXML @FXML
private TableView<Job> jobs; private TableView<BenchmarkJob> jobs;
private BenchmarkJobManager manager; private BenchmarkJobManager manager;
...@@ -97,7 +97,7 @@ public class BenchmarkSPIMController implements FXFrame.Controller { ...@@ -97,7 +97,7 @@ public class BenchmarkSPIMController implements FXFrame.Controller {
} }
private void initMenu() { private void initMenu() {
TableViewContextMenu<Job> menu = new TableViewContextMenu<>(jobs); TableViewContextMenu<BenchmarkJob> menu = new TableViewContextMenu<>(jobs);
menu.addItem("Create job", x -> executeWSCallAsync("Creating job", p -> manager.createJob()), menu.addItem("Create job", x -> executeWSCallAsync("Creating job", p -> manager.createJob()),
j -> true); j -> true);
menu.addItem("Start job", job -> executeWSCallAsync("Starting job", p -> job.startJob(p)), menu.addItem("Start job", job -> executeWSCallAsync("Starting job", p -> job.startJob(p)),
...@@ -118,7 +118,7 @@ public class BenchmarkSPIMController implements FXFrame.Controller { ...@@ -118,7 +118,7 @@ public class BenchmarkSPIMController implements FXFrame.Controller {
} }
private void open(Job j) { private void open(BenchmarkJob j) {
executorServiceUI.execute(() -> { executorServiceUI.execute(() -> {
Desktop desktop = Desktop.getDesktop(); Desktop desktop = Desktop.getDesktop();
try { try {
...@@ -174,15 +174,15 @@ public class BenchmarkSPIMController implements FXFrame.Controller { ...@@ -174,15 +174,15 @@ public class BenchmarkSPIMController implements FXFrame.Controller {
executorServiceUI.execute(() -> { executorServiceUI.execute(() -> {
Set<Job> old = new HashSet<Job>(jobs.getItems()); Set<BenchmarkJob> old = new HashSet<BenchmarkJob>(jobs.getItems());
Map<Job, Job> actual; Map<BenchmarkJob, BenchmarkJob> actual;
try { try {
actual = manager.getJobs().stream(). actual = manager.getJobs().stream().
collect(Collectors.toMap(job -> job, job -> job)); collect(Collectors.toMap(job -> job, job -> job));
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
for (Job job : old) { for (BenchmarkJob job : old) {
if (!actual.containsKey(job)) { if (!actual.containsKey(job)) {
jobs.getItems().remove(job); jobs.getItems().remove(job);
} else { } else {
...@@ -191,7 +191,7 @@ public class BenchmarkSPIMController implements FXFrame.Controller { ...@@ -191,7 +191,7 @@ public class BenchmarkSPIMController implements FXFrame.Controller {
} }
progress.done(); progress.done();
executorServiceFX.execute(() -> { executorServiceFX.execute(() -> {
for (Job job : actual.keySet()) { for (BenchmarkJob job : actual.keySet()) {
if (!old.contains(job)) { if (!old.contains(job)) {
jobs.getItems().add(job); jobs.getItems().add(job);
} }
...@@ -211,9 +211,9 @@ public class BenchmarkSPIMController implements FXFrame.Controller { ...@@ -211,9 +211,9 @@ public class BenchmarkSPIMController implements FXFrame.Controller {
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private void setCellValueFactory(int index, Function<Job, String> mapper) { private void setCellValueFactory(int index, Function<BenchmarkJob, String> mapper) {
((TableColumn<Job, String>) jobs.getColumns().get(index)) ((TableColumn<BenchmarkJob, String>) jobs.getColumns().get(index))
.setCellValueFactory(f -> new ObservableValueAdapter<Job, String>(f.getValue(), mapper)); .setCellValueFactory(f -> new ObservableValueAdapter<BenchmarkJob, String>(f.getValue(), mapper));
} }
......
...@@ -20,7 +20,7 @@ import org.slf4j.LoggerFactory; ...@@ -20,7 +20,7 @@ import org.slf4j.LoggerFactory;
import cz.it4i.fiji.haas.JobManager.JobSynchronizableFile; import cz.it4i.fiji.haas.JobManager.JobSynchronizableFile;
import cz.it4i.fiji.haas_java_client.SynchronizableFileType; import cz.it4i.fiji.haas_java_client.SynchronizableFileType;
import cz.it4i.fiji.haas_spim_benchmark.core.BenchmarkJobManager.Job; import cz.it4i.fiji.haas_spim_benchmark.core.BenchmarkJobManager.BenchmarkJob;
public class JobOutputView { public class JobOutputView {
@SuppressWarnings("unused") @SuppressWarnings("unused")
...@@ -28,11 +28,11 @@ public class JobOutputView { ...@@ -28,11 +28,11 @@ public class JobOutputView {
private Timer timer; private Timer timer;
private JDialog theDialog; private JDialog theDialog;
private JTextArea theText; private JTextArea theText;
private Job job; private BenchmarkJob job;
private ExecutorService executor; private ExecutorService executor;
private long readedChars = 0; private long readedChars = 0;
public JobOutputView(Window parent, ExecutorService executor, Job job, long refreshTimeout) { public JobOutputView(Window parent, ExecutorService executor, BenchmarkJob job, long refreshTimeout) {
this.job = job; this.job = job;
this.executor = executor; this.executor = executor;
constructFrame(parent); constructFrame(parent);
......
...@@ -14,7 +14,7 @@ import cz.it4i.fiji.haas.ui.DummyProgress; ...@@ -14,7 +14,7 @@ import cz.it4i.fiji.haas.ui.DummyProgress;
import cz.it4i.fiji.haas_java_client.JobState; import cz.it4i.fiji.haas_java_client.JobState;
import cz.it4i.fiji.haas_java_client.SynchronizableFileType; 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;
import cz.it4i.fiji.haas_spim_benchmark.core.BenchmarkJobManager.Job; import cz.it4i.fiji.haas_spim_benchmark.core.BenchmarkJobManager.BenchmarkJob;
import cz.it4i.fiji.haas_spim_benchmark.core.BenchmarkSPIMParameters; import cz.it4i.fiji.haas_spim_benchmark.core.BenchmarkSPIMParameters;
public class RunBenchmark { public class RunBenchmark {
...@@ -23,7 +23,7 @@ public class RunBenchmark { ...@@ -23,7 +23,7 @@ public class RunBenchmark {
public static class CreateJob { public static class CreateJob {
public static void main(String[] args) throws IOException { public static void main(String[] args) throws IOException {
BenchmarkJobManager benchmarkJobManager = new BenchmarkJobManager(getBenchmarkSPIMParameters()); BenchmarkJobManager benchmarkJobManager = new BenchmarkJobManager(getBenchmarkSPIMParameters());
Job ji = benchmarkJobManager.createJob(); BenchmarkJob ji = benchmarkJobManager.createJob();
log.info("job: " + ji.getId() + " created."); log.info("job: " + ji.getId() + " created.");
} }
} }
...@@ -31,7 +31,7 @@ public class RunBenchmark { ...@@ -31,7 +31,7 @@ public class RunBenchmark {
public static class ProcessJobs { public static class ProcessJobs {
public static void main(String[] args) throws IOException { public static void main(String[] args) throws IOException {
BenchmarkJobManager benchmarkJobManager = new BenchmarkJobManager(getBenchmarkSPIMParameters()); BenchmarkJobManager benchmarkJobManager = new BenchmarkJobManager(getBenchmarkSPIMParameters());
for (Job job : benchmarkJobManager.getJobs()) { for (BenchmarkJob job : benchmarkJobManager.getJobs()) {
JobState state; JobState state;
log.info("job: " + job.getId() + " hasStatus " + (state = job.getState())); log.info("job: " + job.getId() + " hasStatus " + (state = job.getState()));
if (state == JobState.Configuring) { if (state == JobState.Configuring) {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment