From 3b9f8748f274a8380e1d060e1745d8442903f1b2 Mon Sep 17 00:00:00 2001
From: Stefano Alberto Russo <stefano.russo@gmail.com>
Date: Fri, 16 Aug 2024 13:37:48 +0200
Subject: [PATCH] Code cleanup (removed unecessary spaces).

---
 rosetta/build                                 |  14 +-
 rosetta/logs                                  |   2 +-
 rosetta/shell                                 |   2 +-
 rosetta/status                                |  10 +-
 services/webapp/code/rosetta/auth.py          |  11 +-
 .../webapp/code/rosetta/context_processors.py |   8 +-
 services/webapp/code/rosetta/core_app/api.py  | 451 +++++++++---------
 .../rosetta/core_app/computing_managers.py    | 161 +++----
 .../code/rosetta/core_app/decorators.py       |   9 +-
 .../code/rosetta/core_app/exceptions.py       |   2 +-
 .../webapp/code/rosetta/core_app/fields.py    |   2 +-
 .../management/commands/core_app_populate.py  |  73 +--
 .../webapp/code/rosetta/core_app/models.py    | 121 ++---
 .../rosetta/core_app/templates/account.html   |  51 +-
 .../core_app/templates/add_profile_conf.html  |  27 +-
 .../core_app/templates/add_software.html      |  75 +--
 .../rosetta/core_app/templates/backend.html   |  13 +-
 .../templates/components/computing.html       |  30 +-
 .../templates/components/container.html       |  64 +--
 .../components/container_family.html          |  46 +-
 .../core_app/templates/components/task.html   |  76 +--
 .../templates/components/tzselect.html        |  14 +-
 .../rosetta/core_app/templates/computing.html |  15 +-
 .../rosetta/core_app/templates/error.html     |   9 +-
 .../rosetta/core_app/templates/footer.html    |   9 +-
 .../rosetta/core_app/templates/header.html    |   8 +-
 .../core_app/templates/import_repository.html |  39 +-
 .../rosetta/core_app/templates/login.html     |  25 +-
 .../code/rosetta/core_app/templates/main.html |   9 +-
 .../core_app/templates/navigation.html        |  45 +-
 .../rosetta/core_app/templates/new_task.html  |  65 +--
 .../code/rosetta/core_app/templates/page.html |   5 +-
 .../rosetta/core_app/templates/register.html  |  27 +-
 .../rosetta/core_app/templates/software.html  |  57 +--
 .../rosetta/core_app/templates/storage.html   |   9 +-
 .../rosetta/core_app/templates/success.html   |  13 +-
 .../core_app/templates/task_connect.html      |  49 +-
 .../rosetta/core_app/templates/task_log.html  |  27 +-
 .../rosetta/core_app/templates/tasks.html     |  13 +-
 .../code/rosetta/core_app/tests/common.py     |  11 +-
 .../code/rosetta/core_app/tests/test_apis.py  |  10 +-
 .../rosetta/core_app/tests/test_models.py     |  13 +-
 .../code/rosetta/core_app/tests/test_utils.py |  21 +-
 .../webapp/code/rosetta/core_app/utils.py     | 201 ++++----
 .../webapp/code/rosetta/core_app/views.py     | 287 +++++------
 services/webapp/code/rosetta/settings.py      |  25 +-
 services/webapp/code/rosetta/urls.py          |  25 +-
 services/webapp/prestartup_webapp.sh          |   2 -
 services/webapp/run_webapp.sh                 |  21 +-
 49 files changed, 1158 insertions(+), 1144 deletions(-)

diff --git a/rosetta/build b/rosetta/build
index 661699a..a3238b1 100755
--- a/rosetta/build
+++ b/rosetta/build
@@ -12,7 +12,7 @@ if [[ "x$1" == "xnocache" ]] ; then
     NOCACHE=true
     SERVICE=""
 elif [[ "x$2" == "xnocache" ]] ; then
-    NOCACHE=true 
+    NOCACHE=true
     SERVICE=$1
 else
     if [[ "x$NOCACHE" == "x" ]] ; then
@@ -29,20 +29,20 @@ else
 fi
 
 if [[ "x$SERVICE" == "x" ]] ; then
-    
+
     # Build all services
     NOCACHE=$NOCACHE rosetta/build base_ubuntu18.04
     NOCACHE=$NOCACHE rosetta/build base_ubuntu22.04
     NOCACHE=$NOCACHE rosetta/build slurmbase
-    NOCACHE=$NOCACHE rosetta/build slurmcluster    
-    NOCACHE=$NOCACHE rosetta/build slurmclustermaster    
-    NOCACHE=$NOCACHE rosetta/build slurmclusterworker    
-    NOCACHE=$NOCACHE rosetta/build standaloneworker     
+    NOCACHE=$NOCACHE rosetta/build slurmcluster
+    NOCACHE=$NOCACHE rosetta/build slurmclustermaster
+    NOCACHE=$NOCACHE rosetta/build slurmclusterworker
+    NOCACHE=$NOCACHE rosetta/build standaloneworker
     NOCACHE=$NOCACHE rosetta/build dregistry
     NOCACHE=$NOCACHE rosetta/build webapp
     NOCACHE=$NOCACHE rosetta/build postgres
     NOCACHE=$NOCACHE rosetta/build proxy
-    
+
 else
 
     # Build a specific image
diff --git a/rosetta/logs b/rosetta/logs
index c1f7123..844646e 100755
--- a/rosetta/logs
+++ b/rosetta/logs
@@ -14,7 +14,7 @@ fi
 if [[ "x$2" != "x" ]] ; then
     tail -f -n 1000 data/$1/log/$2.log
 else
-    docker-compose logs -f $1    
+    docker-compose logs -f $1
 fi
 
 
diff --git a/rosetta/shell b/rosetta/shell
index 1cf6033..03580d4 100755
--- a/rosetta/shell
+++ b/rosetta/shell
@@ -14,7 +14,7 @@ elif [[ $# -gt 2 ]] ; then
     echo "Use double quotes to wrap commands with spaces"
     exit 1
 else
-    
+
     COMMAND=$2
     if [[ "x$COMMAND" == "x" ]] ; then
         echo ""
diff --git a/rosetta/status b/rosetta/status
index 57a7260..ca1dccd 100755
--- a/rosetta/status
+++ b/rosetta/status
@@ -10,16 +10,16 @@ if [[ $# -eq 0 ]] ; then
 
     declare -a container_names
     OUT=$(rosetta/ps)
-    
+
     while read -r line; do
-        
+
         if [[ $line == *"Up"* ]]; then
             container_name=$(echo $line | cut -d ' ' -f1)
             container_names+=($container_name);
         fi
-        
+
     done <<< "$OUT" 
-      
+
     for container_name in ${container_names[@]}
     do
         echo ""
@@ -27,7 +27,7 @@ if [[ $# -eq 0 ]] ; then
         docker-compose exec $container_name /bin/bash -c "supervisorctl status"
     done
     echo ""
-    
+
 else
     docker-compose exec $@  /bin/bash -c "supervisorctl status"
 fi
diff --git a/services/webapp/code/rosetta/auth.py b/services/webapp/code/rosetta/auth.py
index 92c25a2..b6bc7fb 100644
--- a/services/webapp/code/rosetta/auth.py
+++ b/services/webapp/code/rosetta/auth.py
@@ -9,9 +9,9 @@ logger = logging.getLogger(__name__)
 
 
 class RosettaOIDCAuthenticationBackend(OIDCAuthenticationBackend):
-    
+
     def create_user(self, claims):
-        
+
         # Call parent user creation function
         user = super(RosettaOIDCAuthenticationBackend, self).create_user(claims)
 
@@ -27,12 +27,12 @@ class RosettaOIDCAuthenticationBackend(OIDCAuthenticationBackend):
 
 
 class RosettaOIDCAuthenticationCallbackView(OIDCAuthenticationCallbackView):
-    
+
     def login_success(self):
-        
+
         # Call parent login_success but do not return
         super(RosettaOIDCAuthenticationCallbackView, self).login_success()
-        
+
         logger.debug('Trying to get cookie-based post login redirect')
         post_login_page = self.request.COOKIES.get('post_login_redirect')
         if post_login_page:
@@ -44,3 +44,4 @@ class RosettaOIDCAuthenticationCallbackView(OIDCAuthenticationCallbackView):
             logger.debug('No cookie-based post login redirect found, redirecting to "%s"', self.success_url)
             return HttpResponseRedirect(self.success_url)
 
+
diff --git a/services/webapp/code/rosetta/context_processors.py b/services/webapp/code/rosetta/context_processors.py
index 0d563a3..bf226ab 100644
--- a/services/webapp/code/rosetta/context_processors.py
+++ b/services/webapp/code/rosetta/context_processors.py
@@ -2,7 +2,7 @@ import os
 from django.conf import settings
 def export_vars(request):
     data = {}
-    
+
     # Set open id connect enabled or not
     if settings.OIDC_RP_CLIENT_ID:
         data['OPENID_ENABLED'] = True
@@ -19,6 +19,6 @@ def export_vars(request):
     if settings.INVITATION_CODE:
         data['INVITATION_CODE_ENABLED'] = True
     else:
-        data['INVITATION_CODE_ENABLED'] = False   
-              
-    return data
\ No newline at end of file
+        data['INVITATION_CODE_ENABLED'] = False
+
+    return data
diff --git a/services/webapp/code/rosetta/core_app/api.py b/services/webapp/code/rosetta/core_app/api.py
index 96acb30..bc8886a 100644
--- a/services/webapp/code/rosetta/core_app/api.py
+++ b/services/webapp/code/rosetta/core_app/api.py
@@ -15,7 +15,7 @@ from .utils import format_exception, send_email, os_shell, now_t, get_ssh_access
 from .models import Profile, Task, TaskStatuses, Computing, Storage, KeyPair
 from .exceptions import ConsistencyException
 import json
- 
+
 # Setup logging
 logger = logging.getLogger(__name__)
 
@@ -24,33 +24,33 @@ ROSETTA_AGENT_CHECK_SSL = booleanize(os.environ.get('ROSETTA_AGENT_CHECK_SSL', T
 #==============================
 #  Common returns
 #==============================
- 
+
 # Ok (with data)
 def ok200(data=None):
     return Response({"results": data}, status=status.HTTP_200_OK)
- 
+
 # Error 400
 def error400(data=None):
     return Response({"detail": data}, status=status.HTTP_400_BAD_REQUEST)
- 
+
 # Error 401
 def error401(data=None):
     return Response({"detail": data}, status=status.HTTP_401_UNAUTHORIZED)
- 
+
 # Error 404
 def error404(data=None):
     return Response({"detail": data}, status=status.HTTP_404_NOT_FOUND)
- 
+
 # Error 500
 def error500(data=None):
     return Response({"detail": data}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
 
 
- 
+
 #==============================
 #  Authentication helper
 #==============================
- 
+
 def rosetta_authenticate(request):
 
     # Get data
@@ -65,22 +65,22 @@ def rosetta_authenticate(request):
 
     # Try username/password  authentication
     elif username or password:
-        
+
         # Check we got both
         if not username:
             return error400('Got empty username')
         if not password:
             return error400('Got empty password')
- 
+
         # Authenticate
         user = authenticate(username=username, password=password)
         if not user:
-            return error401('Wrong username/password')  
+            return error401('Wrong username/password')
         else:
             login(request, user)
             return user
 
-    # Try auth toekn authentication 
+    # Try auth toekn authentication
     elif authtoken:
         try:
             profile = Profile.objects.get(authtoken=authtoken)
@@ -96,7 +96,7 @@ def rosetta_authenticate(request):
 #  CSRF exempt auth class
 #==============================
 
-from rest_framework.authentication import SessionAuthentication, BasicAuthentication 
+from rest_framework.authentication import SessionAuthentication, BasicAuthentication
 
 class CsrfExemptSessionAuthentication(SessionAuthentication):
 
@@ -107,10 +107,10 @@ class CsrfExemptSessionAuthentication(SessionAuthentication):
 #==============================
 #  Base public API class
 #==============================
- 
+
 class PublicPOSTAPI(APIView):
     '''Base public POST API class'''
- 
+
     # POST
     def post(self, request):
         try:
@@ -118,9 +118,9 @@ class PublicPOSTAPI(APIView):
         except Exception as e:
             logger.error(format_exception(e))
             return error500('Got error in processing request: {}'.format(e))
- 
+
 class PublicGETAPI(APIView):
-    '''Base public GET API class''' 
+    '''Base public GET API class'''
     # GET
     def get(self, request):
         try:
@@ -134,43 +134,43 @@ class PublicGETAPI(APIView):
 #==============================
 #  Base private API class
 #==============================
- 
+
 class PrivatePOSTAPI(APIView):
     '''Base private POST API class'''
- 
+
     # POST
     def post(self, request):
         try:
             # Authenticate using rosetta authentication
             response = rosetta_authenticate(request)
-             
+
             # If we got a response return it, otherwise set it as the user.
             if isinstance(response, Response):
                 return response
             else:
                 self.user = response
-             
+
             # Call API logic
             return self._post(request)
         except Exception as e:
             logger.error(format_exception(e))
             return error500('Got error in processing request: {}'.format(e))
- 
+
 class PrivateGETAPI(APIView):
     '''Base private GET API class'''
 
-    # GET  
+    # GET
     def get(self, request):
         try:
             # Authenticate using rosetta authentication
             response = rosetta_authenticate(request)
-             
+
             # If we got a response return it, otherwise set it as the user.
             if isinstance(response, Response):
                 return response
             else:
                 self.user = response
-             
+
             # Call API logic
             return self._get(request)
         except Exception as e:
@@ -191,29 +191,29 @@ class login_api(PrivateGETAPI, PrivatePOSTAPI):
     post:
     Authorize and returns the auth token.
     """
-         
+
     def _post(self, request):
         return ok200({'authtoken': self.user.profile.authtoken})
 
     def _get(self, request):
-        return ok200({'authtoken': self.user.profile.authtoken}) 
- 
- 
+        return ok200({'authtoken': self.user.profile.authtoken})
+
+
 class logout_api(PrivateGETAPI):
     """
     get:
     Logout the user
     """
-         
+
     def _get(self, request):
         logout(request)
         return ok200()
 
 
 class agent_api(PublicGETAPI):
-    
+
     def _get(self, request):
-        
+
         task_uuid = request.GET.get('task_uuid', None)
         if not task_uuid:
             return HttpResponse('MISSING task_uuid')
@@ -228,9 +228,9 @@ class agent_api(PublicGETAPI):
 
         from.utils import get_webapp_conn_string
         webapp_conn_string = get_webapp_conn_string()
-        
+
         action = request.GET.get('action', None)
-        
+
         if not action:
             # Return the agent code
             agent_code='''
@@ -290,7 +290,7 @@ if not check_ssl:
 else:
     response = urlopen("'''+webapp_conn_string+'''/api/v1/base/agent/?task_uuid={}&action=set_ip_port&ip={}&port={}".format(task_uuid, ip, port))
 
-response_content = response.read() 
+response_content = response.read()
 
 if response_content not in ['OK', b'OK']:
     logger.error(response_content)
@@ -301,37 +301,37 @@ else:
     logger.info('Everything OK')
 print(port)
 '''
-        
+
             return HttpResponse(agent_code)
 
 
         elif action=='set_ip_port':
-            
+
             task_interface_ip   = request.GET.get('ip', None)
             if not task_interface_ip:
                 return HttpResponse('IP not valid (got "{}")'.format(task_interface_ip))
-            
+
             task_interface_port = request.GET.get('port', None)
             if not task_interface_port:
                 return HttpResponse('Port not valid (got "{}")'.format(task_interface_port))
-            
+
             try:
                 int(task_interface_port)
             except (TypeError, ValueError):
                 return HttpResponse('Port not valid (got "{}")'.format(task_interface_port))
-              
+
             # Set fields
             logger.info('Agent API setting task "{}" to ip "{}" and port "{}"'.format(task.uuid, task_interface_ip, task_interface_port))
             task.status = TaskStatuses.running
             task.interface_ip = task_interface_ip
-            
+
             # Get container engine
             container_engine = None
             if task.computing_options:
                 container_engine = task.computing_options.get('container_engine', None)
             if not container_engine:
                 container_engine = task.computing.default_container_engine
-            
+
             if container_engine=='singularity':
                 # For Singularity, set this only if the container supports custom
                 # interface ports. Otherwise, use the task container interface port.
@@ -342,10 +342,10 @@ print(port)
             else:
                 # For all other container engines, set it in any case
                 task.interface_port = int(task_interface_port)
-            
+
             # Save the task
             task.save()
-                    
+
             # Notify the user that the task called back home if using a WMS
             if task.computing.wms:
                 if settings.DJANGO_EMAIL_APIKEY:
@@ -357,7 +357,7 @@ print(port)
                     except Exception as e:
                         logger.error('Cannot send task ready email: "{}"'.format(e))
             return HttpResponse('OK')
-            
+
 
         else:
             return HttpResponse('Unknown action "{}"'.format(action))
@@ -375,7 +375,7 @@ class FileManagerAPI(PrivateGETAPI, PrivatePOSTAPI):
     post:
     Perform actions or upload files.
     """
-    
+
     # The RichFilemanager has no CSRF support...
     authentication_classes = (CsrfExemptSessionAuthentication, BasicAuthentication)
 
@@ -384,12 +384,12 @@ class FileManagerAPI(PrivateGETAPI, PrivatePOSTAPI):
 
         # Prepare paths for scp. They have been already made shell-ready, but we need to triple-escape
         # spaces on remote source or destination: My\ Folder must become My\\\ Folder.
-        
+
         if mode=='get':
             source = source.replace('\ ', '\\\\\\ ')
         else:
             dest = dest.replace('\ ', '\\\\\\ ')
-        
+
         # Get credentials
         computing_user, computing_host, computing_port, computing_keys = get_ssh_access_mode_credentials(computing, user)
 
@@ -410,15 +410,15 @@ class FileManagerAPI(PrivateGETAPI, PrivatePOSTAPI):
             if storage.access_through_computing:
                 # Get credentials
                 computing_user, computing_host, computing_port, computing_keys = get_ssh_access_mode_credentials(storage.computing, user)
-        
+
                 # Command
                 command = 'ssh -p {} -o LogLevel=ERROR -i {} -4 -o StrictHostKeyChecking=no {}@{} "{}"'.format(computing_port, computing_keys.private_key_file, computing_user, computing_host, command)
             else:
-                raise NotImplementedError('Not accessing through computing is not implemented for storage type "{}"'.format(storage.type))               
+                raise NotImplementedError('Not accessing through computing is not implemented for storage type "{}"'.format(storage.type))
         elif storage.access_mode == 'cli':
                 try:
                     as_user = storage.conf['as_user']
-                    
+
                     # Is "as_user" a UID?
                     try:
                         uid = int(as_user)
@@ -440,8 +440,8 @@ class FileManagerAPI(PrivateGETAPI, PrivatePOSTAPI):
                                     raise Exception(out.sterr)
                                 as_user = 'user_' + str(uid)
                             else:
-                                as_user = out.stdout.strip() 
- 
+                                as_user = out.stdout.strip()
+
                 except (KeyError, TypeError):
                     as_user = None
                 if as_user:
@@ -449,8 +449,8 @@ class FileManagerAPI(PrivateGETAPI, PrivatePOSTAPI):
                 else:
                     command = '/bin/bash -c "{}"'.format(command)
         else:
-            raise NotImplementedError('Access mode "{}" not implemented for storage type "{}"'.format(storage.access_mode, storage.type))               
-   
+            raise NotImplementedError('Access mode "{}" not implemented for storage type "{}"'.format(storage.access_mode, storage.type))
+
         return command
 
     @staticmethod
@@ -468,14 +468,14 @@ class FileManagerAPI(PrivateGETAPI, PrivatePOSTAPI):
 
     @staticmethod
     def sanitize_and_prepare_shell_path(path, user, storage, escapes=True):
-        
+
         if escapes:
             path = path.replace(' ', '\ ')
             cleaner = re.compile('(?:\\\)+')
             path = re.sub(cleaner,r"\\",path)
-                    
+
         # Prepare the base path (expand it with variables substitution)
-        base_path_expanded = storage.base_path        
+        base_path_expanded = storage.base_path
         if '$SSH_USER' in base_path_expanded:
             if storage.access_through_computing:
                 computing = storage.computing
@@ -486,7 +486,7 @@ class FileManagerAPI(PrivateGETAPI, PrivatePOSTAPI):
                     base_path_expanded = base_path_expanded.replace('$SSH_USER', computing_user)
                 else:
                     base_path_expanded = base_path_expanded.replace('$SSH_USER', computing.conf.get('user'))
-                    
+
             else:
                 raise NotImplementedError('Accessing a storage with ssh+cli without going through its computing resource is not implemented')
         if '$USER' in base_path_expanded:
@@ -495,7 +495,7 @@ class FileManagerAPI(PrivateGETAPI, PrivatePOSTAPI):
         # If the path is not starting with the base path, do it
         if not path.startswith(base_path_expanded):
             path = base_path_expanded+'/'+path
-            
+
         return path
 
     def get_storage_from_path(self, path, request):
@@ -508,10 +508,10 @@ class FileManagerAPI(PrivateGETAPI, PrivatePOSTAPI):
         except IndexError:
             storage_name = storage_id
             computing_name = None
-            
+
         # Get all the storages this user has access to:
         storages = list(Storage.objects.filter(group=None, name=storage_name)) + list(Storage.objects.filter(group__user=request.user, name=storage_name))
-        
+
         # Filter by computing resource name (or None)
         if computing_name:
             unfiltered_storages = storages
@@ -524,8 +524,8 @@ class FileManagerAPI(PrivateGETAPI, PrivatePOSTAPI):
             storages = []
             for storage in unfiltered_storages:
                 if storage.computing is None:
-                    storages.append(storage)            
-            
+                    storages.append(storage)
+
 
         # Check that we had at least and no more than one storage in the end
         if len(storages) == 0:
@@ -537,21 +537,21 @@ class FileManagerAPI(PrivateGETAPI, PrivatePOSTAPI):
         storage = storages[0]
 
         return storage
-                
+
 
     def ls(self, path, user, storage):
-        
-        # Data container 
+
+        # Data container
         data = []
-        
+
         if storage.type == 'generic_posix':
 
             shell_path = self.sanitize_and_prepare_shell_path(path, user, storage)
-            
+
             # Prepare command
             # https://askubuntu.com/questions/1116634/ls-command-show-time-only-in-iso-format
             # https://www.howtogeek.com/451022/how-to-use-the-stat-command-on-linux/
-            
+
             command = self.prepare_sh_command('cd {} && stat --printf=\'%F/%s/%Y/%n\\n\' * .*'.format(shell_path), user, storage)
 
             # Execute_command
@@ -560,39 +560,39 @@ class FileManagerAPI(PrivateGETAPI, PrivatePOSTAPI):
 
                 # Did we just get a "cannot stat - No such file or directory" (bash) or a "can't cd to" (sh) error?
                 if 'No such file or directory' in out.stderr or 'can\'t cd to' in out.stderr :
-                    
+
                     # Create the folder if this was the root for the user (storage base path)
                     # Note: if the folder is completely empty, this gets execute as well.
                     # TODO: fix me (e.g. check for "cannot stat" or similar)
                     if path == '/':
                         self.mkdir(self.sanitize_and_prepare_shell_path('/', user, storage), user, storage, force=True)
-                    
+
                     # Return (empty) data
                     return data
-                
+
                 else:
                     raise Exception(out.stderr)
-                                
-            # Log        
+
+            # Log
             #logger.debug('Shell exec output: "{}"'.format(out))
-            
+
             out_lines = out.stdout.split('\n')
-            
+
             for line in out_lines:
-                
+
                 # Example line: directory/My folder/68/1617030350
-    
+
                 # Set name
                 line_pieces = line.split('/')
                 type = line_pieces[0]
                 size = line_pieces[1]
                 timestamp = line_pieces[2]
                 name = line_pieces[3]
-                         
+
                 # Define and clean listing path:
                 listing_path = '/{}/{}/{}/'.format(storage.id, path, name)
                 listing_path = self.clean_path(listing_path)
-            
+
                 # File or directory?
                 if type == 'directory':
                     if name not in ['.', '..']:
@@ -604,12 +604,12 @@ class FileManagerAPI(PrivateGETAPI, PrivatePOSTAPI):
                                           'name': name,
                                           'readable': 1,
                                           'writable': 1,
-                                          'path': listing_path                                 
+                                          'path': listing_path
                                       }
                                      })
                 else:
                     data.append({
-                                 'id': listing_path[:-1], # Remove trailing slash 
+                                 'id': listing_path[:-1], # Remove trailing slash
                                  'type': 'file',
                                  'attributes':{
                                       'modified': timestamp,
@@ -617,68 +617,68 @@ class FileManagerAPI(PrivateGETAPI, PrivatePOSTAPI):
                                       'readable': 1,
                                       'writable': 1,
                                       "size": size,
-                                      'path': listing_path[:-1] # Remove trailing slash                               
+                                      'path': listing_path[:-1] # Remove trailing slash
                                   }
-                                 })                            
-                
+                                 })
+
         else:
-            raise NotImplementedError('Storage type "{}" not implemented'.format(storage.type))               
-            
+            raise NotImplementedError('Storage type "{}" not implemented'.format(storage.type))
+
         return data
 
 
     def stat(self, path, user, storage):
 
-        # Data container 
+        # Data container
         data = []
 
         if storage.type == 'generic_posix':
 
             shell_path = self.sanitize_and_prepare_shell_path(path, user, storage)
-            
+
             # Prepare command. See the ls function above for some more info
             command = self.prepare_sh_command('stat --printf=\'%F/%s/%Y/%n\\n\' {}'.format(shell_path), user, storage)
-            
+
             # Execute_command
             out = os_shell(command, capture=True)
             if out.exit_code != 0:
-                
+
                 # Did we just get a "cannot stat - No such file or directory error?
                 if 'No such file or directory' in out.stderr:
                     pass
                 else:
                     raise Exception(out.stderr)
-                                
-            # Log        
+
+            # Log
             #logger.debug('Shell exec output: "{}"'.format(out))
-            
+
             out_lines = out.stdout.split('\n')
             if len(out_lines) > 1:
                 raise Exception('Internal error on stat: more than one ouput line')
             out_line = out_lines[0]
-        
+
             # Example output line: directory:My folder:68/1617030350
             # In this context, we also might get the following output:
             # directory/68/1617030350//My folder/
             # ..so, use the clean path to remove all extra slashes.
             # The only uncovered case is to rename the root folder...
-            
+
             out_line = self.clean_path(out_line)
-    
+
             # Set names
             line_pieces = out_line.split('/')
             type = line_pieces[0]
             size = line_pieces[1]
             timestamp = line_pieces[2]
             name = '/'.join(line_pieces[3:])
-            
+
             data = {'type': type, 'name': name, 'size': size, 'timestamp': timestamp}
 
         else:
-            raise NotImplementedError('Storage type "{}" not implemented'.format(storage.type))                           
-        
+            raise NotImplementedError('Storage type "{}" not implemented'.format(storage.type))
+
         return data
-            
+
 
 
     def delete(self, path, user, storage):
@@ -686,18 +686,18 @@ class FileManagerAPI(PrivateGETAPI, PrivatePOSTAPI):
         if storage.type == 'generic_posix':
 
             shell_path = self.sanitize_and_prepare_shell_path(path, user, storage)
-    
+
             # Prepare command
             command = self.prepare_sh_command('rm -rf {}'.format(shell_path), user, storage)
-            
+
             # Execute_command
             out = os_shell(command, capture=True)
             if out.exit_code != 0:
                 raise Exception(out.stderr)
-        
+
         else:
-            raise NotImplementedError('Storage type "{}" not implemented'.format(storage.type))               
-            
+            raise NotImplementedError('Storage type "{}" not implemented'.format(storage.type))
+
 
     def mkdir(self, path, user, storage, force=False):
 
@@ -709,28 +709,28 @@ class FileManagerAPI(PrivateGETAPI, PrivatePOSTAPI):
                 command = self.prepare_sh_command('mkdir -p {}'.format(path), user, storage)
             else:
                 command = self.prepare_sh_command('mkdir {}'.format(path), user, storage)
-            
+
             # Execute_command
             out = os_shell(command, capture=True)
             if out.exit_code != 0:
                 raise Exception(out.stderr)
-        
+
         else:
-            raise NotImplementedError('Storage type "{}" not implemented'.format(storage.type))               
+            raise NotImplementedError('Storage type "{}" not implemented'.format(storage.type))
 
 
     def cat(self, path, user, storage):
-        
-        # Data container 
+
+        # Data container
         data = []
 
         if storage.type == 'generic_posix':
-   
+
             shell_path = self.sanitize_and_prepare_shell_path(path, user, storage)
-            
+
             # Prepare command
             command = self.prepare_sh_command('cat {}'.format(shell_path), user, storage)
-            
+
             # Execute_command
             out = os_shell(command, capture=True)
             if out.exit_code != 0:
@@ -738,7 +738,7 @@ class FileManagerAPI(PrivateGETAPI, PrivatePOSTAPI):
             data = out.stdout
 
         else:
-            raise NotImplementedError('Storage type "{}" not implemented'.format(storage.type))               
+            raise NotImplementedError('Storage type "{}" not implemented'.format(storage.type))
 
         return data
 
@@ -746,22 +746,22 @@ class FileManagerAPI(PrivateGETAPI, PrivatePOSTAPI):
     def rename(self, old, new, user, storage):
 
         if storage.type == 'generic_posix':
-       
+
             old = self.sanitize_and_prepare_shell_path(old, user, storage)
             new = self.sanitize_and_prepare_shell_path(new, user, storage)
-    
+
             # Prepare command
             command = self.prepare_sh_command('mv {} {}'.format(old, new), user, storage)
-    
+
             logger.critical(command)
-            
+
             # Execute_command
             out = os_shell(command, capture=True)
             if out.exit_code != 0:
                 raise Exception(out.stderr)
-        
+
         else:
-            raise NotImplementedError('Storage type "{}" not implemented'.format(storage.type))               
+            raise NotImplementedError('Storage type "{}" not implemented'.format(storage.type))
 
 
     def copy(self, source, target, user, storage):
@@ -770,17 +770,17 @@ class FileManagerAPI(PrivateGETAPI, PrivatePOSTAPI):
 
             source = self.sanitize_and_prepare_shell_path(source, user, storage)
             target = self.sanitize_and_prepare_shell_path(target, user, storage)
-    
+
             # Prepare command
             command = self.prepare_sh_command('cp -a {} {}'.format(source, target), user, storage)
-            
+
             # Execute_command
             out = os_shell(command, capture=True)
             if out.exit_code != 0:
                 raise Exception(out.stderr)
-            
+
         else:
-            raise NotImplementedError('Storage type "{}" not implemented'.format(storage.type))               
+            raise NotImplementedError('Storage type "{}" not implemented'.format(storage.type))
 
 
     def scp_from(self, source, target, user, storage, mode='get'):
@@ -815,44 +815,44 @@ class FileManagerAPI(PrivateGETAPI, PrivatePOSTAPI):
     #   API GET
     #============================
     def _get(self, request):
-        
+
         mode = request.GET.get('mode', None)
         time = request.GET.get('time', None)
         path = request.GET.get('path', None)
         _ = request.GET.get('_', None)
-        
+
         # Clean for some issues that happen sometimes
         if path:
             path = self.clean_path(path)
-        
+
         # Init
         if mode == 'initiate':
             data = json.loads('{"data":{"attributes":{"config":{"options":{"culture":"en"},"security":{"allowFolderDownload":true,"extensions":{"ignoreCase":true,"policy":"DISALLOW_LIST","restrictions":[]},"readOnly":false}}},"id":"/","type":"initiate"}}')
 
         elif mode == 'readfolder':
-            
+
             # Base folder (computing resource-level)
             if path == '/':
-                
-                # Data container 
+
+                # Data container
                 data = {'data':[]}
-                
+
                 # Get storages
                 storages = list(Storage.objects.filter(group=None,browsable=True)) + list(Storage.objects.filter(group__user=request.user,browsable=True))
-                
+
                 # Oder storages (re-orderded in the file manager anyway)
                 storages.sort(key=lambda storage: storage.id)
-                
+
                 # Prepare the output
                 for storage in storages:
-                    
+
                     # For now, we only support generic posix, SSH-based storages
                     if not storage.type=='generic_posix'  and storage.access_mode=='ssh+cli':
                         continue
-                    
+
                     if storage.access_through_computing and not storage.computing.manager.is_configured_for(user=request.user):
                         continue
-                    
+
                     data['data'].append({
                                          'id': '/{}/'.format(storage.id),
                                          'type': 'folder',
@@ -860,15 +860,15 @@ class FileManagerAPI(PrivateGETAPI, PrivatePOSTAPI):
                                               'name': storage.id,
                                               'readable': 1,
                                               'writable': 1,
-                                              'path': '/{}/'.format(storage.id)                                   
+                                              'path': '/{}/'.format(storage.id)
                                           }
                                          })
-                
+
             else:
-                                
+
                 storage = self.get_storage_from_path(path, request)
-                
-                # Get base directoris and files for this storage:                
+
+                # Get base directoris and files for this storage:
                 ls_path = '/'+'/'.join(path.split('/')[2:])
                 data = {'data': self.ls(ls_path, request.user, storage)}
 
@@ -879,12 +879,12 @@ class FileManagerAPI(PrivateGETAPI, PrivatePOSTAPI):
             # Set support vars
             storage = self.get_storage_from_path(path, request)
             file_path = '/'+'/'.join(path.split('/')[2:])
-            
+
             if path.endswith('/'):
                 return error400('Downloading a folder is not supported')
-            
+
             if storage.type != 'generic_posix':
-                raise NotImplementedError('Storage type "{}" not implemented'.format(storage.type))               
+                raise NotImplementedError('Storage type "{}" not implemented'.format(storage.type))
 
             # TODO: here we are not handling the ajax request, Maybe they have been deperacted?
             # The download process consists of 2 requests:
@@ -894,23 +894,23 @@ class FileManagerAPI(PrivateGETAPI, PrivatePOSTAPI):
 
             if storage.access_mode == 'ssh+cli':
                 target_path = '/tmp/{}'.format(uuid.uuid4())
-    
+
                 # Get the file
-                self.scp_from(file_path, target_path, request.user, storage, mode='get') 
-    
+                self.scp_from(file_path, target_path, request.user, storage, mode='get')
+
                 # Detect content type
                 try:
                     content_type =  str(magic.from_file(target_path, mime=True))
                 except:
                     content_type = None
-    
+
                 # Read file data
                 with open(target_path, 'rb') as f:
                     data = f.read()
-                
+
                 # Remove temporary file
                 os.remove(target_path)
-                
+
             elif storage.access_mode == 'cli':
 
                 # Define storage internal source path
@@ -921,13 +921,13 @@ class FileManagerAPI(PrivateGETAPI, PrivatePOSTAPI):
                     content_type =  str(magic.from_file(storage_source_path, mime=True))
                 except:
                     content_type = None
-    
+
                 # Read file data
                 with open(storage_source_path, 'rb') as f:
                     data = f.read()
-            
+
             else:
-                raise NotImplementedError('Storage access mode "{}" not implemented'.format(storage.access_mode))               
+                raise NotImplementedError('Storage access mode "{}" not implemented'.format(storage.access_mode))
 
             # Return file data
             response = HttpResponse(data, status=status.HTTP_200_OK, content_type=content_type)
@@ -936,21 +936,21 @@ class FileManagerAPI(PrivateGETAPI, PrivatePOSTAPI):
 
         elif mode == 'readfile':
             logger.debug('Reading "{}"'.format(path))
-            
+
             # Set support vars
             storage = self.get_storage_from_path(path, request)
             file_path = '/'+'/'.join(path.split('/')[2:])
 
             # Get file contents
             data = self.cat(file_path, request.user, storage)
-            
+
             # Return file contents
             return HttpResponse(data, status=status.HTTP_200_OK)
 
 
         elif mode == 'delete':
             logger.debug('Deleting "{}"'.format(path))
-            
+
             # Set support vars
             storage = self.get_storage_from_path(path, request)
             path = '/'+'/'.join(path.split('/')[2:])
@@ -972,23 +972,23 @@ class FileManagerAPI(PrivateGETAPI, PrivatePOSTAPI):
                                 'name': path,
                                 'readable': 1,
                                 'writable': 1,
-                                'path': '/{}{}'.format(storage.id, path)                            
+                                'path': '/{}{}'.format(storage.id, path)
                             }
                         }
-                    }      
-            
-            
+                    }
+
+
             # Return file contents
             return Response(data, status=status.HTTP_200_OK)
