Index: /branches/OaaS/HeuristicLab.Services.Optimization.Controller/Azure/DAL.cs
===================================================================
--- /branches/OaaS/HeuristicLab.Services.Optimization.Controller/Azure/DAL.cs	(revision 9394)
+++ /branches/OaaS/HeuristicLab.Services.Optimization.Controller/Azure/DAL.cs	(revision 9395)
@@ -18,4 +18,5 @@
     public static readonly string EXPERIMENT_BLOB_CONTAINER = "experiment";
     public static readonly string VISUAL_BLOB_CONTAINER = "visualextensions";
+    public static readonly string JOB_TABLE = "Job";
     public static readonly string CLOUD_SETTINGS_KEY = "Cloudia.WindowsAzure.Storage";
 
@@ -311,8 +312,103 @@
 
     public string FindById(string algorithmId) {
-      CloudBlobContainer container = BlobClient.GetContainerReference(AzureConstants.VISUAL_BLOB_CONTAINER);
-      container.CreateIfNotExist();
-      var blob = container.GetBlobReference(algorithmId);
-      return blob.DownloadText();
+      try {
+        CloudBlobContainer container = BlobClient.GetContainerReference(AzureConstants.VISUAL_BLOB_CONTAINER);
+        container.CreateIfNotExist();
+        var blob = container.GetBlobReference(algorithmId);
+        return blob.DownloadText();
+      }
+      catch (Exception ex) {
+        Trace.TraceError(ex.ToString());
+        return null;
+      }
+    }
+
+
+    public bool Exists(string algorithmId) {
+      try {
+        CloudBlobContainer container = BlobClient.GetContainerReference(AzureConstants.VISUAL_BLOB_CONTAINER);
+        container.CreateIfNotExist();
+        var blob = container.GetBlobReference(algorithmId);
+        blob.FetchAttributes();
+        return true;
+      }
+      catch (StorageClientException ex) {
+        if (ex.ErrorCode == StorageErrorCode.ResourceNotFound) {
+          return false;
+        }
+        Trace.TraceError(ex.ToString());
+        return false;
+      }
+    }
+  }
+
+  internal sealed class JobEntity : TableServiceEntity {
+    public JobEntity() {
+    }
+
+    public JobEntity(string user, string experimentName, string experimentId, string jobId) {
+      PartitionKey = "JobPartition";
+      RowKey = user + "_" + jobId;
+      User = user;
+      ExperimentId = experimentId;
+      JobId = jobId;
+    }
+
+    public string ExperimentId { get; set; }
+
+    public string User { get; set; }
+
+    public string JobId { get; set; }
+  }
+
+  public class JobDao : IJobDao {
+    public IExperimentDao ExperimentDao { get; set; }
+    public CloudTableClient TableClient { get; set; }
+
+    public bool Add(string username, Experiment experiment, string jobId) {
+      try {
+        TableServiceContext serviceContext = TableClient.GetDataServiceContext();
+        TableClient.CreateTableIfNotExist(AzureConstants.JOB_TABLE);
+        serviceContext.AddObject(AzureConstants.JOB_TABLE,
+          new JobEntity(username, experiment.Name, experiment.Id, jobId)
+        );
+        serviceContext.SaveChangesWithRetries();
+        return true;
+      }
+      catch (Exception ex) {
+        Trace.TraceError(ex.ToString());
+        return false;
+      }
+    }
+
+    public bool Delete(string username, string jobId) {
+      try {
+        TableServiceContext serviceContext = TableClient.GetDataServiceContext();
+        TableClient.CreateTableIfNotExist(AzureConstants.JOB_TABLE);
+        var entity = (from e in serviceContext.CreateQuery<JobEntity>(AzureConstants.JOB_TABLE)
+                      where e.JobId == jobId && e.User == username
+                      select e).FirstOrDefault();
+        serviceContext.DeleteObject(entity);        
+        return true;
+      }
+      catch (Exception ex) {
+        Trace.TraceError(ex.ToString());
+        return false;
+      }
+    }
+
+    public Experiment FindByJobId(string username, string jobId) {
+      try {
+        TableServiceContext serviceContext = TableClient.GetDataServiceContext();
+        TableClient.CreateTableIfNotExist(AzureConstants.JOB_TABLE);
+        var entity = (from e in serviceContext.CreateQuery<JobEntity>(AzureConstants.JOB_TABLE)
+                      where e.JobId == jobId && e.User == username
+                      select e).FirstOrDefault();
+        return ExperimentDao.GetExperimentById(new User() { Username = username }, entity.ExperimentId);
+      }
+      catch (Exception ex) {
+        Trace.TraceError(ex.ToString());
+        return null;
+      }
     }
   }
