From 39a7ffc9c57cd91e2b777650f55f4e4d0dea5d0a Mon Sep 17 00:00:00 2001
From: Estók Dániel <estok.daniel@cloud.bme.hu>
Date: Thu, 5 May 2016 13:02:15 +0200
Subject: [PATCH] setty: added server-side access management.

---
 circle/setty/static/setty/setty.js      | 1590 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 circle/setty/templates/setty/index.html |    6 +++---
 circle/setty/views.py                   |  195 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------------------------------------------------------------
 3 files changed, 897 insertions(+), 894 deletions(-)

diff --git a/circle/setty/static/setty/setty.js b/circle/setty/static/setty/setty.js
index 15ef66a..2e01e65 100644
--- a/circle/setty/static/setty/setty.js
+++ b/circle/setty/static/setty/setty.js
@@ -1,809 +1,781 @@
-/* Settimng up csrf token, touch event and zoom options. */
-
-function getCookie(name) {
-    var cookieValue = null;
-    if (document.cookie && document.cookie !== '') {
-        var cookies = document.cookie.split(';');
-        for (var i = 0; i < cookies.length; i++) {
-            var cookie = jQuery.trim(cookies[i]);
-            if (cookie.substring(0, name.length + 1) == (name + '=')) {
-                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
-                break;
-            }
-        }
-    }
-    return cookieValue;
-}
-
-function csrfSafeMethod(method) {
-    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
-}
-
-var csrftoken = getCookie('csrftoken');
-
-$.ajaxSetup({
-    beforeSend: function(xhr, settings) {
-        if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
-            xhr.setRequestHeader("X-CSRFToken", csrftoken);
-        }
-    }
-});
-
-
-/* Setty implementation starts here. */
-
-jsPlumb.ready(function() {
-    var jsPlumbInstance = jsPlumb.getInstance({
-        DragOptions: {
-            zIndex: 2000
-        },
-        EndpointHoverStyle: {
-            fillStyle: "green"
-        },
-        HoverPaintStyle: {
-            strokeStyle: "green"
-        },
-        Container: "dropContainer"
-    });
-    var jsPlumbEndpoint = {
-        endpoint: ["Dot", {
-            radius: 10
-        }],
-        paintStyle: {
-            fillStyle: "#9932cc"
-        },
-        isSource: true,
-        isTarget: true,
-        deleteEndpointsOnDetach: false,
-        zIndex: 20,
-        connectorStyle: {
-            strokeStyle: "#9932cc",
-            lineWidth: 8
-        },
-        connector: ["Bezier", {
-            curviness: 180
-        }],
-        maxConnections: 1,
-        dropOptions: {
-            tolerance: "fit"
-        }
-    };
-    var elementConnections = [];
-    var elementIndex = 0;
-    var dragContainerScroll = 0;
-    var workspaceWidth = $("#dropContainer").width();
-    var workspaceHeight = $("#dropContainer").height();
-
-    var stackIndexer = 0;
-    var stackSize = 0;
-    var objectStack = [];
-    var undoStack = [];
-    var redoStack = [];
-    var clickEvent = 0;
-    var nextStepConstraint = 0;
-
-
-/* Functions. */
-
-    setServiceStatus = function(status) {
-        if (status == "unsaved") {
-            $("#serviceStatus").text("Unsaved");
-        }
-        else {
-            $("#serviceStatus").empty();
-        }
-    };
-
-    addInfo = function(title, info, type, object) {
-        /*
-        $("#informationContainer").empty();
-
-        switch(type){
-            case "connection":
-                div =
-                    '<div class="row">' +
-                        '<div class="col-xs-12 text-center">' +
-                            '<h4>' + title + '</h4>' +
-                        '</div>' +
-                    '</div>&nbsp;' +
-                    '<div class="row">' +
-                        '<div class="col-xs-12">' +
-                            '<textarea class="form-control" rows="28" id="infoInput" placeholder="Config data"></textarea>' +
-                        '</div>' +
-                    '</div>&nbsp;' +
-                    '<div class="row">' +
-                        '<div class="col-xs-12 text-center">' +
-                            '<button id="removeConnection" class="btn btn-info">Remove connection</button>' +
-                        '</div>' +
-                    '</div>';
-                break;
-            case "element":
-                div =
-                    '<div class="row">' +
-                        '<div class="col-xs-12 text-center">' +
-                            '<h4>' + title + '</h4>' +
-                        '</div>' +
-                    '</div>&nbsp;' +
-                    '<div class="row">' +
-                        '<div class="col-xs-12">' +
-                            '<textarea class="form-control" rows="24" id="infoInput" placeholder="Config data"></textarea>' +
-                        '</div>' +
-                    '</div>&nbsp;' +
-                    '<div class="row text-center">' +
-                        '<label>Endpoints</label>' +
-                    '</div>' +
-                    '<div class="row">' +
-                        '<div class="col-xs-6 text-center">' +
-                            '<button id="addEndpoint" class="btn btn-success"><i class="fa fa-plus"></i></button>' +
-                        '</div>' +
-                        '<div class="col-xs-6 text-center">' +
-                            '<button id="removeEndpoint" class="btn btn-danger"><i class="fa fa-minus"></i></button>' +
-                        '</div>' +
-                    '</div>&nbsp;' +
-                    '<div class="row">' +
-                        '<div class="col-xs-12 text-center">' +
-                            '<button id="removeElementFromWorkspace" class="btn btn-info">Remove from workspace</button>' +
-                        '</div>' +
-                    '</div>';
-                break;
-            case "elementTemplate":
-                div =
-                    '<div class="row">' +
-                        '<div class="col-xs-12 text-center">' +
-                            '<h4>' + title + '</h4>' +
-                        '</div>' +
-                    '</div>&nbsp;' +
-                    '<div class="row">' +
-                        '<div class="col-xs-12">' +
-                            '<textarea class="form-control" rows="28" id="infoInput" placeholder="Config data"></textarea>' +
-                        '</div>' +
-                    '</div>&nbsp;' +
-                    '<div class="row">' +
-                        '<div class="col-xs-12 text-center">' +
-                            '<button id="addElementToWorkspace" class="btn btn-success">Add to workspace</button>' +
-                        '</div>' +
-                    '</div>';
-                break;
-        }*/
-        
-        // Here comes the ajax getInformation post.
-        // elementtemplateid vagy hostname
-        
-        
-        div = 0;
-
-        $("#informationContainer").append(div);
-
-        $("#infoInput").val(info);
-
-        $("#changeInformationDialog").modal('show');
-        
-        sharedObject = object;
-    };
-
-    updateConnections = function(connection, remove) {
-        if (!remove) {
-            elementConnections.push(connection);
-        } else {
-            index = -1;
-            for (var i = 0; i < elementConnections.length; i++) {
-                if (elementConnections[i] == connection) {
-                    index = i;
-                    break;
-                }
-            }
-            if (index != -1) {
-                elementConnections.splice(index, 1);
-            }
-        }
-
-        setServiceStatus("unsaved");
-    };
-
-    checkDuplicateConnection = function(connection) {
-        for (var i = 0; i < elementConnections.length; i++) {
-            if (((elementConnections[i].targetId ==
-                        connection.targetId &&
-                        elementConnections[i].sourceId ==
-                        connection.sourceId) ||
-                    (elementConnections[i].targetId ==
-                        connection.sourceId &&
-                        elementConnections[i].sourceId ==
-                        connection.targetId)) &&
-                elementConnections[i] != connection) {
-                addMessage("Twofold connection is forbidden.", "danger");
-                return false;
-            }
-        }
-        return true;
-    };
-
-    checkCompatibility = function(sourceId, targetId) {
-        validTargets = $("#" + sourceId).attr("type").split(',');
-
-        if (jQuery.inArray(targetId.split('_')[1], validTargets) == -1) {
-            addMessage("Connecting incompatible elements is forbidden.", "danger");
-            return false;
-        }
-        return true;
-    };
-
-    checkSourceTargetEquality = function(connection) {
-        if (connection.targetId == connection.sourceId) {
-            addMessage("Connecting element to itself is forbidden.", "danger");
-            return false;
-        }
-        return true;
-    };
-
-    getAnchorCoordinate = function(rate) {
-        x = Math.cos(2.0 * Math.PI * rate) / 2;
-        y = Math.sin(2.0 * Math.PI * rate) / 2;
-        dx = 0;
-        dy = 0;
-
-        if (rate < 0.125) {
-            x = 0.5;
-            dx = 1;
-        } else if (rate > 0.125 && rate < 0.375) {
-            y = -0.5;
-            dy = -1;
-        } else if (rate > 0.375 && rate < 0.625) {
-            x = -0.5;
-            dx = -1;
-        } else if (rate > 0.625 && rate < 0.875) {
-            y = 0.5;
-            dy = 1;
-        } else if (rate > 0.875) {
-            x = -0.5;
-            dx = -1;
-        } else {
-            x = Math.sqrt(2) * Math.cos(2 * Math.PI *
-                rate) / 2;
-            y = Math.sqrt(2) * Math.sin(2 * Math.PI *
-                rate) / 2;
-
-            dx = Math.round(2 * x);
-        }
-        return [y + 0.5, -x + 0.5, dy, -dx];
-    };
-
-    isConnected = function(anchorId) {
-        returnValue = false;
-        $.each(elementConnections, function(index) {
-            if (elementConnections[index].endpoints[0].getUuid() == anchorId ||
-                elementConnections[index].endpoints[1].getUuid() == anchorId) {
-                returnValue = true;
-                return;
-            }
-        });
-        return returnValue;
-    };
-    
-    elementIsConnected = function(element) {
-        anchors = element.attr("anchors");
-        id = element.attr("id");
-        
-        for(i=0;i<anchors;i++)
-        {
-            if(isConnected(i + "_" + id))
-            {
-                return true;
-            }
-        }
-        
-        return false;
-    };
-
-    getConnectionparamAndAnchor = function(anchorId) {
-        parameters = "";
-        otherAnchor = "";
-
-        $.each(elementConnections, function(index) {
-            if (elementConnections[index].endpoints[0].getUuid() == anchorId) {
-                parameters = elementConnections[index].parameters;
-                otherAnchor = elementConnections[index].endpoints[1].getUuid();
-                return;
-            }
-
-            if (elementConnections[index].endpoints[1].getUuid() == anchorId) {
-                parameters = elementConnections[index].parameters;
-                otherAnchor = elementConnections[index].endpoints[0].getUuid();
-                return;
-            }
-        });
-
-        return [otherAnchor, parameters];
-    };
-
-    addEndpoint = function(element) {
-        anchors = element.attr("anchors");
-
-        if (anchors == 8) return;
-
-        anchors++;
-
-        jsPlumbInstance.addEndpoint(document.getElementById(element.attr("id")), {
-                uuid: (anchors - 1) + "_" + element.attr("id")
-            },
-            jsPlumbEndpoint);
-
-        for (i = 0; i < anchors; i++) {
-            jsPlumbInstance.getEndpoint(i + "_" + element.attr("id")).setAnchor(getAnchorCoordinate(i / (anchors)));
-        }
-
-        element.attr("anchors", anchors);
-
-        jsPlumbInstance.repaintEverything();
-    };
-
-    removeEndoint = function(element) {
-        anchors = element.attr("anchors");
-
-        if (anchors == 4) return;
-
-        i = --anchors;
-
-        while (isConnected(i + "_" + element.attr("id")) && i >= 0) i--;
-
-        if (i == -1) {
-            addMessage("Removing anchors is obstructed.", "danger");
-            return;
-        } else if (i == anchors) {
-            jsPlumbInstance.deleteEndpoint(jsPlumbInstance.getEndpoint(anchors + "_" + element.attr("id")));
-        } else {
-            newId = i + "_" + element.attr("id");
-            oldId = anchors + "_" + element.attr("id");
-
-            data = getConnectionparamAndAnchor(oldId);
-            data.splice(0, 0, newId);
-
-            jsPlumbInstance.deleteEndpoint(jsPlumbInstance.getEndpoint(oldId));
-
-            connectEndpoints(data);
-        }
-
-        for (i = 0; i < anchors; i++) jsPlumbInstance.getEndpoint(
-            i + "_" + element.attr("id")).setAnchor(getAnchorCoordinate(i / (anchors)));
-
-        element.attr("anchors", anchors);
-
-        jsPlumbInstance.repaintEverything();
-    };
-
-    connectEndpoints = function(data) {
-        connectionObject =
-            jsPlumbInstance.connect({
-                uuids: [data[0], data[1]]
-            });
-
-        connectionObject.parameters = data[2];
-
-        setServiceStatus("unsaved");
-    };
-
-    disconnectEndpoints = function(data) {
-        for (var i = 0; i < elementConnections.length; i++) {
-            if (elementConnections[i].endpoints[0].getUuid() == data[0] &&
-                elementConnections[i].endpoints[1].getUuid() == data[1]) {
-                jsPlumbInstance.detach(elementConnections[i]);
-                return;
-            }
-        }
-        return;
-    };
-
-    addElement = function(idOrInstance, newId, newPositionY, endpoints, parameters, newPositionX) {
-        newInstance = "";
-
-        if (typeof idOrInstance != "string") {
-            newInstance = idOrInstance;
-            endpoints = newInstance.attr("anchors");
-            newInstance.attr("anchors", 0);
-        } else {
-            newInstance = $('#' + idOrInstance)
-                .clone()
-                .prop("id", newId)
-                .prop("title", "Right click to delete")
-                .removeClass()
-                .addClass("element")
-                .attr("anchors", 0)
-                .attr("parameters", parameters)
-                .css("top", newPositionY)
-                .css("left", newPositionX);
-        }
-
-        $("#dropContainer").append(newInstance);
-                
-        for (i = 0; i <= endpoints; i++) {
-            addEndpoint(newInstance);
-        }
-        
-        jsPlumbInstance.draggable(jsPlumb.getSelector(".element"), {
-            containment: $("#dropContainer")
-        });
-
-        setServiceStatus("unsaved");
-
-        jsPlumbInstance.repaintEverything();
-        
-        return newInstance;
-    };
-
-    removeElement = function(object) {
-        jsPlumbInstance.detachAllConnections(object);
-        jsPlumbInstance.remove(object.attr("id"));
-    };
-
-
-/* Registering events using JsPlumb. */
-
-    jsPlumbInstance.bind("connection", function(info) {
-        updateConnections(info.connection);
-        info.connection.parameters = "";
-
-        if (clickEvent === 0) {
-            undoStack.splice(stackIndexer, 0, disconnectEndpoints);
-            redoStack.splice(stackIndexer, 0, connectEndpoints);
-            connectionArray = [];
-            connectionArray.push(info.connection.endpoints[0].getUuid(),
-                info.connection.endpoints[1].getUuid(),
-                info.connection.parameters);
-            objectStack.splice(stackIndexer, 0, connectionArray);
-            stackIndexer++;
-            stackSize++;
-        }
-    });
-
-    jsPlumbInstance.bind("beforeDrop", function(info) {
-        return checkDuplicateConnection(info.connection) &&
-            checkSourceTargetEquality(info.connection) &&
-            checkCompatibility(info.connection.sourceId, info.connection.targetId);
-    });
-
-    jsPlumbInstance.bind("connectionDetached", function(info) {
-        updateConnections(info.connection, true);
-
-        if (clickEvent === 0) {
-            undoStack.splice(stackIndexer, 0, connectEndpoints);
-            redoStack.splice(stackIndexer, 0, disconnectEndpoints);
-            connectionArray = [];
-            connectionArray.push(info.connection.endpoints[0].getUuid(),
-                info.connection.endpoints[1].getUuid(),
-                info.connection.parameters);
-            objectStack.splice(stackIndexer, 0, connectionArray);
-            stackIndexer++;
-            stackSize++;
-        }
-    });
-
-    jsPlumbInstance.bind("connectionMoved", function(info) {
-        updateConnections(info.connection, true);
-    });
-
-    jsPlumbInstance.bind("contextmenu", function(info) {
-        jsPlumbInstance.detach(info);
-    });
-
-    jsPlumbInstance.bind("dblclick", function(info) {
-        info.setPaintStyle({strokeStyle:"red", lineWidth: 8});
-        addInfo($("#" + info.sourceId.split('_')[1]).attr("alt") + ' - ' + $("#" + info.targetId.split('_')[1]).attr("alt"),
-            info.parameters,
-            "connection",
-            info);
-    });
-
-    jsPlumbInstance.draggable(jsPlumb.getSelector(".element"), {
-        containment: $("#dropContainer")
-    });
-
-
-/* Registering events using JQuery. */
-
-    $('body').on('click', '.elementTemplate', function() {
-        addElement($(this).attr("id"),
-			(++elementIndex) + "_" + $(this).attr("id"),
-			(elementIndex % 21) * 30, 4, "",
-			(elementIndex % 21) * 30);
-
-        undoStack.splice(stackIndexer, 0, removeElement);
-        redoStack.splice(stackIndexer, 0, addElement);
-        objectStack.splice(stackIndexer, 0, newInstance);
-        stackSize++;
-        stackIndexer++;
-    });
-    
-    $('body').on('dblclick', '.element', function() {
-        element = $(this);
-        element.addClass("elementSelected");
-        addInfo(element.attr("alt"),
-			element.attr("parameters"),
-			"element", element);
-        $(document).scrollTop(0);
-    });
-
-    $('body').on('contextmenu', '.element', function(event) {
-        setServiceStatus("unsaved");
-        removeElement($(this));
-
-        undoStack.splice(stackIndexer, 0, addElement);
-        redoStack.splice(stackIndexer, 0, removeElement);
-        objectStack.splice(stackIndexer, 0, $(this));
-        
-        nextStepConstraint = 0;
-        stackSize++;
-        stackIndexer++;
-    });
-
-    $('body').on('click', '#closeInfoPanel', function() {
-        $('#informationPanel').hide();
-        $('#dragPanel').show();
-    });
-
-    $('body').on('keyUp', '#infoInput', function() {
-        setServiceStatus("unsaved");
-        newParams = $("#infoInput").val();
-
-        if (type == "connection") object.parameters = newParams;
-        if (type == "element") object.attr("parameters", newParams);
-    });
-
-    $('body').on('click', '#addEndpoint', function() {
-        addEndpoint(sharedObject);
-        undoStack.splice(stackIndexer, 0, removeEndoint);
-        redoStack.splice(stackIndexer, 0, addEndpoint);
-        objectStack.splice(stackIndexer, 0, sharedObject);
-        stackIndexer++;
-        stackSize++;
-    });
-
-    $('body').on('click', '#removeEndpoint', function() {
-        removeEndoint(sharedObject);
-        undoStack.splice(stackIndexer, 0, addEndpoint);
-        redoStack.splice(stackIndexer, 0, removeEndoint);
-        objectStack.splice(stackIndexer, 0, sharedObject);
-        stackIndexer++;
-        stackSize++;
-    });
-
-    $('body').on('click', '#removeElementFromWorkspace', function() {
-        setServiceStatus("unsaved");
-        removeElement(sharedObject);
-
-        undoStack.splice(stackIndexer, 0, addElement);
-        redoStack.splice(stackIndexer, 0, removeElement);
-        objectStack.splice(stackIndexer, 0, sharedObject);
-        stackSize++;
-        stackIndexer++;
-    });
-
-    $('body').on('click', '#removeConnection', function() {
-        jsPlumbInstance.detach(sharedObject);
-    });
-
-    $('body').on('click', '#addElementToWorkspace', function() {
-        newInstance = addElement(sharedObject.attr("id"),
-			(++elementIndex) + "_" + sharedObject.attr("id"),
-			(elementIndex % 21) * 30, 4, "",
-			(elementIndex % 21) * 30);
-
-        undoStack.splice(stackIndexer, 0, removeElement);
-        redoStack.splice(stackIndexer, 0, addElement);
-        objectStack.splice(stackIndexer, 0, newInstance);
-        stackSize++;
-        stackIndexer++;
-    });
-
-    $('body').on('click', '#clearService', function() {
-        jsPlumbInstance.remove("element");
-        setServiceStatus("unsaved");
-
-        elementIndex = 0;
-    });
-
-    $('body').on('click', '#undoMovement', function() {
-        if (stackIndexer < 1) return;
-        stackIndexer--;
-        clickEvent = 1;
-        object = objectStack[stackIndexer];
-        undoStack[stackIndexer](object);
-        clickEvent = 0;
-    });
-
-    $('body').on('click', '#redoMovement', function() {
-        if (stackIndexer >= stackSize) return;
-        clickEvent = 1;
-        object = objectStack[stackIndexer];
-        redoStack[stackIndexer](object);
-        stackIndexer++;
-        clickEvent = 0;
-    });
-    
-    $('body').on('click', '#addMachineDialog', function() {
-        // Here comes the ajax post of getMachineAvailableList
-        // posting usedhostnames
-        //
-        //
-        // after it, appending obtained content to addmachinedialogbody
-    });
-
-    $('body').on('click', '.elementTemplateInfo', function() {
-        id = $(this).attr("element");
-        addInfo($("#" + id).attr("alt"), $("#" + id).attr("desc"), "elementTemplate", $("#" + id));
-    });
-
-    $('body').on('click', '#serviceName', function() {
-        $('#serviceName').hide();
-        $("#serviceNameEdit").css("display", "inline").val($(this).text()).select();
-        $("#serviceNameSave").css("display", "inline");
-        setServiceStatus("unsaved");
-    });
-
-    $('body').on('click', '#serviceNameSave', function() {
-        $('#serviceNameEdit').hide();
-        $(this).hide();
-        $("#serviceName").show().text($('#serviceNameEdit').val());
-    });
-
-    $('body').on('click', '#dragContainerScrollUp', function() {
-        scrollContainer(-1);
-    });
-
-    $('body').on('click', '#dragContainerScrollDown', function() {
-        scrollContainer(1);
-    });
-
-    $('body').on('hide.bs.modal', '#changeInformationDialog', function () {
-        $('.element').removeClass('elementSelected');
-        jsPlumbInstance.select().setPaintStyle({strokeStyle:'#9932cc', lineWidth: 8});
-    });
-
-    $('body').on('keyup', '#searchElementTemplate', function() {
-        $(".elementTemplate").each(function() {
-            $(this).parent().parent().hide();
-            if ($(this).attr("alt").toLowerCase().indexOf($("#searchElementTemplateInput").val().toLowerCase()) >= 0)
-                $(this).parent().parent().show();
-        });
-    });
-    
-    $('body').on('mousewheel DOMMouseScroll onmousewheel', function(event) {
-        var e = window.event || event;
-        var delta = Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail)));
-
-        $('body').addClass("noScroll");
-
-        dragContainerScroll -= delta;
-
-        if (dragContainerScroll == $(".elementTemplate").length - 2) dragContainerScroll--;
-        if (dragContainerScroll == -1) dragContainerScroll++;
-
-        $("#dragContainer").scrollTop(
-            dragContainerScroll * $("#elementTemplatePanel").height()
-        );
-
-        $('body').removeClass("noScroll");
-    });
-    
-    $(document).on('keydown', function(e) {
-		var eventObject = window.event ? event : e;
-		
-		// Undo (CTRL + Z)
-		if (eventObject.keyCode == 90 && eventObject.ctrlKey)
-		{
-			eventObject.preventDefault();
-			$('#undoMovement').click();
-		}
-		
-		// Redo (CTRL + Y)
-		if (eventObject.keyCode == 89 && eventObject.ctrlKey)
-		{
-			eventObject.preventDefault();
-			$('#redoMovement').click();
-		}
-		
-		// Add element (CTRL + A)
-		if (eventObject.keyCode == 65 && eventObject.ctrlKey)
-		{
-			eventObject.preventDefault();
-			$('#showAddElementDialog').click();
-		}
-		
-		// Clean (CTRL + C)
-		if (eventObject.keyCode == 67 && eventObject.ctrlKey)
-		{
-			eventObject.preventDefault();
-			$('#clearService').click();
-		}
-		
-		// Save (CTRL + S)
-		if (eventObject.keyCode == 83 && eventObject.ctrlKey)
-		{
-			eventObject.preventDefault();
-			$('#saveService').click();
-		}
-		
-		// Delete (CTRL + D)
-		if (eventObject.keyCode == 68 && eventObject.ctrlKey)
-		{
-			eventObject.preventDefault();
-			$('#deleteService').click();
-		}
-	});
-
-    $(window).on('resize', function() {
-        $(".element").each(function() {
-            rate = ($(this).position().left)/workspaceWidth;
-            left = rate*($("#dropContainer").width());
-            $(this).css("left", left);
-        });
-        workspaceWidth = $("#dropContainer").width();
-        jsPlumbInstance.repaintEverything();
-    });
-
-
-/* Registering events concerning persistence. */
-
-    $('body').on('click', '#saveService', function() {
-        serviceName = $("#serviceName").text();
-        connectionSet = [];
-        instanceSet = [];
-
-        $.each(elementConnections, function(index) {
-            connectionSet.push({
-                "sourceId": elementConnections[index].sourceId,
-                "sourceEndpoint": elementConnections[index].endpoints[0].getUuid(),
-                "targetId": elementConnections[index].targetId,
-                "targetEndpoint": elementConnections[index].endpoints[1].getUuid(),
-                "parameters": elementConnections[index].parameters});
-        });
-
-        $.each($(".element"), function() {
-            instanceSet.push({
-                "displayId": $(this).prop("id"),
-                "positionLeft": $(this).position().left/workspaceWidth,
-                "positionTop": $(this).position().top/workspaceHeight,
-                "anchorNumber": $(this).attr("anchors"),
-                "parameters": $(this).attr("parameters")});
-        });
-
-        $.post("", {
-            event: "saveService",
-            data: JSON.stringify({
-                "serviceName": serviceName,
-                "elementConnections": connectionSet,
-                "elements": instanceSet})
-        }, function(result) {
-            addMessage(result.serviceName + " saved successfully.","success");
-            setServiceStatus("saved");
-        });
-    });
-
-    $(document).ready(function() {
-		if(!$("#dropContainer").length) return;  // Protection for not posting sites that differ from setty sites.
-        $.post("", {
-            event: "loadService"
-        }, function(result) {
-            $("#serviceName").text(result.serviceName);
-
-            $.each(result.elements, function(i, element) {
-                addElement(element.displayId.split('_')[1],
-                    element.displayId,
-                    (element.positionTop*workspaceHeight) + "px",
-                    element.anchorNumber,
-                    element.parameters,
-                    (element.positionLeft*workspaceWidth) + "px");
-                if (elementIndex < element.displayId.split('_')[0])
-                    elementIndex = element.displayId.split('_')[0];
-                elementIndex++;
-            });
-
-            clickEvent = 1;
-            $.each(result.elementConnections,
-                function(i, connection) {
-                    connectEndpoints([connection.sourceEndpoint, connection.targetEndpoint, connection.parameters]);
-                });
-            clickEvent = 0;
-            setServiceStatus("saved");
-        });
-    });
-});
+/* Settimng up csrf token, touch event and zoom options. */
+function getCookie(name) {
+  var cookieValue = null;
+  if (document.cookie && document.cookie !== '') {
+    var cookies = document.cookie.split(';');
+    for (var i = 0; i < cookies.length; i++) {
+      var cookie = jQuery.trim(cookies[i]);
+      if (cookie.substring(0, name.length + 1) == (name + '=')) {
+        cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
+        break;
+      }
+    }
+  }
+  return cookieValue;
+}
+
+function csrfSafeMethod(method) {
+  return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
+}
+
+var csrftoken = getCookie('csrftoken');
+
+$.ajaxSetup({
+  beforeSend: function(xhr, settings) {
+    if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
+      xhr.setRequestHeader("X-CSRFToken", csrftoken);
+    }
+  }
+});
+
+
+/* Setty implementation starts here. */
+
+jsPlumb.ready(function() {
+  var jsPlumbInstance = jsPlumb.getInstance({
+    DragOptions: {
+      zIndex: 2000
+    },
+    EndpointHoverStyle: {
+      fillStyle: "green"
+    },
+    HoverPaintStyle: {
+      strokeStyle: "green"
+    },
+    Container: "dropContainer"
+  });
+  var jsPlumbEndpoint = {
+    endpoint: ["Dot", {
+      radius: 10
+    }],
+    paintStyle: {
+      fillStyle: "#9932cc"
+    },
+    isSource: true,
+    isTarget: true,
+    deleteEndpointsOnDetach: false,
+    zIndex: 20,
+    connectorStyle: {
+      strokeStyle: "#9932cc",
+      lineWidth: 8
+    },
+    connector: ["Bezier", {
+      curviness: 180
+    }],
+    maxConnections: 1,
+    dropOptions: {
+      tolerance: "fit"
+    }
+  };
+  var elementConnections = [];
+  var elementIndex = 0;
+  var dragContainerScroll = 0;
+  var workspaceWidth = $("#dropContainer").width();
+  var workspaceHeight = $("#dropContainer").height();
+
+  var stackIndexer = 0;
+  var stackSize = 0;
+  var objectStack = [];
+  var undoStack = [];
+  var redoStack = [];
+  var clickEvent = 0;
+  var nextStepConstraint = 0;
+
+
+  /* Functions. */
+
+  setServiceStatus = function(status) {
+    if (status == "unsaved") {
+      $("#serviceStatus").text(gettext("Unsaved"));
+    } else {
+      $("#serviceStatus").empty();
+    }
+  };
+
+  addInfo = function(title, info, object, type) {
+    mainDiv = $("<div>", {
+      class: "row",
+      html: $("<div>", {
+        class: "col-xs-12 text-center",
+        html: row = $("<h4>", {
+          html: title
+        })
+      })
+    }).add($("<div>", {
+      class: "row",
+      style: "margin-top: 16px",
+      html: $("<div>", {
+        class: "col-xs-12 text-center",
+        html: row = $("<textarea>", {
+          class: "form-control",
+          style: "text-align: justify;",
+          rows: "18",
+          id: "infoInput",
+          disabled: !type,
+          text: info
+        })
+      })
+    }));
+    controlDiv = $("<div>", {
+      class: "row",
+      style: "margin-top: 16px",
+      html: $("<div>", {
+        class: "col-xs-3 text-center",
+        html: $("<button>", {
+          class: "btn btn-success btn-block",
+          id: "addEndpoint",
+          html: gettext("Add endpoint")
+        })
+      }).add($("<div>", {
+        class: "col-xs-3 text-center",
+        html: $("<button>", {
+          class: "btn btn-danger btn-block",
+          id: "removeEndpoint",
+          html: gettext("Delete endpoint")
+        })
+      })).add($("<div>", {
+        class: "col-xs-6 text-center",
+        html: $("<button>", {
+          class: "btn btn-info btn-block",
+          id: "removeElementFromWorkspace",
+          html: gettext("Remove from workspace")
+        })
+      }))
+    });
+    addElementDiv = $("<div>", {
+      class: "row",
+      style: "margin-top: 16px",
+      html: $("<div>", {
+        class: "col-xs-12 text-center",
+        html: row = $("<button>", {
+          class: "btn btn-success",
+          id: "addElementToWorkspace",
+          html: gettext("Add to workspace")
+        })
+      })
+    });
+
+    $("#informationContainer").html(type?mainDiv.add(controlDiv):mainDiv.add(addElementDiv));
+
+    $("#changeInformationDialog").modal('show');
+
+    sharedObject = object;
+  };
+
+  updateConnections = function(connection, remove) {
+    if (!remove) {
+      elementConnections.push(connection);
+    } else {
+      index = -1;
+      for (var i = 0; i < elementConnections.length; i++) {
+        if (elementConnections[i] == connection) {
+          index = i;
+          break;
+        }
+      }
+      if (index != -1) {
+        elementConnections.splice(index, 1);
+      }
+    }
+
+    setServiceStatus("unsaved");
+  };
+
+  checkDuplicateConnection = function(connection) {
+    for (var i = 0; i < elementConnections.length; i++) {
+      if (((elementConnections[i].targetId ==
+            connection.targetId &&
+            elementConnections[i].sourceId ==
+            connection.sourceId) ||
+          (elementConnections[i].targetId ==
+            connection.sourceId &&
+            elementConnections[i].sourceId ==
+            connection.targetId)) &&
+        elementConnections[i] != connection) {
+        addMessage(gettext("Twofold connection is forbidden."), "danger");
+        return false;
+      }
+    }
+    return true;
+  };
+
+  checkCompatibility = function(sourceId, targetId) {
+    validTargets = $("#" + sourceId).attr("type").split(',');
+
+    if (jQuery.inArray(targetId.split('_')[1], validTargets) == -1) {
+      addMessage(gettext("Connecting incompatible elements is forbidden."), "danger");
+      return false;
+    }
+    return true;
+  };
+
+  checkSourceTargetEquality = function(connection) {
+    if (connection.targetId == connection.sourceId) {
+      addMessage(gettext("Connecting element to itself is forbidden."), "danger");
+      return false;
+    }
+    return true;
+  };
+
+  getAnchorCoordinate = function(rate) {
+    x = Math.cos(2.0 * Math.PI * rate) / 2;
+    y = Math.sin(2.0 * Math.PI * rate) / 2;
+    dx = 0;
+    dy = 0;
+
+    if (rate < 0.125) {
+      x = 0.5;
+      dx = 1;
+    } else if (rate > 0.125 && rate < 0.375) {
+      y = -0.5;
+      dy = -1;
+    } else if (rate > 0.375 && rate < 0.625) {
+      x = -0.5;
+      dx = -1;
+    } else if (rate > 0.625 && rate < 0.875) {
+      y = 0.5;
+      dy = 1;
+    } else if (rate > 0.875) {
+      x = -0.5;
+      dx = -1;
+    } else {
+      x = Math.sqrt(2) * Math.cos(2 * Math.PI *
+        rate) / 2;
+      y = Math.sqrt(2) * Math.sin(2 * Math.PI *
+        rate) / 2;
+
+      dx = Math.round(2 * x);
+    }
+    return [y + 0.5, -x + 0.5, dy, -dx];
+  };
+
+  isConnected = function(anchorId) {
+    returnValue = false;
+    $.each(elementConnections, function(index) {
+      if (elementConnections[index].endpoints[0].getUuid() == anchorId ||
+        elementConnections[index].endpoints[1].getUuid() == anchorId) {
+        returnValue = true;
+        return;
+      }
+    });
+    return returnValue;
+  };
+
+  elementIsConnected = function(element) {
+    anchors = element.attr("anchors");
+    id = element.attr("id");
+
+    for (i = 0; i < anchors; i++) {
+      if (isConnected(i + "_" + id)) {
+        return true;
+      }
+    }
+
+    return false;
+  };
+
+  getConnectionparamAndAnchor = function(anchorId) {
+    parameters = "";
+    otherAnchor = "";
+
+    $.each(elementConnections, function(index) {
+      if (elementConnections[index].endpoints[0].getUuid() == anchorId) {
+        parameters = elementConnections[index].parameters;
+        otherAnchor = elementConnections[index].endpoints[1].getUuid();
+        return;
+      }
+
+      if (elementConnections[index].endpoints[1].getUuid() == anchorId) {
+        parameters = elementConnections[index].parameters;
+        otherAnchor = elementConnections[index].endpoints[0].getUuid();
+        return;
+      }
+    });
+
+    return [otherAnchor, parameters];
+  };
+
+  addEndpoint = function(element) {
+    anchors = element.attr("anchors");
+
+    if (anchors == 8) return 1;
+
+    anchors++;
+
+    jsPlumbInstance.addEndpoint(document.getElementById(element.attr("id")), {
+        uuid: (anchors - 1) + "_" + element.attr("id")
+      },
+      jsPlumbEndpoint);
+
+    for (i = 0; i < anchors; i++) {
+      jsPlumbInstance.getEndpoint(i + "_" + element.attr("id")).setAnchor(getAnchorCoordinate(i / (anchors)));
+    }
+
+    element.attr("anchors", anchors);
+
+    jsPlumbInstance.repaintEverything();
+    
+    return 0;
+  };
+
+  removeEndoint = function(element) {
+    anchors = element.attr("anchors");
+
+    if (anchors == 4) return 1;
+
+    i = --anchors;
+
+    while (isConnected(i + "_" + element.attr("id")) && i >= 0) i--;
+
+    if (i == -1) {
+      addMessage(gettext("Removing anchors is obstructed."), "danger");
+      return;
+    } else if (i == anchors) {
+      jsPlumbInstance.deleteEndpoint(jsPlumbInstance.getEndpoint(anchors + "_" + element.attr("id")));
+    } else {
+      newId = i + "_" + element.attr("id");
+      oldId = anchors + "_" + element.attr("id");
+
+      data = getConnectionparamAndAnchor(oldId);
+      data.splice(0, 0, newId);
+
+      jsPlumbInstance.deleteEndpoint(jsPlumbInstance.getEndpoint(oldId));
+
+      connectEndpoints(data);
+    }
+
+    for (i = 0; i < anchors; i++) jsPlumbInstance.getEndpoint(
+      i + "_" + element.attr("id")).setAnchor(getAnchorCoordinate(i / (anchors)));
+
+    element.attr("anchors", anchors);
+
+    jsPlumbInstance.repaintEverything();
+    
+    return 0;
+  };
+
+  connectEndpoints = function(data) {
+    connectionObject =
+      jsPlumbInstance.connect({
+        uuids: [data[0], data[1]]
+      });
+
+    connectionObject.parameters = data[2];
+
+    setServiceStatus("unsaved");
+  };
+
+  disconnectEndpoints = function(data) {
+    for (var i = 0; i < elementConnections.length; i++) {
+      if (elementConnections[i].endpoints[0].getUuid() == data[0] &&
+        elementConnections[i].endpoints[1].getUuid() == data[1]) {
+        jsPlumbInstance.detach(elementConnections[i]);
+        return;
+      }
+    }
+    return;
+  };
+
+  addElement = function(idOrInstance, newId, newPositionY, endpoints, parameters, newPositionX) {
+    newInstance = "";
+
+    if (typeof idOrInstance != "string") {
+      newInstance = idOrInstance;
+      endpoints = newInstance.attr("anchors");
+      newInstance.attr("anchors", 0);
+    } else {
+      newInstance = $('#' + idOrInstance)
+        .clone()
+        .prop("id", newId)
+        .prop("title", "Right click to delete")
+        .removeClass()
+        .addClass("element")
+        .attr("anchors", 0)
+        .attr("parameters", parameters)
+        .css("top", newPositionY)
+        .css("left", newPositionX);
+    }
+
+    $("#dropContainer").append(newInstance);
+
+    for (i = 0; i <= endpoints; i++) {
+      addEndpoint(newInstance);
+    }
+
+    jsPlumbInstance.draggable(jsPlumb.getSelector(".element"), {
+      containment: $("#dropContainer")
+    });
+
+    setServiceStatus("unsaved");
+
+    jsPlumbInstance.repaintEverything();
+
+    return newInstance;
+  };
+
+  removeElement = function(object) {
+    jsPlumbInstance.detachAllConnections(object);
+    jsPlumbInstance.remove(object.attr("id"));
+  };
+
+
+  /* Registering events using JsPlumb. */
+
+  jsPlumbInstance.bind("connection", function(info) {
+    updateConnections(info.connection);
+    info.connection.parameters = "";
+
+    if (clickEvent === 0) {
+      undoStack.splice(stackIndexer, 0, disconnectEndpoints);
+      redoStack.splice(stackIndexer, 0, connectEndpoints);
+      connectionArray = [];
+      connectionArray.push(info.connection.endpoints[0].getUuid(),
+        info.connection.endpoints[1].getUuid(),
+        info.connection.parameters);
+      objectStack.splice(stackIndexer, 0, connectionArray);
+      stackIndexer++;
+      stackSize++;
+    }
+  });
+
+  jsPlumbInstance.bind("beforeDrop", function(info) {
+    return checkDuplicateConnection(info.connection) &&
+      checkSourceTargetEquality(info.connection) &&
+      checkCompatibility(info.connection.sourceId, info.connection.targetId);
+  });
+
+  jsPlumbInstance.bind("connectionDetached", function(info) {
+    updateConnections(info.connection, true);
+
+    if (clickEvent === 0) {
+      undoStack.splice(stackIndexer, 0, connectEndpoints);
+      redoStack.splice(stackIndexer, 0, disconnectEndpoints);
+      connectionArray = [];
+      connectionArray.push(info.connection.endpoints[0].getUuid(),
+        info.connection.endpoints[1].getUuid(),
+        info.connection.parameters);
+      objectStack.splice(stackIndexer, 0, connectionArray);
+      stackIndexer++;
+      stackSize++;
+    }
+  });
+
+  jsPlumbInstance.bind("connectionMoved", function(info) {
+    updateConnections(info.connection, true);
+  });
+
+  jsPlumbInstance.bind("contextmenu", function(info) {
+    jsPlumbInstance.detach(info);
+  });
+
+  jsPlumbInstance.draggable(jsPlumb.getSelector(".element"), {
+    containment: $("#dropContainer")
+  });
+
+
+  /* Registering events using JQuery. */
+
+  $('body').on('click', '.elementTemplate', function() {
+    addElement($(this).attr("id"),
+      (++elementIndex) + "_" + $(this).attr("id"),
+      (elementIndex % 21) * 30, 4, "",
+      (elementIndex % 21) * 30);
+
+    undoStack.splice(stackIndexer, 0, removeElement);
+    redoStack.splice(stackIndexer, 0, addElement);
+    objectStack.splice(stackIndexer, 0, newInstance);
+    stackSize++;
+    stackIndexer++;
+  });
+
+  $('body').on('dblclick', '.element', function() {
+    element = $(this);
+    element.addClass("elementSelected");
+    addInfo(element.attr("alt"),
+      element.attr("parameters"),
+      element, 1);
+    $(document).scrollTop(0);
+  });
+
+  $('body').on('contextmenu', '.element', function(event) {
+    setServiceStatus("unsaved");
+    removeElement($(this));
+
+    undoStack.splice(stackIndexer, 0, addElement);
+    redoStack.splice(stackIndexer, 0, removeElement);
+    objectStack.splice(stackIndexer, 0, $(this));
+
+    nextStepConstraint = 0;
+    stackSize++;
+    stackIndexer++;
+  });
+
+  $('body').on('keyup', '#infoInput', function() {
+    setServiceStatus("unsaved");
+    newParams = $("#infoInput").val();
+
+    sharedObject.attr("parameters", newParams);
+  });
+
+  $('body').on('click', '#addEndpoint', function() {
+    setServiceStatus("unsaved");
+    if(addEndpoint(sharedObject)) return;
+    undoStack.splice(stackIndexer, 0, removeEndoint);
+    redoStack.splice(stackIndexer, 0, addEndpoint);
+    objectStack.splice(stackIndexer, 0, sharedObject);
+    stackIndexer++;
+    stackSize++;
+  });
+
+  $('body').on('click', '#removeEndpoint', function() {
+    setServiceStatus("unsaved");
+    if(removeEndoint(sharedObject)) return;
+    undoStack.splice(stackIndexer, 0, addEndpoint);
+    redoStack.splice(stackIndexer, 0, removeEndoint);
+    objectStack.splice(stackIndexer, 0, sharedObject);
+    stackIndexer++;
+    stackSize++;
+  });
+
+  $('body').on('click', '#removeElementFromWorkspace', function() {
+    setServiceStatus("unsaved");
+    removeElement(sharedObject);
+
+    undoStack.splice(stackIndexer, 0, addElement);
+    redoStack.splice(stackIndexer, 0, removeElement);
+    objectStack.splice(stackIndexer, 0, sharedObject);
+    stackSize++;
+    stackIndexer++;
+
+    $("#changeInformationDialog").modal('hide');
+  });
+
+  $('body').on('click', '#removeConnection', function() {
+    jsPlumbInstance.detach(sharedObject);
+  });
+
+  $('body').on('click', '#addElementToWorkspace', function() {
+    newInstance = addElement(sharedObject.attr("id"),
+      (++elementIndex) + "_" + sharedObject.attr("id"),
+      (elementIndex % 21) * 30, 4, "",
+      (elementIndex % 21) * 30);
+
+    undoStack.splice(stackIndexer, 0, removeElement);
+    redoStack.splice(stackIndexer, 0, addElement);
+    objectStack.splice(stackIndexer, 0, newInstance);
+    stackSize++;
+    stackIndexer++;
+  });
+
+  $('body').on('click', '#clearService', function() {
+    //Todo
+    setServiceStatus("unsaved");
+
+    elementIndex = 0;
+  });
+
+  $('body').on('click', '#undoMovement', function() {
+    if (stackIndexer < 1) return;
+    stackIndexer--;
+    clickEvent = 1;
+    object = objectStack[stackIndexer];
+    undoStack[stackIndexer](object);
+    clickEvent = 0;
+  });
+
+  $('body').on('click', '#redoMovement', function() {
+    if (stackIndexer >= stackSize) return;
+    clickEvent = 1;
+    object = objectStack[stackIndexer];
+    redoStack[stackIndexer](object);
+    stackIndexer++;
+    clickEvent = 0;
+  });
+
+  $('body').on('click', '#addMachineDialog', function() {
+    // Here comes the ajax post of getting machines
+  });
+
+  $('body').on('click', '.elementTemplateInfo', function() {
+    id = $(this).attr("element");
+    addInfo($("#" + id).attr("alt"), $("#" + id).attr("desc"), $("#" + id), 0);
+  });
+
+  $('body').on('click', '#serviceName', function() {
+    $('#serviceName').hide();
+    $("#serviceNameEdit").css("display", "inline").val($(this).text()).select();
+    $("#serviceNameSave").css("display", "inline");
+    setServiceStatus("unsaved");
+  });
+
+  $('body').on('click', '#serviceNameSave', function() {
+    $('#serviceNameEdit').hide();
+    $(this).hide();
+    $("#serviceName").show().text($('#serviceNameEdit').val());
+  });
+
+  $('body').on('click', '#dragContainerScrollUp', function() {
+    scrollContainer(-1);
+  });
+
+  $('body').on('click', '#dragContainerScrollDown', function() {
+    scrollContainer(1);
+  });
+
+  $('body').on('hide.bs.modal', '#changeInformationDialog', function() {
+    $('.element').removeClass('elementSelected');
+  });
+
+  $('body').on('keyup', '#searchElementTemplate', function() {
+    $(".elementTemplate").each(function() {
+      $(this).parent().parent().hide();
+      if ($(this).attr("alt").toLowerCase().indexOf($("#searchElementTemplateInput").val().toLowerCase()) >= 0)
+        $(this).parent().parent().show();
+    });
+  });
+
+  $('body').on('mousewheel DOMMouseScroll onmousewheel', function(event) {
+    var e = window.event || event;
+    var delta = Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail)));
+
+    $('body').addClass("noScroll");
+
+    dragContainerScroll -= delta;
+
+    if (dragContainerScroll == $(".elementTemplate").length - 2) dragContainerScroll--;
+    if (dragContainerScroll == -1) dragContainerScroll++;
+
+    $("#dragContainer").scrollTop(
+      dragContainerScroll * $("#elementTemplatePanel").height()
+    );
+
+    $('body').removeClass("noScroll");
+  });
+
+  $(document).on('keydown', function(e) {
+    var eventObject = window.event ? event : e;
+
+    // Undo (CTRL + Z)
+    if (eventObject.keyCode == 90 && eventObject.ctrlKey) {
+      eventObject.preventDefault();
+      $('#undoMovement').click();
+    }
+
+    // Redo (CTRL + Y)
+    if (eventObject.keyCode == 89 && eventObject.ctrlKey) {
+      eventObject.preventDefault();
+      $('#redoMovement').click();
+    }
+
+    // Add element (CTRL + A)
+    if (eventObject.keyCode == 65 && eventObject.ctrlKey) {
+      eventObject.preventDefault();
+      $('#showAddElementDialog').click();
+    }
+
+    // Clean (CTRL + C)
+    if (eventObject.keyCode == 67 && eventObject.ctrlKey) {
+      eventObject.preventDefault();
+      $('#clearService').click();
+    }
+
+    // Save (CTRL + S)
+    if (eventObject.keyCode == 83 && eventObject.ctrlKey) {
+      eventObject.preventDefault();
+      $('#saveService').click();
+    }
+
+    // Delete (CTRL + D)
+    if (eventObject.keyCode == 68 && eventObject.ctrlKey) {
+      eventObject.preventDefault();
+      $('#deleteService').click();
+    }
+
+    // Close dialog (ESC)
+    if (eventObject.keyCode == 27) {
+      eventObject.preventDefault();
+      $("#changeInformationDialog").modal('hide');
+      $("#addElementDialog").modal('hide');
+    }
+  });
+
+  $(window).on('resize', function() {
+    $(".element").each(function() {
+      rate = ($(this).position().left) / workspaceWidth;
+      left = rate * ($("#dropContainer").width());
+      $(this).css("left", left);
+    });
+    workspaceWidth = $("#dropContainer").width();
+    jsPlumbInstance.repaintEverything();
+  });
+
+
+  /* Registering events concerning persistence. */
+
+  $('body').on('click', '#saveService', function() {
+    serviceName = $("#serviceName").text();
+    connectionSet = [];
+    instanceSet = [];
+
+    $.each(elementConnections, function(index) {
+      connectionSet.push({
+        "sourceId": elementConnections[index].sourceId,
+        "sourceEndpoint": elementConnections[index].endpoints[0].getUuid(),
+        "targetId": elementConnections[index].targetId,
+        "targetEndpoint": elementConnections[index].endpoints[1].getUuid(),
+        "parameters": elementConnections[index].parameters
+      });
+    });
+
+    $.each($(".element"), function() {
+      instanceSet.push({
+        "displayId": $(this).prop("id"),
+        "positionLeft": $(this).position().left / workspaceWidth,
+        "positionTop": $(this).position().top / workspaceHeight,
+        "anchorNumber": $(this).attr("anchors"),
+        "parameters": $(this).attr("parameters")
+      });
+    });
+
+    $.post("", {
+      event: "saveService",
+      data: JSON.stringify({
+        "serviceName": serviceName,
+        "elementConnections": connectionSet,
+        "elements": instanceSet
+      })
+    }, function(result) {
+      addMessage(result.serviceName + gettext(" saved successfully."), "success");
+      setServiceStatus("saved");
+    });
+  });
+
+  $(document).ready(function() {
+    if (!$("#dropContainer").length) return; // Protection for not posting sites that differ from setty sites.
+    $.post("", {
+      event: "loadService"
+    }, function(result) {
+      $("#serviceName").text(result.serviceName);
+
+      $.each(result.elements, function(i, element) {
+        addElement(element.displayId.split('_')[1],
+          element.displayId,
+          (element.positionTop * workspaceHeight) + "px",
+          element.anchorNumber,
+          element.parameters,
+          (element.positionLeft * workspaceWidth) + "px");
+        if (elementIndex < element.displayId.split('_')[0])
+          elementIndex = element.displayId.split('_')[0];
+        elementIndex++;
+      });
+
+      clickEvent = 1;
+      $.each(result.elementConnections,
+        function(i, connection) {
+          connectEndpoints([connection.sourceEndpoint, connection.targetEndpoint, connection.parameters]);
+        });
+      clickEvent = 0;
+      setServiceStatus("saved");
+    });
+  });
+});
diff --git a/circle/setty/templates/setty/index.html b/circle/setty/templates/setty/index.html
index eb4a154..8b02319 100644
--- a/circle/setty/templates/setty/index.html
+++ b/circle/setty/templates/setty/index.html
@@ -118,14 +118,14 @@
           </div>
           <div class="panel-body container-fluid" id="dragContainer">
             {% for element in elementTemplateList %}