-            
+
 
         elif mode == 'addfolder':
             logger.debug('Deleting "{}"'.format(path))
-            
+
             name = request.GET.get('name', None)
             if not name:
                 raise ValueError('No folder name set')
-            
+
             # Set support vars
             storage = self.get_storage_from_path(path, request)
             path = '/'+'/'.join(path.split('/')[2:]) + name
@@ -1005,27 +1005,27 @@ class FileManagerAPI(PrivateGETAPI, PrivatePOSTAPI):
                                 'name': name,
                                 'readable': 1,
                                 'writable': 1,
-                                'path': '/{}{}'.format(storage.id, path)                            
+                                'path': '/{}{}'.format(storage.id, path)
                             }
                         }
-                    }      
-            
+                    }
+
             # Return file contents
             return Response(data, status=status.HTTP_200_OK)
 
 
         elif mode == 'rename':
             logger.debug('Renaming "{}"'.format(path))
-            
+
             # Get old file name with path
             old_name_with_path = request.GET.get('old', None)
             if not old_name_with_path:
-                raise Exception('Missing old name')            
-            
+                raise Exception('Missing old name')
+
             # Set support vars
             storage = self.get_storage_from_path(old_name_with_path, request)
             old_name_with_path = '/'+'/'.join(old_name_with_path.split('/')[2:])
-            
+
             # Is it a folder?
             if old_name_with_path.endswith('/'):
                 is_folder=True
@@ -1036,7 +1036,7 @@ class FileManagerAPI(PrivateGETAPI, PrivatePOSTAPI):
             new_name = request.GET.get('new', None)
             if not new_name:
                 raise Exception('Missing new name')
-            
+
             if is_folder:
                 new_name_with_path = '/'.join(old_name_with_path.split('/')[:-2]) + '/' +  new_name
                 old_name_with_path = old_name_with_path[:-1]
@@ -1045,11 +1045,11 @@ class FileManagerAPI(PrivateGETAPI, PrivatePOSTAPI):
 
             # Rename
             self.rename(old_name_with_path, new_name_with_path, request.user, storage)
-            
+
             # Add trailing slash for listing
             if is_folder:
                 new_name_with_path = new_name_with_path+'/'
-            
+
             # Get new info
             stat = self.stat(new_name_with_path, request.user, storage)
 
@@ -1062,31 +1062,31 @@ class FileManagerAPI(PrivateGETAPI, PrivatePOSTAPI):
                                 'name': new_name,
                                 'readable': 1,
                                 'writable': 1,
-                                'path': '/{}{}'.format(storage.id, new_name_with_path)                              
+                                'path': '/{}{}'.format(storage.id, new_name_with_path)
                             }
                         }
-                    }      
-            
+                    }
+
             # Add size if file
             if not is_folder: data['data']['attributes']['size'] = stat['size']
-            
+
             # Return file contents
             return Response(data, status=status.HTTP_200_OK)
 
 
         elif mode == 'copy':
             logger.debug('Copying "{}"'.format(path))
-            
+
             # Get source for copy
             source_name_with_path = request.GET.get('source', None)
             if not source_name_with_path:
-                raise Exception('Missing source for copy') 
-            
+                raise Exception('Missing source for copy')
+
             # Get target for copy
             target_path = request.GET.get('target', None)
             if not target_path:
                 raise Exception('Missing target for copy')
-            
+
 
             if source_name_with_path.endswith('/'):
                 is_folder=True
@@ -1096,10 +1096,10 @@ class FileManagerAPI(PrivateGETAPI, PrivatePOSTAPI):
 
             # Set support vars
             storage = self.get_storage_from_path(source_name_with_path, request)
-            
+
             if is_folder:
                 source_name_with_path = '/'+'/'.join(source_name_with_path.split('/')[2:])[:-1]
-                target_name_with_path = '/'+'/'.join(target_path.split('/')[2:]) +  source_name_with_path.split('/')[-1]            
+                target_name_with_path = '/'+'/'.join(target_path.split('/')[2:]) +  source_name_with_path.split('/')[-1]
             else:
                 source_name_with_path = '/'+'/'.join(source_name_with_path.split('/')[2:])
                 target_name_with_path = '/'+'/'.join(target_path.split('/')[2:]) +  source_name_with_path.split('/')[-1]
@@ -1121,7 +1121,7 @@ class FileManagerAPI(PrivateGETAPI, PrivatePOSTAPI):
 
             # Get new info
             stat = self.stat(target_name_with_path, request.user, storage)
- 
+
             # Response data
             data = { 'data': {
                             'id': '/{}{}'.format(storage.id, target_name_with_path),
@@ -1131,25 +1131,25 @@ class FileManagerAPI(PrivateGETAPI, PrivatePOSTAPI):
                                 'name': target_name_with_path.split('/')[-2] if is_folder else target_name_with_path.split('/')[-1],
                                 'readable': 1,
                                 'writable': 1,
-                                'path': '/{}{}'.format(storage.id, target_name_with_path)                            
+                                'path': '/{}{}'.format(storage.id, target_name_with_path)
                             }
                         }
                     }
 
             # Add size if file
-            if not is_folder: data['data']['attributes']['size'] = stat['size']      
-            
+            if not is_folder: data['data']['attributes']['size'] = stat['size']
+
             # Return file contents
             return Response(data, status=status.HTTP_200_OK)
-  
+
         else:
             return error400('Operation "{}" not supported'.format(mode))
-  
+
         return Response(data, status=status.HTTP_200_OK)
 
 
     #============================
-    #   API POST 
+    #   API POST
     #============================
     def _post(self, request):
 
@@ -1160,33 +1160,33 @@ class FileManagerAPI(PrivateGETAPI, PrivatePOSTAPI):
 
         if mode == 'savefile':
             return error400('Operation "{}" not supported'.format(mode))
-        
+
         elif mode == 'upload':
 
             # Set support vars
             storage = self.get_storage_from_path(path, request)
             path = '/'+'/'.join(path.split('/')[2:])
-            
+
             # Bug workaround?
             if not path.endswith('/'):
-                path += '/' 
+                path += '/'
 
             # Get the file upload
             file_upload = request.FILES['files']
 
             if storage.access_mode == 'ssh+cli':
-                
+
                 # Generate temporary UUID
                 file_uuid = uuid.uuid4()
-                
+
                 with open('/tmp/{}'.format(file_uuid), 'wb') as temp_file:
                     temp_file.write(file_upload.read())
-                
+
                 logger.debug('Wrote "/tmp/{}" for "{}"'.format(file_uuid, file_upload.name))
-    
+
                 # Now copy with scp
                 self.scp_to('/tmp/{}'.format(file_uuid), path + file_upload.name , request.user, storage, mode='put')
-            
+
                 # Response data
                 data = { 'data': [{
                                 'id': '/{}{}{}'.format(storage.id, path, file_upload.name),
@@ -1197,19 +1197,19 @@ class FileManagerAPI(PrivateGETAPI, PrivatePOSTAPI):
                                     'readable': 1,
                                     'size': os.path.getsize('/tmp/{}'.format(file_uuid)), # This is kind of an approximation!
                                     'writable': 1,
-                                    'path': '/{}{}{}'.format(storage.id, path, file_upload.name)                            
+                                    'path': '/{}{}{}'.format(storage.id, path, file_upload.name)
                                 }
                             }]
                         }
-                
+
                 # Remove file
-                os.remove('/tmp/{}'.format(file_uuid)) 
-                   
+                os.remove('/tmp/{}'.format(file_uuid))
+
             if storage.access_mode == 'cli':
-      
+
                 try:
                     as_user = storage.conf['as_user']
-                    
+
                     # Is "as_user" a UID?
                     try:
                         uid = int(as_user)
@@ -1231,12 +1231,12 @@ class FileManagerAPI(PrivateGETAPI, PrivatePOSTAPI):
                                     raise Exception(out.sterr)
                                 as_user = 'user_' + str(uid)
                             else:
-                                as_user = out.stdout.strip() 
- 
+                                as_user = out.stdout.strip()
+
                 except (KeyError, TypeError):
                     as_user = None
-      
-          
+
+
                 # Define storage internal dest path
                 storage_dest_path = self.sanitize_and_prepare_shell_path(path + file_upload.name, request.user, storage, escapes=False)
                 storage_dest_path_escaped = self.sanitize_and_prepare_shell_path(path + file_upload.name, request.user, storage, escapes=True)
@@ -1246,26 +1246,26 @@ class FileManagerAPI(PrivateGETAPI, PrivatePOSTAPI):
                 if as_user:
                     # Generate temporary UUID
                     file_uuid = uuid.uuid4()
-                    
+
                     with open('/tmp/{}'.format(file_uuid), 'wb') as temp_file:
                         temp_file.write(file_upload.read())
                     file_size = os.path.getsize('/tmp/{}'.format(file_uuid))
-                                        
+
                     # Change ownership and move
                     os_shell('sudo -i -u {0} chown {0}:{0} /tmp/{1}'.format(as_user, file_uuid), capture=True)
                     if out.exit_code != 0:
                         raise Exception(out.sterr)
                     os_shell('sudo -i -u {0} mv /tmp/{1} {2}'.format(as_user, file_uuid, storage_dest_path_escaped), capture=True)
                     if out.exit_code != 0:
-                        raise Exception(out.sterr)                   
-                       
+                        raise Exception(out.sterr)
+
                 else:
                     with open(storage_dest_path, 'wb') as upload_file:
                         upload_file.write(file_upload.read())
                     file_size = os.path.getsize(storage_dest_path)
-                    
+
                 logger.debug('Wrote "{}" for "{}"'.format(storage_dest_path, file_upload.name))
-    
+
                 # Response data
                 data = { 'data': [{
                                 'id': '/{}{}{}'.format(storage.id, path, file_upload.name),
@@ -1276,17 +1276,17 @@ class FileManagerAPI(PrivateGETAPI, PrivatePOSTAPI):
                                     'readable': 1,
                                     'size': file_size,
                                     'writable': 1,
-                                    'path': '/{}{}{}'.format(storage.id, path, file_upload.name)                            
+                                    'path': '/{}{}{}'.format(storage.id, path, file_upload.name)
                                 }
                             }]
                         }
 
             else:
-                raise NotImplementedError('Storage access mode "{}" not implemented'.format(storage.access_mode))               
-              
+                raise NotImplementedError('Storage access mode "{}" not implemented'.format(storage.access_mode))
+
             # Return
             return Response(data, status=status.HTTP_200_OK)
-        
+
         else:
             return error400('Operation "{}" not supported'.format(mode))
 