@@ -323,4 +419,5 @@
     private IExperimentDao expDao;
     private IVisualExtensionDao visualDao;
+    private IJobDao jobDao;
 
     private CloudStorageAccount storageAccount;
@@ -377,4 +474,14 @@
       }
     }
+
+
+    public IJobDao JobDao {
+      get {
+        if (jobDao == null) {
+          jobDao = new JobDao() { ExperimentDao = ExperimentDao, TableClient = StorageAccount.CreateCloudTableClient() };
+        }
+        return jobDao;
+      }
+    }
   }
 }
Index: /branches/OaaS/HeuristicLab.Services.Optimization.Controller/HL/HiveScenarioManager.cs
===================================================================
--- /branches/OaaS/HeuristicLab.Services.Optimization.Controller/HL/HiveScenarioManager.cs	(revision 9394)
+++ /branches/OaaS/HeuristicLab.Services.Optimization.Controller/HL/HiveScenarioManager.cs	(revision 9395)
@@ -110,4 +110,5 @@
             IAlgorithm algo;
             mapper.MapScenario(optScen, out algo);
+            algo.Name = child.Id;
             entry.Parent.Optimizers.Add(algo);
           }  
@@ -115,5 +116,11 @@
       }
       details.JobTitle = exp.Name;
-      return SendExperimentToHive(user, hiveExperiment, details) != null;
+      var jobId = SendExperimentToHive(user, hiveExperiment, details);
+
+      // add relationship to azure tablestorage      
+      if (jobId != null) {
+        dal.JobDao.Add(user.Username, exp, jobId);
+      }
+      return jobId != null;
     }
 
@@ -214,7 +221,5 @@
       HiveServiceLocator.Instance.Password = user.Password;
       HiveServiceLocator.Instance.EndpointConfigurationName = Configuration.HiveEndpointName;
-      HiveClient.StartJob((ex) => { 
-        Console.WriteLine(ex.StackTrace); 
-      }, job, new CancellationToken());
+      HiveClient.Store(job, new CancellationToken());
       
       job.StopResultPolling();
@@ -286,4 +291,6 @@
         }
       }
+      //var experiment = dal.JobDao.FindByJobId(user.Username, id);
+
       IDictionary<Guid, HiveTask> hiveTasks = downloader.Results;
       IList<Model.Run> runs = new List<Model.Run>();
@@ -294,5 +301,11 @@
             Model.Run taskRun = new Model.Run();
             taskRun.Id = taskRun.Name = run.Name;
-            taskRun.AlgorithmName = run.Algorithm != null ? run.Algorithm.Name : run.Name;
+            // We try to extract the original algorithm name here
+            var index = taskRun.Name.LastIndexOf(" Run ");
+            var algorithName = taskRun.Name.Substring(0, index);
+            taskRun.AlgorithmName = algorithName;
+            if (taskRun.AlgorithmName == null)
+              taskRun.AlgorithmName = run.Algorithm != null ? run.Algorithm.Name : run.Name;
+            
             IList<Parameter> resultValues = new List<Model.Parameter>();
             foreach (var key in run.Results.Keys) {
@@ -617,4 +630,18 @@
       return dal.VisualExtensionDao.FindById(algorithmId);
     }
+
+
+    public bool AddVisualExtension(string algorithmId, string script) {
+      return dal.VisualExtensionDao.Add(algorithmId, script);
+    }
+
+    public bool DeleteVisualExtension(string algorithmId) {
+      return dal.VisualExtensionDao.DeleteById(algorithmId);
+    }
+
+
+    public bool ExistsVisualExtension(string algorithmId) {
+      return dal.VisualExtensionDao.Exists(algorithmId);
+    }
   }
 }
Index: /branches/OaaS/HeuristicLab.Services.Optimization.Controller/Interfaces/DAL.cs
===================================================================
--- /branches/OaaS/HeuristicLab.Services.Optimization.Controller/Interfaces/DAL.cs	(revision 9394)
+++ /branches/OaaS/HeuristicLab.Services.Optimization.Controller/Interfaces/DAL.cs	(revision 9395)
@@ -30,4 +30,10 @@
   }
 