-            <div class="col-md-12 col-sm-4" id="elementTemplatePanel">
+            <div class="col-md-6 col-sm-4" id="elementTemplatePanel">
               <div class="panel panel-default">
                 <div class="panel-heading">
                   <div class="row text-center">
-                    <div class="col-xs-10 col-xs-push-1 text-center">
+                    <div class="col-xs-8 col-xs-push-2 text-center">
                       <label class="no-margin">{{ element.name }}</label>
                     </div>
-                    <div class="col-xs-1 col-xs-push-1 text-right">
+                    <div class="col-xs-2 col-xs-push-2 text-left">
                       <button class="btn btn-primary btn-xs elementTemplateInfo" element="{{ element.id }}">
                         <i class="fa fa-info"></i>
                       </button>
diff --git a/circle/setty/views.py b/circle/setty/views.py
index 56b10a7..084853c 100644
--- a/circle/setty/views.py
+++ b/circle/setty/views.py
@@ -15,7 +15,7 @@
 # You should have received a copy of the GNU General Public License along
 # with CIRCLE.  If not, see <http://www.gnu.org/licenses/>.
 
-from django.contrib import messages  # NOTE: ezt tettem ide
+from django.contrib import messages
 from django.core.exceptions import PermissionDenied
 from django.core.urlresolvers import reverse, reverse_lazy
 from django.db.models import Q