@@ -1303,7 +1303,7 @@ class ImportRepositoryAPI(PrivateGETAPI):
     """
 
     def _get(self, request):
-        
+
         repository_url = request.GET.get('repository_url', None)
         repository_tag = request.GET.get('repository_tag', None)
         container_name = request.GET.get('container_name', None)
@@ -1314,11 +1314,11 @@ class ImportRepositoryAPI(PrivateGETAPI):
 
         if not repository_tag:
             return error400('Missing "repository_tag"')
-  
+
         logger.debug('Importing repository "%s" with tag "%s"', repository_url, repository_tag)
 
         results = {}
-        try:     
+        try:
             container = get_or_create_container_from_repository(request.user, repository_url, repository_tag, container_name, container_description)
         except Exception as e:
             results['import_succeded'] = False
@@ -1326,8 +1326,9 @@ class ImportRepositoryAPI(PrivateGETAPI):
         else:
             results['import_succeded'] = True
             results['container_uuid'] = str(container.uuid)
-             
-        return ok200(results) 
+
+        return ok200(results)
+
 
 
 
diff --git a/services/webapp/code/rosetta/core_app/computing_managers.py b/services/webapp/code/rosetta/core_app/computing_managers.py
index 8e676a4..af507e5 100644
--- a/services/webapp/code/rosetta/core_app/computing_managers.py
+++ b/services/webapp/code/rosetta/core_app/computing_managers.py
@@ -12,37 +12,37 @@ ROSETTA_AGENT_CHECK_SSL = booleanize(os.environ.get('ROSETTA_AGENT_CHECK_SSL', T
 CHECK_CURL_CERT_STR = '--insecure' if not ROSETTA_AGENT_CHECK_SSL else ''
 
 class ComputingManager(object):
-    
+
     def __init__(self, computing):
         self.computing = computing
-    
+
     def start_task(self, task, **kwargs):
-        
+
         # Check for run task logic implementation
         try:
             self._start_task
         except AttributeError:
             raise NotImplementedError('Not implemented')
-        
+
         # Call actual run task logic
         self._start_task(task, **kwargs)
 
 
     def stop_task(self, task, **kwargs):
-        
+
         # Check for stop task logic implementation
         try:
             self._stop_task
         except AttributeError:
             raise NotImplementedError('Not implemented')
-        
+
         # Call actual stop task logic
         self._stop_task(task, **kwargs)
-        
+
         # Ok, save status as deleted
         task.status = 'stopped'
         task.save()
-        
+
         # Check if the tunnel is active and if so kill it
         logger.debug('Checking if task "{}" has a running tunnel'.format(task.uuid))
         check_command = 'ps -ef | grep ":'+str(task.tcp_tunnel_port)+':'+str(task.interface_ip)+':'+str(task.interface_port)+'" | grep -v grep | awk \'{print $2}\''
@@ -54,10 +54,10 @@ class ComputingManager(object):
             tunnel_pid = out.stdout
             # Kill Tunnel command
             kill_tunnel_command= 'kill -9 {}'.format(tunnel_pid)
-        
+
             # Log
             logger.debug('Killing tunnel with command: {}'.format(kill_tunnel_command))
-        
+
             # Execute
             os_shell(kill_tunnel_command, capture=True)
             if out.exit_code != 0:
@@ -65,16 +65,16 @@ class ComputingManager(object):
 
 
     def get_task_log(self, task, **kwargs):
-        
+
         # Check for get task log logic implementation
         try:
             self._get_task_log
         except AttributeError:
             raise NotImplementedError('Not implemented')
-        
+
         # Call actual get task log logic
         return self._get_task_log(task, **kwargs)
-    
+
     def is_configured_for(self, user):
         return True
 
@@ -88,7 +88,7 @@ class ClusterComputingManager(ComputingManager):
 
 
 class SSHComputingManager(ComputingManager):
-    
+
     def is_configured_for(self, user):
         try:
             get_ssh_access_mode_credentials(self.computing, user)
@@ -100,7 +100,7 @@ class SSHComputingManager(ComputingManager):
 
 
 class InternalStandaloneComputingManager(StandaloneComputingManager):
-    
+
     def _start_task(self, task):
 
         # Init run command #--cap-add=NET_ADMIN --cap-add=NET_RAW
@@ -121,10 +121,10 @@ class InternalStandaloneComputingManager(StandaloneComputingManager):
 
         # Env vars if any
         if task.container.env_vars:
-            
+
             # Sanitize again just in case the DB got somehow compromised:
             env_vars = sanitize_container_env_vars(task.container.env_vars)
-            
+
             for env_var in env_vars:
                 run_command += ' -e{}={} '.format(env_var, env_vars[env_var])
 
@@ -136,17 +136,17 @@ class InternalStandaloneComputingManager(StandaloneComputingManager):
         storages = Storage.objects.filter(computing=self.computing)
         for storage in storages:
             if storage.type == 'generic_posix' and storage.bind_path:
-                
+
                 # Expand the base path
-                expanded_base_path = storage.base_path        
+                expanded_base_path = storage.base_path
                 if '$USER' in expanded_base_path:
                     expanded_base_path = expanded_base_path.replace('$USER', task.user.username)
-                    
+
                 # Expand the bind_path
-                expanded_bind_path = storage.bind_path        
+                expanded_bind_path = storage.bind_path
                 if '$USER' in expanded_bind_path:
                     expanded_bind_path = expanded_bind_path.replace('$USER', task.user.username)
-                    
+
                 # Add the bind
                 if not binds:
                     binds = '-v{}:{}'.format(expanded_base_path, expanded_bind_path)
@@ -158,14 +158,14 @@ class InternalStandaloneComputingManager(StandaloneComputingManager):
 
         # Debug
         logger.debug('Running new task with command="{}"'.format(run_command))
-        
-        # Run the task 
+
+        # Run the task
         out = os_shell(run_command, capture=True)
         if out.exit_code != 0:
             logger.error('Got error in starting task: {}'.format(out))
             raise Exception(out.stderr)
         else:
-            
+
             # Get task IP address
             out = os_shell('export CONTAINER_ID=$(sudo docker ps -a --filter name=task-'+task.short_uuid+' --format {{.ID}}) && sudo docker inspect --format \'{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}\' $CONTAINER_ID | tail -n1', capture=True)
             if out.exit_code != 0:
@@ -179,7 +179,7 @@ class InternalStandaloneComputingManager(StandaloneComputingManager):
 
             # Save
             task.save()
-        
+
         # Setup the tunnel if using a custom protocol (otherwise it will get set up via the "connect" button)
         if task.container.interface_protocol not in ['http', 'https']:
             setup_tunnel_and_proxy(task)
@@ -188,7 +188,7 @@ class InternalStandaloneComputingManager(StandaloneComputingManager):
 
         # Delete the Docker container
         stop_command = 'export CONTAINER_ID=$(sudo docker ps -a --filter name=task-'+task.short_uuid+' --format {{.ID}}) && sudo docker stop $CONTAINER_ID && sudo docker rm $CONTAINER_ID'
-    
+
         out = os_shell(stop_command, capture=True)
         if out.exit_code != 0:
             if 'No such container' in out.stderr:
@@ -199,12 +199,12 @@ class InternalStandaloneComputingManager(StandaloneComputingManager):
                 pass
             else:
                 raise Exception(out.stderr)
- 
+
         # Set task as stopped
         task.status = TaskStatuses.stopped
         task.save()
 
-    
+
     def _get_task_log(self, task, **kwargs):
 
         # View the Docker container log (attach)
@@ -219,7 +219,7 @@ class InternalStandaloneComputingManager(StandaloneComputingManager):
 
 
 class SSHStandaloneComputingManager(StandaloneComputingManager, SSHComputingManager):
-    
+
     def _start_task(self, task, **kwargs):
         logger.debug('Starting a remote task "{}"'.format(self.computing))
 
@@ -229,7 +229,7 @@ class SSHStandaloneComputingManager(StandaloneComputingManager, SSHComputingMana
         # Get webapp conn string
         from.utils import get_webapp_conn_string
         webapp_conn_string = get_webapp_conn_string()
-            
+
         # Handle container engine
         container_engine = None
         if task.computing_options:
@@ -237,7 +237,7 @@ class SSHStandaloneComputingManager(StandaloneComputingManager, SSHComputingMana
         if not container_engine:
             container_engine = task.computing.default_container_engine
 
-        # engine-specific part 
+        # engine-specific part
         if container_engine == 'singularity':
 
             #if not task.container.supports_custom_interface_port:
@@ -253,20 +253,20 @@ class SSHStandaloneComputingManager(StandaloneComputingManager, SSHComputingMana
                 varsstring = ''
                 # Sanitize again just in case the DB got somehow compromised:
                 env_vars = sanitize_container_env_vars(task.container.env_vars)
-                
+
                 for env_var in env_vars:
                     varsstring += ' && export SINGULARITYENV_{}={} '.format(env_var, env_vars[env_var])
             else:
                 varsstring = ''
-                    
+
             # Handle storages (binds)
             binds = ''
             storages = Storage.objects.filter(computing=self.computing)
             for storage in storages:
                 if storage.type == 'generic_posix' and storage.bind_path:
-                    
+
                     # Expand the base path
-                    expanded_base_path = storage.base_path        
+                    expanded_base_path = storage.base_path
                     if '$SSH_USER' in expanded_base_path:
                         if storage.access_through_computing:
                             expanded_base_path = expanded_base_path.replace('$SSH_USER', computing_user)
@@ -274,9 +274,9 @@ class SSHStandaloneComputingManager(StandaloneComputingManager, SSHComputingMana
                             raise NotImplementedError('Accessing a storage with ssh+cli without going through its computing resource is not implemented')
                     if '$USER' in expanded_base_path:
                         expanded_base_path = expanded_base_path.replace('$USER', task.user.username)
-                        
+
                     # Expand the bind_path
-                    expanded_bind_path = storage.bind_path        
+                    expanded_bind_path = storage.bind_path
                     if '$SSH_USER' in expanded_bind_path:
                         if storage.access_through_computing:
                             expanded_bind_path = expanded_bind_path.replace('$SSH_USER', computing_user)
@@ -284,19 +284,19 @@ class SSHStandaloneComputingManager(StandaloneComputingManager, SSHComputingMana
                             raise NotImplementedError('Accessing a storage with ssh+cli without going through its computing resource is not implemented')
                     if '$USER' in expanded_bind_path:
                         expanded_bind_path = expanded_bind_path.replace('$USER', task.user.username)
-                        
+
                     # Add the bind
                     if not binds:
                         binds = '-B {}:{}'.format(expanded_base_path, expanded_bind_path)
                     else:
                         binds += ',{}:{}'.format(expanded_base_path, expanded_bind_path)
-            
+
             run_command  = 'ssh -p {} -o LogLevel=ERROR -i {} -4 -o StrictHostKeyChecking=no {}@{} '.format(computing_port, computing_keys.private_key_file, computing_user, computing_host)
-            run_command += '/bin/bash -c \'"rm -rf /tmp/{}_data && mkdir -p /tmp/{}_data/tmp && mkdir -p /tmp/{}_data/home && chmod 700 /tmp/{}_data && '.format(task.uuid, task.uuid, task.uuid, task.uuid) 
+            run_command += '/bin/bash -c \'"rm -rf /tmp/{}_data && mkdir -p /tmp/{}_data/tmp && mkdir -p /tmp/{}_data/home && chmod 700 /tmp/{}_data && '.format(task.uuid, task.uuid, task.uuid, task.uuid)
             run_command += 'curl {} {}/api/v1/base/agent/?task_uuid={} -o /tmp/{}_data/agent.py &> /dev/null && export BASE_PORT=\$(python3 /tmp/{}_data/agent.py 2> /tmp/{}_data/task.log) && '.format(CHECK_CURL_CERT_STR, webapp_conn_string, task.uuid, task.uuid, task.uuid, task.uuid)
             run_command += 'export SINGULARITY_NOHTTPS=true && export SINGULARITYENV_BASE_PORT=\$BASE_PORT {} {} &&'.format(authstring, varsstring)
             run_command += 'exec nohup singularity run {} --pid --writable-tmpfs --no-home --home=/home/metauser --workdir /tmp/{}_data/tmp -B/tmp/{}_data/home:/home --containall --cleanenv '.format(binds, task.uuid, task.uuid)
-            
+
             # Container part
             run_command+='docker://{}/{}:{} &>> /tmp/{}_data/task.log & echo \$!"\''.format(task.container.registry, task.container.image_name, task.container.image_tag, task.uuid)
 
@@ -313,20 +313,20 @@ class SSHStandaloneComputingManager(StandaloneComputingManager, SSHComputingMana
                 varsstring = ''
                 # Sanitize again just in case the DB got somehow compromised:
                 env_vars = sanitize_container_env_vars(task.container.env_vars)
-                
+
                 for env_var in env_vars:
                     varsstring += ' -e {}={} '.format(env_var, env_vars[env_var])
             else:
                 varsstring = ''
-         
+
             # Handle storages (binds)
             binds = ''
             storages = Storage.objects.filter(computing=self.computing)
             for storage in storages:
                 if storage.type == 'generic_posix' and storage.bind_path:
-                    
+
                     # Expand the base path
-                    expanded_base_path = storage.base_path        
+                    expanded_base_path = storage.base_path
                     if '$SSH_USER' in expanded_base_path:
                         if storage.access_through_computing:
                             expanded_base_path = expanded_base_path.replace('$SSH_USER', computing_user)
@@ -334,9 +334,9 @@ class SSHStandaloneComputingManager(StandaloneComputingManager, SSHComputingMana
                             raise NotImplementedError('Accessing a storage with ssh+cli without going through its computing resource is not implemented')
                     if '$USER' in expanded_base_path:
                         expanded_base_path = expanded_base_path.replace('$USER', task.user.username)
-                        
+
                     # Expand the bind_path
-                    expanded_bind_path = storage.bind_path        
+                    expanded_bind_path = storage.bind_path
                     if '$SSH_USER' in expanded_bind_path:
                         if storage.access_through_computing:
                             expanded_bind_path = expanded_bind_path.replace('$SSH_USER', computing_user)
@@ -344,26 +344,26 @@ class SSHStandaloneComputingManager(StandaloneComputingManager, SSHComputingMana
                             raise NotImplementedError('Accessing a storage with ssh+cli without going through its computing resource is not implemented')
                     if '$USER' in expanded_bind_path:
                         expanded_bind_path = expanded_bind_path.replace('$USER', task.user.username)
-                        
+
                     # Add the bind
                     if not binds:
                         binds = '-v{}:{}'.format(expanded_base_path, expanded_bind_path)
                     else:
                         binds += ' -v{}:{}'.format(expanded_base_path, expanded_bind_path)
-            
+
             # TODO: remove this hardcoding
             prefix = 'sudo' if (computing_host == 'slurmclusterworker' and container_engine=='docker') else ''
-            
+
             run_command  = 'ssh -p {} -o LogLevel=ERROR -i {} -4 -o StrictHostKeyChecking=no {}@{} '.format(computing_port, computing_keys.private_key_file, computing_user, computing_host)
-            run_command += '/bin/bash -c \'"rm -rf /tmp/{}_data && mkdir /tmp/{}_data && chmod 700 /tmp/{}_data && '.format(task.uuid, task.uuid, task.uuid) 
+            run_command += '/bin/bash -c \'"rm -rf /tmp/{}_data && mkdir /tmp/{}_data && chmod 700 /tmp/{}_data && '.format(task.uuid, task.uuid, task.uuid)
             run_command += 'curl {} {}/api/v1/base/agent/?task_uuid={} -o /tmp/{}_data/agent.py &> /dev/null && export TASK_PORT=\$(python3 /tmp/{}_data/agent.py 2> /tmp/{}_data/task.log) && '.format(CHECK_CURL_CERT_STR, webapp_conn_string, task.uuid, task.uuid, task.uuid, task.uuid)
-            run_command += 'exec nohup {} {} run -p \$TASK_PORT:{} {} {} {} '.format(prefix, container_engine, task.container.interface_port, authstring, varsstring, binds)        
+            run_command += 'exec nohup {} {} run -p \$TASK_PORT:{} {} {} {} '.format(prefix, container_engine, task.container.interface_port, authstring, varsstring, binds)
             if container_engine == 'podman':
                 run_command += '--network=private --uts=private --userns=keep-id '
             #run_command += '-d -t {}/{}:{}'.format(task.container.registry, task.container.image_name, task.container.image_tag)
             run_command += '-h task-{} --name task-{}  -t {}/{}:{}'.format(task.short_uuid, task.short_uuid, task.container.registry, task.container.image_name, task.container.image_tag)
             run_command += '&>> /tmp/{}_data/task.log &"\''.format(task.uuid)
-            
+
         else:
             raise NotImplementedError('Container engine {} not supported'.format(container_engine))
 
@@ -371,8 +371,8 @@ class SSHStandaloneComputingManager(StandaloneComputingManager, SSHComputingMana
         if out.exit_code != 0:
             logger.error('Got error in starting task: {}'.format(out))
             raise Exception(out.stderr)
-        
-        # Log        
+
+        # Log
         logger.debug('Shell exec output: "{}"'.format(out))
 
         # Load back the task to avoid  concurrency problems in the agent call
@@ -392,7 +392,7 @@ class SSHStandaloneComputingManager(StandaloneComputingManager, SSHComputingMana
 
 
     def _stop_task(self, task, **kwargs):
-        
+
         # Get credentials
         computing_user, computing_host, computing_port, computing_keys = get_ssh_access_mode_credentials(self.computing, task.user)
 
@@ -404,7 +404,7 @@ class SSHStandaloneComputingManager(StandaloneComputingManager, SSHComputingMana
             container_engine = task.computing.default_container_engine
 
         if container_engine=='singularity':
-            internal_stop_command = 'kill -9 {}'.format(task.process_id)            
+            internal_stop_command = 'kill -9 {}'.format(task.process_id)
         elif container_engine in ['docker', 'podman']:
             # TODO: remove this hardcoding
             prefix = 'sudo' if (computing_host == 'slurmclusterworker' and container_engine=='docker') else ''
@@ -415,7 +415,7 @@ class SSHStandaloneComputingManager(StandaloneComputingManager, SSHComputingMana
 
         stop_command = 'ssh -p {} -o LogLevel=ERROR -i {} -4 -o StrictHostKeyChecking=no {}@{} \'/bin/bash -c "{}"\''.format(computing_port, computing_keys.private_key_file, computing_user, computing_host, internal_stop_command)
         out = os_shell(stop_command, capture=True)
-        
+
         if out.exit_code != 0:
             if ('No such process' in out.stderr) or ('No such container' in out.stderr) or ('no container' in out.stderr) or ('missing' in out.stderr):
                 pass
@@ -432,7 +432,7 @@ class SSHStandaloneComputingManager(StandaloneComputingManager, SSHComputingMana
 
         # Get credentials
         computing_user, computing_host, computing_port, computing_keys = get_ssh_access_mode_credentials(self.computing, task.user)
-        
+
         # Handle container engine
         container_engine = None
         if task.computing_options:
@@ -441,13 +441,13 @@ class SSHStandaloneComputingManager(StandaloneComputingManager, SSHComputingMana
             container_engine = task.computing.default_container_engine
 
         if container_engine=='singularity':
-            internal_view_log_command = 'cat /tmp/{}_data/task.log'.format(task.uuid)            
+            internal_view_log_command = 'cat /tmp/{}_data/task.log'.format(task.uuid)
         elif container_engine in ['docker','podman']:
             # TODO: consider podman/docker logs?
             internal_view_log_command = 'cat /tmp/{}_data/task.log'.format(task.uuid)
         else:
             raise NotImplementedError('Container engine {} not supported'.format(container_engine))
-            
+
         # Prepare full comand
         view_log_command = 'ssh -p {} -o LogLevel=ERROR -i {} -4 -o StrictHostKeyChecking=no {}@{} \'/bin/bash -c "{}"\''.format(computing_port, computing_keys.private_key_file, computing_user, computing_host, internal_view_log_command)
 
@@ -460,7 +460,7 @@ class SSHStandaloneComputingManager(StandaloneComputingManager, SSHComputingMana
 
 
 class SlurmSSHClusterComputingManager(ClusterComputingManager, SSHComputingManager):
-    
+
     def _start_task(self, task, **kwargs):
         logger.debug('Starting a remote task "{}"'.format(self.computing))
 
@@ -473,7 +473,7 @@ class SlurmSSHClusterComputingManager(ClusterComputingManager, SSHComputingManag
 
         # Initialize sbatch args (force 1 task for now)
         sbatch_args = '-N1 '
-            
+
         # Get task computing parameters and set sbatch args
         if task.computing_options:
             task_partition = task.computing_options.get('partition', None)
@@ -498,7 +498,7 @@ class SlurmSSHClusterComputingManager(ClusterComputingManager, SSHComputingManag
         if not container_engine:
             container_engine = task.computing.default_container_engine
 
-        # engine-specific part 
+        # engine-specific part
         if container_engine == 'singularity':
 
             #if not task.container.supports_custom_interface_port:
@@ -514,20 +514,20 @@ class SlurmSSHClusterComputingManager(ClusterComputingManager, SSHComputingManag
                 varsstring = ''
                 # Sanitize again just in case the DB got somehow compromised:
                 env_vars = sanitize_container_env_vars(task.container.env_vars)
-                
+
                 for env_var in env_vars:
                     varsstring += ' && export SINGULARITYENV_{}={} '.format(env_var, env_vars[env_var])
             else:
                 varsstring = ''
-        
+
             # Handle storages (binds)
             binds = ''
             storages = Storage.objects.filter(computing=self.computing)
             for storage in storages:
                 if storage.type == 'generic_posix' and storage.bind_path:
-                    
+
                     # Expand the base path
-                    expanded_base_path = storage.base_path        
+                    expanded_base_path = storage.base_path
                     if '$SSH_USER' in expanded_base_path:
                         if storage.access_through_computing:
                             expanded_base_path = expanded_base_path.replace('$SSH_USER', computing_user)
@@ -535,9 +535,9 @@ class SlurmSSHClusterComputingManager(ClusterComputingManager, SSHComputingManag
                             raise NotImplementedError('Accessing a storage with ssh+cli without going through its computing resource is not implemented')
                     if '$USER' in expanded_base_path:
                         expanded_base_path = expanded_base_path.replace('$USER', task.user.username)
-                        
+
                     # Expand the bind_path
-                    expanded_bind_path = storage.bind_path        
+                    expanded_bind_path = storage.bind_path
                     if '$SSH_USER' in expanded_bind_path:
                         if storage.access_through_computing:
                             expanded_bind_path = expanded_bind_path.replace('$SSH_USER', computing_user)
@@ -545,7 +545,7 @@ class SlurmSSHClusterComputingManager(ClusterComputingManager, SSHComputingManag
                             raise NotImplementedError('Accessing a storage with ssh+cli without going through its computing resource is not implemented')
                     if '$USER' in expanded_bind_path:
                         expanded_bind_path = expanded_bind_path.replace('$USER', task.user.username)
-                        
+
                     # Add the bind
                     if not binds:
                         binds = '-B {}:{}'.format(expanded_base_path, expanded_bind_path)
@@ -557,7 +557,7 @@ class SlurmSSHClusterComputingManager(ClusterComputingManager, SSHComputingManag
             run_command += 'export SINGULARITY_NOHTTPS=true && export SINGULARITYENV_BASE_PORT=\\\\\\$BASE_PORT {} {} && '.format(authstring, varsstring)
             run_command += 'rm -rf /tmp/{}_data && mkdir -p /tmp/{}_data/tmp &>> \$HOME/{}.log && mkdir -p /tmp/{}_data/home &>> \$HOME/{}.log && chmod 700 /tmp/{}_data && '.format(task.uuid, task.uuid, task.uuid, task.uuid, task.uuid, task.uuid)
             run_command += 'exec nohup singularity run {} --pid --writable-tmpfs --no-home --home=/home/metauser --workdir /tmp/{}_data/tmp -B/tmp/{}_data/home:/home --containall --cleanenv '.format(binds, task.uuid, task.uuid)
-            
+
             # Double to escape for Python, six for shell (double times three as \\\ escapes a single slash in shell)
             run_command+='docker://{}/{}:{} &> \$HOME/{}.log\\" > \$HOME/{}.sh && sbatch {} \$HOME/{}.sh"\''.format(task.container.registry, task.container.image_name, task.container.image_tag, task.uuid, task.uuid, sbatch_args, task.uuid)
 
@@ -569,7 +569,7 @@ class SlurmSSHClusterComputingManager(ClusterComputingManager, SSHComputingManag
             logger.error('Got error in starting task: {}'.format(out))
             raise Exception(out.stderr)
 
-        # Log        
+        # Log
         logger.debug('Shell exec output: "{}"'.format(out))
 
         # Parse sbatch output. Example: Output(stdout='Submitted batch job 3', stderr='', exit_code=0)
@@ -578,18 +578,18 @@ class SlurmSSHClusterComputingManager(ClusterComputingManager, SSHComputingManag
             int(job_id)
         except:
             raise Exception('Cannot find int job id from output string "{}"'.format(out.stdout))
-        
+
         # Load back the task to avoid concurrency problems in the agent call
         task_uuid = task.uuid
         task = Task.objects.get(uuid=task_uuid)
 
         # Save job id
         task.job_id = job_id
-        
+
         # Set status (only fi we get here before the agent which sets the status as running via the API)
         if task.status != TaskStatuses.running:
             task.status = TaskStatuses.sumbitted
-        
+
         # Save
         task.save()
 
@@ -598,7 +598,7 @@ class SlurmSSHClusterComputingManager(ClusterComputingManager, SSHComputingManag
             setup_tunnel_and_proxy(task)
 
     def _stop_task(self, task, **kwargs):
-        
+
         # Get credentials
         computing_user, computing_host, computing_port, computing_keys = get_ssh_access_mode_credentials(self.computing, task.user)
 
@@ -607,14 +607,14 @@ class SlurmSSHClusterComputingManager(ClusterComputingManager, SSHComputingManag
         out = os_shell(stop_command, capture=True)
         if out.exit_code != 0:
             raise Exception(out.stderr)
-        
+
         # Set task as topped
         task.status = TaskStatuses.stopped
         task.save()
 
 
     def _get_task_log(self, task, **kwargs):
-        
+
         # Get credentials
         computing_user, computing_host, computing_port, computing_keys = get_ssh_access_mode_credentials(self.computing, task.user)
 
@@ -626,3 +626,4 @@ class SlurmSSHClusterComputingManager(ClusterComputingManager, SSHComputingManag
             raise Exception(out.stderr)
         else:
             return out.stdout
+
diff --git a/services/webapp/code/rosetta/core_app/decorators.py b/services/webapp/code/rosetta/core_app/decorators.py
index d6e13e0..d38473e 100644
--- a/services/webapp/code/rosetta/core_app/decorators.py
+++ b/services/webapp/code/rosetta/core_app/decorators.py
@@ -51,7 +51,7 @@ def public_view(wrapped_view):
                 error_text = str(e)
             else:
 
-                # Log the exception 
+                # Log the exception
                 logger.error(format_exception(e))
 
                 # Raise the exception if we are in debug mode
@@ -109,13 +109,13 @@ def private_view(wrapped_view):
                     error_text = str(e)
                 else:
 
-                    # Log the exception 
+                    # Log the exception
                     logger.error(format_exception(e))
-    
+
                     # Raise the exception if we are in debug mode
                     if settings.DEBUG:
                         raise
-    
+
                     # Otherwise, mask it
                     else:
                         error_text = 'something went wrong ({})'.format(e)
@@ -137,3 +137,4 @@ def private_view(wrapped_view):
             response.set_cookie('post_login_redirect', request.build_absolute_uri())
             return response
     return private_view_wrapper
+
diff --git a/services/webapp/code/rosetta/core_app/exceptions.py b/services/webapp/code/rosetta/core_app/exceptions.py
index 44676fc..12a3bd8 100644
--- a/services/webapp/code/rosetta/core_app/exceptions.py
+++ b/services/webapp/code/rosetta/core_app/exceptions.py
@@ -3,4 +3,4 @@ class ErrorMessage(Exception):
     pass
 
 class ConsistencyException(Exception):
-    pass
\ No newline at end of file
+    pass
diff --git a/services/webapp/code/rosetta/core_app/fields.py b/services/webapp/code/rosetta/core_app/fields.py
index bc59f97..05a90bd 100644
--- a/services/webapp/code/rosetta/core_app/fields.py
+++ b/services/webapp/code/rosetta/core_app/fields.py
@@ -26,4 +26,4 @@ class JSONField(Field):
     def value_to_string(self, obj):
         return self.value_from_object(obj)
 
-# Credits: https://medium.com/@philamersune/using-postgresql-jsonfield-in-sqlite-95ad4ad2e5f1
\ No newline at end of file
+# Credits: https://medium.com/@philamersune/using-postgresql-jsonfield-in-sqlite-95ad4ad2e5f1
diff --git a/services/webapp/code/rosetta/core_app/management/commands/core_app_populate.py b/services/webapp/code/rosetta/core_app/management/commands/core_app_populate.py
index 32ff1c1..5dba794 100644
--- a/services/webapp/code/rosetta/core_app/management/commands/core_app_populate.py
+++ b/services/webapp/code/rosetta/core_app/management/commands/core_app_populate.py
@@ -8,13 +8,13 @@ class Command(BaseCommand):
     def handle(self, *args, **options):
 
 
-        #=====================    
+        #=====================
         #  Testuser
         #=====================
         try:
             testuser = User.objects.get(username='testuser')
             print('Not creating test user as it already exists')
-        
+
         except User.DoesNotExist:
             print('Creating test user with default password')
             testuser = User.objects.create_user('testuser', 'testuser@rosetta.platform', 'testpass')
@@ -22,7 +22,7 @@ class Command(BaseCommand):
             testuser.is_staff = True
             testuser.is_admin=True
             testuser.is_superuser=True
-            testuser.save() 
+            testuser.save()
             print('Creating testuser profile')
             Profile.objects.create(user=testuser, auth='local', authtoken='129aac94-284a-4476-953c-ffa4349b4a50')
 
@@ -32,23 +32,23 @@ class Command(BaseCommand):
                                    default = True,
                                    private_key_file = '/rosetta/.ssh/id_rsa',
                                    public_key_file = '/rosetta/.ssh/id_rsa.pub')
-        
 
-        #=====================    
+
+        #=====================
         #  Platform keys
         #=====================
         # TODO: create a different pair
         try:
             KeyPair.objects.get(user=None, default=True)
             print('Not creating default platform keys as they already exist')
-        
+
         except KeyPair.DoesNotExist:
             print('Creating platform default keys')
             KeyPair.objects.create(user = None,
                                    default = True,
                                    private_key_file = '/rosetta/.ssh/id_rsa',
                                    public_key_file = '/rosetta/.ssh/id_rsa.pub')
-                  
+
 
         #=====================
         #  Default home page
@@ -60,7 +60,7 @@ class Command(BaseCommand):
             <h1>&nbsp;&nbsp;Rosetta <img src="/static/img/emoji_u1f6f0.png" style="height:84px; width:64px; padding-bottom:20px"></h1>
             <h2 style="margin-top:10px; margin-left:25px; margin-right:25px; font-weight:100; line-height: 30px;"><i>A container-centric Science Platform<br></i></h2>
         </div>
-    </div>   
+    </div>
     <div class="container">
         <div class="dashboard">
             <div class="span8 offset2" style="margin: 30px auto; max-width:800px">
@@ -69,7 +69,7 @@ class Command(BaseCommand):
                 This is the default main page content loaded after populating the platform with the default/demo data.
                 To change it, head to the <a href="/admin">admin</a> section and edit the <code>Page</code> model with id "main".
                 <br/><br/>
-                A test user with admin rights registered with email <code>testuser@rosetta.platform</code> and password 
+                A test user with admin rights registered with email <code>testuser@rosetta.platform</code> and password
                 <code>testpass</code> has been created as well, which you can use to login on the menu on the right and give Rosetta
                 immediately a try. If you are using the default docker-compose file (i.e. you just ran <code>rosetta/setup</code>),
                 then you will also have a few demo computing and storage resources (beside the internal one) already available
@@ -79,10 +79,10 @@ class Command(BaseCommand):
                 <br />
                 You can also create custom pages and access them under <code>/pages/page_id</code> should you need to provide
                 your users informations about the platform and its storage and computing resources. For example, see this
-                demo extra <a href="/pages/help">help page</a>. 
+                demo extra <a href="/pages/help">help page</a>.
             </div>
         </div>
-    </div>          
+    </div>
 </header>
 '''
         home_page = Page.objects.filter(id='main')
@@ -96,15 +96,15 @@ class Command(BaseCommand):
 <h1>Help!</h1>
 <hr>
 <p>
-This is a demo extra page (a help page, in this case). Here you could for example provide the instructions on how to set up SSH-based 
+This is a demo extra page (a help page, in this case). Here you could for example provide the instructions on how to set up SSH-based
 computing resources using user keys, or who to contact to join a specific group to access its software and computing resources.
 </p>
 
 <p>
-In general, the part of the URL following the <code>/pages/</code> path is parsed as the page id, 
+In general, the part of the URL following the <code>/pages/</code> path is parsed as the page id,
 so that if a page with that id exists in the database, its content will show up here.
-You can use this system for creating a mini-website inside the platform 
-to provide help, news and informations on your deployment. Or you can just ignore the whole thing and leave a plain logo in the main page. 
+You can use this system for creating a mini-website inside the platform
+to provide help, news and informations on your deployment. Or you can just ignore the whole thing and leave a plain logo in the main page.
 </p>
 '''
 
@@ -117,16 +117,16 @@ to provide help, news and informations on your deployment. Or you can just ignor
 
 
 
-        #===================== 
+        #=====================
         # Platform containers
-        #===================== 
-        
+        #=====================
+
         platform_containers = Container.objects.filter(user=None)
         if platform_containers:
             print('Not creating public containers as they already exist')
         else:
             print('Creating platform containers...')
-            
+
             # Minimal Desktop
             Container.objects.create(user     = None,
                                      name     = 'Minimal Desktop',
@@ -157,8 +157,8 @@ to provide help, news and informations on your deployment. Or you can just ignor
                                      supports_custom_interface_port = True,
                                      supports_interface_auth = True,
                                      interface_auth_user = None)
- 
- 
+
+
             # Jupyter Notebook
             Container.objects.create(user     = None,
                                      name     = 'Jupyter Notebook',
@@ -178,7 +178,7 @@ to provide help, news and informations on your deployment. Or you can just ignor
 
             # Official Jupyter containers
             for tag in ['lab-3.2.2', 'lab-3.1.17']:
-                
+
                 Container.objects.create(user     = None,
                                          name     = 'Jupyter Data Science Lab',
                                          description = 'The official Jupyter Lab. The Data Science variant, which includes libraries for data analysis from the Julia, Python, and R communities.',
@@ -192,7 +192,7 @@ to provide help, news and informations on your deployment. Or you can just ignor
                                          interface_transport = 'tcp/ip',
                                          supports_custom_interface_port = True,
                                          supports_interface_auth = True)
-                
+
                 for arch in ['amd64', 'arm64']:
                     Container.objects.create(user     = None,
                                              name     = 'Jupyter Lab',
@@ -225,9 +225,9 @@ to provide help, news and informations on your deployment. Or you can just ignor
                                      supports_interface_auth = True,
                                      interface_auth_user = 'metauser')
 
-        #===================== 
+        #=====================
         # Testuser containers
-        #===================== 
+        #=====================
         #testuser_containers = Container.objects.filter(user=testuser)
         #if testuser_containers:
         #    print('Not creating testuser private containers as they already exist')
@@ -250,9 +250,9 @@ to provide help, news and informations on your deployment. Or you can just ignor
         #                             supports_interface_auth = False)
 
 
-        #===================== 
+        #=====================
         # Computing resources
-        #===================== 
+        #=====================
         computing_resources = Computing.objects.all()
         if computing_resources:
             print('Not creating demo computing resources as they already exist')
@@ -270,7 +270,7 @@ to provide help, news and informations on your deployment. Or you can just ignor
                                      wms = None,
                                      container_engines = ['docker'])
 
-            
+
             # Demo standalone computing plus conf
             demo_standalone_computing = Computing.objects.create(name = 'Demo Standalone',
                                                                  description = 'A demo standalone computing resource.',
@@ -311,22 +311,22 @@ to provide help, news and informations on your deployment. Or you can just ignor
                                                             wms = 'slurm',
                                                             conf = {'host': 'slurmclustermaster', 'default_partition': 'partition1'},
                                                             container_engines = ['singularity'])
-           
+
             # Add testuser extra conf for this computing resource
             testuser.profile.add_extra_conf(conf_type = 'computing_user', object=demo_slurm_computing, value= 'testuser')
 
-        #===================== 
+        #=====================
         # Storages
-        #===================== 
+        #=====================
         storages = Storage.objects.all()
         if storages:
             print('Not creating demo storage resources as they already exist')
         else:
             print('Creating demo storage resources...')
- 
+
             # Get demo computing resources
             demo_computing_resources = []
-            try:    
+            try:
                 demo_slurm_computing = Computing.objects.get(name='Demo Cluster')
                 demo_computing_resources.append(demo_slurm_computing)
             except:
@@ -336,8 +336,8 @@ to provide help, news and informations on your deployment. Or you can just ignor
                 demo_computing_resources.append(demo_standalone_computing)
             except:
                 pass
-             
- 
+
+
             for computing in demo_computing_resources:
                 # Demo shared storage
                 Storage.objects.create(computing = computing,
@@ -348,7 +348,7 @@ to provide help, news and informations on your deployment. Or you can just ignor
                                        auth_mode = 'user_keys',
                                        base_path = '/shared/data/shared',
                                        bind_path = '/storages/shared')
-     
+
                 # Demo personal storage
                 Storage.objects.create(computing = computing,
                                        access_through_computing = True,
@@ -359,3 +359,4 @@ to provide help, news and informations on your deployment. Or you can just ignor
                                        base_path = '/shared/data/users/$SSH_USER',
                                        bind_path = '/storages/personal')
 
+
diff --git a/services/webapp/code/rosetta/core_app/models.py b/services/webapp/code/rosetta/core_app/models.py
index 76061c1..9d6cb5f 100644
--- a/services/webapp/code/rosetta/core_app/models.py
+++ b/services/webapp/code/rosetta/core_app/models.py
@@ -37,7 +37,7 @@ class TaskStatuses(object):
 # using an UUID pointing to some other model instead of the value in future, should this be necessary.
 
 #=========================
-#  Profile 
+#  Profile
 #=========================
 
 class Profile(models.Model):
@@ -68,25 +68,25 @@ class Profile(models.Model):
             self.extra_confs = {}
         self.extra_confs[str(uuid.uuid4())] = {'type': conf_type, 'object_uuid': str(object.uuid), 'value': value}
         self.save()
-        
+
 
     def get_extra_conf(self, conf_type, object=None):
-       
+
         if self.extra_confs:
             for extra_conf in self.extra_confs:
                 if conf_type == self.extra_confs[extra_conf]['type']:
                     if object:
                         #logger.debug("{} vs {}".format(self.extra_confs[extra_conf]['object_uuid'], str(object.uuid)))
                         if self.extra_confs[extra_conf]['object_uuid'] == str(object.uuid):
-                            return self.extra_confs[extra_conf]['value']                        
+                            return self.extra_confs[extra_conf]['value']
                     else:
                         return self.extra_confs[extra_conf]['value']
         return None
-            
+
 
 
 #=========================
-#  Login Token 
+#  Login Token
 #=========================
 
 class LoginToken(models.Model):
@@ -106,7 +106,7 @@ class LoginToken(models.Model):
 class Container(models.Model):
 
     uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
-    user = models.ForeignKey(User, related_name='containers', on_delete=models.CASCADE, blank=True, null=True)  
+    user = models.ForeignKey(User, related_name='containers', on_delete=models.CASCADE, blank=True, null=True)
     # If a container has no user, it will be available to anyone. Can be created, edited and deleted only by admins.
     group = models.ForeignKey(Group, related_name='containers', on_delete=models.CASCADE, blank=True, null=True)
     # If a container has no group, it will be available to anyone. Can be created, edited and deleted only by admins.
@@ -114,25 +114,25 @@ class Container(models.Model):
     # Generic attributes
     name        = models.CharField('Name', max_length=255, blank=False, null=False)
     description = models.TextField('Description', blank=True, null=True)
-    
+
     # Registry
     registry = models.CharField('Registry', max_length=255, blank=False, null=False)
 
     # Image name
     image_name = models.CharField('Image', max_length=255, blank=False, null=False)
-    
+
     # Image identifiers
     image_tag  = models.CharField('Tag', max_length=255, blank=False, null=False, default='latest')
     image_arch = models.CharField('Architecture', max_length=36, blank=True, null=True)
     image_os   = models.CharField('Operating system', max_length=36, blank=True, null=True)
     # -- OR --
     image_digest  = models.CharField('SHA 256 digest', max_length=96, blank=True, null=True)
-    
-    # TODO: do we want more control with respect to kernel, CPUs, instruction sets? 
+
+    # TODO: do we want more control with respect to kernel, CPUs, instruction sets?
     # requires = i.e. kernel > 3, intel, AVX2
-    
+
     # Port, protocol and transport for the container interface
-    interface_port = models.IntegerField('Interface port', blank=True, null=True) 
+    interface_port = models.IntegerField('Interface port', blank=True, null=True)
     interface_protocol = models.CharField('Interface protocol', max_length=36, blank=True, null=True)
     interface_transport = models.CharField('Interface transport', max_length=36, blank=True, null=True)
 
@@ -156,7 +156,7 @@ class Container(models.Model):
         # Check that digest starts with sha256:
         if self.image_digest and not self.image_digest.startswith('sha256:'):
             raise ValueError('The digest field must start with "sha256:"')
-        
+
         super(Container, self).save(*args, **kwargs)
 
     @property
@@ -183,7 +183,7 @@ class Computing(models.Model):
     uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
     group = models.ForeignKey(Group, related_name='computings', on_delete=models.CASCADE, blank=True, null=True)
     # If a compute resource has no group, it will be available to anyone. Can be created, edited and deleted only by admins.
-    
+
     name        = models.CharField('Name', max_length=255, blank=False, null=False)
     description = models.TextField('Description', blank=True, null=True)
 
@@ -195,16 +195,16 @@ class Computing(models.Model):
     access_mode = models.CharField('Access (control) mode', max_length=36, blank=False, null=False)
     auth_mode   = models.CharField('Auth mode', max_length=36, blank=False, null=False)
     wms         = models.CharField('Workload management system', max_length=36, blank=True, null=True)
-    
+
     # Supported container engines (e.g. ['docker', 'singularity', 'podman'])
     container_engines = JSONField('Container engines/runtimes', blank=False, null=False)
     #container_runtime = models.CharField('Container runtimes', max_length=256, blank=False, null=False)
- 
+
     # Supported architectures (i.e. 386 for amd64), as list: ['386']
-    supported_archs = JSONField('Supported architectures', blank=True, null=True) 
+    supported_archs = JSONField('Supported architectures', blank=True, null=True)
 
-    # Emulated architectures, by container runtime: {'docker': ['arm64/v7', 'arm64/v8']    
-    emulated_archs = JSONField('Emulated architectures', blank=True, null=True) 
+    # Emulated architectures, by container runtime: {'docker': ['arm64/v7', 'arm64/v8']
+    emulated_archs = JSONField('Emulated architectures', blank=True, null=True)
 
     # Conf
     conf = JSONField(blank=True, null=True)
@@ -233,23 +233,23 @@ class Computing(models.Model):
     @property
     def default_container_engine(self):
         return self.container_engines[0]
-    
+
 
     #=======================
     # Computing manager
     #=======================
-    
+
     @property
     def manager(self):
         from . import computing_managers
-        
+
         # Hash table mapping
         managers_mapping = {}
         managers_mapping['cluster'+'ssh+cli'+'user_keys'+'slurm'] = computing_managers.SlurmSSHClusterComputingManager
         managers_mapping['standalone'+'ssh+cli'+'user_keys'+'None'] = computing_managers.SSHStandaloneComputingManager
-        managers_mapping['standalone'+'ssh+cli'+'platform_keys'+'None'] = computing_managers.SSHStandaloneComputingManager        
+        managers_mapping['standalone'+'ssh+cli'+'platform_keys'+'None'] = computing_managers.SSHStandaloneComputingManager
         managers_mapping['standalone'+'internal'+'internal'+'None'] = computing_managers.InternalStandaloneComputingManager
-        
+
         # Instantiate the computing manager and return (if not already done)
         try:
             return self._manager
@@ -262,10 +262,10 @@ class Computing(models.Model):
             else:
                 return self._manager
 
-    
+
 
 #=========================
-#  Tasks 
+#  Tasks
 #=========================
 
 class Task(models.Model):
@@ -277,16 +277,16 @@ class Task(models.Model):
     # Task management
     status     = models.CharField('Status', max_length=36, blank=True, null=True)
     created    = models.DateTimeField('Created on', default=timezone.now)
-    process_id = models.CharField('Process ID', max_length=64, blank=True, null=True) # i.e. Singularity PID 
-    job_id = models.CharField('Job ID', max_length=64, blank=True, null=True) # i.e. Slurm job id 
+    process_id = models.CharField('Process ID', max_length=64, blank=True, null=True) # i.e. Singularity PID
+    job_id = models.CharField('Job ID', max_length=64, blank=True, null=True) # i.e. Slurm job id
 
     # How to reach the task interface. The IP has to be intended either as the container IP if this is directly
     # reachable (i.e. using a Docker or Kubernetes network) or as the host IP address, depending on the
     # computing resource and its computing manager/WMS/container runtime. The port is to be intended
     # as the port where the task interface is exposed on its IP address.
     interface_ip   = models.CharField('Interface IP address', max_length=36, blank=True, null=True)
-    interface_port = models.IntegerField('Interface port', blank=True, null=True) 
-    
+    interface_port = models.IntegerField('Interface port', blank=True, null=True)
+
     # Task access
     requires_tcp_tunnel = models.BooleanField('Requires TCP tunnel')
     tcp_tunnel_port     = models.IntegerField('TCP tunnel port', blank=True, null=True)
@@ -301,13 +301,13 @@ class Task(models.Model):
     # Computing options
     # TODO: add the option for selecting the runtime as advanced option when creating the task?
     computing_options = JSONField('Computing options', blank=True, null=True) # i.e. CPUs, RAM, cluster partition etc. TODO: why here?
-    
-    
+
+
     class Meta:
         ordering = ['-created']
 
     def save(self, *args, **kwargs):
-        
+
         try:
             getattr(TaskStatuses, str(self.status))
         except AttributeError:
@@ -318,25 +318,25 @@ class Task(models.Model):
 
     def update_status(self):
         if self.computing == 'local':
-            
+
             check_command = 'sudo docker inspect --format \'{{.State.Status}}\' ' + self.tid # or, .State.Running
             out = os_shell(check_command, capture=True)
             logger.debug('Status: "{}"'.format(out.stdout))
-            if out.exit_code != 0: 
+            if out.exit_code != 0:
                 if (('No such' in out.stderr) and (self.tid in out.stderr)):
                     logger.debug('Task "{}" is not running in reality'.format(self.tid))
                 self.status = TaskStatuses.exited
             else:
                 if out.stdout == 'running':
                     self.status = TaskStatuses.running
-                    
+
                 elif out.stdout == 'exited':
                     self.status = TaskStatuses.exited
-                    
+
                 else:
                     raise Exception('Unknown task status: "{}"'.format(out.stdout))
-                
-            self.save()                   
+
+            self.save()
 
 
     def __str__(self):
@@ -351,11 +351,11 @@ class Task(models.Model):
         string_int_hash = hash_string_to_int(self.name)
         color_map_index = string_int_hash % len(color_map)
         return color_map[color_map_index]
-    
+
     @property
     def sharable_link(self):
         return 'https://{}/t/{}'.format(settings.ROSETTA_HOST, self.short_uuid)
-    
+
     @property
     def tcp_tunnel_host(self):
         return get_rosetta_tasks_tunnel_host()
@@ -369,32 +369,32 @@ class Task(models.Model):
 #=========================
 
 class Storage(models.Model):
- 
+
     uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
     group = models.ForeignKey(Group, related_name='storages', on_delete=models.CASCADE, blank=True, null=True)
-  
+
     name = models.CharField('Name', max_length=255, blank=False, null=False)
     #description = models.TextField('Description', blank=True, null=True)
- 
+
     # Storage type
     type = models.CharField('Type', max_length=255, blank=False, null=False)
- 
-    # Access and auth mode 
+
+    # Access and auth mode
     access_mode = models.CharField('Access (control) mode', max_length=36, blank=False, null=False)
     auth_mode   = models.CharField('Auth mode', max_length=36, blank=False, null=False)
-     
+
     # Paths
-    base_path = models.CharField('Base path', max_length=4096, blank=False, null=False) 
-    bind_path = models.CharField('Bind path', max_length=4096, blank=True, null=True) 
- 
+    base_path = models.CharField('Base path', max_length=4096, blank=False, null=False)
+    bind_path = models.CharField('Bind path', max_length=4096, blank=True, null=True)
+
     # Link with a computing resource
     computing = models.ForeignKey(Computing, related_name='storages', on_delete=models.CASCADE, blank=True, null=True) # Make optional?
     access_through_computing = models.BooleanField('Access through linked computing resource?', default=False)
     # If the above is linked, some configuration can be taken from the linked computing resource (i.e. the hostname)
- 
+
     # Configuration
     conf = JSONField(blank=True, null=True)
- 
+
     # Include as browsable in the file manager?
     browsable = models.BooleanField('Browsable in the file manager?', default=True)
 
@@ -405,29 +405,29 @@ class Storage(models.Model):
 
     class Meta:
         ordering = ['name']
- 
+
     def __str__(self):
         if self.group:
             return str('Storage "{}" of group "{}"'.format(self.id, self.group))
         else:
             return str('Storage "{}"'.format(self.id))
- 
+
     @property
     def id(self):
         return (self.name if not self.computing else '{}:{}'.format(self.computing.name,self.name))
- 
+
 
 
 
 
 #=========================
-#  KeyPair 
+#  KeyPair
 #=========================
 
 class KeyPair(models.Model):
 
     uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
-    user = models.ForeignKey(User, related_name='key_pairs', on_delete=models.CASCADE, blank=True, null=True)  
+    user = models.ForeignKey(User, related_name='key_pairs', on_delete=models.CASCADE, blank=True, null=True)
 
     private_key_file = models.CharField('Private key file', max_length=4096, blank=False, null=False)
     public_key_file  = models.CharField('Public key file', max_length=4096, blank=False, null=False)
@@ -440,12 +440,12 @@ class KeyPair(models.Model):
             return str('KeyPair of user "{}" (default={})'.format( self.user.email, self.default))
         else:
             return str('KeyPair of user Platform (default={})'.format(self.default))
-            
+
 
 
 
 #=========================
-#  Page 
+#  Page
 #=========================
 
 class Page(models.Model):
@@ -461,3 +461,4 @@ class Page(models.Model):
 
 
 
+
diff --git a/services/webapp/code/rosetta/core_app/templates/account.html b/services/webapp/code/rosetta/core_app/templates/account.html
index b8f07fe..051caeb 100644
--- a/services/webapp/code/rosetta/core_app/templates/account.html
+++ b/services/webapp/code/rosetta/core_app/templates/account.html
@@ -1,4 +1,4 @@
-{% load static %} 
+{% load static %}
 {% include "header.html" %}
 {% include "navigation.html" %}
 {% include "logo.html" %}
@@ -23,24 +23,24 @@
         {{data.user.username}}
         </td>
        </tr>
-      
+
        <tr>
         <td>
         <b>Email</b>
         </td>
         <td>
-        {% if data.edit == 'email' %}    
+        {% if data.edit == 'email' %}
           <table class="frametab"><tr><td>
           <input type='hidden' name='edit' value='email' />
           <input type="email" value="{{data.user.email}}" name='value' style='width:95%' required autofocus />
           </td><td>
           <input type="submit" value="Go">
-          </td></tr></table>          
+          </td></tr></table>
         {% else %}
          {{data.user.email}}{% if data.user.profile.auth == 'local' %} | <a href="/account/?edit=email">Change</a>{% endif %}
         {% endif %}
         </td>
-       </tr>      
+       </tr>
 
        {% if data.user.profile.auth == 'local' %}
        <tr>
@@ -48,19 +48,19 @@
         <b>Password</b>
         </td>
         <td>
-        {% if data.edit == 'password' %}    
+        {% if data.edit == 'password' %}
           <table class="frametab"><tr><td>
           <input type='hidden' name='edit' value='password' />
           <input type="password" name='value' style='width:95%' required autofocus />
           </td><td>
           <input type="submit" value="Go">
-          </td></tr></table>          
+          </td></tr></table>
         {% else %}
          ******* | <a href="/account/?edit=password">Change</a>
         {% endif %}
         </td>
        </tr>
-       {% endif %}  
+       {% endif %}
 
 
        <tr>
@@ -75,24 +75,24 @@
         {% else %}
         {{ data.user.profile.auth }}
         {% endif %}
-        </td>    
+        </td>
        </tr>
 
 
 
       </table>
       <br />
-       
+
       <h3>Profile</h3>
       <table class="dashboard">
-       
+
        <tr>
         <td>
         <b>Time Zone</b>
         </td>
         <td>
-        
-        {% if data.edit == 'timezone' %}    
+
+        {% if data.edit == 'timezone' %}
           {% include "components/tzselect.html" %}
           <input type='hidden' name='edit' value='timezone' />
           <input type="submit" value="Go">
@@ -101,7 +101,7 @@
         {% endif %}
         </td>
        </tr>
-       
+
 
        <tr>
         <td valign=top>
@@ -117,23 +117,23 @@
         {% endif %}
         {% endfor %}
         {% endif %}
-        
+
         : <code>{{conf_data.value}}</code> |  <a href='?delete_extra_conf_uuid={{conf_uuid}}'>delete</a>
-        <br/> 
+        <br/>
         {% endfor %}
-        
-        
-        
+
+
+
         <span style="margin:3px"><a href="/add_profile_conf" style="line-height:2em">Add new...</a></span>
         </td>
-       </tr>       
+       </tr>
 
       </table>
 
       <br />
       <h3>KeyPair</h3>
       <table class="dashboard">
-       
+
        <tr>
         <td valign="top">
         <b>Default public key</b>
@@ -145,7 +145,7 @@
 
       </table>
       </form>
-      
+
       <div style="margin-left:10px; margin-top:40px">
         {% if data.user.profile.auth == 'oidc' %}
         <form action="{% url 'oidc_logout' %}" method="post">
@@ -155,18 +155,18 @@
         {% else %}
         <form action="/logout/" method="get">
         <input type="submit" value="logout">
-        </form>        
+        </form>
         {% endif %}
       </div>
 
-      
+
       <br/>
       <br/>
       <br/>
       <br/>
       <br/>
       <br/>
-      
+
     </div>
   </div>
 </div>
@@ -178,3 +178,4 @@
 
 
 
+
diff --git a/services/webapp/code/rosetta/core_app/templates/add_profile_conf.html b/services/webapp/code/rosetta/core_app/templates/add_profile_conf.html
index 56e275f..1c70116 100644
--- a/services/webapp/code/rosetta/core_app/templates/add_profile_conf.html
+++ b/services/webapp/code/rosetta/core_app/templates/add_profile_conf.html
@@ -1,4 +1,4 @@
-{% load static %} 
+{% load static %}
 {% include "header.html" %}
 {% include "navigation.html" %}
 {% include "logo.html" %}
@@ -6,19 +6,19 @@
 <div class="container">
   <div class="dashboard">
     <div class="span8 offset2">
-      <h1>Add extra profile configuration</h1> 
+      <h1>Add extra profile configuration</h1>
       <hr>
 
-      <h4>Chose the configuration type and add the values</h4> 
-      
+      <h4>Chose the configuration type and add the values</h4>
+
       <br/>
-      
+
       <form action="/add_profile_conf/" method="POST">
       {% csrf_token %}
-      
+
       <table class="dashboard" style="max-width:430px">
        <tr>
-       
+
         <td>
          {%if data.conf_type %}
          <select name="conf_type">
@@ -29,7 +29,7 @@
           {% for conf_type in data.conf_types %}
           <option value="{{conf_type}}">{{conf_type}}</option>
           {% endfor %}
-         </select>         
+         </select>
          {% endif %}
         </td>
 
@@ -44,11 +44,11 @@
           {% for computing in data.computings %}
           <option value="{{computing.uuid}}">{{computing.name}}</option>
           {% endfor %}
-         </select>         
+         </select>
          {% endif %}
         </td>
         {% endif %}
-      
+
 
        {% if data.last_step %}
         <td colspan=2 align=center style="padding:20px">
@@ -62,11 +62,10 @@
          <input type="submit" value="Next">
         </td>
        {% endif %}
-       
+
       </table>
       </form>
 
-      <br/>          
       <br/>
       <br/>
       <br/>
@@ -75,7 +74,8 @@
       <br/>
       <br/>
       <br/>
-      
+      <br/>
+
     </div>
   </div>
 </div>
@@ -87,3 +87,4 @@
 
 
 
+
diff --git a/services/webapp/code/rosetta/core_app/templates/add_software.html b/services/webapp/code/rosetta/core_app/templates/add_software.html
index 2ef2970..ecef3eb 100644
--- a/services/webapp/code/rosetta/core_app/templates/add_software.html
+++ b/services/webapp/code/rosetta/core_app/templates/add_software.html
@@ -1,4 +1,4 @@
-{% load static %} 
+{% load static %}
 {% include "header.html" %}
 {% include "navigation.html" %}
 {% include "logo.html" %}
@@ -6,24 +6,24 @@
 <div class="container">
   <div class="dashboard">
     <div class="span8 offset2">
-      <h1>Add software container</h1> 
+      <h1>Add software container</h1>
       <hr>
 
       {% if not data.added %}
 
           Here you can add a new software container on the platform. You can add containers from image registries
           as <a href="https://hub.docker.com/">Docker Hub </a>or by importing Git repositories, provided that they
-          are compatible with <a href="https://mybinder.readthedocs.io/en/latest/introduction.html">Binder</a> specifications.          
+          are compatible with <a href="https://mybinder.readthedocs.io/en/latest/introduction.html">Binder</a> specifications.
           <br/>
           <br/>
-          
+
           {% if data.new_container_from == 'registry' %}
           <div style="font-size:1.1em; background:whitesmoke; display:inline-block; padding:2px 15px 2px 15px">New container from registry</div>
-          <div style="font-size:1.1em; background:white; display:inline-block; padding:2px 15px 2px 15px"><a href="?new_container_from=repository">New container from Git repository</a></div>         
+          <div style="font-size:1.1em; background:white; display:inline-block; padding:2px 15px 2px 15px"><a href="?new_container_from=repository">New container from Git repository</a></div>
           <hr style="margin-top:0;">
 
-          <h4>Basics</h4> 
-                    
+          <h4>Basics</h4>
+
           <form action="#" method="POST">
           {% csrf_token %}
 
@@ -43,7 +43,7 @@
              ​<textarea name="container_description" rows="3" cols="22"></textarea>
             </td>
            </tr>
-    
+
            <tr>
             <td><b>Registry</b></td><td>
              <input type="text" name="container_registry" value="docker.io" size="23" required />
@@ -68,7 +68,7 @@
 
 
 
-          <h4>Interface </h4> 
+          <h4>Interface </h4>
           <table class="dashboard" style="width:400px; margin-bottom:25px">
 
            <tr>
@@ -80,7 +80,7 @@
             <td><b>Interface protocol</b></td>
             <td>
              {% if request.user.profile.is_power_user %}
-             <input type="text" value="http" name="container_interface_protocol" size="5" /> 
+             <input type="text" value="http" name="container_interface_protocol" size="5" />
              {% else %}
              <select name="container_interface_protocol" >
              <option value="http" selected>http</option>
@@ -91,13 +91,13 @@
            </tr>
            </table>
 
-           
+
            <a href="javascript:void(0);" id="show_button" onclick="toggle_visibility('advanced_div')">Advanced...</a>
-           
+
 
            <div id="advanced_div" style="display:none; width:400px;">
            <h4>Advanced <font size=-1>| <a href="javascript:void(0);" id="hide_button" onclick="toggle_visibility('advanced_div')" style="display:none">hide</a></font></h4>
-  
+
            <table class="dashboard" style="width:400px; margin-bottom:25px">
 
            <tr>
@@ -130,21 +130,21 @@
 
            <tr>
             <td colspan=2>
-             <b>Supports custom interface port</b> &nbsp; 
+             <b>Supports custom interface port</b> &nbsp;
              <input type="checkbox" name="container_supports_custom_interface_port" value="True" />
             </td>
            </tr>
 
            <tr>
             <td colspan=2>
-             <b>Supports interface auth</b> &nbsp; 
+             <b>Supports interface auth</b> &nbsp;
              <input type="checkbox" name="container_supports_interface_auth" value="True" />
             </td>
            </tr>
 
            <tr>
             <td colspan=2>
-             <b>Disable HTTP auth embedding</b> &nbsp; 
+             <b>Disable HTTP auth embedding</b> &nbsp;
              <input type="checkbox" name="container_disable_http_basicauth_embedding" value="True" />
             </td>
            </tr>
@@ -158,7 +158,7 @@
 
           </table>
           </div>
-          
+
           <table style="width:400px; border:0; background:#ffffff; margin-top:20px">
           <tr><td align="center">
           <input type="submit" value="Add">
@@ -166,17 +166,17 @@
           </table>
 
           <input type="hidden" name="new_container_from" value="registry">
-     
+
           </form>
 
 
           {% else %}
           <div style="font-size:1.1em; background:white; display:inline-block; padding:2px 15px 2px 15px"><a href="?new_container_from=registry">New container from registry</a></div>
-          <div style="font-size:1.1em; background:whitesmoke; display:inline-block; padding:2px 15px 2px 15px">New container from Git repository</div>         
+          <div style="font-size:1.1em; background:whitesmoke; display:inline-block; padding:2px 15px 2px 15px">New container from Git repository</div>
           <hr style="margin-top:0;">
 
-          <h4>Basics</h4> 
-                    
+          <h4>Basics</h4>
+
           <form action="#" method="POST">
           {% csrf_token %}
 
@@ -196,7 +196,7 @@
              ​<textarea name="container_description" rows="3" cols="22"></textarea>
             </td>
            </tr>
-    
+
            <tr>
             <td><b>Repository URL</b></td><td>
              <input type="text" name="repository_url" size="23" required />
@@ -214,24 +214,23 @@
            </table>
 
 
-                    
+
           <table style="width:400px; border:0; background:#ffffff; margin-top:20px">
           <tr><td align="center">
           <input type="submit" value="Add">
           </td></tr>
           </table>
-          
+
           <input type="hidden" name="new_container_from" value="repository">
-                 
-          </form>          
-          
-          
-          
+
+          </form>
+
+
+
           {% endif %}
 
 
 
-          <br/>          
           <br/>
           <br/>
           <br/>
@@ -240,21 +239,22 @@
           <br/>
           <br/>
           <br/>
-          
- 
+          <br/>
+
+
       {% else %}
         Ok, software container added. Go to <a href="/software">software</a>.
-        
 
-      {% endif %} 
-  
+
+      {% endif %}
+
       <br/>
       <br/>
       <br/>
       <br/>
       <br/>
       <br/>
-      
+
     </div>
   </div>
 </div>
@@ -270,7 +270,7 @@ function toggle_visibility(id) {
         x.style.display = "block";
         y.style.display = "none"
         z.style.display= "inline"
-        
+
       } else {
         x.style.display = "none";
         y.style.display= "inline"
@@ -283,3 +283,4 @@ function toggle_visibility(id) {
 
 
 
+
diff --git a/services/webapp/code/rosetta/core_app/templates/backend.html b/services/webapp/code/rosetta/core_app/templates/backend.html
index e679084..757e34e 100644
--- a/services/webapp/code/rosetta/core_app/templates/backend.html
+++ b/services/webapp/code/rosetta/core_app/templates/backend.html
@@ -13,10 +13,10 @@
             <div style="color:green">
               {{data.success}}
             </div>
-            {% else %}            
+            {% else %}
             <br/>
-            {% endif %} 
-            
+            {% endif %}
+
             {% if request.user.is_authenticated %}
             Logged in as <b>{{ request.user.username }}</b> | <a href="/logout">Logout</a>
             {% else %}
@@ -41,11 +41,12 @@
                 <li><a href="/api/v1/base/login/">/api/v1/base/login/</a></li>
                 <li><a href="/api/v1/base/logout/">/api/v1/base/logout/</a></li>
             </ul>
-            
+
         </div>
-        
+
     </body>
-    
+
 
 </html>
 
+
diff --git a/services/webapp/code/rosetta/core_app/templates/components/computing.html b/services/webapp/code/rosetta/core_app/templates/components/computing.html
index 8e709da..8b3826f 100644
--- a/services/webapp/code/rosetta/core_app/templates/components/computing.html
+++ b/services/webapp/code/rosetta/core_app/templates/components/computing.html
@@ -1,5 +1,5 @@
 
-      {% if data.computing %}  
+      {% if data.computing %}
 
       <div style="float:left; width:500px; margin:10px; margin-bottom:20px">
       <table class="dashboard" style="width:100%">
@@ -23,7 +23,7 @@
         <td><b>Type</b></td>
         <td>{{ data.computing.type }}</td>
        </tr>
-       
+
        <tr>
         <td><b>Access mode</b></td>
         <td>{{ data.computing.access_mode }}</td>
@@ -73,7 +73,7 @@
 
       </table>
       </div>
-      
+
       {% else %}
 
 
@@ -95,10 +95,10 @@
         {% if not computing_configured %}
         <div style="width:298px; float:left; margin:0; margin-bottom:5px; padding:2px; background: gary; color:black; text-align:center; border-bottom: #e0e0e0 solid 1px;">
         <i class="fa fa-info-circle"></i> Not configured <!-- style="color:#337ab7" -->
-        </div>      
+        </div>
         {% endif %}
 
-        
+
 
         {% if not computing_configured %}
         <!--  <div style="padding:10px; -webkit-filter: blur(5px); -moz-filter: blur(5px); -o-filter: blur(5px); -ms-filter: blur(5px); filter: blur(5px);"> -->
@@ -107,12 +107,12 @@
         <div style="padding:10px;">
         {% endif %}
 
-        {% if computing.description %} 
+        {% if computing.description %}
         <div class="description-box" title="{{ computing.description }}">
         {{ computing.description }}
         </div>
         {% else %}
-        <br/>  
+        <br/>
         {% endif %}
         <div class="image-version-box">
         <b>Type:</b> {{ computing.type }} <font style="font-size:0.9em">({{ computing.arch }})</font>
@@ -133,7 +133,7 @@
         <!-- ><b>Access:</b> {{ computing.access_mode }}<br/> --
         <!-- <b>Owner:</b> {% if computing.user %}{{ computing.user }}{% else %}Platform{% endif %}<br/> -->
         <!--  <b>Engines:</b> {{ computing.container_engines }} -->
-        
+
         <!-- {% if 'docker' in computing.container_engines %}<img src="/static/img/docker-logo.svg" style="height:18px; width:18px; margin-bottom:2px" />{% endif %}
         {% if 'singularity' in computing.container_engines %}<img src="/static/img/singularity-logo.svg" style="height:18px; width:18px; margin-bottom:2px" />{% endif %}-->
         {% if container %}
@@ -152,15 +152,15 @@
         {% endif %}
         </div>
         {% endif %}
-        
-        </div>  
+
+        </div>
 
       </div>
       {% endif %}
-      
 
-      
+
+
       {% endif %}
-      
-      
-      
\ No newline at end of file
+
+
+
diff --git a/services/webapp/code/rosetta/core_app/templates/components/container.html b/services/webapp/code/rosetta/core_app/templates/components/container.html
index 00d561d..eec4445 100644
--- a/services/webapp/code/rosetta/core_app/templates/components/container.html
+++ b/services/webapp/code/rosetta/core_app/templates/components/container.html
@@ -1,6 +1,6 @@
 
 
-      {% if details %}     
+      {% if details %}
 
       <div style="width:400px; float:left; border: #e0e0e0 solid 1px; margin:10px; background:#f8f8f8; margin-bottom:15px">
       <table class="dashboard" style="margin:0px; border:0px; width:398px">
@@ -8,7 +8,7 @@
        <tr>
         <td colspan=2 align=center style="padding:10px; font-size:1.2em"><a href="/software/?container_uuid={{ container.uuid }}">{{ container.name }} <font style="font-size:0.9em">({{ container.image_tag }})</font></a></td>
        </tr>
-        
+
        <tr>
         <td colspan="2" style="background:{{ container.color }}; height:15px"></td>
        </tr>
@@ -43,7 +43,7 @@
 
        <tr><td colspan=2><hr style="margin:5px"></td></tr>
        </table>
-       
+
       <table class="dashboard" style="margin:0px; border:0px;">
        <tr>
         <td><b>Interface protocol</b></td>
@@ -85,33 +85,33 @@
 
        <tr>
         <td colspan=2>
-         <b>Supports custom interface port</b> &nbsp; 
+         <b>Supports custom interface port</b> &nbsp;
          {% if container.supports_custom_interface_port %}
-           <input type="checkbox" name="container_supports_user_auth" checked disabled/> 
+           <input type="checkbox" name="container_supports_user_auth" checked disabled/>
          {% else %}
-           <input type="checkbox" name="container_supports_user_auth" disabled/> 
+           <input type="checkbox" name="container_supports_user_auth" disabled/>
          {% endif %}
         </td>
        </tr>
 
        <tr>
         <td colspan=2>
-         <b>Supports interface auth</b> &nbsp; 
+         <b>Supports interface auth</b> &nbsp;
          {% if container.supports_interface_auth %}
-           <input type="checkbox" name="supports_interface_auth" checked disabled/> 
+           <input type="checkbox" name="supports_interface_auth" checked disabled/>
          {% else %}
-           <input type="checkbox" name="supports_interface_auth" disabled/> 
+           <input type="checkbox" name="supports_interface_auth" disabled/>
          {% endif %}
          </td>
        </tr>
 
        <tr>
         <td colspan=2>
-         <b>Disable HTTP auth embedding</b> &nbsp; 
+         <b>Disable HTTP auth embedding</b> &nbsp;
          {% if container.disable_http_basicauth_embedding %}
-           <input type="checkbox" name="disable_http_basicauth_embedding" checked disabled/> 
+           <input type="checkbox" name="disable_http_basicauth_embedding" checked disabled/>
          {% else %}
-           <input type="checkbox" name="disable_http_basicauth_embedding" disabled/> 
+           <input type="checkbox" name="disable_http_basicauth_embedding" disabled/>
          {% endif %}
          </td>
        </tr>
@@ -122,7 +122,7 @@
         <td><pre>{{container.env_vars}}</pre></td>
        </tr>
        {% endif %}
-       
+
        {% if container.user %}
        <tr>
         <td><b>Operations</b></td>
@@ -131,26 +131,26 @@
        {% endif %}
       </table>
       </div>
-      
-      
+
+
       {% else %}
       <div style="width:300px; float:left; border: #e0e0e0 solid 1px; margin:10px; background:#f8f8f8; margin-bottom:15px">
 
-        
+
         <div style="padding:10px; margin-top:5px; text-align:center; border-bottom: {{container.color}} solid 10px; ">
-        <a href="/software/?container_uuid={{ container.uuid }}">{{ container.name }}</a>&nbsp; 
+        <a href="/software/?container_uuid={{ container.uuid }}">{{ container.name }}</a>&nbsp;
         </div>
-        
+
         <div style="padding:10px; height: 110px; vertical-align: middle; ">
-        
-        {% if container.description %} 
+
+        {% if container.description %}
         <div class="description-box" title="{{ container.description }}">
         {{ container.description }}
         </div>
         {% else %}
-        <br/>  
+        <br/>
         {% endif %}
-        
+
         <div class="image-version-box">
         <!-- <font style="font-family:monospace; font-size:1.2em"></font> -->
         <b>Image:</b> <code>{{ container.image_name }}</code><br/>
@@ -158,22 +158,22 @@
         {% if container.image_arch %}
         <font style="font-size:0.9em">({{ container.image_arch }})</font>
         {% endif %}
-        
+
         <!--  &nbsp; <b>Arch:</b> {{ container.image_arch }} -->
-        </div> 
-       
         </div>
-        
+
+        </div>
+
         <div style="margin-bottom:18px; margin-top: 3px; text-align:center">
         {% if not disable_play_button %}
         <a href="/new_task?task_container_uuid={{ container.uuid }}&step=two" class="btn btn-light" style="border: #c0c0c0 1px solid">&nbsp;<i class="fa fa-play" style="color:green"></i></a>
         {% endif %}
-        </div>    
-      
-      
-      
+        </div>
+
+
+
       </div>
-      
+
       {% endif  %}
 
 
@@ -181,4 +181,4 @@
 
 
 
-      
\ No newline at end of file
+
diff --git a/services/webapp/code/rosetta/core_app/templates/components/container_family.html b/services/webapp/code/rosetta/core_app/templates/components/container_family.html
index 2dc88c6..e39dcbe 100644
--- a/services/webapp/code/rosetta/core_app/templates/components/container_family.html
+++ b/services/webapp/code/rosetta/core_app/templates/components/container_family.html
@@ -3,33 +3,33 @@
       {% for container in container_family.members %}
       {% include "components/container.html" with container=container details=data.details %}
       {% endfor %}
-      
-      {% else %}    
+
+      {% else %}
 
       <div style="width:300px; float:left; border: #e0e0e0 solid 1px; margin:10px; background:#f8f8f8; margin-bottom:15px">
         <form action="/new_task" method=GET>
         <input type="hidden" name="step" value="two">
-        
-        
+
+
         <div style="padding:10px; margin-top:5px; text-align:center; border-bottom: {{container_family.color}} solid 10px; ">
-        <a href="/software/?container_family_id={{ container_family_id }}&details=True">{{ container_family.name }}</a>&nbsp; 
+        <a href="/software/?container_family_id={{ container_family_id }}&details=True">{{ container_family.name }}</a>&nbsp;
         </div>
-        
+
         <div style="padding:10px; height: 125px; ">
         <!-- <div style="position: relative; top: 50%; transform: translateY(-50%);"> -->
-        
-        {% if container_family.description %} 
+
+        {% if container_family.description %}
         <div class="description-box" title="{{ container_family.description }}">
         {{ container_family.description }}
         </div>
         {% else %}
-        <br/>  
+        <br/>
         {% endif %}
-        
+
         <div class="image-version-box">
         <b>Image:</b> <code>{{ container_family.image_name }}</code><br/>
         <div style="margin-top:2px">
-        
+
         <!-- <span style="vertical-align:top;"><b>Tag:</b>&nbsp;</span>
         <select name="task_container_uuid" style="font-size:0.8em">
         {% for container in container_family.members %}
@@ -79,32 +79,32 @@
         </optgroup>
 
 
-   
+
 
         </select>
 
-            
+
         </div>
         </div>
         <!-- </div> -->
         </div>
-        
+
         <div style="margin-bottom:8px; margin-top: 3px; text-align:center">
         {% if not disable_play_button %}
-        
-               
+
+
         <button type="submit" onclick="myFunction()" class="btn-link btn btn-light" style="border: #c0c0c0 1px solid; padding-left:14px">
         <i class="fa fa-play" style="color:green"></i>
         </button>
-        
+
         {% endif %}
         </form>
-        </div>    
-      
-      
-      
+        </div>
+
+
+
       </div>
-      
+
       {% endif %}
 
 
@@ -112,4 +112,4 @@
 
 
 
-      
\ No newline at end of file
+
diff --git a/services/webapp/code/rosetta/core_app/templates/components/task.html b/services/webapp/code/rosetta/core_app/templates/components/task.html
index 6c075a3..ffbc84a 100644
--- a/services/webapp/code/rosetta/core_app/templates/components/task.html
+++ b/services/webapp/code/rosetta/core_app/templates/components/task.html
@@ -1,34 +1,34 @@
 
-          {% if data.task %} 
+          {% if data.task %}
           <center>
           <div style="width:350px; display:block; border: #e0e0e0 solid 1px; margin:10px; background:#f8f8f8; margin-bottom:20px">
             <div style="margin-top:5px; padding:10px; text-align:center; border-bottom: #f8f8f8 solid 1px; ">
             <b>{{data.task.name}}</b>
             </div>
             <hr style="margin:0">
-            
+
           {% else %}
           <div style="width:350px; float:left; border: #e0e0e0 solid 1px; margin:10px; background:#f8f8f8; margin-bottom:20px">
-            
+
             <div style="margin-top:5px; padding:10px; text-align:center; border-bottom: #e0e0e0 solid 1px; ">
             <a href="?uuid={{ task.uuid }}"><b>{{ task.name }}</b></a>
             </div>
 
 
           {% endif %}
-            
 
-            
+
+
             <!-- <div style="background:{{task.color}}; height:24px;"></div> -->
 
             <!-- <div style="background:{{ task.container.color }}; height:14px;"></div> -->
-            
+
             <!-- <div style="margin-bottom:15px; margin-top:0px">
               <div style="background:{{task.container.color}}; height:14px; width:149px; float:left"></div>
               <div style="background:{{task.computing.color}}; height:14px; width:149px; float:left"></div>
             </div> -->
 
-            
+
             <div style="padding:10px; padding-left:15px; padding-right:15px; text-align:left;">
             <!-- <b>Container:</b> {{ task.container.name }} <span style="font-size:14px; background-color:{{task.container.color}}">&nbsp;&nbsp;&nbsp;&nbsp;</span> <br/>
             <b>Computing:</b> {{ task.computing.name }} <span style="font-size:14px; background-color:{{task.computing.color}}">&nbsp;&nbsp;&nbsp;&nbsp;</span><br/> -->
@@ -39,68 +39,68 @@
             {% if task.container.type == 'singularity' %}<img src="/static/img/singularity-logo.svg" style="height:18px; width:18px; margin-bottom:4px" />{% endif %}
 
             <br/>
-            
+
             <b>Computing:</b> <a href="/computing/?uuid={{ task.computing.uuid }}">{{ task.computing.name }}</a>
-            <!-- <a href="/computing/?uuid={{ task.computing.uuid }}" no_style="color:{{task.computing.color}}"><i class="fa fa-external-link" ></i></a><br/> -->           
-            
+            <!-- <a href="/computing/?uuid={{ task.computing.uuid }}" no_style="color:{{task.computing.color}}"><i class="fa fa-external-link" ></i></a><br/> -->
+
             <div style="margin-top:2px">
             {% if task.status == "running" %}
              <b>Status:</b> <font color="green">running</font>
              {% if task.container.interface_protocol == 'http' or task.container.interface_protocol == 'https' %}
              {% else %}
-             @ port {{ task.tcp_tunnel_port }} 
+             @ port {{ task.tcp_tunnel_port }}
              {% endif %}
-             
-             
+
+
             {% else %}
              <b>Status:</b> {{ task.status }}
             {% endif %}
             </div>
             </div>
- 
+
             <div style="margin-bottom:10px; text-align:center; padding:5px">
-            
+
             <!-- Stop / Delete / Cancel -->
             {% if task.status == "stopped" or task.status == "created" %}
             <a href="?uuid={{task.uuid}}&action=delete&fromlist=True" class="btn btn-action">Delete</a>
-            {% else %}            
+            {% else %}
             <a href="?uuid={{task.uuid}}&action=stop&fromlist=True" class="btn btn-action">Stop</a>
             {% endif %}
-            
+
             <!-- Connect -->
             {% if task.interface_port %}
             {% if task.container.interface_protocol == 'http' or task.container.interface_protocol == 'https' %}
             {% if task.status == "running" %}
             <a href="/task_connect/?uuid={{task.uuid}}" class="btn btn-connect">Connect</a>
             {% else %}
-            <a href="" class="btn btn-disabled">Connect</a>  
+            <a href="" class="btn btn-disabled">Connect</a>
             {% endif %}
             {% endif %}
             {% endif %}
-                        
+
             <!-- View log -->
             {% if task.status == "running" %}
-            <a href="/task_log/?uuid={{task.uuid}}&action=viewlog" class="btn btn-action">Logs</a> 
+            <a href="/task_log/?uuid={{task.uuid}}&action=viewlog" class="btn btn-action">Logs</a>
             {% else %}
-            <a href="" class="btn btn-disabled">Logs</a> 
+            <a href="" class="btn btn-disabled">Logs</a>
             {% endif %}
-            </div>    
-          
-          
-          
+            </div>
+
+
+
           </div>
 
 
-          {% if data.task %}      
+          {% if data.task %}
           <br/>
-          
+
            <a href="javascript:void(0);" id="show_button" onclick="toggle_visibility('details_div')">Details..</a>
-           
+
 
            <div id="details_div" style="display:none; width:400px;">
            <b>Details <font size=-1>| <a href="javascript:void(0);" id="hide_button" onclick="toggle_visibility('details_div')" style="display:none">hide</a></font></b>
-  
-          
+
+
           <div style="display:block"; max-width:450px">
           <table class="dashboard" style="margin:10px">
 
@@ -132,7 +132,7 @@
            <tr>
             <td><b>Status</b></td>
             <td>{{ task.status }}</td>
-           </tr> 
+           </tr>
 
            <tr>
             <td><b>Created at</b></td>
@@ -148,7 +148,7 @@
             <td><b>Interface port</b></td>
             <td>{{ task.interface_port }}</td>
            </tr>
-           
+
            <tr>
             <td><b>Tunnel port</b></td>
             <td>{{ task.tcp_tunnel_port }}</td>
@@ -160,17 +160,17 @@
             <td>{{ task.auth_token }}</td>
            </tr>
            {% endif %}
-           
+
            {% if task.computing_options %}
            <tr>
             <td><b>Computing options</b></td>
             <td>{{ task.computing_options }}</td>
            </tr>
-           {% endif %}           
+           {% endif %}
 
 
             <!-- <tr><td style="padding-right:0"><b>Direct link</b>
-            <td>{% if task.status == "running" %}<a href="{{ task.sharable_link }}">{{ task.sharable_link }}</a>{% else %}N.A. (task not running) {% endif %}</td> 
+            <td>{% if task.status == "running" %}<a href="{{ task.sharable_link }}">{{ task.sharable_link }}</a>{% else %}N.A. (task not running) {% endif %}</td>
            </tr>-->
 
 
@@ -178,7 +178,7 @@
 
           </table>
           </div>
-          
+
           <!-- <p style="margin-left:10px; font-size:0.9em; color:#484848">
           <i class="fa fa-info-circle" style="color:#337ab7"></i> You can share a direct link with other people, but remember that if you have no authentication in place anyone will be able to access.
           </p> -->
@@ -186,5 +186,5 @@
 
           </center>
 
-          
-          {% endif  %}
\ No newline at end of file
+
+          {% endif  %}
diff --git a/services/webapp/code/rosetta/core_app/templates/components/tzselect.html b/services/webapp/code/rosetta/core_app/templates/components/tzselect.html
index 18b5f10..18ddf0f 100644
--- a/services/webapp/code/rosetta/core_app/templates/components/tzselect.html
+++ b/services/webapp/code/rosetta/core_app/templates/components/tzselect.html
@@ -1,7 +1,7 @@
 <select name="value" >
     <option disabled selected style='display:none;'>Time Zone...</option>
 
-    <optgroup label="US (Common)">  
+    <optgroup label="US (Common)">
         <option value="America/Puerto_Rico">Puerto Rico (Atlantic)</option>
         <option value="America/New_York">New York (Eastern)</option>
         <option value="America/Chicago">Chicago (Central)</option>
@@ -232,7 +232,7 @@
         <option value="Europe/Zaporozhye">Zaporozhye</option>
         <option value="Europe/Zurich">Zurich</option>
     </optgroup>
-    
+
     <optgroup label="Asia">
         <option value="Asia/Aden">Aden</option>
         <option value="Asia/Almaty">Almaty</option>
@@ -379,7 +379,7 @@
         <option value="Africa/Tunis">Tunis</option>
         <option value="Africa/Windhoek">Windhoek</option>
     </optgroup>
-    
+
     <optgroup label="Australia">
         <option value="Australia/ACT">ACT</option>
         <option value="Australia/Adelaide">Adelaide</option>
@@ -419,7 +419,7 @@
         <option value="Indian/Mayotte">Mayotte</option>
         <option value="Indian/Reunion">Reunion</option>
     </optgroup>
-    
+
     <optgroup label="Atlantic">
         <option value="Atlantic/Azores">Azores</option>
         <option value="Atlantic/Bermuda">Bermuda</option>
@@ -477,7 +477,7 @@
         <option value="Pacific/Wallis">Wallis</option>
         <option value="Pacific/Yap">Yap</option>
     </optgroup>
-    
+
     <optgroup label="Antarctica">
         <option value="Antarctica/Casey">Casey</option>
         <option value="Antarctica/Davis">Davis</option>
@@ -529,5 +529,5 @@
         <option value="UTC+13">UTC+13</option>
         <option value="UTC+14">UTC+14</option>
     </optgroup>
-    
-</select>
\ No newline at end of file
+
+</select>
diff --git a/services/webapp/code/rosetta/core_app/templates/computing.html b/services/webapp/code/rosetta/core_app/templates/computing.html
index 41bec5c..35a9c65 100644
--- a/services/webapp/code/rosetta/core_app/templates/computing.html
+++ b/services/webapp/code/rosetta/core_app/templates/computing.html
@@ -1,4 +1,4 @@
-{% load static %} 
+{% load static %}
 {% include "header.html" %}
 {% include "navigation.html" %}
 {% include "logo.html" %}
@@ -6,25 +6,25 @@
 <div class="container">
   <div class="dashboard">
     <div class="span8 offset2">
-      
+
       {% if data.computing %}
-      <h1><a href="/computing">Computing resources</a> <span style="font-size:18px"> / {{ data.computing.name }}</span></h1>      
+      <h1><a href="/computing">Computing resources</a> <span style="font-size:18px"> / {{ data.computing.name }}</span></h1>
       {% else %}
       <h1>Computing resources</h1>
       {% endif %}
-      
+
       <hr/>
       <div class="row" style="padding:5px">
       {% if data.computing %}
       {% include "components/computing.html" with computing=data.computing details=True %}
-      {% else %}      
+      {% else %}
       {% for computing in data.computings %}
       {% include "components/computing.html" with computing=computing %}
       {% endfor %}
       {% endif %}
       </div>
-      
-      <!-- <div class="row" style="padding:10px; padding-left:15px">   
+
+      <!-- <div class="row" style="padding:10px; padding-left:15px">
       <a href="/add_container">Add new...</a>
       </div> -->
 
@@ -45,3 +45,4 @@
 
 
 
+
diff --git a/services/webapp/code/rosetta/core_app/templates/error.html b/services/webapp/code/rosetta/core_app/templates/error.html
index 2c88790..9bf49bb 100644
--- a/services/webapp/code/rosetta/core_app/templates/error.html
+++ b/services/webapp/code/rosetta/core_app/templates/error.html
@@ -1,4 +1,4 @@
-{% load static %} 
+{% load static %}
 {% include "header.html" %}
 {% include "navigation.html" %}
 {% include "logo.html" %}
@@ -10,8 +10,8 @@
       <hr>
       <br/>
       <br/><br/>
-      <div class='centerbox-error-outer'> 
-          <span class='centerbox-error-inner'>     
+      <div class='centerbox-error-outer'>
+          <span class='centerbox-error-inner'>
           {{data.error}}
           </span>
       </div>
@@ -22,7 +22,7 @@
       <br/>
       <br/>
       <br/>
-      
+
     </div>
   </div>
 </div>
@@ -33,3 +33,4 @@
 
 
 
+
diff --git a/services/webapp/code/rosetta/core_app/templates/footer.html b/services/webapp/code/rosetta/core_app/templates/footer.html
index 6e4daa4..7c9cbbc 100644
--- a/services/webapp/code/rosetta/core_app/templates/footer.html
+++ b/services/webapp/code/rosetta/core_app/templates/footer.html
@@ -42,13 +42,14 @@
 
         colour_rgb = hexToRgb(colour)
 
-        return "rgba(" + colour_rgb.r + "," + colour_rgb.g + "," + colour_rgb.b + ",0.3)"    
-        
+        return "rgba(" + colour_rgb.r + "," + colour_rgb.g + "," + colour_rgb.b + ",0.3)"
+
     }
 
     </script>
-    
-    
+
+
 </body>
 
 </html>
+
diff --git a/services/webapp/code/rosetta/core_app/templates/header.html b/services/webapp/code/rosetta/core_app/templates/header.html
index 8e26792..7161aab 100644
--- a/services/webapp/code/rosetta/core_app/templates/header.html
+++ b/services/webapp/code/rosetta/core_app/templates/header.html
@@ -12,7 +12,7 @@
     {% if refresh %}
     <meta http-equiv="refresh" content="{{refresh}}" >
     {% endif %}
-    
+
     {% if title %}
     <title>Rosetta - {{ title }}</title>
     {% else %}
@@ -49,10 +49,10 @@
 
     <!-- jQuery -->
     <script src="/static/js/jquery-1.11.1.js"></script>
-    
+
     <!-- Bootstrap Core JavaScript -->
     <script src="/static/js/bootstrap-3.3.5.min.js"></script>
-    
+
     <!-- Moment Javascript -->
     <script src="/static/js/moment-with-locales-2.22.2.js"></script>
 
@@ -62,4 +62,4 @@
 </head>
 
 <body {{ body_args }}>
-  
\ No newline at end of file
+
diff --git a/services/webapp/code/rosetta/core_app/templates/import_repository.html b/services/webapp/code/rosetta/core_app/templates/import_repository.html
index eb4346d..4e6476b 100644
--- a/services/webapp/code/rosetta/core_app/templates/import_repository.html
+++ b/services/webapp/code/rosetta/core_app/templates/import_repository.html
@@ -1,4 +1,4 @@
-{% load static %} 
+{% load static %}
 {% include "header.html" %}
 {% include "navigation.html" %}
 {% include "logo.html" %}
@@ -6,24 +6,24 @@
 <div class="container">
   <div class="dashboard">
     <div class="span8 offset2">
-      {% if data.mode == 'new_task' %} 
-      <h1>New Task</h1> 
+      {% if data.mode == 'new_task' %}
+      <h1>New Task</h1>
       {% elif data.mode == 'new_container' %}
-      <h1>Add software container</h1> 
+      <h1>Add software container</h1>
       {% else %}
-      <h1>Importing repository</h1>       
+      <h1>Importing repository</h1>
       {% endif %}
       <hr>
 
       <div id="importing">
-      Importing repository <code>{{ data.repository_url }}</code>... 
+      Importing repository <code>{{ data.repository_url }}</code>...
       <br>
       <br>
       <br>
       <br>
       <center><img src="/static/img/ajax-loader.gif"></center>
       </div>
-      
+
       <div id="import_succeded" style="display:none">
       Ok, software container added. Go to <a href="/software">software</a>.
       </div>
@@ -32,7 +32,7 @@
       <div id="import_failed" style="display:none">
       FAILED: <span id="import_failed_text"></span>
       </div>
-      
+
         <script type="text/javascript">
             var apiUrl = '/api/v1/import_repository/?repository_url={{data.repository_url}}&repository_tag={{data.repository_tag}}&container_name={{data.container_name}}&container_description={{data.container_description}}';
             fetch(apiUrl).then(response => {
@@ -45,21 +45,21 @@
             }).then(data => {
               // Work with JSON data here
               console.log(data)
-              
+
               if (data.results.import_succeded){
-            	  
+
             	  // Terrbile django templating mixed with javascript
-                  {% if data.mode == 'new_task' %} 
-                  
-            	    window.location.replace("/new_task/?step=two&task_container_uuid="+data.results.container_uuid) 
-  
+                  {% if data.mode == 'new_task' %}
+
+            	    window.location.replace("/new_task/?step=two&task_container_uuid="+data.results.container_uuid)
+
                   {% else %}
-                  
+
                     $("#importing").hide();
-                    $("#import_succeded").show(); 
-                 
+                    $("#import_succeded").show();
+
                   {% endif %}
-            	   
+
               } else {
             	  throw data.results.error_message
               }
@@ -72,7 +72,7 @@
               $("#import_failed_text").html(error);
             });
         </script>
-        
+
     </div>
   </div>
 </div>
@@ -89,3 +89,4 @@
 
 
 
+
diff --git a/services/webapp/code/rosetta/core_app/templates/login.html b/services/webapp/code/rosetta/core_app/templates/login.html
index 40bd704..80e40a7 100644
--- a/services/webapp/code/rosetta/core_app/templates/login.html
+++ b/services/webapp/code/rosetta/core_app/templates/login.html
@@ -1,4 +1,4 @@
-{% load static %} 
+{% load static %}
 {% include "header.html" %}
 {% include "navigation.html"%}
 {% include "logo.html" %}
@@ -17,44 +17,44 @@
         <input type="password" class="form-control" placeholder="Password" name='password'>
         <br />
         <input type='submit' style="width:110px" class="btn btn-lg btn-success btn-block" value='Log in' />
-        
+
 
         <div style="margin-top:25px; margin-bottom:15px">
         {% if OPENID_ENABLED %}<font color="#a9a9a9"> — OR —</font>{% endif %}
         </div>
-        
+
         {% if OPENID_ENABLED %}
         <a href="{% url 'oidc_authentication_init' %}">Login with OpenID Connect &nbsp;</a>
         {% endif %}
-        
+
         <br /><br />
-        
+
         {% if data.error %}
         <br/>
         <div class='centerbox-error'>
           {{ data.error }}
         </div>
-        
+
         {% elif data.success %}
         <br/>
         <div class='centerbox-success'>
           {{data.success}}
         </div>
-        
+
         {% else %}
         <br />
-        
+
         {% endif %}
-             
+
 
         </p>
-        
-      </form>      
+
+      </form>
     </div>
     {% if not data.success %}
     <b>Forgot password?</b><br/> Just leave it empty to get a login link by email!
     {% endif %}
-    
+
     <br /><br /><br />
     </center>
 
@@ -62,3 +62,4 @@
 
 
 {% include "footer.html" %}
+
diff --git a/services/webapp/code/rosetta/core_app/templates/main.html b/services/webapp/code/rosetta/core_app/templates/main.html
index eb1a989..0bb1686 100644
--- a/services/webapp/code/rosetta/core_app/templates/main.html
+++ b/services/webapp/code/rosetta/core_app/templates/main.html
@@ -1,4 +1,4 @@
-{% load static %} 
+{% load static %}
 {% include "header.html" %}
 {% include "navigation.html"%}
 
@@ -12,7 +12,7 @@
                 <h2 style="margin-top:10px; margin-left:25px; margin-right:25px; font-weight:100; line-height: 30px;"><i>A container-centric Science Platform<br></i></h2>
             </div>
         </div>
-        
+
         <div class="container">
             <div class="dashboard">
                 <div class="span8 offset2" style="margin: 30px auto; max-width:800px">
@@ -21,9 +21,9 @@
                 <br/><br/>
                 This is an empty installation. To load some demo data, run <code>rosetta/populate</code>.
                 </div>
-                
+
             </div>
-        </div>          
+        </div>
     </header>
     {% endif %}
 
@@ -31,3 +31,4 @@
 
 
 
+
diff --git a/services/webapp/code/rosetta/core_app/templates/navigation.html b/services/webapp/code/rosetta/core_app/templates/navigation.html
index ecc8fbf..25ab05e 100644
--- a/services/webapp/code/rosetta/core_app/templates/navigation.html
+++ b/services/webapp/code/rosetta/core_app/templates/navigation.html
@@ -4,9 +4,9 @@
     <nav id="sidebar-wrapper">
         <ul class="sidebar-nav">
 
-            
+
             <a id="menu-close" href="#" class="btn btn-light btn-lg pull-right toggle"><i class="fa fa-times"></i></a>
-            <a href="/main" class="btn btn-light btn-lg pull-right toggle"><i class="fa fa-home"></i></a>      
+            <a href="/main" class="btn btn-light btn-lg pull-right toggle"><i class="fa fa-home"></i></a>
 
 
             <li class="sidebar-brand" style="margin-top:50px">
@@ -16,13 +16,13 @@
             <hr style="margin-top:10px; margin-bottom:20px; margin-left:10px; margin-right:10px">
 
             {% if user.is_authenticated %}
-    
+
             <li>
                 <a href="/software" onclick = $("#menu-close").click(); >Software</a>
             </li>
             <li>
                 <a href="/computing" onclick = $("#menu-close").click(); >Computing</a>
-            </li>            
+            </li>
 
             <li>
                 <a href="/storage" onclick = $("#menu-close").click(); >Storage</a>
@@ -34,30 +34,30 @@
 
             <li>
                 <a href="/account" onclick = $("#menu-close").click(); >Account</a>
-            </li>           
+            </li>
             {% else %}
-            
-            
-            {% if LOCAL_AUTH_ENABLED %}        
+
+
+            {% if LOCAL_AUTH_ENABLED %}
             <li>
               <center>
                 <form class="form-signin" role="form" action='/login/' method='POST'>
                 {% csrf_token %}
-                <input type="username" class="form-control" placeholder="Email" name='username' required>            
+                <input type="username" class="form-control" placeholder="Email" name='username' required>
                 <input type="password" class="form-control" placeholder="Password" name='password'>
                 <input type='submit' class="btn btn-lg ha-btn-lg" value='Login' />
                 </form>
-              </center>         
+              </center>
             </li>
-  
+
             {% if OPENID_ENABLED %}
             <center><div style="margin-top:15px;margin-bottom:10px"><font color="#a9a9a9"> — OR —</font></div></center>
-            {% endif %} 
-            
+            {% endif %}
+
             {% endif %}
             <center>
             {% if OPENID_ENABLED %}
-            {% if LOCAL_AUTH_ENABLED %}  
+            {% if LOCAL_AUTH_ENABLED %}
             <li style="padding-left:0; text-indent: 0"> <a href="{% url 'oidc_authentication_init' %}" style="padding-left:0; text-indent: 0">Login with OpenID Connect</a></li>
             {% else %}
             <li style="padding-left:0; text-indent: 0"> <a href="{% url 'oidc_authentication_init' %}" style="padding-left:0; text-indent: 0">Login</a></li>
@@ -65,20 +65,21 @@
             {% endif %}
             {% if LOCAL_AUTH_ENABLED %}
             <div style="padding:10px;">
-            <font color="gray">Forgot password? Just leave it empty to get a login link by email. 
+            <font color="gray">Forgot password? Just leave it empty to get a login link by email.
             Or, <a href="/register" style="color: #c0c0c0" onclick = $("#menu-close").click(); >Register</a>.</font>
             </div>
             {% endif %}
             </center>
             {% endif %}
 
-      
+
         </ul>
-        
-  
-        
-        
-        
-        
+
+
+
+
+
+
     </nav>
     {% endif %}
+
diff --git a/services/webapp/code/rosetta/core_app/templates/new_task.html b/services/webapp/code/rosetta/core_app/templates/new_task.html
index ec3536b..af0621e 100644
--- a/services/webapp/code/rosetta/core_app/templates/new_task.html
+++ b/services/webapp/code/rosetta/core_app/templates/new_task.html
@@ -1,4 +1,4 @@
-{% load static %} 
+{% load static %}
 {% include "header.html" %}
 {% include "navigation.html" %}
 {% include "logo.html" %}
@@ -6,14 +6,14 @@
 <div class="container">
   <div class="dashboard">
     <div class="span8 offset2">
-      <h1>New Task</h1> 
+      <h1>New Task</h1>
       <hr>
 
 
-      <!-- {% if data.step == 'two' %} 
-      <h3>Choose computing resource</h3> 
-      {% elif data.step == 'three' %}  
-      <h3>Task details and confirm</h3>    
+      <!-- {% if data.step == 'two' %}
+      <h3>Choose computing resource</h3>
+      {% elif data.step == 'three' %}
+      <h3>Task details and confirm</h3>
       {% endif %}
 
       <br/> -->
@@ -26,7 +26,7 @@
           </div>
       </div>
       {% endif %}
-      
+
 
       {% if data.step == 'two' %}
 
@@ -49,8 +49,8 @@
           {% include "components/computing.html" with computing=data.task_computing %}
           </div>
       </div>
-          
-          
+
+
           <!-- <div style="width:300px; float:left; border: #e0e0e0 solid 0px; margin:10px; background:#f8f8f8; margin-bottom:15px">
           <table style="width:100%; height:126px;  border: #e0e0e0 solid 1px; margin:0">
 
@@ -69,12 +69,12 @@
 
           <h4>Details and confirm</h4>
           <div style="width:620px; float:left; border: #e0e0e0 solid 0px; margin-top:10px; ; margin-bottom:15px">
-              
-        
+
+
           <form action="/new_task/" method="POST">
           {% csrf_token %}
           <input type="hidden" name="task_container_uuid" value="{{data.task_container.uuid}}">
-          <input type="hidden" name="task_container_arch" value="{{data.task_container_arch}}">          
+          <input type="hidden" name="task_container_arch" value="{{data.task_container_arch}}">
           <input type="hidden" name="step" value="{{ data.next_step }}" />
           <input type="hidden" name="task_name" value="{{ data.task_name }}" />
           <input type="hidden" name="task_container_uuid" value="{{ data.task_container.uuid }}" />
@@ -87,10 +87,10 @@
             <td valign="top"><b>Task name</b></td>
             <td><input type="text" name="task_name" value="" placeholder="" size="37" required /></td>
            </tr>
-           
+
            <tr>
             <td valign="top">
-            {% if request.user.profile.is_power_user %} 
+            {% if request.user.profile.is_power_user %}
             <b>Task&nbsp;password</b></td>
             {% else %}
             <b>Auth&nbsp;token</b></td>
@@ -99,11 +99,11 @@
 
              <input type="hidden" name="task_auth_token" value="{{data.task_auth_token}}">
 
-             {% if request.user.profile.is_power_user %}            
+             {% if request.user.profile.is_power_user %}
              <input type="text" name="task_auth_password" placeholder="{{data.task_auth_token}}" size="37" style="-webkit-text-security: disc;" /><br>
              <font size=-1>
              A one-time task password. By default set to a randomly generated token, and usually automatically handled by Rosetta. Six chars min.
-             </font>   
+             </font>
              {% else %}
              <input type="text" name="task_auth_password_disabled" value="{{data.task_auth_token}}" size="37" readonly/><br>
              <font size=-1>A randomly generated token to be used as task password. Usually automatically handled by Rosetta when loggin-in to the task.</font>
@@ -111,9 +111,9 @@
 
             </td>
            </tr>
-           
-           
-           {% if request.user.profile.is_power_user %}    
+
+
+           {% if request.user.profile.is_power_user %}
            <tr>
             <td><b>Access method</b></td><td>
              <select name="access_method" >
@@ -138,7 +138,7 @@
             </td>
            </tr>
            {% endif %}
-           
+
            {% if data.task_computing.wms == 'slurm' %}
            <tr>
             <td><b>Computing options</b></td>
@@ -151,14 +151,14 @@
             </td>
            </tr>
            {% endif %}
-             
+
            <tr><td colspan=2>
-           
+
            </td></tr>
 
           </table>
-          
-          
+
+
           {% if data.task_computing.default_container_engine == 'singularity' and not data.task_container.supports_custom_interface_port %}
           <div> <p style="font-size:15px; max-width:700px; margin-bottom:20px; margin-left:5px">
           <i class="fa fa-exclamation-triangle" style="color:orange"></i> This container does not support custom interface ports and the computing resource you selected might use a container engine/runtime which does not support port mapping. In this case, if the container interface port is already allocated, the task will fail to start.
@@ -176,21 +176,21 @@
           <i class="fa fa-exclamation-triangle" style="color:orange"></i> The selected software container does not specify any architecture. This will leave to the container engine/runtime either to auto-select the right image architecture on the registry, or to fallback on emulation if not found. Beware of potential incompatibilities or slowdowns.
           </p></div>
           {% endif %}
-          
+
           <!-- {% if data.task_container.interface_port and not data.task_container.supports_interface_auth %}
           <div> <p style="font-size:15px; max-width:700px; margin-bottom:20px; margin-left:5px">
           <i class="fa fa-exclamation-triangle" style="color:orange"></i> This container does not support configuring any authentication. This means that unless it is somehow built-in within the container, anyone will be able to access it.
           </p></div>
           {% endif %}  -->
-         
+
           <table style="max-width:620px;"><tr><td  style="border: 1px solid lightgray;" >
           I understand that files saved or modified in the task, if not explicitly saved to a persistent storage, will be LOST upon task completition.
           </td><td  style="border: 1px solid lightgray;" >
           <input class="form-check-input" type="checkbox" value="" id="invalidCheck" required>
           </td></table>
-          
+
           <div style="width:640px; text-align:center; padding:20px">
-          <input type="submit" value="Create task">    
+          <input type="submit" value="Create task">
           </div>
           </form>
           </div>
@@ -199,12 +199,12 @@
 
       {% else %}
         Ok, task created. Go to your <a href="/tasks">task list</a>.
-        
 
-      {% endif %} 
-  
 
-      
+      {% endif %}
+
+
+
     </div>
   </div>
 </div>
@@ -221,3 +221,4 @@
 
 
 
+
diff --git a/services/webapp/code/rosetta/core_app/templates/page.html b/services/webapp/code/rosetta/core_app/templates/page.html
index 9e13b28..c165dac 100644
--- a/services/webapp/code/rosetta/core_app/templates/page.html
+++ b/services/webapp/code/rosetta/core_app/templates/page.html
@@ -1,4 +1,4 @@
-{% load static %} 
+{% load static %}
 {% include "header.html" with title=data.page.title %}
 {% include "navigation.html"%}
 {% include "logo.html" %}
@@ -9,7 +9,7 @@
       <!-- <h1>Example title</h1>
       <hr> -->
       {{ data.page.content | safe }}
-      
+
     </div>
   </div>
 </div>
@@ -24,3 +24,4 @@
 
 
 
+
diff --git a/services/webapp/code/rosetta/core_app/templates/register.html b/services/webapp/code/rosetta/core_app/templates/register.html
index 66bb4bf..9c137f5 100644
--- a/services/webapp/code/rosetta/core_app/templates/register.html
+++ b/services/webapp/code/rosetta/core_app/templates/register.html
@@ -1,4 +1,4 @@
-{% load static %} 
+{% load static %}
 {% include "header.html" %}
 {% include "navigation.html" %}
 {% include "logo.html" %}
@@ -6,15 +6,15 @@
 <div class="container">
   <div class="dashboard">
     <div class="span8 offset2">
-    
+
       <h1>Register</h1>
       <hr>
-      
-      {% if data.status == "wrong_invite" %}   
+
+      {% if data.status == "wrong_invite" %}
       <div class='centerbox-error'>
           Sorry, this invitation code is not valid.
       </div>
-      
+
       {% elif data.status == "already" %}
       <div class='centerbox'>
           You are already signed in, cannot create a new account.
@@ -30,7 +30,7 @@
           Ok, account created!
       </div>
       <br />
-      
+
       You signed up with the following email address: <b>{{data.user.email}}</b>. If this is wrong, change it now in your account settings.
       <br/>
       <br/>
@@ -38,7 +38,7 @@
       {% else %}
 
       <p><b>Welcome!</b></p>
-      
+
       <p>
       {% if INVITATION_CODE_ENABLED %}
       An invitation code is required to register on the platform. If you have one, then you can sign up right now. Otherwise, please get in touch.
@@ -46,10 +46,10 @@
       Enter your email address and choose a password to register on the platform.
       {% endif %}
       </p>
-      
+
       <br/>
       <br/>
-      
+
       <div class='centerbox'>
           <form class="form-signin" role="form" action='/register/' method='POST'>
           {% csrf_token %}
@@ -66,12 +66,12 @@
       <center>Please not that we do not verify email addressed and passwords at this stage, so please <u>double check</u> the form above before signing up.</center>
 </div> -->
       {% endif %}
-      
-      {% if data.error %}   
+
+      {% if data.error %}
       <div class='centerbox-error'>
           {{ data.error }}
       </div>
-      
+
       {% endif %}
       <br/>
       <br/>
@@ -79,7 +79,7 @@
       <br/>
       <br/>
       <br/>
-      
+
     </div>
   </div>
 </div>
@@ -90,3 +90,4 @@
 
 
 
+
diff --git a/services/webapp/code/rosetta/core_app/templates/software.html b/services/webapp/code/rosetta/core_app/templates/software.html
index fc69df7..c94a41e 100644
--- a/services/webapp/code/rosetta/core_app/templates/software.html
+++ b/services/webapp/code/rosetta/core_app/templates/software.html
@@ -1,4 +1,4 @@
-{% load static %} 
+{% load static %}
 {% include "header.html" %}
 {% include "navigation.html" %}
 {% include "logo.html" %}
@@ -6,11 +6,11 @@
 <div class="container">
   <div class="dashboard">
     <div class="span8 offset2">
-      
+
       {% if data.details or data.container %}
       {% if data.container_families %}
       <h1><a href="/software">Software containers</a> <span style="font-size:18px"> / {{ data.containers.0.name }}</span></h1>
-      {% else %}      
+      {% else %}
       <h1><a href="/software">Software containers</a> <span style="font-size:18px"> / <a href="/software/?container_family_id={{data.container.family_id}}&details=True">{{ data.container.name }}</a> / {{ data.container.image_tag}}</span></h1>
       {% endif %}
       {% else %}
@@ -18,62 +18,62 @@
       <h1>New Task</h1>
       <hr/>
       <div style="padding-left:10px; padding-top:1px"><h4>Software container</h4></div>
-      <br/> 
+      <br/>
       {% else %}
       <h1>Software containers</h1>
       <hr/>
       {% endif %}
- 
 
-      
-      
+
+
+
       <div class="form-filter" style="margin-bottom:20px">
         <form action="" method="POST">
-          
+
           <input type="hidden" name="mode" value="{{data.mode}}">
-                    
+
           <input type="text" class="form-control" id="search_text" name="search_text" placeholder="Search..." style="width:200px; margin:0; display:inline" value="{{data.search_text}}" autofocus>
 
           <!-- onchange="this.form.submit()"  -->
           <select class="form-control" id="search_owner" name="search_owner" style="width:120px; margin:0; display:inline">
-            
+
             {% if data.search_owner == 'All' %}
             <option selected>All</option>
             {% else %}
-            <option>All</option>            
+            <option>All</option>
             {% endif %}
-            
+
             {% if data.search_owner == 'Platform' %}
             <option selected>Platform</option>
             {% else %}
-            <option>Platform</option>            
+            <option>Platform</option>
             {% endif %}
-            
+
             {% if data.search_owner == 'User' %}
             <option selected>User</option>
             {% else %}
-            <option>User</option>            
+            <option>User</option>
             {% endif %}
-            
+
           </select>
           {% csrf_token %}
           <button type="submit" class="btn btn-secondary">Go</button>
-          
+
           &nbsp; &nbsp; <font size=4.0em>|</font> &nbsp; <a href="/add_software">Add new...</a>
-          
+
         </form>
-        
-        
-              
+
+
+
       </div>
-      
-      
+
+
       {% endif %}
-      
+
       <div class="row" style="padding:5px">
       {% if data.container %}
       {% include "components/container.html" with container=data.container details=True %}
-      {% else %}     
+      {% else %}
       {% if data.container_families %}
       {% for container_family_id, container_family in data.container_families.items %}
       {% include "components/container_family.html" with container_family=container_family container_family_id=container_family_id%}
@@ -82,10 +82,10 @@
       {% for container in data.containers %}
       {% include "components/container.html" with container=container %}
       {% endfor %}
-      {% endif  %}      
+      {% endif  %}
       {% endif %}
       </div>
-        
+
       <br/>
       <br/>
       <br/>
@@ -102,7 +102,7 @@
 <script>
 
 $(document).ready(function() {
-	  
+
     var search_text_input = $("#search_text");
     var len = search_text_input.val().length;
     search_text_input[0].focus();
@@ -113,3 +113,4 @@ $(document).ready(function() {
 
 
 
+
diff --git a/services/webapp/code/rosetta/core_app/templates/storage.html b/services/webapp/code/rosetta/core_app/templates/storage.html
index f4a4c25..62ef047 100644
--- a/services/webapp/code/rosetta/core_app/templates/storage.html
+++ b/services/webapp/code/rosetta/core_app/templates/storage.html
@@ -1,4 +1,4 @@
-{% load static %} 
+{% load static %}
 {% include "header.html" %}
 {% include "navigation.html" %}
 {% include "logo.html" %}
@@ -6,7 +6,7 @@
 <div class="container" style="height:75%;">
   <div class="dashboard" style="height:100%;">
     <div class="span8 offset2" style="height:100%;">
-      
+
 
       <h1>Storage resources</h1>
 
@@ -14,8 +14,8 @@
 
 
       <iframe src="/static/RichFilemanager/index.html" style="overflow:hidden;height:100%;width:100%; border: 1px solid #c0c0c0" height="100%" width="100%"></iframe>
-    
-    
+
+
     </div>
   </div>
 </div>
@@ -23,3 +23,4 @@
 {% include "footer.html" %}
 
 
+
diff --git a/services/webapp/code/rosetta/core_app/templates/success.html b/services/webapp/code/rosetta/core_app/templates/success.html
index 44ef368..728ec4e 100644
--- a/services/webapp/code/rosetta/core_app/templates/success.html
+++ b/services/webapp/code/rosetta/core_app/templates/success.html
@@ -1,4 +1,4 @@
-{% load static %} 
+{% load static %}
 {% include "header.html" %}
 {% include "navigation.html" %}
 {% include "logo.html" %}
@@ -9,13 +9,13 @@
       <h1>Success</h1>
       <hr>
       <br/>
-      <div class='centerbox-success-outer'> 
-          <span class='centerbox-success-inner'>     
+      <div class='centerbox-success-outer'>
+          <span class='centerbox-success-inner'>
           {{data.success}}
           </span>
       </div>
-      
-      
+
+
 
       <br/>
       <br/>
@@ -23,7 +23,7 @@
       <br/>
       <br/>
       <br/>
-      
+
     </div>
   </div>
 </div>
@@ -34,3 +34,4 @@
 
 
 
+
diff --git a/services/webapp/code/rosetta/core_app/templates/task_connect.html b/services/webapp/code/rosetta/core_app/templates/task_connect.html
index c1ba20b..ac276f8 100644
--- a/services/webapp/code/rosetta/core_app/templates/task_connect.html
+++ b/services/webapp/code/rosetta/core_app/templates/task_connect.html
@@ -1,9 +1,9 @@
-{% load static %} 
+{% load static %}
 {% include "header.html" %}
 {% include "navigation.html"%}
 <!-- with body_args="style='background: #202020'" -->
     <center>
-    
+
     <div style="width:370px;">
       <form class="form-signin" role="form" action='/direct_connect/{{data.task.uuid}}/' method='POST'>
         {% csrf_token %}
@@ -14,7 +14,7 @@
         <h2> Connecting to task <b>{{ data.task.name }}</b></h2>
         <p style="font-size: 16px;">
         <br />
-        
+
         {% if not data.task.interface_status == 'running' %}
         <br/>
         <div class="alert alert-warning" role="alert"><i class="fa fa-warning"></i> the task interface is not up, cannot connect.</div>
@@ -22,20 +22,20 @@
         <br/><br/>
         <i>Note: if you just launched the task, this alert might be due to the normal task startup time.</i>
         {% else %}
-        
+
         {% if not data.task.requires_proxy_auth %}
         {% if data.task.container.interface_auth_user %}
-        User: <input style="margin-bottom:15px;" type="username" class="form-control" value="{{ data.task.container.interface_auth_user }}"name='username' readonly >        
+        User: <input style="margin-bottom:15px;" type="username" class="form-control" value="{{ data.task.container.interface_auth_user }}"name='username' readonly >
         {% else %}
-        
+
         {% endif %}
         {% else %}
         User: <input style="margin-bottom:15px;" type="username" class="form-control" value="{{ request.user.email }}"name='username' readonly >
         {% endif %}
-        
-        
+
+
         {% if data.task.requires_proxy_auth %}
-        
+
           {% if data.task.auth_token %}
           Password: <input type="text" size=37 class="form-control" placeholder="" value="{{data.task.auth_token}}" name='password' readonly>
           {% if data.task.container.disable_http_basicauth_embedding %}
@@ -49,11 +49,11 @@
           <p style="margin-left:10px; font-size:0.9em; color:#484848">
           <i class="fa fa-info-circle" style="color:#337ab7"></i>
           This task will require to manually enter the password set up when creating the task
-          </p> 
+          </p>
           {% endif %}
-                 
+
         {% else %}
-        
+
           {% if data.task.auth_token %}
           Password: <input type="text" class="form-control" placeholder="" value="{{data.task.auth_token}}" name='password' readonly>
           <p style="margin-left:10px; margin-top:30px; font-size:0.9em; color:#484848">
@@ -61,9 +61,9 @@
           {% if not data.task.requires_proxy_auth and data.task.container.interface_auth_user %}
           This task will require to manually enter the above user and password token
           {% else %}
-          This task will require to manually enter the above password token          
+          This task will require to manually enter the above password token
           {% endif %}
-          </p> 
+          </p>
           {% else %}
           Password: <input type="password" class="form-control" placeholder="" value="placeholder" name='password' readonly>
           <p style="margin-left:10px; margin-top:30px; font-size:0.9em; color:#484848">
@@ -71,17 +71,17 @@
           {% if not data.task.requires_proxy_auth and data.task.container.interface_auth_user %}
           This task will require to manually enter the above user and the password set up when creating the task
           {% else %}
-          This task will require to manually enter the password set up when creating the task          
+          This task will require to manually enter the password set up when creating the task
           {% endif %}
-          </p> 
+          </p>
           {% endif %}
-          
+
         {% endif %}
-        
+
         <br />
-        
-        
-        {% if data.task.container.interface_protocol == 'http' or data.task.container.interface_protocol == 'https' %}       
+
+
+        {% if data.task.container.interface_protocol == 'http' or data.task.container.interface_protocol == 'https' %}
         <input type='submit' style="width:110px" class="btn btn-lg btn-success btn-block" value='Log in' />
         {% else %}
         To connect, use a program suitable for this task interface protocol ({{data.task.container.interface_protocol}}) with:<br />
@@ -92,8 +92,8 @@
         {% endif %}
         {% endif%}
         </p>
-        
-      </form>      
+
+      </form>
     </div>
     <br /><br />
     {% if data.task.interface_status == 'running' %}
@@ -101,7 +101,7 @@
     <p style="margin-left:10px; font-size:0.9em; color:rgb(200,200,200); max-width:600px">
     <i class="fa fa-info-circle"></i>
     Some web browsers (i.e. Safari) might require to manually re-enter the above user credentials. You can copy-paste them, or switch
-    to a web browser which supports embedding user credentials in the connection URL (as Chorme, Edge or Firefox). 
+    to a web browser which supports embedding user credentials in the connection URL (as Chorme, Edge or Firefox).
     </p>
     {% endif %}
     {% endif %}
@@ -112,3 +112,4 @@
 
 
 {% include "footer.html" %}
+
diff --git a/services/webapp/code/rosetta/core_app/templates/task_log.html b/services/webapp/code/rosetta/core_app/templates/task_log.html
index bc4e0ad..1ee47bf 100644
--- a/services/webapp/code/rosetta/core_app/templates/task_log.html
+++ b/services/webapp/code/rosetta/core_app/templates/task_log.html
@@ -1,4 +1,4 @@
-{% load static %} 
+{% load static %}
 {% include "header.html" with refresh=data.refresh %}
 {% include "navigation.html" %}
 {% include "logo.html" %}
@@ -6,20 +6,20 @@
 <div class="container">
   <div class="dashboard">
     <div class="span8 offset2">
-    
-      <h1><a href="/tasks">Tasks</a> <span style="font-size:18px"> / <a href="/tasks/?uuid={{data.task.uuid}}">{{ data.task.name }}</a> / Log</span></h1>      
-       
+
+      <h1><a href="/tasks">Tasks</a> <span style="font-size:18px"> / <a href="/tasks/?uuid={{data.task.uuid}}">{{ data.task.name }}</a> / Log</span></h1>
+
       <hr>
 
-  
-      <b>UUID:</b> {{ data.task.uuid }} &nbsp; &nbsp; 
-      <b>Status:</b> {{ data.task.status }} &nbsp; &nbsp; 
+
+      <b>UUID:</b> {{ data.task.uuid }} &nbsp; &nbsp;
+      <b>Status:</b> {{ data.task.status }} &nbsp; &nbsp;
       <b>Auto refresh:{{data.refresh}}</b>&nbsp;
-      {% if not data.refresh %} OFF {% else %} <a href="?uuid={{data.task.uuid}}">OFF</a> {% endif %} | 
-      {% if data.refresh == "3" %} 3s {% else %} <a href="?uuid={{data.task.uuid}}&refresh=3">3s</a> {% endif %} |   
-      {% if data.refresh == "10" %} 10s{% else %} <a href="?uuid={{data.task.uuid}}}&refresh=10">10s</a> {% endif %} |   
-      {% if data.refresh == "60" %} 60s{% else %} <a href="?uuid={{data.task.uuid}}}&refresh=60">60s</a> {% endif %}  
-        
+      {% if not data.refresh %} OFF {% else %} <a href="?uuid={{data.task.uuid}}">OFF</a> {% endif %} |
+      {% if data.refresh == "3" %} 3s {% else %} <a href="?uuid={{data.task.uuid}}&refresh=3">3s</a> {% endif %} |
+      {% if data.refresh == "10" %} 10s{% else %} <a href="?uuid={{data.task.uuid}}}&refresh=10">10s</a> {% endif %} |
+      {% if data.refresh == "60" %} 60s{% else %} <a href="?uuid={{data.task.uuid}}}&refresh=60">60s</a> {% endif %}
+
       <pre id="output" style="border: 1px solid #a0a0a0; width: 100%; height: 500px; background-color:black; color:white; white-space: pre-wrap; white-space: -moz-pre-wrap; white-space: white-space: -o-pre-wrap; word-wrap: break-word;">{{ data.log }}</pre>
 
 
@@ -29,7 +29,7 @@
       <br/>
       <br/>
       <br/>
-      
+
     </div>
   </div>
 </div>
@@ -47,3 +47,4 @@ jQuery( function(){
 
 
 
+
diff --git a/services/webapp/code/rosetta/core_app/templates/tasks.html b/services/webapp/code/rosetta/core_app/templates/tasks.html
index 11ea3ad..22a79d1 100644
--- a/services/webapp/code/rosetta/core_app/templates/tasks.html
+++ b/services/webapp/code/rosetta/core_app/templates/tasks.html
@@ -1,4 +1,4 @@
-{% load static %} 
+{% load static %}
 {% include "header.html" %}
 {% include "navigation.html" %}
 {% include "logo.html" %}
@@ -6,9 +6,9 @@
 <div class="container">
   <div class="dashboard">
     <div class="span8 offset2">
-      
+
       {% if data.task %}
-      <h1><a href="/tasks">Tasks</a> <span style="font-size:18px"> / {{ data.task.name }}</span></h1>      
+      <h1><a href="/tasks">Tasks</a> <span style="font-size:18px"> / {{ data.task.name }}</span></h1>
       {% else %}
       <h1>Tasks</h1>
       {% endif %}
@@ -23,7 +23,7 @@
       {% endfor %}
       {% endif %}
       </div>
-      
+
       {% if not data.task %}
       <div class="row" style="padding:10px; padding-left:15px">
       <a href="/new_task">New task...</a>
@@ -36,7 +36,7 @@
       <br/>
       <br/>
       <br/>
-      
+
     </div>
   </div>
 </div>
@@ -53,7 +53,7 @@ function toggle_visibility(id) {
         x.style.display = "block";
         y.style.display = "none"
         z.style.display= "inline"
-        
+
       } else {
         x.style.display = "none";
         y.style.display= "inline"
@@ -63,3 +63,4 @@ function toggle_visibility(id) {
 </script>
 
 
+
diff --git a/services/webapp/code/rosetta/core_app/tests/common.py b/services/webapp/code/rosetta/core_app/tests/common.py
index 75a1a7e..88839cb 100644
--- a/services/webapp/code/rosetta/core_app/tests/common.py
+++ b/services/webapp/code/rosetta/core_app/tests/common.py
@@ -26,14 +26,14 @@ class BaseAPITestCase(TestCase):
 
         request_func = getattr(self.client, request_method)
         status_code  = None
-       
+
         if 'multipart' in kwargs and kwargs['multipart'] is True:
-            # Do nothing, this is a "special", multipart request 
+            # Do nothing, this is a "special", multipart request
             pass
         else:
             if 'content_type' not in kwargs and request_method != 'get':
                 kwargs['content_type'] = 'application/json'
-            
+
             if 'data' in kwargs and request_method != 'get' and kwargs['content_type'] == 'application/json':
                 data = kwargs.get('data', '')
                 kwargs['data'] = json.dumps(data)
@@ -54,10 +54,10 @@ class BaseAPITestCase(TestCase):
                 self.response.content_dict = json.loads(self.response.content)
             else:
                 self.response.content_dict = {}
-            
+
         except:
             self.response.content_dict = {}
-        
+
         if status_code:
             if not self.response.status_code == status_code:
                 raise Exception('Error with response:' + str(self.response))
@@ -91,3 +91,4 @@ class BaseAPITestCase(TestCase):
 
 
 
+
diff --git a/services/webapp/code/rosetta/core_app/tests/test_apis.py b/services/webapp/code/rosetta/core_app/tests/test_apis.py
index 7ef1ed7..530d9a6 100644
--- a/services/webapp/code/rosetta/core_app/tests/test_apis.py
+++ b/services/webapp/code/rosetta/core_app/tests/test_apis.py
@@ -1,14 +1,14 @@
 import json
 
 from django.contrib.auth.models import User
-        
+
 from .common import BaseAPITestCase
 from ..models import Profile
 
 class ApiTests(BaseAPITestCase):
 
     def setUp(self):
-        
+
         # Create test users
         self.user = User.objects.create_user('testuser', password='testpass')
         self.anotheruser = User.objects.create_user('anotheruser', password='anotherpass')
@@ -18,8 +18,8 @@ class ApiTests(BaseAPITestCase):
 
 
     def test_api_web_auth(self):
-        '''Test auth using login api''' 
-         
+        '''Test auth using login api'''
+
         # No user at all
         resp = self.post('/api/v1/base/login/', data={})
         self.assertEqual(resp.status_code, 401)
@@ -46,4 +46,4 @@ class ApiTests(BaseAPITestCase):
 
 
 
-        
\ No newline at end of file
+
diff --git a/services/webapp/code/rosetta/core_app/tests/test_models.py b/services/webapp/code/rosetta/core_app/tests/test_models.py
index 5fc304a..1e1da97 100644
--- a/services/webapp/code/rosetta/core_app/tests/test_models.py
+++ b/services/webapp/code/rosetta/core_app/tests/test_models.py
@@ -1,14 +1,14 @@
 import json
 
 from django.contrib.auth.models import User
-        
+
 from .common import BaseAPITestCase
 from ..models import Profile, Computing
 
 class Modeltest(BaseAPITestCase):
 
     def setUp(self):
-        
+
         # Create test users
         self.user = User.objects.create_user('testuser', password='testpass')
         self.anotheruser = User.objects.create_user('anotheruser', password='anotherpass')
@@ -18,9 +18,10 @@ class Modeltest(BaseAPITestCase):
 
 
     def test_computing(self):
-        '''Test Computing and their Conf models''' 
-         
+        '''Test Computing and their Conf models'''
+
         computing = Computing.objects.create(name='MyComp', type='remote')
-        
-        
+
+
+
 
diff --git a/services/webapp/code/rosetta/core_app/tests/test_utils.py b/services/webapp/code/rosetta/core_app/tests/test_utils.py
index f48fbde..380e2c2 100644
--- a/services/webapp/code/rosetta/core_app/tests/test_utils.py
+++ b/services/webapp/code/rosetta/core_app/tests/test_utils.py
@@ -1,7 +1,7 @@
 import json
 
 from django.contrib.auth.models import User
-        
+
 from .common import BaseAPITestCase
 from ..utils import sanitize_container_env_vars
 
@@ -11,8 +11,8 @@ class TestUtils(BaseAPITestCase):
         pass
 
     def test_sanitize_user_env_vars(self):
-        '''Test sanitize use env vars''' 
-        
+        '''Test sanitize use env vars'''
+
         # Basic
         env_vars = {'myvar': 'a'}
         self.assertEqual(sanitize_container_env_vars(env_vars),env_vars)
@@ -20,15 +20,16 @@ class TestUtils(BaseAPITestCase):
         # Allowed specia
         env_vars = {'myvar': '/a_directory/a-test'}
         self.assertEqual(sanitize_container_env_vars(env_vars),env_vars)
-        
+
         # Potential malicious
         env_vars = {'myvar': '$(rm -rf)'}
         with self.assertRaises(ValueError):
             sanitize_container_env_vars(env_vars)
-            
-        
-         
-        
-        
-        
+
+
+
+
+
+
+
 
diff --git a/services/webapp/code/rosetta/core_app/utils.py b/services/webapp/code/rosetta/core_app/utils.py
index ae57126..dc4a44c 100644
--- a/services/webapp/code/rosetta/core_app/utils.py
+++ b/services/webapp/code/rosetta/core_app/utils.py
@@ -45,11 +45,11 @@ def booleanize(*args, **kwargs):
             break
     else:
         raise Exception('Internal Error')
-    
+
     # Handle shortcut: an arg with its name equal to ist value is considered as True
     if name==value:
         return True
-    
+
     if isinstance(value, bool):
         return value
     else:
@@ -63,7 +63,7 @@ def send_email(to, subject, text):
 
     # Importing here instead of on top avoids circular dependencies problems when loading booleanize in settings
     from django.conf import settings
-    
+
     if settings.DJANGO_EMAIL_SERVICE == 'Sendgrid':
         import sendgrid
         from sendgrid.helpers.mail import Email,Content,Mail
@@ -74,7 +74,7 @@ def send_email(to, subject, text):
         subject = subject
         content = Content('text/plain', text)
         mail = Mail(from_email, subject, to_email, content)
-        
+
         try:
             response = sg.client.mail.send.post(request_body=mail.get())
 
@@ -83,17 +83,17 @@ def send_email(to, subject, text):
             #logger.debug(response.headers)
         except Exception as e:
             logger.error(e)
-        
+
         #logger.debug(response)
-    
+
 
 def format_exception(e, debug=False):
-    
+
     # Importing here instead of on top avoids circular dependencies problems when loading booleanize in settings
     from django.conf import settings
 
     if settings.DEBUG:
-        # Cutting away the last char removed the newline at the end of the stacktrace 
+        # Cutting away the last char removed the newline at the end of the stacktrace
         return str('Got exception "{}" of type "{}" with traceback:\n{}'.format(e.__class__.__name__, type(e), traceback.format_exc()))[:-1]
     else:
         return str('Got exception "{}" of type "{}" with traceback "{}"'.format(e.__class__.__name__, type(e), traceback.format_exc().replace('\n', '|')))
@@ -106,7 +106,7 @@ def log_user_activity(level, msg, request, caller=None):
     #caller =  inspect.stack()[1][3]
     #if caller == "post":
     #    caller =  inspect.stack()[2][3]
-    
+
     try:
         msg = str(caller) + " view - USER " + str(request.user.email) + ": " + str(msg)
     except AttributeError:
@@ -116,12 +116,12 @@ def log_user_activity(level, msg, request, caller=None):
         level = getattr(logging, level)
     except:
         raise
-    
+
     logger.log(level, msg)
 
 
 def username_hash(email):
-    '''Create md5 base 64 (25 chrars) hash from user email:'''             
+    '''Create md5 base 64 (25 chrars) hash from user email:'''
     m = hashlib.md5()
     m.update(email)
     username = m.hexdigest().decode('hex').encode('base64')[:-3]
@@ -129,7 +129,7 @@ def username_hash(email):
 
 
 def random_username():
-    '''Create a random string of 156 chars to be used as username'''             
+    '''Create a random string of 156 chars to be used as username'''
     username = ''.join(random.choice('abcdefghilmnopqrtuvz') for _ in range(16))
     return username
 
@@ -155,27 +155,27 @@ def finalize_user_creation(user, auth='local'):
     if not out.exit_code == 0:
         logger.error(out)
         raise ErrorMessage('Something went wrong in creating user keys folder. Please contact support')
-        
-    command= "/bin/bash -c \"ssh-keygen -q -t rsa -N '' -C {}@rosetta -f /data/resources/keys/{}_id_rsa 2>/dev/null <<< y >/dev/null\"".format(user.email.split('@')[0], user.username)                        
+
+    command= "/bin/bash -c \"ssh-keygen -q -t rsa -N '' -C {}@rosetta -f /data/resources/keys/{}_id_rsa 2>/dev/null <<< y >/dev/null\"".format(user.email.split('@')[0], user.username)
     out = os_shell(command, capture=True)
     if not out.exit_code == 0:
         logger.error(out)
         raise ErrorMessage('Something went wrong in creating user keys. Please contact support')
-        
-    
+
+
     # Create key objects
     KeyPair.objects.create(user = user,
                           default = True,
                           private_key_file = '/data/resources/keys/{}_id_rsa'.format(user.username),
                           public_key_file = '/data/resources/keys/{}_id_rsa.pub'.format(user.username))
-    
+
 
 def sanitize_shell_encoding(text):
     return text.encode("utf-8", errors="ignore")
 
 
 def format_shell_error(stdout, stderr, exit_code):
-    
+
     string  = '\n#---------------------------------'
     string += '\n# Shell exited with exit code {}'.format(exit_code)
     string += '\n#---------------------------------\n'
@@ -193,14 +193,14 @@ def format_shell_error(stdout, stderr, exit_code):
 def os_shell(command, capture=False, verbose=False, interactive=False, silent=False):
     '''Execute a command in the OS shell. By default prints everything. If the capture switch is set,
     then it returns a namedtuple with stdout, stderr, and exit code.'''
-    
+
     if capture and verbose:
         raise Exception('You cannot ask at the same time for capture and verbose, sorry')
 
     # Log command
     logger.debug('Shell executing command: "%s"', command)
 
-    # Execute command in interactive mode    
+    # Execute command in interactive mode
     if verbose or interactive:
         exit_code = subprocess.call(command, shell=True)
         if exit_code == 0:
@@ -210,7 +210,7 @@ def os_shell(command, capture=False, verbose=False, interactive=False, silent=Fa
 
     # Execute command getting stdout and stderr
     # http://www.saltycrane.com/blog/2008/09/how-get-stdout-and-stderr-using-python-subprocess-module/
-    
+
     process          = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
     (stdout, stderr) = process.communicate()
     exit_code        = process.wait()
@@ -230,8 +230,8 @@ def os_shell(command, capture=False, verbose=False, interactive=False, silent=Fa
         if capture:
             return Output(stdout, stderr, exit_code)
         else:
-            print(format_shell_error(stdout, stderr, exit_code))      
-            return False    
+            print(format_shell_error(stdout, stderr, exit_code))
+            return False
     else:
         if capture:
             return Output(stdout, stderr, exit_code)
@@ -247,16 +247,16 @@ def os_shell(command, capture=False, verbose=False, interactive=False, silent=Fa
 def get_md5(string):
     if not string:
         raise Exception("Colund not compute md5 of empty/None value")
-    
+
     m = hashlib.md5()
-    
+
     # Fix for Python3
     try:
         if isinstance(string,unicode):
             string=string.encode('utf-8')
     except NameError:
         string=string.encode('utf-8')
-        
+
     m.update(string)
     md5 = str(m.hexdigest())
     return md5
@@ -264,14 +264,14 @@ def get_md5(string):
 
 def timezonize(timezone):
     '''Convert a string representation of a timezone to its pytz object or do nothing if the argument is already a pytz timezone'''
-    
+
     # Check if timezone is a valid pytz object is hard as it seems that they are spread arount the pytz package.
     # Option 1): Try to convert if string or unicode, else try to
-    # instantiate a datetiem object with the timezone to see if it is valid 
+    # instantiate a datetiem object with the timezone to see if it is valid
     # Option 2): Get all memebers of the pytz package and check for type, see
     # http://stackoverflow.com/questions/14570802/python-check-if-object-is-instance-of-any-class-from-a-certain-module
     # Option 3) perform a hand.made test. We go for this one, tests would fail if it gets broken
-    
+
     if not 'pytz' in str(type(timezone)):
         timezone = pytz.timezone(timezone)
     return timezone
@@ -296,25 +296,25 @@ def now_dt(tzinfo='UTC'):
 def dt(*args, **kwargs):
     '''Initialize a datetime object in the proper way. Using the standard datetime leads to a lot of
      problems with the tz package. Also, it forces UTC timezone if no timezone is specified'''
-    
+
     if 'tz' in kwargs:
         tzinfo = kwargs.pop('tz')
     else:
         tzinfo  = kwargs.pop('tzinfo', None)
-        
-    offset_s  = kwargs.pop('offset_s', None)   
+
+    offset_s  = kwargs.pop('offset_s', None)
     trustme   = kwargs.pop('trustme', None)
-    
+
     if kwargs:
         raise Exception('Unhandled arg: "{}".'.format(kwargs))
-        
+
     if (tzinfo is None):
         # Force UTC if None
         timezone = timezonize('UTC')
-        
+
     else:
         timezone = timezonize(tzinfo)
-    
+
     if offset_s:
         # Special case for the offset
         if not tzoffset:
@@ -324,7 +324,7 @@ def dt(*args, **kwargs):
         # Standard  timezone
         time_dt = timezone.localize(datetime.datetime(*args))
 
-    # Check consistency    
+    # Check consistency
     if not trustme and timezone != pytz.UTC:
         if not check_dt_consistency(time_dt):
             raise Exception('Sorry, time {} does not exists on timezone {}'.format(time_dt, timezone))
@@ -342,11 +342,11 @@ def check_dt_consistency(date_dt):
 
     # https://en.wikipedia.org/wiki/Tz_database
     # https://www.iana.org/time-zones
-    
+
     if date_dt.tzinfo is None:
         return True
     else:
-        
+
         # This check is quite heavy but there is apparently no other way to do it.
         if date_dt.utcoffset() != dt_from_s(s_from_dt(date_dt), tz=date_dt.tzinfo).utcoffset():
             return False
@@ -396,7 +396,7 @@ def dt_from_s(timestamp_s, tz=None):
 
     pytz_tz = timezonize(tz)
     timestamp_dt = timestamp_dt.replace(tzinfo=pytz.utc).astimezone(pytz_tz)
-    
+
     return timestamp_dt
 
 
@@ -414,38 +414,38 @@ def dt_from_str(string, timezone=None):
     # 1) YYYY-MM-DDThh:mm:ssZ
     # 2) YYYY-MM-DDThh:mm:ss.{u}Z
 
-    # Supported formats with offset    
+    # Supported formats with offset
     # 3) YYYY-MM-DDThh:mm:ss+ZZ:ZZ
     # 4) YYYY-MM-DDThh:mm:ss.{u}+ZZ:ZZ
 
     # Split and parse standard part
     date, time = string.split('T')
-    
+
     if time.endswith('Z'):
         # UTC
         offset_s = 0
         time = time[:-1]
-        
+
     elif ('+') in time:
         # Positive offset
         time, offset = time.split('+')
         # Set time and extract positive offset
-        offset_s = (int(offset.split(':')[0])*60 + int(offset.split(':')[1]) )* 60   
-        
+        offset_s = (int(offset.split(':')[0])*60 + int(offset.split(':')[1]) )* 60
+
     elif ('-') in time:
         # Negative offset
         time, offset = time.split('-')
         # Set time and extract negative offset
-        offset_s = -1 * (int(offset.split(':')[0])*60 + int(offset.split(':')[1])) * 60      
-    
+        offset_s = -1 * (int(offset.split(':')[0])*60 + int(offset.split(':')[1])) * 60
+
     else:
         raise Exception('Format error')
-    
+
     # Handle time
     hour, minute, second = time.split(':')
-    
+
     # Now parse date (easy)
-    year, month, day = date.split('-') 
+    year, month, day = date.split('-')
 
     # Convert everything to int
     year    = int(year)
@@ -459,7 +459,7 @@ def dt_from_str(string, timezone=None):
     else:
         second  = int(second)
         usecond = 0
-    
+
     return dt(year, month, day, hour, minute, second, usecond, offset_s=offset_s)
 
 
@@ -524,7 +524,7 @@ def get_platform_registry():
     platform_registry_conn_string = '{}:{}'.format(platform_registry_host, platform_registry_port)
     return platform_registry_conn_string
 
-  
+
 def get_rosetta_tasks_tunnel_host():
     # Importing here instead of on top avoids circular dependencies problems when loading booleanize in settings
     from django.conf import settings
@@ -544,9 +544,9 @@ def hash_string_to_int(string):
 
 
 def get_ssh_access_mode_credentials(computing, user):
-    
+
     from .models import KeyPair
-    
+
     # Get computing host
     try:
         computing_host = computing.conf.get('host')
@@ -562,7 +562,7 @@ def get_ssh_access_mode_credentials(computing, user):
         computing_port = 22
     if not computing_port:
         computing_port = 22
-      
+
     # Get computing user and keys
     if computing.auth_mode == 'user_keys':
         computing_user = user.profile.get_extra_conf('computing_user', computing)
@@ -570,7 +570,7 @@ def get_ssh_access_mode_credentials(computing, user):
             raise ValueError('No \'computing_user\' parameter found for computing resource \'{}\' in user profile'.format(computing.name))
         # Get user key
         computing_keys = KeyPair.objects.get(user=user, default=True)
-    elif computing.auth_mode == 'platform_keys':        
+    elif computing.auth_mode == 'platform_keys':
         computing_user = computing.conf.get('user')
         computing_keys = KeyPair.objects.get(user=None, default=True)
     else:
@@ -584,7 +584,7 @@ def setup_tunnel_and_proxy(task):
 
     # Importing here instead of on top avoids circular dependencies problems when loading booleanize in settings
     from .models import Task, KeyPair, TaskStatuses
-    
+
     # If there is no tunnel port allocated yet, find one
     if not task.tcp_tunnel_port:
 
@@ -629,8 +629,8 @@ def setup_tunnel_and_proxy(task):
         user_keys = KeyPair.objects.get(user=task.user, default=True)
 
         # Tunnel command
-        if task.computing.type == 'remotehop':           
-            
+        if task.computing.type == 'remotehop':
+
             # Get computing params
             first_host = task.computing.conf.get('first_host')
             first_user = task.computing.conf.get('first_user')
@@ -638,18 +638,18 @@ def setup_tunnel_and_proxy(task):
             #second_user = task.computing.conf.get('second_user')
             #setup_command = task.computing.conf.get('setup_command')
             #base_port = task.computing.conf.get('base_port')
-                     
+
             tunnel_command= 'ssh -4 -i {} -o StrictHostKeyChecking=no -nNT -L 0.0.0.0:{}:{}:{} {}@{} & '.format(user_keys.private_key_file, task.tcp_tunnel_port, task.interface_ip, task.interface_port, first_user, first_host)
 
         else:
-            
+
             if task.computing.access_mode.startswith('ssh'):
                 computing_user, computing_host, computing_port, computing_keys = get_ssh_access_mode_credentials(task.computing, task.user)
                 tunnel_command  = 'ssh -p {} -o LogLevel=ERROR -i {} -4 -o StrictHostKeyChecking=no -o ConnectTimeout=10 '.format(computing_port, computing_keys.private_key_file)
                 tunnel_command += '-nNT -L 0.0.0.0:{}:{}:{} {}@{}'.format(task.tcp_tunnel_port, task.interface_ip, task.interface_port, computing_user, computing_host)
             else:
                 tunnel_command= 'ssh -4 -o StrictHostKeyChecking=no -nNT -L 0.0.0.0:{}:{}:{} localhost & '.format(task.tcp_tunnel_port, task.interface_ip, task.interface_port)
-        
+
         background_tunnel_command = 'nohup {} >/dev/null 2>&1 &'.format(tunnel_command)
 
         # Log
@@ -658,20 +658,20 @@ def setup_tunnel_and_proxy(task):
         # Execute
         subprocess.Popen(background_tunnel_command, shell=True)
 
-  
+
     # Setup the proxy now (if required.)
     if task.requires_proxy:
-        
+
         # Ensure conf directory exists
         if not os.path.exists('/shared/etc_apache2_sites_enabled'):
             os.makedirs('/shared/etc_apache2_sites_enabled')
-    
+
         # Set conf file name
         apache_conf_file = '/shared/etc_apache2_sites_enabled/{}.conf'.format(task.uuid)
-    
-        # Check if proxy conf exists 
+
+        # Check if proxy conf exists
         if not os.path.exists(apache_conf_file):
-    
+
             # Write conf file
             # Some info about the various SSL switches: https://serverfault.com/questions/577616/using-https-between-apache-loadbalancer-and-backends
             logger.debug('Writing task proxy conf to {}'.format(apache_conf_file))
@@ -679,7 +679,7 @@ def setup_tunnel_and_proxy(task):
             rosetta_tasks_proxy_host = get_rosetta_tasks_proxy_host()
             apache_conf_content = '''
 #---------------------------
-#  Task interface proxy 
+#  Task interface proxy
 #---------------------------
 
 Listen '''+str(task.tcp_tunnel_port)+'''
@@ -694,19 +694,19 @@ Listen '''+str(task.tcp_tunnel_port)+'''
 </VirtualHost>
 
 <VirtualHost *:'''+str(task.tcp_tunnel_port)+'''>
-    
+
     ServerName  '''+rosetta_tasks_proxy_host+'''
     ServerAdmin admin@rosetta.platform
-    
+
     SSLEngine on
     SSLCertificateFile /etc/letsencrypt/live/'''+rosetta_tasks_proxy_host+'''/cert.pem
     SSLCertificateKeyFile /etc/letsencrypt/live/'''+rosetta_tasks_proxy_host+'''/privkey.pem
     SSLCACertificateFile /etc/letsencrypt/live/'''+rosetta_tasks_proxy_host+'''/fullchain.pem
-        
+
     SSLProxyEngine On
-    SSLProxyVerify none 
+    SSLProxyVerify none
     SSLProxyCheckPeerCN off
-    SSLProxyCheckPeerName off  
+    SSLProxyCheckPeerName off
 
     BrowserMatch "MSIE [2-6]" \
         nokeepalive ssl-unclean-shutdown \
@@ -723,7 +723,7 @@ Listen '''+str(task.tcp_tunnel_port)+'''
       AuthType Basic
       AuthName "Restricted area"
       AuthUserFile /shared/etc_apache2_sites_enabled/'''+str(task.uuid)+'''.htpasswd
-      Require valid-user  
+      Require valid-user
 
       # preserve Host header to avoid cross-origin problems
       ProxyPreserveHost on
@@ -737,32 +737,32 @@ Listen '''+str(task.tcp_tunnel_port)+'''
 '''
             with open(apache_conf_file, 'w') as f:
                 f.write(apache_conf_content)
-    
+
         # Now check if conf exist on proxy
         logger.debug('Checking if conf is enabled on proxy service')
         out = os_shell('ssh -o StrictHostKeyChecking=no proxy "[ -e /etc/apache2/sites-enabled/{}.conf ]"'.format(task.uuid), capture=True)
-    
+
         if out.exit_code == 1:
-      
+
             logger.debug('Conf not enabled on proxy service, linkig it and reloading Apache conf')
-      
+
             # Link on proxy since conf does not exist
             out = os_shell('ssh -o StrictHostKeyChecking=no proxy "sudo ln -s /shared/etc_apache2_sites_enabled/{0}.conf /etc/apache2/sites-enabled/{0}.conf"'.format(task.uuid), capture=True)
             if out.exit_code != 0:
                 logger.error(out.stderr)
-                raise ErrorMessage('Something went wrong when activating the task proxy conf')        
-            
+                raise ErrorMessage('Something went wrong when activating the task proxy conf')
+
             # Reload apache conf on Proxy
             out = os_shell('ssh -o StrictHostKeyChecking=no proxy "sudo apache2ctl graceful"', capture=True)
             if out.exit_code != 0:
-                logger.error(out.stderr) 
-                raise ErrorMessage('Something went wrong when loading the task proxy conf')        
-            
+                logger.error(out.stderr)
+                raise ErrorMessage('Something went wrong when loading the task proxy conf')
+
 
 def sanitize_container_env_vars(env_vars):
-    
+
     for env_var in env_vars:
-        
+
         # Check only alphanumeric chars, slashed, dashes and underscores
         if not re.match("^[/A-Za-z0-9_-]*$", env_vars[env_var]):
             raise ValueError('Value "{}" for env var "{}" is not valid: only alphanumeric, slashes, dashes and underscores are.'.format(env_vars[env_var], env_var))
@@ -770,9 +770,9 @@ def sanitize_container_env_vars(env_vars):
     return env_vars
 
 
-def get_or_create_container_from_repository(user, repository_url, repository_tag=None, container_name=None, container_description=None): 
-    
-    from .models import Container    
+def get_or_create_container_from_repository(user, repository_url, repository_tag=None, container_name=None, container_description=None):
+
+    from .models import Container
     logger.debug('Called get_or_create_container_from_repository with repository_url="{}" and repository_tag="{}"'.format(repository_url,repository_tag))
 
     # Set repo name
@@ -781,13 +781,13 @@ def get_or_create_container_from_repository(user, repository_url, repository_tag
     # If building:
     #{"message": "Successfully built 5a2089b2c334\n", "phase": "building"}
     #{"message": "Successfully tagged r2dhttps-3a-2f-2fgithub-2ecom-2fnorvig-2fpytudes5e745c3:latest\n", "phase": "building"}
-    
+
     # If reusing:
     #{"message": "Reusing existing image (r2dhttps-3a-2f-2fgithub-2ecom-2fnorvig-2fpytudes5e745c3), not building."}
-    
+
     appendix = 'CMD ["jupyter", "notebook", "--ip", "0.0.0.0", "--NotebookApp.token", ""]'
 
-    
+
     # Build the Docker container for this repo
     if repository_tag:
         command = 'sudo jupyter-repo2docker --ref {} --user-id 1000 --user-name jovyan --no-run --appendix \'{}\' --json-logs {}'.format(repository_tag, appendix, repository_url)
@@ -796,7 +796,7 @@ def get_or_create_container_from_repository(user, repository_url, repository_tag
     out = os_shell(command, capture=True)
     if out.exit_code != 0:
         logger.error(out.stderr)
-        raise ErrorMessage('Something went wrong when creating the Dockerfile for repository "{}"'.format(repository_url))   
+        raise ErrorMessage('Something went wrong when creating the Dockerfile for repository "{}"'.format(repository_url))
 
     # Convert output to lines
     out_lines = out.stderr.split('\n')
@@ -818,7 +818,7 @@ def get_or_create_container_from_repository(user, repository_url, repository_tag
         image_name_for_tag = repo2docker_image_name.replace(':latest','')
     else:
         image_name_for_tag = repo2docker_image_name
-    
+
     image_tag = image_name_for_tag[-7:] # The last part of the image name generated by repo2docker is the git short hash
 
     # Re-tag image taking into account that if we are using the proxy as registry we use localhost or it won't work
@@ -826,17 +826,17 @@ def get_or_create_container_from_repository(user, repository_url, repository_tag
         push_registry = 'localhost:5000'
     else:
         push_registry = registry
-        
+
     out = os_shell('sudo docker tag {} {}/{}:{}'.format(repo2docker_image_name,push_registry,image_name,image_tag) , capture=True)
     if out.exit_code != 0:
         logger.error(out.stderr)
-        raise ErrorMessage('Something went wrong when tagging the container for repository "{}"'.format(repository_url))   
+        raise ErrorMessage('Something went wrong when tagging the container for repository "{}"'.format(repository_url))
 
     # Push image to the (local) registry
     out = os_shell('sudo docker push {}/{}:{}'.format(push_registry,image_name,image_tag) , capture=True)
     if out.exit_code != 0:
         logger.error(out.stderr)
-        raise ErrorMessage('Something went wrong when pushing the container for repository "{}"'.format(repository_url))   
+        raise ErrorMessage('Something went wrong when pushing the container for repository "{}"'.format(repository_url))
 
     # Create the container if not already existent
     try:
@@ -858,11 +858,11 @@ def get_or_create_container_from_repository(user, repository_url, repository_tag
                     repository_description_from_source += ' Built from {}'.format(repository_url)
                 except:
                     pass
-        
-        # Set default container name and description            
+
+        # Set default container name and description
         if not container_name:
             container_name = repository_name_from_source if repository_name_from_source else repository_name
-        
+
         if not container_description:
             container_description = repository_description_from_source if repository_description_from_source else 'Built from {}'.format(repository_url)
 
@@ -882,3 +882,4 @@ def get_or_create_container_from_repository(user, repository_url, repository_tag
                                              supports_interface_auth = False)
     return container
 
+
diff --git a/services/webapp/code/rosetta/core_app/views.py b/services/webapp/code/rosetta/core_app/views.py
index c74f08c..ff90b2f 100644
--- a/services/webapp/code/rosetta/core_app/views.py
+++ b/services/webapp/code/rosetta/core_app/views.py
@@ -38,7 +38,7 @@ _task_cache = {}
 def login_view(request):
 
     data = {}
-    
+
     # Set post login page
     post_login_page = request.COOKIES.get('post_login_redirect')
     if post_login_page is None:
@@ -93,9 +93,9 @@ def login_view(request):
                 if user.profile.auth == 'local':
 
                     logger.debug('Sending login token via mail to {}'.format(user.email))
-    
+
                     token = uuid.uuid4()
-    
+
                     # Create token or update if existent (and never used)
                     try:
                         loginToken = LoginToken.objects.get(user=user)
@@ -109,7 +109,7 @@ def login_view(request):
                     except Exception as e:
                         logger.error(format_exception(e))
                         raise ErrorMessage('Something went wrong. Please retry later.')
-    
+
                     # Return here, we don't want to give any hints about existing users
                     data['success'] = 'Ok, if we have your data you will receive a login link by email shortly.'
                     return render(request, 'success.html', {'data': data})
@@ -178,20 +178,20 @@ def register_view(request):
             email    = request.POST.get('email')
             password = request.POST.get('password')
             invitation = request.POST.get('invitation')
-            
+
             if settings.INVITATION_CODE:
                 if invitation != settings.INVITATION_CODE:
                     raise ErrorMessage('Wrong invitation code')
 
             if '@' not in email:
                 raise ErrorMessage('Detected invalid email address')
-            
+
             # Register the user
             user = User.objects.create_user(random_username(), password=password, email=email)
 
             # Is this necessary?
             user.save()
-            
+
             data['user'] = user
 
             finalize_user_creation(user)
@@ -199,7 +199,7 @@ def register_view(request):
             # Manually set the auth backend for the user
             user.backend = 'django.contrib.auth.backends.ModelBackend'
             login(request, user)
-            
+
             data['status'] = 'activated'
 
     # All other cases, render the login page again with no other data than title
@@ -218,7 +218,7 @@ def main_view(request):
 
     # Init data
     data = {}
-    
+
     # Get custom home page if any
     try:
         page = Page.objects.get(id='main')
@@ -234,7 +234,7 @@ def page_view(request, page_id):
 
     # Init data
     data = {}
-    
+
     # Get the page
     try:
         page = Page.objects.get(id=page_id)
@@ -321,7 +321,7 @@ def account(request):
             return render(request, 'error.html', {'data': data})
 
     # Lastly, do we have to remove an extra conf?
-    
+
     delete_extra_conf_uuid = request.GET.get('delete_extra_conf_uuid', None)
     if delete_extra_conf_uuid:
         #logger.debug('Deleting extra conf "{}"'.format(delete_extra_conf_uuid))
@@ -332,9 +332,9 @@ def account(request):
         profile.extra_confs = new_extra_confs
         profile.save()
         return redirect('/account')
-                
-            
-    
+
+
+
     return render(request, 'account.html', {'data': data})
 
 
@@ -357,13 +357,13 @@ def tasks(request):
     uuid    = request.GET.get('uuid', None)
     fromlist = request.GET.get('fromlist', False)
     details = booleanize(request.GET.get('details', None))
-    
+
 
     # Do we have to operate on a specific task?
     if uuid:
 
         try:
-            
+
             # Get the task (raises if none available including no permission)
             try:
                 task = Task.objects.get(user=request.user, uuid=uuid)
@@ -371,7 +371,7 @@ def tasks(request):
                 raise ErrorMessage('Task does not exists or no access rights')
 
             data['task'] = task
-            
+
             #  Task actions
             if action=='delete':
                 if task.status not in [TaskStatuses.stopped, TaskStatuses.exited]:
@@ -392,20 +392,20 @@ def tasks(request):
                         os.remove('/shared/etc_apache2_sites_enabled/{}.htpasswd'.format(task.uuid))
                     except:
                         pass
-    
+
                     # Delete
                     task.delete()
-                    
+
                     # Unset task
-                    data['task'] = None    
-    
+                    data['task'] = None
+
                 except Exception as e:
                     data['error'] = 'Error in deleting the task'
                     logger.error('Error in deleting task with uuid="{}": "{}"'.format(uuid, e))
                     return render(request, 'error.html', {'data': data})
-                
 
-    
+
+
             elif action=='stop': # or delete,a and if delete also remove object
                 # Remove proxy files. Do it here or will cause issues when reloading the conf re-using ports of stopped tasks.
                 try:
@@ -416,7 +416,7 @@ def tasks(request):
                     os.remove('/shared/etc_apache2_sites_enabled/{}.htpasswd'.format(task.uuid))
                 except:
                     pass
-                   
+
                 task.computing.manager.stop_task(task)
 
         except Exception as e:
@@ -441,18 +441,18 @@ def tasks(request):
 
         # Get all tasks for list
         try:
-            tasks = Task.objects.filter(user=request.user).order_by('created') 
+            tasks = Task.objects.filter(user=request.user).order_by('created')
         except Exception as e:
             data['error'] = 'Error in getting Tasks info'
             logger.error('Error in getting Virtual Devices: "{}"'.format(e))
             return render(request, 'error.html', {'data': data})
-    
+
         # Update task statuses
         for task in tasks:
             task.update_status()
-        
+
         # Set task and tasks variables
-        data['task']  = None   
+        data['task']  = None
         data['tasks'] = tasks
 
     return render(request, 'tasks.html', {'data': data})
@@ -473,7 +473,7 @@ def new_task(request):
     def get_task_container(request):
         task_container_uuid = request.POST.get('task_container_uuid', None)
         if not task_container_uuid:
-            # At the second step the task uuid is set via a GET request 
+            # At the second step the task uuid is set via a GET request
             task_container_uuid = request.GET.get('task_container_uuid', None)
         try:
             task_container = Container.objects.get(uuid=task_container_uuid, user=None)
@@ -493,7 +493,7 @@ def new_task(request):
             try:
                 task_computing =  Computing.objects.get(uuid=task_computing_uuid, group__user=request.user)
             except Computing.DoesNotExist:
-                raise Exception('Consistency error, computing with uuid "{}" does not exists or user "{}" does not have access rights'.format(task_computing_uuid, request.user.email))        
+                raise Exception('Consistency error, computing with uuid "{}" does not exists or user "{}" does not have access rights'.format(task_computing_uuid, request.user.email))
         return task_computing
 
     # Get task name helper function
@@ -507,22 +507,22 @@ def new_task(request):
     step = request.POST.get('step', None)
     if not step:
         step = request.GET.get('step', None)
-    
+
 
     # Handle the various steps
     if not step:
-        
+
         # Step one is assumed: chose software container
         return HttpResponseRedirect('/software/?mode=new_task')
-        
+
     elif step == 'two':
-        
+
         # Get software container and arch
         data['task_container'] = get_task_container(request)
 
-        # List all computing resources 
+        # List all computing resources
         data['computings'] = list(Computing.objects.filter(group=None)) + list(Computing.objects.filter(group__user=request.user))
-            
+
         data['step'] = 'two'
         data['next_step'] = 'three'
 
@@ -533,23 +533,23 @@ def new_task(request):
 
         # Get computing resource
         data['task_computing'] = get_task_computing(request)
-        
+
         # Check that container required architecture is compatible with the computing resource
         # TODO: support setting the container engine/engine when creating the task
         # TODO: refactor and unroll this code
         if data['task_computing'].supported_archs is None: data['task_computing'].supported_archs=[]
         if data['task_computing'].emulated_archs is None: data['task_computing'].emulated_archs={}
         data['arch_emulation'] = False
-        
+
         if data['task_container'].image_arch:
             if (data['task_container'].image_arch != data['task_computing'].arch) and (data['task_container'].image_arch not in data['task_computing'].supported_archs):
 
                 # Does container engines/engines support emulated archs?
                 if data['task_computing'].emulated_archs:
-                                        
+
                     # For now by default our container engine is the first one
                     container_engine = data['task_computing'].container_engines[0]
-                    
+
                     # Check for emulation against the engine
                     if container_engine in data['task_computing'].emulated_archs and data['task_container'].image_arch in data['task_computing'].emulated_archs[container_engine]:
                         data['arch_emulation'] = True
@@ -561,14 +561,14 @@ def new_task(request):
                         else:
                             container_engines = container_engine.split('[')[1].replace(']','').split(',')
                             return container_engines
-                        
+
                     for container_engine in get_engines(container_engine):
                         if container_engine in data['task_computing'].emulated_archs and data['task_container'].image_arch in data['task_computing'].emulated_archs[container_engine]:
                             data['arch_emulation'] = True
 
                     if not data['arch_emulation']:
                         raise ErrorMessage('This computing resource does not support architecture \'{}\' nor as native or emulated'.format(data['task_container'].image_arch))
-                
+
                 else:
                     raise ErrorMessage('This computing resource does not support architecture \'{}\' nor as native or emulated'.format(data['task_container'].image_arch))
 
@@ -576,7 +576,7 @@ def new_task(request):
             data['arch_auto_selection'] = True
             #raise ErrorMessage('Auto selecting architectures is not supported yet')
 
-        # Generate random auth token        
+        # Generate random auth token
         data['task_auth_token'] = str(uuid.uuid4())
 
         # Set current and next step
@@ -624,7 +624,7 @@ def new_task(request):
 
         # Any task requires the TCP tunnel for now
         task.requires_tcp_tunnel = True
-        
+
         # Task access method
         access_method = request.POST.get('access_method', 'auto')
         if access_method and access_method != 'auto' and not request.user.profile.is_power_user:
@@ -635,10 +635,10 @@ def new_task(request):
                 task.requires_proxy_auth = True
             else:
                 task.requires_proxy      = False
-                task.requires_proxy_auth = False                
+                task.requires_proxy_auth = False
         elif access_method == 'direct_tunnel':
             task.requires_proxy      = False
-            task.requires_proxy_auth = False            
+            task.requires_proxy_auth = False
         elif access_method == 'https_proxy':
             task.requires_proxy      = True
             task.requires_proxy_auth = True
@@ -647,7 +647,7 @@ def new_task(request):
 
         # Computing options
         computing_options = {}
-        
+
         # Container engine if any set
         container_engine = request.POST.get('container_engine', None)
         if container_engine:
@@ -655,11 +655,11 @@ def new_task(request):
                 raise ErrorMessage('Unknown container engine "{}"'.format(container_engine))
             computing_options['container_engine'] = container_engine
 
-        # CPUs, memory and partition if set 
+        # CPUs, memory and partition if set
         computing_cpus = request.POST.get('computing_cpus', None)
         computing_memory = request.POST.get('computing_memory', None)
         computing_partition = request.POST.get('computing_partition', None)
-        
+
         if computing_cpus:
             try:
                 int(computing_cpus)
@@ -671,11 +671,11 @@ def new_task(request):
             computing_options['memory'] = computing_memory
 
         if computing_partition:
-            computing_options['partition'] = computing_partition        
-        
+            computing_options['partition'] = computing_partition
+
         if computing_options:
             task.computing_options = computing_options
-                    
+
         # Save the task before starting it, or the computing manager will not be able to work properly
         task.save()
 
@@ -685,22 +685,22 @@ def new_task(request):
         except:
             # Delete the task if could not start it
             task.delete()
-            
+
             # ..and re-raise
             raise
 
         # Ensure proxy conf directory exists
         if not os.path.exists('/shared/etc_apache2_sites_enabled'):
             os.makedirs('/shared/etc_apache2_sites_enabled')
-    
+
         # Add here proxy auth file as we have the password
         if task.requires_proxy_auth:
             out = os_shell('ssh -o StrictHostKeyChecking=no proxy "cd /shared/etc_apache2_sites_enabled/ && htpasswd -bc {}.htpasswd {} {}"'.format(task.uuid, task.user.email, task.password), capture=True)
             if out.exit_code != 0:
                 logger.error(out.stderr)
-                raise ErrorMessage('Something went wrong when enabling proxy auth')   
+                raise ErrorMessage('Something went wrong when enabling proxy auth')
 
-        # Set step        
+        # Set step
         data['step'] = 'created'
 
 
@@ -731,7 +731,7 @@ def task_log(request):
     task = Task.objects.get(user=request.user, uuid=uuid)
 
     # Set back task and refresh
-    data['task']    = task 
+    data['task']    = task
     data['refresh'] = refresh
 
     # Get the log
@@ -793,7 +793,7 @@ def software(request):
             try:
                 container = Container.objects.get(uuid=container_uuid)
             except Container.DoesNotExist:
-                raise ErrorMessage('Container does not exists or no access rights')                
+                raise ErrorMessage('Container does not exists or no access rights')
             if container.user and container.user != request.user:
                 raise ErrorMessage('Container does not exists or no access rights')
             data['container'] = container
@@ -803,7 +803,7 @@ def software(request):
 
                 # Delete
                 container.delete()
-                
+
                 # Redirect
                 return HttpResponseRedirect('/software')
 
@@ -811,20 +811,20 @@ def software(request):
             data['error'] = 'Error in getting the software container or performing the required action'
             logger.error('Error in getting container with uuid="{}" or performing the required action: "{}"'.format(uuid, e))
             return render(request, 'error.html', {'data': data})
-    
+
     else:
         # Ddo we have to operate on a container family?
         if container_family_id:
-            
+
             # Get back name, registry and image from contsainer url
             container_name, container_registry, container_image_name = base64.b64decode(container_family_id.encode('utf8')).decode('utf8').split('\t')
-          
+
             # get containers from the DB
             user_containers = Container.objects.filter(user=request.user, name=container_name, registry=container_registry, image_name=container_image_name)
             platform_containers = Container.objects.filter(user=None, name=container_name, registry=container_registry, image_name=container_image_name)
-        
-        else:    
-            
+
+        else:
+
             # Get containers (fitered by search term, or all)
             if search_text:
                 search_query=(Q(name__icontains=search_text) | Q(description__icontains=search_text) | Q(image_name__icontains=search_text))
@@ -833,24 +833,24 @@ def software(request):
             else:
                 user_containers = Container.objects.filter(user=request.user)
                 platform_containers = Container.objects.filter(user=None)
-    
-            
+
+
         # Ok, nilter by owner
         if search_owner != 'All':
             if search_owner == 'User':
                 platform_containers =[]
             if search_owner == 'Platform':
                 user_containers = []
-                
+
         # Create all container list
         data['containers'] = list(user_containers) + list(platform_containers)
-            
+
         # Merge containers with the same name, registry and image name
         data['container_families'] = {}
-        
+
         # Container family support class
         class ContainerFamily(object):
-        
+
             def __init__(self, id, name, registry, image_name):
                 self.id = id
                 self.name = name
@@ -859,34 +859,34 @@ def software(request):
                 self.description = None
                 self.members = []
                 self.all_archs = []
-                self.container_by_tags_by_arch = {} 
-    
+                self.container_by_tags_by_arch = {}
+
             def add(self, container):
                 self.members.append(container)
-    
+
                 if not self.description:
                     self.description = container.description
-    
+
                 if not container.image_arch in self.all_archs:
                     self.all_archs.append(container.image_arch)
-    
+
                 if not container.image_arch in self.container_by_tags_by_arch:
                     self.container_by_tags_by_arch[container.image_arch]={}
                 self.container_by_tags_by_arch[container.image_arch][container.image_tag] = container
-                
+
                 # Lastly, add the container to the "all tags"
                 #if None not in self.container_by_tags_by_arch:
                 #    self.container_by_tags_by_arch[None]={}
                 #self.container_by_tags_by_arch[None][container.image_tag] = container
-    
-            
+
+
             @ property
             def color(self):
                 try:
                     return self.members[0].color
                 except IndexError:
                     return '#000000'
-            
+
         # Populate container families
         for container in data['containers']:
             if container.family_id not in data['container_families']:
@@ -897,7 +897,7 @@ def software(request):
         #    if len(data['container_families'][container.family_id].all_archs) == 1:
         #        if data['container_families'][container.family_id].all_archs[0] != None:
         #            data['container_families'][container.family_id].container_by_tags_by_arch.pop(None)
-                
+
     return render(request, 'software.html', {'data': data})
 
 
@@ -912,7 +912,7 @@ def add_software(request):
     # Init data
     data = {}
     data['user'] = request.user
-    
+
     # Loop back the new container mode in the page to handle the switch
     data['new_container_from'] = request.GET.get('new_container_from', 'registry')
 
@@ -920,59 +920,59 @@ def add_software(request):
     container_name = request.POST.get('container_name', None)
 
     if container_name:
-        
+
         # How do we have to add this new container?
         new_container_from = request.POST.get('new_container_from', None)
 
         if new_container_from == 'registry':
-    
+
             # Container description
             container_description = request.POST.get('container_description', None)
-    
+
             # Container registry
             container_registry = request.POST.get('container_registry', None)
-    
+
             # Container image name
             container_image_name = request.POST.get('container_image_name',None)
-            
+
             # Container image tag
             container_image_tag = request.POST.get('container_image_tag', None)
-    
+
             # Container image architecture
             container_image_arch = request.POST.get('container_image_arch', None)
-    
-            # Container image OS 
+
+            # Container image OS
             container_image_os = request.POST.get('container_image_os', None)
-    
+
             # Container image digest
             container_image_digest = request.POST.get('container_image_digest', None)
-    
+
             # Container interface port
-            container_interface_port = request.POST.get('container_interface_port', None) 
-            if container_interface_port:       
+            container_interface_port = request.POST.get('container_interface_port', None)
+            if container_interface_port:
                 try:
                     container_interface_port = int(container_interface_port)
                 except:
                     raise ErrorMessage('Invalid container port "{}"')
             else:
                 container_interface_port = None
-    
-            # Container interface protocol 
+
+            # Container interface protocol
             container_interface_protocol = request.POST.get('container_interface_protocol', None)
-    
+
             if container_interface_protocol and not container_interface_protocol in ['http','https']:
                 raise ErrorMessage('Sorry, only power users can add custom software containers with interface protocols other than \'http\' or \'https\'.')
-    
-            # Container interface transport 
+
+            # Container interface transport
             container_interface_transport = request.POST.get('container_interface_transport')
-    
+
             # Capabilities
             container_supports_custom_interface_port = request.POST.get('container_supports_custom_interface_port', None)
             if container_supports_custom_interface_port and container_supports_custom_interface_port == 'True':
                 container_supports_custom_interface_port = True
             else:
                 container_supports_custom_interface_port = False
-    
+
             container_supports_interface_auth = request.POST.get('container_supports_interface_auth', None)
             if container_supports_interface_auth and container_supports_interface_auth == 'True':
                 container_supports_interface_auth = True
@@ -983,16 +983,16 @@ def add_software(request):
             if container_disable_http_basicauth_embedding and container_disable_http_basicauth_embedding == 'True':
                 container_disable_http_basicauth_embedding = True
             else:
-                container_disable_http_basicauth_embedding = False           
+                container_disable_http_basicauth_embedding = False
 
             # Environment variables
             container_env_vars = request.POST.get('container_env_vars', None)
             if container_env_vars:
                 container_env_vars = sanitize_container_env_vars(json.loads(container_env_vars))
-    
+
             # Log
             #logger.debug('Creating new container object with image="{}", type="{}", registry="{}", ports="{}"'.format(container_image, container_type, container_registry, container_ports))
-    
+
             # Create
             Container.objects.create(user         = request.user,
                                      name         = container_name,
@@ -1010,21 +1010,21 @@ def add_software(request):
                                      supports_interface_auth = container_supports_interface_auth,
                                      disable_http_basicauth_embedding = container_disable_http_basicauth_embedding,
                                      env_vars = container_env_vars)
-            
+
         elif new_container_from == 'repository':
 
             container_description = request.POST.get('container_description', None)
-            
+
             repository_url = request.POST.get('repository_url', None)
             repository_tag = request.POST.get('repository_tag', 'HEAD')
 
             return HttpResponseRedirect('/import_repository/?repository_url={}&repository_tag={}&container_name={}&container_description={}'.format(repository_url,repository_tag,container_name,container_description))
-        
+
             # The return type here is a container, not created
             #get_or_create_container_from_repository(request.user, repository_url, repository_tag=repository_tag, container_name=container_name, container_description=container_description)
 
         else:
-            raise Exception('Unknown new container mode "{}"'.format(new_container_from)) 
+            raise Exception('Unknown new container mode "{}"'.format(new_container_from))
         # Set added switch
         data['added'] = True
 
@@ -1051,7 +1051,7 @@ def computing(request):
     computing_uuid = request.GET.get('uuid', None)
     data['details'] = details
     data['action'] = action
-    
+
     if details and computing_uuid:
         try:
             data['computing'] = Computing.objects.get(uuid=computing_uuid, group__user=request.user)
@@ -1059,7 +1059,7 @@ def computing(request):
             data['computing'] = Computing.objects.get(uuid=computing_uuid, group=None)
     else:
         data['computings'] = list(Computing.objects.filter(group=None)) + list(Computing.objects.filter(group__user=request.user))
-        
+
     return render(request, 'computing.html', {'data': data})
 
 
@@ -1072,7 +1072,7 @@ def storage(request):
     # Set data & render
     data = {}
     data['user'] = request.user
-    
+
     return render(request, 'storage.html', {'data': data})
 
 
@@ -1081,17 +1081,17 @@ def storage(request):
 #=========================
 #  Add profile conf
 #=========================
- 
+
 @private_view
 def add_profile_conf(request):
- 
+
     # Init data
     data={}
     data['user']    = request.user
-    
+
     # Set conf types we can add
     data['conf_types'] = ['computing_user'] #,'computing_custom_binds']
-    
+
     # Process adding the new conf
     conf_type = request.POST.get('conf_type', None)
     if conf_type:
@@ -1102,7 +1102,7 @@ def add_profile_conf(request):
                 try:
                     computing = Computing.objects.get(uuid=computing_uuid, group__user=request.user)
                 except Computing.DoesNotExist:
-                    computing = Computing.objects.get(uuid=computing_uuid, group=None)                
+                    computing = Computing.objects.get(uuid=computing_uuid, group=None)
                 data['computing'] = computing
                 data['last_step'] = True
                 value = request.POST.get('value', None)
@@ -1110,13 +1110,13 @@ def add_profile_conf(request):
                     request.user.profile.add_extra_conf(conf_type=conf_type, object=computing, value=value)
                     # Now redirect to site
                     return HttpResponseRedirect('/account/')
-            
+
             else:
                 data['computings'] = list(Computing.objects.filter(group=None)) + list(Computing.objects.filter(group__user=request.user))
         else:
             raise ErrorMessage('Unknown conf type \'{}\''.format(conf_type))
-    
- 
+
+
     return render(request, 'add_profile_conf.html', {'data': data})
 
 
@@ -1131,15 +1131,15 @@ def task_connect(request):
     if not task_uuid:
         raise ErrorMessage('Empty task uuid')
 
-    # Get the task     
+    # Get the task
     task = Task.objects.get(uuid=task_uuid)
-    
+
     if task.user != request.user:
         raise ErrorMessage('You do not have access to this task.')
 
     # Ensure that the tunnel and proxy are set up
     setup_tunnel_and_proxy(task)
-    
+
     # Set default interface status as unknown
     task.interface_status = 'unknown'
 
@@ -1177,7 +1177,7 @@ def task_connect(request):
             #         task.interface_status = 'running'
 
     data ={}
-    data['task'] = task    
+    data['task'] = task
     return render(request, 'task_connect.html', {'data': data})
 
 
@@ -1188,7 +1188,7 @@ def task_connect(request):
 @private_view
 def direct_connection_handler(request, uuid):
 
-    # Get the task     
+    # Get the task
     #task = Task.objects.get(uuid__startswith=short_uuid)
     task = Task.objects.get(uuid=uuid)
 
@@ -1197,26 +1197,26 @@ def direct_connection_handler(request, uuid):
 
     # Ensure that the tunnel and proxy are set up
     setup_tunnel_and_proxy(task)
-    
+
     # Get task and tunnel proxy host
     rosetta_tasks_proxy_host = get_rosetta_tasks_proxy_host()
     rosetta_tasks_tunnel_host = get_rosetta_tasks_tunnel_host()
 
-    # Redirect to the task through the tunnel    
+    # Redirect to the task through the tunnel
     if task.requires_proxy:
         if task.requires_proxy_auth and task.auth_token and not task.container.disable_http_basicauth_embedding:
             user = request.user.email
             password = task.auth_token
-            redirect_string = 'https://{}:{}@{}:{}'.format(user, password, rosetta_tasks_proxy_host, task.tcp_tunnel_port)        
+            redirect_string = 'https://{}:{}@{}:{}'.format(user, password, rosetta_tasks_proxy_host, task.tcp_tunnel_port)
         else:
-            redirect_string = 'https://{}:{}'.format(rosetta_tasks_proxy_host, task.tcp_tunnel_port)       
+            redirect_string = 'https://{}:{}'.format(rosetta_tasks_proxy_host, task.tcp_tunnel_port)
     else:
         redirect_string = '{}://{}:{}'.format(task.container.interface_protocol, rosetta_tasks_tunnel_host, task.tcp_tunnel_port)
-    
+
     logger.debug('Task direct connect redirect: "{}"'.format(redirect_string))
     return redirect(redirect_string)
-        
-    
+
+
 
 #===========================
 #  Sharable link handler
@@ -1227,20 +1227,20 @@ def sharable_link_handler(request, short_uuid):
 
     # Get the task (if the short uuid is not enough an error wil be raised)
     task = Task.objects.get(uuid__startswith=short_uuid)
-    
+
     # First ensure that the tunnel and proxy are set up
     setup_tunnel_and_proxy(task)
-    
+
     # Get task and tunnel proxy host
     rosetta_tasks_proxy_host = get_rosetta_tasks_proxy_host()
     rosetta_tasks_tunnel_host = get_rosetta_tasks_tunnel_host()
 
-    # Redirect to the task through the tunnel    
+    # Redirect to the task through the tunnel
     if task.requires_proxy:
-        redirect_string = 'https://{}:{}'.format(rosetta_tasks_proxy_host, task.tcp_tunnel_port)       
+        redirect_string = 'https://{}:{}'.format(rosetta_tasks_proxy_host, task.tcp_tunnel_port)
     else:
         redirect_string = '{}://{}:{}'.format(task.container.interface_protocol, rosetta_tasks_tunnel_host, task.tcp_tunnel_port)
-    
+
     logger.debug('Task sharable link connect redirect: "{}"'.format(redirect_string))
     return redirect(redirect_string)
 
@@ -1258,8 +1258,8 @@ def new_binder_task(request, repository):
 
     # Convert the Git repository as a Docker container
     logger.debug('Got a new Binder task request for repository "%s"', repository)
-        
-    # Set repository name/tag/url        
+
+    # Set repository name/tag/url
     repository_tag = repository.split('/')[-1]
     repository_url = repository.replace('/'+repository_tag, '')
 
@@ -1267,13 +1267,13 @@ def new_binder_task(request, repository):
     # Here i work around this, but TODO: understand what the hell is going on.
     if 'https:/' in repository_url and not 'https://' in repository_url:
         repository_url = repository_url.replace('https:/', 'https://')
-    
+
     if not repository_tag:
         repository_tag='HEAD'
 
     data['repository_url'] = repository_url
     data['repository_tag'] = repository_tag
-    
+
     data['mode'] = 'new_task' #new container
 
     # Render the import page. This will call an API, and when the import is done, it
@@ -1291,17 +1291,17 @@ def import_repository(request):
     # Init data
     data={}
     data['user']  = request.user
-    
+
     repository_url = request.GET.get('repository_url', None)
     # I have no idea why the https:// of the repo part of the url gets transfrmed in https:/
     # Here i work around this, but TODO: understand what the hell is going on.
     if 'https:/' in repository_url and not 'https://' in repository_url:
         repository_url = repository_url.replace('https:/', 'https://')
-    
+
     repository_tag= request.GET.get('repository_tag', None)
     if not repository_tag:
         repository_tag='HEAD'
-        
+
     data['repository_url'] = repository_url
     data['repository_tag'] = repository_tag
 
@@ -1314,3 +1314,4 @@ def import_repository(request):
     # will automatically say "Ok, crrated, go to software".
     return render(request, 'import_repository.html', {'data': data})
 
+
diff --git a/services/webapp/code/rosetta/settings.py b/services/webapp/code/rosetta/settings.py
index 9f854ac..a1ac099 100644
--- a/services/webapp/code/rosetta/settings.py
+++ b/services/webapp/code/rosetta/settings.py
@@ -43,7 +43,7 @@ INSTALLED_APPS = [
     'django.contrib.staticfiles',
     'rest_framework',
     'rest_framework_swagger',
-    'django_extensions', 
+    'django_extensions',
 ]
 
 MIDDLEWARE = [
@@ -176,7 +176,7 @@ ROSETTA_LOG_LEVEL = os.environ.get('ROSETTA_LOG_LEVEL','ERROR')
 LOGGING = {
     'version': 1,
     'disable_existing_loggers': False,
- 
+
     'formatters': {
         'verbose': {
             'format': '%(levelname)s %(asctime)s %(module)s %(process)d '
@@ -187,13 +187,13 @@ LOGGING = {
             'datefmt': '%m/%d/%Y %I:%M:%S %p'
         }
     },
- 
+
     'filters': {
         'require_debug_false': {
             '()': 'django.utils.log.RequireDebugFalse'
         }
     },
- 
+
     'handlers': {
         'mail_admins': {
             'level': 'ERROR',
@@ -206,18 +206,18 @@ LOGGING = {
             'formatter': 'halfverbose',
         },
     },
- 
+
     'loggers': {
         'rosetta': {
             'handlers': ['console'],
             'level': ROSETTA_LOG_LEVEL,
-            'propagate': False, # Do not propagate or the root logger will emit as well, and even at lower levels. 
+            'propagate': False, # Do not propagate or the root logger will emit as well, and even at lower levels.
         },
         'django': {
             'handlers': ['console'],
             'level': DJANGO_LOG_LEVEL,
-            'propagate': False, # Do not propagate or the root logger will emit as well, and even at lower levels. 
-        }, 
+            'propagate': False, # Do not propagate or the root logger will emit as well, and even at lower levels.
+        },
         # Read more about the 'django' logger: https://docs.djangoproject.com/en/2.2/topics/logging/#django-logger
         # Read more about logging in the right way: https://lincolnloop.com/blog/django-logging-right-way/
     }
@@ -246,7 +246,7 @@ if OIDC_RP_CLIENT_ID:
         'django.contrib.auth.backends.ModelBackend',
         'rosetta.auth.RosettaOIDCAuthenticationBackend'
     )
-    
+
     # Base
     OIDC_RP_CLIENT_SECRET  = os.environ.get('OIDC_RP_CLIENT_SECRET')
     OIDC_OP_AUTHORIZATION_ENDPOINT = os.environ.get('OIDC_OP_AUTHORIZATION_ENDPOINT')
@@ -255,7 +255,7 @@ if OIDC_RP_CLIENT_ID:
     OIDC_RP_SIGN_ALGO = os.environ.get('OIDC_RP_SIGN_ALGO', 'RS256')
     OIDC_RP_IDP_SIGN_KEY = os.environ.get('OIDC_RP_IDP_SIGN_KEY', None)
     OIDC_OP_JWKS_ENDPOINT = os.environ.get('OIDC_OP_JWKS_ENDPOINT', None)
-    
+
     # Check
     if OIDC_RP_SIGN_ALGO == 'RS256':
         if not OIDC_RP_IDP_SIGN_KEY and not OIDC_OP_JWKS_ENDPOINT:
@@ -267,7 +267,7 @@ if OIDC_RP_CLIENT_ID:
 
     # Custom callback to enable session-based post-login redirects
     OIDC_CALLBACK_CLASS = 'rosetta.auth.RosettaOIDCAuthenticationCallbackView'
-    
+
     # Non-customizable stuff
     LOGIN_REDIRECT_URL = '/'
     LOGOUT_REDIRECT_URL = '/'
@@ -277,7 +277,8 @@ if OIDC_RP_CLIENT_ID:
     # Required for the Open ID connect redirects to work properly
     USE_X_FORWARDED_HOST = True
     SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
-    
+
+
 
 
 
diff --git a/services/webapp/code/rosetta/urls.py b/services/webapp/code/rosetta/urls.py
index 4e0f57f..06c2d0a 100644
--- a/services/webapp/code/rosetta/urls.py
+++ b/services/webapp/code/rosetta/urls.py
@@ -35,7 +35,7 @@ from rest_framework.documentation import include_docs_urls
 from rest_framework_swagger.views import get_swagger_view
 
 urlpatterns = [
-               
+
     # Pages
     url(r'^$', core_app_views.entrypoint),
     path('main/', core_app_views.main_view),
@@ -44,24 +44,24 @@ urlpatterns = [
     url(r'^register/$', core_app_views.register_view),
     url(r'^pages/(?P<page_id>\w{0,36})/$', core_app_views.page_view),
 
-    
-    # Software    
+
+    # Software
     url(r'^software/$', core_app_views.software),
-    url(r'^add_software/$', core_app_views.add_software),    
-    url(r'^import_repository/$', core_app_views.import_repository),    
-    
+    url(r'^add_software/$', core_app_views.add_software),
+    url(r'^import_repository/$', core_app_views.import_repository),
+
     #Computing
     url(r'^computing/$', core_app_views.computing),
-    
+
     # Storage
     url(r'^storage/$', core_app_views.storage),
-    
+
     # Tasks
     url(r'^tasks/$', core_app_views.tasks),
     url(r'^new_task/$', core_app_views.new_task),
     url(r'^task_log/$', core_app_views.task_log),
     url(r'^task_connect/$', core_app_views.task_connect),
-    
+
     # Sharable and direct connection links for tasks
     url(r'^direct_connect/(?P<uuid>[0-9a-f-]+)/$', core_app_views.direct_connection_handler),
     url(r'^t/(?P<short_uuid>\w{0,36})/$', core_app_views.sharable_link_handler),
@@ -76,7 +76,7 @@ urlpatterns = [
     # Admin and API docs (Swagger)
     path('admin/', admin.site.urls),
     path('api/v1/doc/', get_swagger_view(title="Swagger Documentation")),
-    
+
     # APIs
     path('api/v1/base/login/', core_app_api.login_api.as_view(), name='login_api'),
     path('api/v1/base/logout/', core_app_api.logout_api.as_view(), name='logout_api'),
@@ -97,7 +97,7 @@ urlpatterns = [
 
 # Get admin files location
 admin_files_path = '/'.join(django.__file__.split('/')[0:-1]) + '/contrib/admin/static/admin'
- 
+
 if not settings.DEBUG:
 
     # Admin files
@@ -105,7 +105,7 @@ if not settings.DEBUG:
 
     # Rosetta Core app files
     document_root = 'rosetta/core_app/static'
-     
+
     if os.path.isdir(document_root):
         logger.info('Serving static files for app "core_app" from document root "{}"'.format(document_root))
         # Static
@@ -116,3 +116,4 @@ else:
     logger.info('Not serving static files at all as DEBUG=True (Django will do it automatically)')
 
 
+
diff --git a/services/webapp/prestartup_webapp.sh b/services/webapp/prestartup_webapp.sh
index e986a46..6688bba 100644
--- a/services/webapp/prestartup_webapp.sh
+++ b/services/webapp/prestartup_webapp.sh
@@ -9,5 +9,3 @@ mkdir -p /data/resources
 chown rosetta:rosetta /data/resources
 chown rosetta:rosetta /shared
 
-
-
diff --git a/services/webapp/run_webapp.sh b/services/webapp/run_webapp.sh
index 622b6f4..5e0070c 100644
--- a/services/webapp/run_webapp.sh
+++ b/services/webapp/run_webapp.sh
@@ -35,7 +35,7 @@ echo ""
 
 
 if [[ "x$DJANGO_DEV_SERVER" == "xTrue" ]] ; then
-    
+
 # Run the (development) server
     echo "Now starting the development server and logging in /var/log/webapp/server.log."
     exec python3 manage.py runserver 0.0.0.0:8080 2>> /var/log/webapp/server.log
@@ -43,7 +43,7 @@ if [[ "x$DJANGO_DEV_SERVER" == "xTrue" ]] ; then
 else
     # Move to the code dir
     cd /opt/code
-    
+
     # Collect static
     echo "Collecting static files..."
     python3 manage.py collectstatic
@@ -63,20 +63,3 @@ else
 	      --disable-logging 2>> /var/log/webapp/server.log
 fi
 
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-- 
GitLab