+  public interface IJobDao {
+    bool Add(string username, Experiment experiment, string jobId);
+    bool Delete(string username, string jobId);
+    Experiment FindByJobId(string username, string jobId);
+  }
+
   public interface IBlobDao {
     bool Add(StringEntry entry);
@@ -41,4 +47,5 @@
     bool DeleteById(string algorithmId);
     string FindById(string algorithmId);
+    bool Exists(string algorithmId);
   }
 
@@ -48,4 +55,5 @@
     IExperimentDao ExperimentDao { get; }
     IVisualExtensionDao VisualExtensionDao { get; }
+    IJobDao JobDao { get; }
   }
 
Index: /branches/OaaS/HeuristicLab.Services.Optimization.Controller/Interfaces/IControllerService.cs
===================================================================
--- /branches/OaaS/HeuristicLab.Services.Optimization.Controller/Interfaces/IControllerService.cs	(revision 9394)
+++ /branches/OaaS/HeuristicLab.Services.Optimization.Controller/Interfaces/IControllerService.cs	(revision 9395)
@@ -68,5 +68,5 @@
 
     [OperationContract]
-    string GetVisualExtension(string algorithmId);
+    VisualExtension GetVisualExtension(string algorithmId);
 
     [OperationContract]
@@ -75,4 +75,7 @@
     [OperationContract]
     bool DeleteVisualExtension(string algorithmId);
+
+    [OperationContract]
+    bool ExistsVisualExtension(string algorithmId);
   }
 }
Index: /branches/OaaS/HeuristicLab.Services.Optimization.Controller/Interfaces/IScenarioManager.cs
===================================================================
--- /branches/OaaS/HeuristicLab.Services.Optimization.Controller/Interfaces/IScenarioManager.cs	(revision 9394)
+++ /branches/OaaS/HeuristicLab.Services.Optimization.Controller/Interfaces/IScenarioManager.cs	(revision 9395)
@@ -30,4 +30,10 @@
 
     string GetVisualExtension(string algorithmId);
+
+    bool AddVisualExtension(string algorithmId, string script);
+
+    bool DeleteVisualExtension(string algorithmId);
+
+    bool ExistsVisualExtension(string algorithmId);
   }
 }
Index: /branches/OaaS/HeuristicLab.Services.Optimization.Controller/Interfaces/Model/ControllerModel.cs
===================================================================
--- /branches/OaaS/HeuristicLab.Services.Optimization.Controller/Interfaces/Model/ControllerModel.cs	(revision 9394)
+++ /branches/OaaS/HeuristicLab.Services.Optimization.Controller/Interfaces/Model/ControllerModel.cs	(revision 9395)
@@ -467,5 +467,13 @@
       set { tasks = value; }
     }
-
+  }
+
+  [DataContract]
+  public class VisualExtension {
+    [DataMember]
+    public string ScenarioId { get; set; }
+
+    [DataMember]
+    public string ScenarioJs { get; set; }
   }
 
@@ -484,4 +492,5 @@
     public IList<Parameter> InputParameters { get; set; }
 
+    [DataMember]
     public string AlgorithmName { get; set; }
   }
Index: /branches/OaaS/HeuristicLab.Services.Optimization.Controller/Mockup/MockupDAL.cs
===================================================================
--- /branches/OaaS/HeuristicLab.Services.Optimization.Controller/Mockup/MockupDAL.cs	(revision 9394)
+++ /branches/OaaS/HeuristicLab.Services.Optimization.Controller/Mockup/MockupDAL.cs	(revision 9395)
@@ -258,4 +258,9 @@
       get { throw new NotImplementedException(); }
     }
+
+
+    public IJobDao JobDao {
+      get { throw new NotImplementedException(); }
+    }
   }
 }
Index: /branches/OaaS/HeuristicLab.Services.Optimization.Controller/Mockup/MockupScenarioManager.cs
===================================================================
--- /branches/OaaS/HeuristicLab.Services.Optimization.Controller/Mockup/MockupScenarioManager.cs	(revision 9394)
+++ /branches/OaaS/HeuristicLab.Services.Optimization.Controller/Mockup/MockupScenarioManager.cs	(revision 9395)
@@ -291,4 +291,18 @@
       throw new NotImplementedException();
     }