@@ -41,85 +41,99 @@ class DetailView(LoginRequiredMixin, TemplateView):
     template_name = "setty/index.html"
 
     def get_context_data(self, **kwargs):
-        context = super(DetailView, self).get_context_data(**kwargs)
-        context['elementTemplateList'] = ElementTemplate.objects.all()
-        context['actualId'] = kwargs['pk']
-        return context
+        logger.debug('DetailView.get_context_data() called. User: %s',
+                     unicode(self.request.user))
+        service = Service.objects.get(id=kwargs['pk'])
 
-    def post(self, request, *args, **kwargs):
-        if self.request.POST.get('event') == "saveService":
-            data = json.loads(self.request.POST.get('data'))
-            service = Service.objects.get(id=kwargs['pk'])
-            service.name = data['serviceName']
-            service.save()
-
-            Element.objects.filter(service=service).delete()
-
-            for element in data['elements']:
-                elementObject = Element(
-                    service=service,
-                    parameters=element['parameters'],
-                    display_id=element['displayId'],
-                    position_left=element['positionLeft'],
-                    position_top=element['positionTop'],
-                    anchor_number=element['anchorNumber']
-                )
-                elementObject.save()
-
-            for elementConnection in data['elementConnections']:
-                sourceId = elementConnection['sourceId']
-                targetId = elementConnection['targetId']
-                sourceEndpoint = elementConnection['sourceEndpoint']
-                targetEndpoint = elementConnection['targetEndpoint']
-                connectionParameters = elementConnection['parameters']
-
-                targetObject = Element.objects.get(
-                    display_id=targetId,
-                    service=service)
-
-                sourceObject = Element.objects.get(
-                    display_id=sourceId,
-                    service=service)
-
-                connectionObject = ElementConnection(
-                    target=targetObject,
-                    source=sourceObject,
-                    target_endpoint=targetEndpoint,
-                    source_endpoint=sourceEndpoint,
-                    parameters=connectionParameters
-                )
-                connectionObject.save()
-
-            return JsonResponse({'serviceName': service.name})
-
-        elif self.request.POST.get('event') == "loadService":
-            service = Service.objects.get(id=kwargs['pk'])
-            elementList = Element.objects.filter(service=service)
-            elementConnectionList = ElementConnection.objects.filter(
-                Q(target__in=elementList) | Q(source__in=elementList))
-
-            elements = []
-            elementConnections = []
-
-            for item in elementList:
-                elements.append({
-                    'parameters': item.parameters,
-                    'displayId': item.display_id,
-                    'positionLeft': item.position_left,
-                    'positionTop': item.position_top,
-                    'anchorNumber': item.anchor_number})
-
-            for item in elementConnectionList:
-                elementConnections.append({
-                    'targetEndpoint': item.target_endpoint,
-                    'sourceEndpoint': item.source_endpoint,
-                    'parameters': item.parameters})
-
-            return JsonResponse(
-                {'elements': elements,
-                 'elementConnections': elementConnections,
-                 'serviceName': service.name})
+        if self.request.user == service.user or self.request.user.is_superuser:
+            context = super(DetailView, self).get_context_data(**kwargs)
+            context['elementTemplateList'] = ElementTemplate.objects.all()
+            context['actualId'] = kwargs['pk']
+            return context
+        else:
+            raise PermissionDenied
 
