diff --git a/kadmos/vistoms/templates/VISTOMS.html b/kadmos/vistoms/templates/VISTOMS.html
index c6b1e9f9aca60a4180111476a119a0a1649bc753..d414490cdfd3c52cb47c3044d1c6443ea8912e27 100644
--- a/kadmos/vistoms/templates/VISTOMS.html
+++ b/kadmos/vistoms/templates/VISTOMS.html
@@ -655,7 +655,7 @@
                     $('#addForm').on('submit',function(event){
                         event.preventDefault();
                         //aigner: Uploading files for KADMOS
-                        formData = new FormData($('form')[0]);
+                        var formData = new FormData($('#addForm')[0]);
                         formData.append('newGraphID', newGraphID);
                         formData.append('fileType',selectValue)
                        
@@ -20961,6 +20961,161 @@
                 //####################################################################################################################
                 
                 
+                //aigner: Upload custom KADMOS script
+                //HIER WEITER!!
+                //####################################################################################################################
+                var uploadCustomScript_ul = optionsDiv.append("ul")
+				var uploadCustomScript_li = uploadCustomScript_ul.append("li")
+                    .on("mouseover", function(){
+                        d3.select(this)
+                            .style("cursor", "pointer")
+                    })
+                    .on("mousedown", function(){
+                            bootbox.dialog({
+                                title: "Upload custom script",
+                                message: "<button id='downloadBtn' class='btn btn-primary'><i class='glyphicon glyphicon-download-alt '></i> Download template script</button>"
+                                        +"<form style='margin-top:20px;' id='scriptForm' method='post' enctype='multipart/form-data'>" 
+                                        +"<label>"
+                                        +"<text>Upload script file:</text>"
+                                        +"<input type='file' name='file[]' />"
+                                        +"<input type='submit' value='Submit'/>"
+                                        +"</label></form>",
+                                buttons : 
+                                { 
+                                    cancel: {
+                                        label: "Cancel",
+                                        className: 'btn-danger'
+                                    }
+                                }                                
+                            });
+                            
+                            //aigner: template for custom script that user can download
+                            $('#downloadBtn').on("mousedown", function(){
+                                    var script_template = "import sys\n\n"
+                                    +"from kadmos.graph import *\n\n\n"
+                                    +"def script(graph, mpg):\n"
+                                    +"    \"\"\"\n"
+                                    +"    Script to include manual operations in the KADMOS integration in VISTOMS\n\n"
+                                    +"    :param graph: Any kadmos graph\n"
+                                    +"    :param mpg: A corresponding MDO process graph\n"
+                                    +"    :return: graph, mpg\n"
+                                    +"    \"\"\"\n"
+                                    +"    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #\n"
+                                    +"    #                                       ADD YOUR SCRIPT BELOW THIS LINE                                           #\n"
+                                    +"    # Example script:\n"
+                                    +"    # graph.remove_node('node_ID')\n"
+                                    +"    # graph.remove_edge('node_ID1', 'node_ID2')\n"
+                                    +"    #                                          END SCRIPT ABOVE THIS LINE                                             #\n"
+                                    +"    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #\n"
+                                    +"    return graph, mpg\n"
+
+                                    download('script_template.py',script_template);
+                            })
+                            //upload of custom script
+                            $('#scriptForm').on('submit',function(event){
+                                event.preventDefault();
+                                var formData = new FormData($('#scriptForm')[0]);
+                                formData.append('graphID', graphID);
+                               
+                                if (typeof currentGraph.xdsm.workflow !== 'undefined' && currentGraph.xdsm.workflow.length > 0) 
+                                {
+                                    // the array is defined and has at least one element
+                                    upload_custom_script()
+                                }
+                                else
+                                {
+                                    upload_custom_script()
+                                }
+                                
+                                function upload_custom_script()
+                                {
+                                    var bootboxContent = {title: "Upload custom KADMOS script", message: '<p>Please be patient...</p>'};
+                                    var xhr = $.ajax({
+                                        type: 'POST',
+                                        url: '/kadmosRunCustomScript',
+                                        data: formData,
+                                        processData: false,
+                                        contentType: false,
+                                        success: function(result)
+                                        {
+                                            if (result.includes("ERROR:"))
+                                            {
+                                                bootboxContent.message = result
+                                                kadmosErrorMessage(bootboxContent);
+                                            }
+                                            else
+                                            {
+                                                var updatedData = {};
+                                                updatedData = data;
+                                                var graphData = JSON.parse(result);             
+                                                for (var i = 0; i < updatedData.graphs.length; i++)
+                                                {
+                                                    if (graphID == updatedData.graphs[i].id)
+                                                    {
+                                                        updatedData.graphs[i] = graphData.graphs[0];   
+                                                    }
+                                                }
+                                                                                                                
+                                                clearView();
+                                                makeKadmosMenu(updatedData);
+                                                xdsm_script(updatedData,graphID);
+                                                
+                                                bootboxContent.message = "Success!"
+                                                kadmosSuccessMessage(bootboxContent)
+                                            }
+                                        },
+                                        error: function(result)
+                                        {
+                                            bootboxContent.message = result
+                                            kadmosErrorMessage(bootboxContent);
+                                        }
+                                    });
+                                    kadmosHavePatience(xhr, bootboxContent)
+                                }
+                            });
+                    })
+                    
+                uploadCustomScript_li.append("a").text("Upload Custom Script")
+                //####################################################################################################################
+                
+				
+				//aigner: Data Model Tree View Button
+				//####################################################################################################################
+				var dataModelDiv = d3.select(".xdsmDiv").append("div").attr("class","dataModelDiv").attr("transform","translate(10,0)")
+				var ul = dataModelDiv.append("ul")
+				var dropdown1 = ul.append("li").on("mouseover", function(){d3.select(this).style("cursor", "default")})
+				dropdown1.append("img").attr("src",fileReference.AGILE_Icon)
+					.attr("align","left")
+					.style("margin-left","6px")
+					.style("margin-right","-10px")
+					.style("margin-top","10px")
+					.style("margin-bottom","0px")
+					.attr("height","20")
+					.attr("width","20")
+				dropdown1.append("a").text("Data Model Tree")
+				var links = dropdown1.append("ul");
+                var xOffset_ul = dropdown1._groups[0][0].offsetLeft+dropdown1._groups[0][0].offsetWidth-40;
+                links.style("left", String(xOffset_ul)+"px")
+				for (var j=0; j< varCategories.length; j++)
+				{
+					//console.log(varCategories[j])
+					var linkLi = links.append("li");
+					var linkA = linkLi.append("a")
+						.attr("id",j)
+						.text(varCategories[j].description)
+						.on("mouseover", function(){d3.select(this).style("cursor", "pointer")})
+						.on("click", function()
+						{		
+							showFullTree(varCategories[this.id].name,varCategories[this.id].description)
+						})
+				}
+				//aigner: Set width of the div, so the VISTOMS dropdown (in the top of the page) still works
+				//dataModelDiv.style("width", String(dropdown1.node().getBoundingClientRect().width+20)+"px")
+				//####################################################################################################################
+                
+                //aigner: Data Model List View Button
+				//####################################################################################################################
+				//aigner: Function, that shows a list of elements
                 function showList(aTitle,aList,aMenu)
                 {
                     if (aList.length != 0)
@@ -21004,44 +21159,7 @@
                     }
                 }
                 
-				
-				//aigner: Data Model Tree View Button
-				//####################################################################################################################
-				var dataModelDiv = d3.select(".xdsmDiv").append("div").attr("class","dataModelDiv").attr("transform","translate(10,0)")
-				var ul = dataModelDiv.append("ul")
-				var dropdown1 = ul.append("li").on("mouseover", function(){d3.select(this).style("cursor", "default")})
-				dropdown1.append("img").attr("src",fileReference.AGILE_Icon)
-					.attr("align","left")
-					.style("margin-left","6px")
-					.style("margin-right","-10px")
-					.style("margin-top","10px")
-					.style("margin-bottom","0px")
-					.attr("height","20")
-					.attr("width","20")
-				dropdown1.append("a").text("Data Model Tree")
-				var links = dropdown1.append("ul");
-                var xOffset_ul = dropdown1._groups[0][0].offsetLeft+dropdown1._groups[0][0].offsetWidth-40;
-                links.style("left", String(xOffset_ul)+"px")
-				for (var j=0; j< varCategories.length; j++)
-				{
-					//console.log(varCategories[j])
-					var linkLi = links.append("li");
-					var linkA = linkLi.append("a")
-						.attr("id",j)
-						.text(varCategories[j].description)
-						.on("mouseover", function(){d3.select(this).style("cursor", "pointer")})
-						.on("click", function()
-						{		
-							showFullTree(varCategories[this.id].name,varCategories[this.id].description)
-						})
-				}
-				//aigner: Set width of the div, so the VISTOMS dropdown (in the top of the page) still works
-				//dataModelDiv.style("width", String(dropdown1.node().getBoundingClientRect().width+20)+"px")
-				//####################################################################################################################
-                
-                //aigner: Data Model List View Button
-				//####################################################################################################################
-				var ul_list = dataModelDiv.append("ul")
+                var ul_list = dataModelDiv.append("ul")
 				var dropdownList = ul_list.append("li").on("mouseover", function(){d3.select(this).style("cursor", "default")})
 				dropdownList.append("img").attr("src",fileReference.AGILE_Icon)
 					.attr("align","left")
@@ -21913,10 +22031,6 @@
                             
                             $('form').on('submit',function(event){
                                 event.preventDefault();
-                                
-                                var formData = new FormData($('form')[0]);
-                                formData.append('graphID', graphID);
-                                
                             });
                         
                         
diff --git a/kadmos/vistoms/vistoms.py b/kadmos/vistoms/vistoms.py
index 7b3d1160175cc87758811884a53eef91224a9b78..e23622ccecc0acaeb65c2054c250211b2dc79e4a 100644
--- a/kadmos/vistoms/vistoms.py
+++ b/kadmos/vistoms/vistoms.py
@@ -618,6 +618,70 @@ def kadmosL3Check():
         # Logs the error appropriately.
 ########################################################################################################################
 
+# Upload custom kadmos script
+########################################################################################################################
+@app.route('/kadmosRunCustomScript', methods=['POST'])
+def kadmosRunCustomScript():
+    """
+        Generic function to import and execute a custom kadmos script
+
+        :param script_file: the custom kadmos script
+        :param graph: the kadmos graph, on which the changes are performed
+        :return: newVistomsData: Merged string of the vistoms data and the script string value
+    """
+    try:
+        # Get request form
+        graphID = request.form['graphID']
+        uploaded_files = request.files.getlist("file[]")
+
+        script_file = []
+        for aFile in uploaded_files:
+            file_type = aFile.filename.rsplit('.', 1)[1].lower()
+            if not file_type == "py":
+                return "ERROR: wrong file type \"" + file_type + "\""
+            script_file = aFile
+
+        # Save previous graph as backup before making the changes
+        savePreviousGraph(graphID)
+
+        path = UPLOAD_FOLDER
+        graphFileName = TEMP_FILE + '_' + graphID + '.kdms'
+        mpgFileName = TEMP_FILE + '_' + graphID + '_mpg.kdms'
+        if os.path.exists(os.path.join(path, mpgFileName)):
+            graph = load(os.path.join(path, graphFileName), file_check_critical=False)
+            mpg = load(os.path.join(path, mpgFileName), file_check_critical=False)
+        else:
+            graph = load(os.path.join(path, graphFileName), file_check_critical=False)
+            mpg = None
+
+        # save kadmos script in temp folder
+        script_file.save(os.path.join(UPLOAD_FOLDER, script_file.filename))
+        kadmos_file_path = os.path.join(UPLOAD_FOLDER, script_file.filename)
+
+        # execute script and return graph data (graph, mpg)
+        import imp
+        script_module = imp.load_source('kadmos_custom_fun_{}', kadmos_file_path)
+        graph, mpg = script_module.script(graph, mpg)
+
+        # Get function order for VISTOMS in case of FPG
+        function_order = None
+        if mpg == None:
+            # Get function_oder of the graph after the script has done the manipulations
+            if graph.graph_has_nested_attributes('problem_formulation', 'function_order'):
+                function_order = graph.graph['problem_formulation']['function_order']
+
+        # Add modified graph to VISTOMS
+        newVistomsData = graph.vistoms_add_json(function_order=function_order, graph_id=graphID, mpg=mpg)
+        # Save the graph in temp/tmp.kdms
+        graph.save(os.path.join(UPLOAD_FOLDER, TEMP_FILE + '_' + graphID + '.kdms'), file_type='kdms',
+                   graph_check_critical=False, mpg=mpg)
+        return newVistomsData
+
+    except Exception as e:
+        return "ERROR: " + e.message
+        # Logs the error appropriately.
+########################################################################################################################
+
 
 # FPG manipulation functions
 ########################################################################################################################
@@ -748,9 +812,11 @@ def kadmosDeleteNode():
             # update function order
             function_order.remove(nodeName)
 
-
             # Add the graph with the updated function order to VISTOMS
             newVistomsData = graph.vistoms_add_json(function_order=function_order, graph_id=graphID, mpg=mpg)
+            # Use function order for VISTOMS if it is available in the graph information
+            if graph.graph_has_nested_attributes('problem_formulation', 'function_order') and mpg == None:
+                graph.graph['problem_formulation']['function_order'] = function_order
             # Save the graph in temp/tmp.kdms
             graph.save(os.path.join(UPLOAD_FOLDER, TEMP_FILE+'_'+graphID+'.kdms'), file_type='kdms', graph_check_critical=False, mpg=mpg)