+
+
+    public bool AddVisualExtension(string algorithmId, string script) {
+      throw new NotImplementedException();
+    }
+
+    public bool DeleteVisualExtension(string algorithmId) {
+      throw new NotImplementedException();
+    }
+
+
+    public bool ExistsVisualExtension(string algorithmId) {
+      throw new NotImplementedException();
+    }
   }
 }
Index: /branches/OaaS/HeuristicLab.Services.Optimization.Controller/Parsers/AlgorithmConverter.cs
===================================================================
--- /branches/OaaS/HeuristicLab.Services.Optimization.Controller/Parsers/AlgorithmConverter.cs	(revision 9394)
+++ /branches/OaaS/HeuristicLab.Services.Optimization.Controller/Parsers/AlgorithmConverter.cs	(revision 9395)
@@ -190,5 +190,5 @@
       jrun["results"] = ConvertParametersToJson(run.Results);
       jrun["params"] = ConvertParametersToJson(run.InputParameters);
-      jrun["algorithmName"] = run.AlgorithmName;
+      jrun["algorithmName"] = run.AlgorithmName;      
       return jrun;
     }
Index: /branches/OaaS/HeuristicLab.Services.Optimization.Controller/PlaceholderControllerService.cs
===================================================================
--- /branches/OaaS/HeuristicLab.Services.Optimization.Controller/PlaceholderControllerService.cs	(revision 9394)
+++ /branches/OaaS/HeuristicLab.Services.Optimization.Controller/PlaceholderControllerService.cs	(revision 9395)
@@ -100,5 +100,5 @@
       var added = hiveManager.AddScenario(user, scenario.Id, scenarioXml, scenarioMapper);
       if (added)
-        scenarios.Add(scenario);
+        scenarios.Add(scenario);      
       return added;
     }
@@ -192,17 +192,20 @@
 
 
-    public string GetVisualExtension(string algorithmId) {
-      return hiveManager.GetVisualExtension(algorithmId);
+    public VisualExtension GetVisualExtension(string algorithmId) {
+      return new VisualExtension() { ScenarioId = algorithmId, ScenarioJs = hiveManager.GetVisualExtension(algorithmId) };
     }
 
 
     public bool AddVisualExtension(string algorithmId, string script) {
-      //return hiveManager.AddVisualExtension(algorithmId, script);
-      return true;
+      return hiveManager.AddVisualExtension(algorithmId, script);
     }
 
     public bool DeleteVisualExtension(string algorithmId) {
-      //return hiveManager.DeleteVisualExtension(algorithmId);
-      return true;
+      return hiveManager.DeleteVisualExtension(algorithmId);
+    }
+
+
+    public bool ExistsVisualExtension(string algorithmId) {
+      return hiveManager.ExistsVisualExtension(algorithmId);
     }
   }
Index: /branches/OaaS/HeuristicLab.Services.Optimization.Web/Content/job.controller.js
===================================================================
--- /branches/OaaS/HeuristicLab.Services.Optimization.Web/Content/job.controller.js	(revision 9394)
+++ /branches/OaaS/HeuristicLab.Services.Optimization.Web/Content/job.controller.js	(revision 9395)
@@ -1,3 +1,19 @@
 ﻿var OAAS_CONTROLLER = (function (my, Backbone, OAAS_VIEW, OAAS_MODEL, _, $) {
+    my.JobVisualExtensionListener = function (model, element) {
+        var extension = new OAAS_MODEL.VisualExtension({ id: model.get('algorithmName') });
+        extension.fetch({ cache: true, success: function () {
+            //eval extension.js -> execute addVisualExtension(model, element): 
+            var js = extension.get('ScenarioJs');
+            if (js != null) {
+                (function (model, element) {
+                    addExtension = undefined;
+                    eval(js);
+                    if (addExtension)
+                        addExtension(model, element);
+                } (model, element));
+            }
+        }
+        });
+    },
     my.JobPageController = function () {
         this.create = function () {
@@ -23,4 +39,5 @@
                     var div = $('<div/>').appendTo($('#jobDetails'));
                     var rv = new OAAS_VIEW.ResultView({ model: runList, el: div });
+                    listener.listenTo(rv, 'renderVisualExtension', my.JobVisualExtensionListener);
                     rv.render();
                     var av = new OAAS_VIEW.AccordionView({ el: div });
@@ -30,4 +47,6 @@
             });
 
+
+
             jobList.poll();
         }
Index: /branches/OaaS/HeuristicLab.Services.Optimization.Web/Content/job.model.js
===================================================================
--- /branches/OaaS/HeuristicLab.Services.Optimization.Web/Content/job.model.js	(revision 9394)
+++ /branches/OaaS/HeuristicLab.Services.Optimization.Web/Content/job.model.js	(revision 9395)
@@ -77,4 +77,14 @@
     });
 