+    def post(self, request, *args, **kwargs):
+        logger.debug('DetailView.post() called. User: %s',
+                     unicode(self.request.user))
+        service = Service.objects.get(id=kwargs['pk'])
+
+        if self.request.user == service.user or self.request.user.is_superuser:
+            if self.request.POST.get('event') == "saveService":
+                data = json.loads(self.request.POST.get('data'))
+                service = Service.objects.get(id=kwargs['pk'])
+                service.name = data['serviceName']
+                service.save()
+
+                Element.objects.filter(service=service).delete()
+
+                for element in data['elements']:
+                    elementObject = Element(
+                        service=service,
+                        parameters=element['parameters'],
+                        display_id=element['displayId'],
+                        position_left=element['positionLeft'],
+                        position_top=element['positionTop'],
+                        anchor_number=element['anchorNumber']
+                    )
+                    elementObject.save()
+
+                for elementConnection in data['elementConnections']:
+                    sourceId = elementConnection['sourceId']
+                    targetId = elementConnection['targetId']
+                    sourceEndpoint = elementConnection['sourceEndpoint']
+                    targetEndpoint = elementConnection['targetEndpoint']
+                    connectionParameters = elementConnection['parameters']
+
+                    targetObject = Element.objects.get(
+                        display_id=targetId,
+                        service=service)
+
+                    sourceObject = Element.objects.get(
+                        display_id=sourceId,
+                        service=service)
+
+                    connectionObject = ElementConnection(
+                        target=targetObject,
+                        source=sourceObject,
+                        target_endpoint=targetEndpoint,
+                        source_endpoint=sourceEndpoint,
+                        parameters=connectionParameters
+                    )
+                    connectionObject.save()
+
+                return JsonResponse({'serviceName': service.name})
+
+            elif self.request.POST.get('event') == "loadService":
+                service = Service.objects.get(id=kwargs['pk'])
+                elementList = Element.objects.filter(service=service)
+                elementConnectionList = ElementConnection.objects.filter(
+                    Q(target__in=elementList) | Q(source__in=elementList))
+
+                elements = []
+                elementConnections = []
+
+                for item in elementList:
+                    elements.append({
+                        'parameters': item.parameters,
+                        'displayId': item.display_id,
+                        'positionLeft': item.position_left,
+                        'positionTop': item.position_top,
+                        'anchorNumber': item.anchor_number})
+
+                for item in elementConnectionList:
+                    elementConnections.append({
+                        'targetEndpoint': item.target_endpoint,
+                        'sourceEndpoint': item.source_endpoint,
+                        'parameters': item.parameters})
+
+                return JsonResponse(
+                    {'elements': elements,
+                     'elementConnections': elementConnections,
+                     'serviceName': service.name})
+
+            else:
+                raise PermissionDenied
         else:
             raise PermissionDenied
 