+    my.VisualExtension = Backbone.Model.extend({
+        defaults: {
+            id: null,
+            js: null
+        },
+        url: function () {
+            return '/Job/VisualExtension?scenarioId=' + this.get('id');
+        }
+    });
+
     return my;
 } (OAAS_MODEL || {}, Backbone));
Index: /branches/OaaS/HeuristicLab.Services.Optimization.Web/Content/job.view.js
===================================================================
--- /branches/OaaS/HeuristicLab.Services.Optimization.Web/Content/job.view.js	(revision 9394)
+++ /branches/OaaS/HeuristicLab.Services.Optimization.Web/Content/job.view.js	(revision 9395)
@@ -90,6 +90,11 @@
                 $('<h3></h3>').text(this.model.models[i].get('name')).appendTo(this.$el);
                 var rev = new my.ResultEntryView({ model: this.model.models[i], el: this.$el });
-                rev.render();
-            }
+                this.listenTo(rev, 'renderVisualExtension', this.renderVisualExtension);
+                rev.render();                          
+            }            
+        },
+        renderVisualExtension: function(model, element) {
+            // propagate to client listener
+            this.trigger('renderVisualExtension', model, element);
         }
     });
@@ -161,6 +166,8 @@
             var results = this.model.get('results');
             for (var i = 0; i < results.length; i++) {
-                this.renderModelEntry(results[i], i, body, 'results');
-            }
+                this.renderModelEntry(results[i], i, body, 'results');                
+            }
+            // get the visual extension, execute it!
+            this.trigger('renderVisualExtension', this.model, body);
 
             var inputs = this.model.get('params');