@@ -128,9 +142,18 @@ class DeleteView(LoginRequiredMixin, DeleteView):
     model = Service
     success_url = reverse_lazy("dashboard.index")
 
+    def post(self, request, *args, **kwargs):
+        logger.debug('DeleteView.post() called. User: %s',
+                     unicode(self.request.user))
+        service = Service.objects.get(id=kwargs['pk'])
 
-class CreateView(LoginRequiredMixin, TemplateView):
+        if self.request.user == service.user or self.request.user.is_superuser:
+            return super(DeleteView, self).post(request, *args, **kwargs)
+        else:
+            return PermissionDenied
 
+
+class CreateView(LoginRequiredMixin, TemplateView):
     def get_template_names(self):
         if self.request.is_ajax():
             return ['dashboard/_modal.html']
@@ -138,6 +161,8 @@ class CreateView(LoginRequiredMixin, TemplateView):
             return ['dashboard/nojs-wrapper.html']
 
     def get_context_data(self, *args, **kwargs):
+        logger.debug('CreateView.get_context_data() called. User: %s',
+                     unicode(self.request.user))
         context = super(CreateView, self).get_context_data(*args, **kwargs)
 
         context.update({
@@ -148,6 +173,8 @@ class CreateView(LoginRequiredMixin, TemplateView):
         return context
 
     def post(self, request, *args, **kwargs):
+        logger.debug('CreateView.post() called. User: %s',
+                     unicode(self.request.user))
         service_name = self.request.POST.get('serviceName')
 
         if not service_name:
@@ -181,11 +208,15 @@ class ListView(LoginRequiredMixin, FilterMixin, SingleTableView):
     }
 
     def get_context_data(self, *args, **kwargs):
+        logger.debug('ListView.get_context_data() called. User: %s',
+                     unicode(self.request.user))
         context = super(ListView, self).get_context_data(*args, **kwargs)
         context['search_form'] = self.search_form
         return context
 
     def get(self, *args, **kwargs):
+        logger.debug('ListView.get() called. User: %s',
+                     unicode(self.request.user))
         self.search_form = ServiceListSearchForm(self.request.GET)
         self.search_form.full_clean()
 
@@ -203,14 +234,14 @@ class ListView(LoginRequiredMixin, FilterMixin, SingleTableView):
             return super(ListView, self).get(*args, **kwargs)
 
     def get_queryset(self):
-        logger.debug('ListView.get  _queryset() called. User: %s',
+        logger.debug('ListView.get_queryset() called. User: %s',
                      unicode(self.request.user))
         qs = self.model.objects.all()
-        self.create_fake_get()  # NOTE: ezt tettem ide
+        self.create_fake_get()
         try:
             filters, excludes = self.get_queryset_filters()
             if not self.request.user.is_superuser:
-                filters['user'] = self.request.user  # NOTE: ezt visszairtam
+                filters['user'] = self.request.user
             qs = qs.filter(**filters).exclude(**excludes).distinct()
         except ValueError:
             messages.error(self.request, _("Error during filtering."))
--
libgit2 0.26.0