Index: /branches/OaaS/HeuristicLab.Services.Optimization.Web/Controllers/AdminController.cs
===================================================================
--- /branches/OaaS/HeuristicLab.Services.Optimization.Web/Controllers/AdminController.cs	(revision 9394)
+++ /branches/OaaS/HeuristicLab.Services.Optimization.Web/Controllers/AdminController.cs	(revision 9395)
@@ -34,7 +34,12 @@
         public ActionResult Index()
         {
-          var names = ControllerService.withControllerService<IEnumerable<string>>((service) => {            
+          var names = ControllerService.withControllerService<IEnumerable<ScenarioModel>>((service) => {            
             User u = new User() { Username = Membership.GetUser().UserName, Password = Session["pw"] as string };
-            return service.GetOptimizationScenarioNames();
+            var scenModel = new List<ScenarioModel>();
+            var scenarios = service.GetOptimizationScenarioNames();
+            foreach (var scenario in scenarios) {
+              scenModel.Add(new ScenarioModel() { Exists = service.ExistsVisualExtension(scenario), Scenario = scenario });              
+            }
+            return scenModel;
           });
           return View(names);
@@ -65,4 +70,27 @@
         }
 
+        [HttpPost]
+        public ActionResult AddVisualExtension(UploadVisualExtension extension) {          
+          StreamReader reader = new StreamReader(extension.ScenarioJs.InputStream);
+          string scenarioJs = reader.ReadToEnd();
+
+          var ok = ControllerService.withControllerService<bool>((service) => {
+            OptimizationModel model = new OptimizationModel();
+            User u = new User() { Username = Membership.GetUser().UserName, Password = Session["pw"] as string };
+            return service.AddVisualExtension(extension.ScenarioId, scenarioJs);
+          });
+          return RedirectToAction("Index");
+        }
+
+        [HttpPost]
+        public ActionResult DeleteVisualExtension(UploadVisualExtension extension) {
+          var ok = ControllerService.withControllerService<bool>((service) => {
+            OptimizationModel model = new OptimizationModel();
+            User u = new User() { Username = Membership.GetUser().UserName, Password = Session["pw"] as string };
+            return service.DeleteVisualExtension(extension.ScenarioId);
+          });
+          return RedirectToAction("Index");
+        }
+
         public ActionResult DeleteScenario(string id) {
           ControllerService.withControllerService<bool>((service) => {            
Index: /branches/OaaS/HeuristicLab.Services.Optimization.Web/Controllers/JobController.cs
===================================================================
--- /branches/OaaS/HeuristicLab.Services.Optimization.Web/Controllers/JobController.cs	(revision 9394)
+++ /branches/OaaS/HeuristicLab.Services.Optimization.Web/Controllers/JobController.cs	(revision 9395)
@@ -59,10 +59,10 @@
 
       [HttpGet]
-      public ActionResult VisualExtension(string algorithmId) {
-        var script = ControllerService.withControllerService<string>((service) => {
+      public JsonResult VisualExtension(string scenarioId) {
+        var extension = ControllerService.withControllerService<VisualExtension>((service) => {
           User u = new User() { Username = Membership.GetUser().UserName, Password = Session["pw"] as string };
-          return service.GetVisualExtension(algorithmId);
+          return service.GetVisualExtension(scenarioId);
         });
-        return Content(script, "text/javascript", System.Text.Encoding.UTF8);
+        return Json(extension, JsonRequestBehavior.AllowGet);
       }
     }
Index: /branches/OaaS/HeuristicLab.Services.Optimization.Web/Mappings/tsp.js
===================================================================
--- /branches/OaaS/HeuristicLab.Services.Optimization.Web/Mappings/tsp.js	(revision 9395)
+++ /branches/OaaS/HeuristicLab.Services.Optimization.Web/Mappings/tsp.js	(revision 9395)
@@ -0,0 +1,88 @@
+/*
+ * Model ... the domain model
+ * Element ... the table to add new elements to
+ */
+function addExtension(model, element) {
+  /* Specify the name of your row entry */
+  var name = 'TSP Solution';
+
+  /* Create the content of your row by using the model */
+  var content = $('<div/>');  
+
+  // look up coordinates for TSP
+  var coords = [];
+  
+  coords = _.find(model.get('results'), function(elem) {
+    return elem.Name == "Best TSP Solution";
+  }).Value;
+   
+  // draw TSP
+  var canvasWidth = 400;
+  var canvasHeight = 400;
+  var radius = 6;
+  var canvas = $('<canvas/>').prop({
+      width: canvasWidth,
+      height: canvasHeight
+  }).appendTo(content);
+
+  var ctx = undefined;
+  if (canvas[0].getContext == undefined) {
+    ctx = G_vmlCanvasManager.initElement(canvas[0]).getContext("2d");
+  } else {
+    ctx = canvas[0].getContext("2d");
+  }
+  ctx.fillStyle = "#FFFFFF";    
+  ctx.fillRect(0, 0, canvasWidth, canvasHeight);
+  ctx.fillStyle = "#000000";
+  if (coords && coords.length > 0) {
+      // determine max/min boundings
+    var xMin = Number.MAX_VALUE;
+    var xMax = Number.MIN_VALUE;
+    var yMin = Number.MAX_VALUE;
+    var yMax = Number.MIN_VALUE;
+    for (var i = 0; i < coords.length; i++) {
+      if (xMin > coords[i][0]) xMin = coords[i][0];
+      if (yMin > coords[i][1]) yMin = coords[i][1];
+      if (xMax < coords[i][0]) xMax = coords[i][0];
+      if (yMax < coords[i][1]) yMax = coords[i][1];
+    }
+
+    var border = 20;
+    var xStep = 1;
+    if (xMax != xMin) xStep = (canvasWidth - 2 * border) / (xMax - xMin);
+    var yStep = 1;
+    if (yMax != yMin) yStep = (canvasHeight - 2 * border) / (yMax - yMin);
+
+    ctx.beginPath();
+    var x = Math.round(border + (coords[0][0] - xMin) * xStep);
+    var y = Math.round(canvasHeight - (border + (coords[0][1] - yMin) * yStep));
+    ctx.moveTo(x, y);
+    for (var i = 1; i < coords.length + 1; i++) {
+      var x = Math.round(border + (coords[i % coords.length][0] - xMin) * xStep);
+      var y = Math.round(canvasHeight - (border + (coords[i % coords.length][1] - yMin) * yStep));
+      ctx.lineTo(x, y);
+    }
+    ctx.closePath();
+    ctx.stroke();
+    for (var i = 0; i < coords.length + 1; i++) {
+      var x = Math.round(border + (coords[i % coords.length][0] - xMin) * xStep);
+      var y = Math.round(canvasHeight - (border + (coords[i % coords.length][1] - yMin) * yStep));
+      ctx.beginPath();
+      ctx.arc(x, y, radius, 0, 2 * Math.PI);
+      ctx.closePath();
+      ctx.fill();
+    }
+  } else {
+    ctx.font = "20px Arial";
+    var txt = "No coordinates defined or in wrong format.";
+    var w = ctx.measureText(txt).width;
+    ctx.fillText("No coordinates defined or in wrong format.", (canvasWidth - w) / 2, (canvasHeight - 20) / 2);
+  }
+
+  /* Creates a new row and adds it to element */
+  var row = $('<tr/>');
+  var nameTd = $('<td/>').text(name).appendTo(row);
+  var contentTd = $('<td/>').appendTo(row);
+  content.appendTo(contentTd);
+  row.appendTo(element);
+}
Index: /branches/OaaS/HeuristicLab.Services.Optimization.Web/Models/AdminModels.cs
===================================================================
--- /branches/OaaS/HeuristicLab.Services.Optimization.Web/Models/AdminModels.cs	(revision 9394)
+++ /branches/OaaS/HeuristicLab.Services.Optimization.Web/Models/AdminModels.cs	(revision 9395)
@@ -29,4 +29,27 @@
       set { scenarioJs = value; }
     }
+  }
+
+  public class ScenarioModel {
+    public string Scenario { get; set; }
+    public bool Exists { get; set; }
+  }
+
+  public class UploadVisualExtension {
+
+    private string scenarioId;
+
+    public string ScenarioId {
+      get { return scenarioId; }
+      set { scenarioId = value; }
+    }
+
+
+    private HttpPostedFileBase scenarioJs;
+
+    public HttpPostedFileBase ScenarioJs {
+      get { return scenarioJs; }
+      set { scenarioJs = value; }
+    }
 
   }
Index: /branches/OaaS/HeuristicLab.Services.Optimization.Web/Views/Admin/Index.cshtml
===================================================================
--- /branches/OaaS/HeuristicLab.Services.Optimization.Web/Views/Admin/Index.cshtml	(revision 9394)
+++ /branches/OaaS/HeuristicLab.Services.Optimization.Web/Views/Admin/Index.cshtml	(revision 9395)
@@ -1,3 +1,3 @@
-﻿@model IEnumerable<string>
+﻿@model IEnumerable<HeuristicLab.Services.Optimization.Web.Models.ScenarioModel>
 
 @{
@@ -11,8 +11,6 @@
     <label for="scenarioMapper">Scenario Mapper</label>
     <input type="file" name="scenarioMapper" id="scenarioMapper" />
-    <label for="scenarioMapper">Scenario XML</label>
+    <label for="scenarioXml">Scenario XML</label>
     <input type="file" name="scenarioXml" id="scenarioXml" />
-    <label for="scenarioMapper">Visual extension (JavaScript) for Scenario</label>
-    <input type="file" name="scenarioJs" id="scenarioJs" />
     <input type="submit" value="Upload scenario" />    
   </fieldset>
@@ -31,9 +29,9 @@
       @foreach (var scen in Model) {
         <tr>
-          <td>@scen</td>
+          <td>@scen.Scenario</td>
           <td>
-             <input type="hidden" value="@scen" name="id" />
+             <input type="hidden" value="@scen.Scenario" name="id" />
              <input type="submit" value="Delete" />       
-          </td>          
+          </td>
        </tr>
       }
@@ -42,3 +40,30 @@
 }
 
+<h2>Visual extensions:</h2>
+@using (Html.BeginForm("DeleteVisualExtension", "Admin", FormMethod.Post, new { enctype = "multipart/form-data" })) {
+  <fieldset>    
+    <label for="scenarioId">Scenario</label>
+    <select name="scenarioId">
+        @foreach (var scen in Model) {
+            if (scen.Exists) {
+                <option>@scen.Scenario</option>
+            }
+        }
+    </select>
+    <input type="submit" value="Delete visual extension" />    
+  </fieldset>
+}
 
+@using (Html.BeginForm("AddVisualExtension", "Admin", FormMethod.Post, new { enctype = "multipart/form-data" })) {
+  <fieldset>    
+    <label for="scenarioId">Scenario</label>
+    <select name="scenarioId">
+        @foreach (var scen in Model) {
+            <option>@scen.Scenario</option>
+        }
+    </select>
+    <label for="scenarioJs">Visual extension (JavaScript) for Scenario</label>
+    <input type="file" name="scenarioJs" id="scenarioJs" />
+    <input type="submit" value="Upload visual extension" />    
+  </fieldset>
+}
