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 b5ffae06cc56e4441f6b905413c9a933ed8b7b41..ce496da65f44bb3b05549795bda942c8ccaff097 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
@@ -159,7 +159,7 @@ to provide help, news and informations on your deployment. Or you can just ignor
                                      interface_auth_user = None)
  
  
-            # Jupyter Notebook 
+            # Jupyter Notebook
             Container.objects.create(user     = None,
                                      name     = 'Jupyter Notebook',
                                      description = 'A Jupyter Notebook server',
@@ -175,6 +175,37 @@ to provide help, news and informations on your deployment. Or you can just ignor
                                      supports_interface_auth = True,
                                      interface_auth_user = None)
 
+            # Official Jupyter Lab
+            Container.objects.create(user     = None,
+                                     name     = 'Jupyter Lab',
+                                     description = 'The official Jupyter Lab. The Scipy variant, which includes popular packages from the scientific Python ecosystem.',
+                                     registry = 'docker.io',
+                                     image    = 'jupyter/scipy-notebook',
+                                     tag      = 'lab-3.2.2',
+                                     arch = 'amd64,arm64',
+                                     os = 'linux',
+                                     interface_port     = '8888',
+                                     interface_protocol = 'http',
+                                     interface_transport = 'tcp/ip',
+                                     supports_custom_interface_port = True,
+                                     supports_interface_auth = True)
+
+            Container.objects.create(user     = None,
+                                     name     = 'Jupyter Lab',
+                                     description = 'The official Jupyter Lab. Includes popular packages from the scientific Python ecosystem.',
+                                     registry = 'docker.io',
+                                     image    = 'jupyter/scipy-notebook',
+                                     tag      = 'lab-3.1.17',
+                                     arch = 'amd64,arm64',
+                                     os = 'linux',
+                                     interface_port     = '8888',
+                                     interface_protocol = 'http',
+                                     interface_transport = 'tcp/ip',
+                                     supports_custom_interface_port = True,
+                                     supports_interface_auth = True)
+
+
+
             # SSH server
             Container.objects.create(user     = None,
                                      name     = 'SSH server',
diff --git a/services/webapp/code/rosetta/core_app/models.py b/services/webapp/code/rosetta/core_app/models.py
index 77514a195336d0f778c95a0318ea50c6e6f4c07b..60159fa8403766ebeb4dd9b47332ac4c396910fd 100644
--- a/services/webapp/code/rosetta/core_app/models.py
+++ b/services/webapp/code/rosetta/core_app/models.py
@@ -144,10 +144,9 @@ class Container(models.Model):
         user_str = self.user.email if self.user else None
         return str('Container "{}" of user "{}" with image "{}" and tag "{}" on registry "{}" '.format(self.name, user_str, self.image, self.tag, self.registry))
 
-
     @ property
     def color(self):
-        string_int_hash = hash_string_to_int(self.image + self.tag + self.registry)
+        string_int_hash = hash_string_to_int(self.name + self.registry + self.image)
         color_map_index = string_int_hash % len(color_map)
         return color_map[color_map_index]
 
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 dfbbb418239939e88ea9fffd955dc5d78952ace3..76169573a7061ce6a86abce7035c661b074dc895 100644
--- a/services/webapp/code/rosetta/core_app/templates/components/computing.html
+++ b/services/webapp/code/rosetta/core_app/templates/components/computing.html
@@ -115,6 +115,7 @@
         {% csrf_token %}
         <input type="hidden" name="step" value="{{ data.next_step }}" />
         <input type="hidden" name="task_container_uuid" value="{{container.uuid}}">
+        <input type="hidden" name="task_container_arch" value="{{container_arch}}">
         <input type="hidden" name="task_computing_uuid" value="{{computing.uuid}}">
         <input type="submit" value="Choose" class="btn btn-connect">
         </form>
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 d6981795f90ab97aa5196f0db2974db50e4fbb17..c4e167ac1049b59c2329a5fea10cb63748ea6ada 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 %}     
 
       <table class="dashboard" style="margin:10px; max-width:600px">
         
@@ -109,7 +109,7 @@
 
         
         <div style="padding:10px; margin-top:5px; text-align:center; border-bottom: {{container.color}} solid 10px; ">
-        <a href="/software/?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; ">
@@ -125,7 +125,7 @@
         <div class="image-version-box">
         <!-- <font style="font-family:monospace; font-size:1.2em"></font> -->
         <b>Image:</b> <code>{{ container.image }}</code><br/>
-        <b>Tag:</b> &nbsp;{{ container.tag }}
+        <b>Tag:</b> &nbsp;{{ container.tag }} &nbsp;<b>Arch:</b> {{container_arch}}
         </div> 
        
         </div>
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
new file mode 100644
index 0000000000000000000000000000000000000000..043523a2b4304e2337a692f1a99fd174c73cbc69
--- /dev/null
+++ b/services/webapp/code/rosetta/core_app/templates/components/container_family.html
@@ -0,0 +1,78 @@
+
+      {% if data.details %}
+      {% for container in container_family.members %}
+      {% include "components/container.html" with container=container details=data.details %}
+      {% endfor %}
+      
+      {% 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; 
+        </div>
+        
+        <div style="padding:10px; height: 125px; ">
+        <!-- <div style="position: relative; top: 50%; transform: translateY(-50%);"> -->
+        
+        {% if container_family.description %} 
+        <div class="description-box" title="{{ container_family.description }}">
+        {{ container_family.description }}
+        </div>
+        {% else %}
+        <br/>  
+        {% endif %}
+        
+        <div class="image-version-box">
+        <b>Image:</b> <code>{{ container_family.image }}</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 %}
+        <option value="{{ container.uuid }}">{{ container.tag }}</option>
+        {% endfor %}
+        </select>
+
+        <span style="vertical-align:top; margin-left:5px"><b>Arch:</b>&nbsp;</span>
+        <select name="task_container_arch" style="font-size:0.8em">
+        <option value="auto" selected>auto</option>
+
+        {% for arch in container_family.all_archs %}
+        <option value="{{ arch }}">{{ arch }}</option>
+        {% endfor %}
+        </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">
+        &nbsp;<i class="fa fa-play" style="color:green"></i>
+        </button>
+        
+        {% endif %}
+        </form>
+        </div>    
+      
+      
+      
+      </div>
+      
+      {% endif %}
+
+
+
+
+
+
+      
\ No newline at end of file
diff --git a/services/webapp/code/rosetta/core_app/templates/components/container_family_mah.html b/services/webapp/code/rosetta/core_app/templates/components/container_family_mah.html
new file mode 100644
index 0000000000000000000000000000000000000000..c2bf49b5e147b9e98f2e04c0b2a6f4e544a76c49
--- /dev/null
+++ b/services/webapp/code/rosetta/core_app/templates/components/container_family_mah.html
@@ -0,0 +1,64 @@
+
+
+      <div style="width:300px; float:left; border: #e0e0e0 solid 1px; margin:10px; background:#f8f8f8; margin-bottom:15px">
+        <form action="/aaa" method=GET>
+        
+        
+        <div style="padding:10px; margin-top:5px; text-align:center; border-bottom: {{container.color}} solid 10px; ">
+        <a href="/software/?container_family={{ family_id }}">{{ 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 %} 
+        <div class="description-box" title="{{ container_family.description }}">
+        {{ container_family.description }}
+        </div>
+        {% else %}
+        <br/>  
+        {% endif %}
+        
+        <div class="image-version-box">
+        <b>Image:</b> <code>{{ container_family.image }}</code><br/>
+        <div style="margin-top:2px">
+        
+        <span style="vertical-align:top;"><b>Tag:</b>&nbsp;</span>
+        <select name="task_container_uuid_and_arch" style="font-size:0.8em">
+        {% for arch,container_by_tags in container_family.container_by_tags_by_arch.items %}
+        <optgroup label={{ arch }}>
+        {% for tag,container in container_by_tags.items %}
+        <option value="{{ container.uuid }}-{{ arch }}">{{ tag }}</option>
+        {% endfor %}
+        </optgroup>
+        {% endfor %}
+        </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">
+        &nbsp;<i class="fa fa-play" style="color:green"></i>
+        </button>
+        
+        {% endif %}
+        </form>
+        </div>    
+      
+      
+      
+      </div>
+      
+
+
+
+
+
+
+      
\ No newline at end of file
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 23db343aefb01a77fe92c45076ade8a1de3436fc..eef352b8585bded34d08027bad98e3fc5223e587 100644
--- a/services/webapp/code/rosetta/core_app/templates/new_task.html
+++ b/services/webapp/code/rosetta/core_app/templates/new_task.html
@@ -24,7 +24,7 @@
       <div style="float:left; background:#ffffff; margin-left:10px; margin-right:10px; margin-top:0px; margin-bottom:20px">
           <h4>Software container</h4>
           <div class="row" style="padding:5px">
-          {% include "components/container.html" with container=data.task_container disable_play_button=True %}
+          {% include "components/container.html" with container=data.task_container container_arch=data.task_container_arch disable_play_button=True  %}
           </div>
       </div>
       {% endif %}
@@ -36,7 +36,7 @@
           <h4>Computing resource</h4>
           <div class="row" style="padding:5px">
           {% for computing in data.computings %}
-          {% include "components/computing.html" with container=data.task_container %}
+          {% include "components/computing.html" with container=data.task_container container_arch=data.task_container_arch %}
           {% endfor %}
           </div>
       </div>
@@ -76,6 +76,7 @@
           <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="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 }}" />
diff --git a/services/webapp/code/rosetta/core_app/templates/software.html b/services/webapp/code/rosetta/core_app/templates/software.html
index 8be03d0b5deed876bd26394f2d26f618dc23ec76..b5094966c39a8706b89c225b1291705942bcefc2 100644
--- a/services/webapp/code/rosetta/core_app/templates/software.html
+++ b/services/webapp/code/rosetta/core_app/templates/software.html
@@ -9,8 +9,12 @@
   <div class="dashboard">
     <div class="span8 offset2">
       
-      {% if data.container %}
+      {% if data.details %}
+      {% if data.container_families %}
+      <h1><a href="/software">Software containers</a> <span style="font-size:18px"> / {{ data.containers.0.name }}</span></h1>
+      {% else %}
       <h1><a href="/software">Software containers</a> <span style="font-size:18px"> / {{ data.container.name }}</span></h1>
+      {% endif %}
       {% else %}
       {% if data.mode == 'new_task' %}
       <h1>New Task</h1>
@@ -65,10 +69,16 @@
       <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%}
+      {% endfor %}
+      {% else %}
       {% for container in data.containers %}
       {% include "components/container.html" with container=container %}
       {% endfor %}
+      {% endif  %}      
       {% endif %}
       </div>
       
diff --git a/services/webapp/code/rosetta/core_app/views.py b/services/webapp/code/rosetta/core_app/views.py
index 80f454208e16173b060ec5e5af49b827e1fca4ef..4b56e040041caefd9f8d1f819b3fe2d8621305f7 100644
--- a/services/webapp/code/rosetta/core_app/views.py
+++ b/services/webapp/code/rosetta/core_app/views.py
@@ -2,6 +2,7 @@ import os
 import uuid
 import json
 import subprocess
+import base64
 from django.conf import settings
 from django.shortcuts import render
 from django.contrib.auth import authenticate, login, logout
@@ -10,7 +11,7 @@ from django.contrib.auth.models import User
 from django.shortcuts import redirect
 from django.db.models import Q
 from .models import Profile, LoginToken, Task, TaskStatuses, Container, Computing, KeyPair, Page
-from .utils import send_email, format_exception, timezonize, os_shell, booleanize, debug_param, get_task_tunnel_host, get_task_proxy_host, random_username, setup_tunnel_and_proxy, finalize_user_creation
+from .utils import send_email, format_exception, timezonize, os_shell, booleanize, debug_param, get_task_tunnel_host, get_task_proxy_host, random_username, setup_tunnel_and_proxy, finalize_user_creation, get_md5
 from .decorators import public_view, private_view
 from .exceptions import ErrorMessage
 
@@ -463,6 +464,14 @@ def new_task(request):
                 raise Exception('Consistency error, container with uuid "{}" does not exists or user "{}" does not have access rights'.format(task_container_uuid, request.user.email))
         return task_container
 
+    # Get task container arch helper function
+    def get_task_container_arch(request):
+        container_arch = request.POST.get('task_container_arch', None)
+        if not container_arch:
+            # At the second step the task uuid is set via a GET request 
+            container_arch = request.GET.get('task_container_arch', None)
+        return container_arch
+
     # Get task computing helper function
     def get_task_computing(request):
         task_computing_uuid = request.POST.get('task_computing_uuid', None)
@@ -496,8 +505,9 @@ def new_task(request):
         
     elif step == 'two':
         
-        # Get software container
+        # Get software container and arch
         data['task_container'] = get_task_container(request)
+        data['task_container_arch'] = get_task_container_arch(request)
 
         # List all computing resources 
         data['computings'] = list(Computing.objects.filter(group=None)) + list(Computing.objects.filter(group__user=request.user))
@@ -507,8 +517,9 @@ def new_task(request):
 
     elif step == 'three':
 
-        # Get software container
+        # Get software container and arch
         data['task_container'] = get_task_container(request)
+        data['task_container_arch'] = get_task_container_arch(request)
 
         # Get computing resource
         data['task_computing'] = get_task_computing(request)
@@ -523,8 +534,9 @@ def new_task(request):
 
     elif step == 'last':
 
-        # Get software container
+        # Get software container and arch
         data['task_container'] = get_task_container(request)
+        data['task_container_arch'] = get_task_container_arch(request)
 
         # Get computing resource
         data['task_computing'] = get_task_computing(request)
@@ -691,8 +703,11 @@ def software(request):
     data['profile'] = Profile.objects.get(user=request.user)
 
     # Get action if any
-    uuid   = request.GET.get('uuid', None)
+    container_uuid = request.GET.get('container_uuid', None)
+    container_family_id = request.GET.get('container_family_id', None)
     action = request.GET.get('action', None)
+    details = booleanize(request.GET.get('details', False))
+
 
     # Get filter/search if any
     search_text   = request.POST.get('search_text', '')
@@ -701,6 +716,7 @@ def software(request):
     # Set back to page data
     data['search_owner'] = search_owner
     data['search_text']  = search_text
+    data['details'] = details
 
     # Are we using this page as first step of a new task?
     data['mode'] = request.GET.get('mode', None)
@@ -708,14 +724,14 @@ def software(request):
         data['mode'] = request.POST.get('mode', None)
 
 
-    # Do we have to operate on a specific container?
-    if uuid:
+    # Do we have to operate on a specific container, or family of containers?
+    if container_uuid:
 
         try:
 
             # Get the container (raises if none available including no permission)
             try:
-                container = Container.objects.get(uuid=uuid)
+                container = Container.objects.get(uuid=container_uuid)
             except Container.DoesNotExist:
                 raise ErrorMessage('Container does not exists or no access rights')                
             if container.user and container.user != request.user:
@@ -735,26 +751,83 @@ 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})
-
-
-    # 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__icontains=search_text))
-        user_containers = Container.objects.filter(search_query, user=request.user)
-        platform_containers = Container.objects.filter(search_query, user=None)
-    else:
-        user_containers = Container.objects.filter(user=request.user)
-        platform_containers = Container.objects.filter(user=None)
     
-    # Filter by owner
+    # Or, do we have to operate on a container family?
+    elif container_family_id:
+        
+        # Get back name, registry and image from contsainer url
+        container_name, container_registry, container_image = 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=container_image)
+        platform_containers = Container.objects.filter(user=None, name=container_name, registry=container_registry, image=container_image)
+    
+    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__icontains=search_text))
+            user_containers = Container.objects.filter(search_query, user=request.user)
+            platform_containers = Container.objects.filter(search_query, user=None)
+        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
+    data['container_families'] = {}
+    
+    # Container family support class
+    class ContainerFamily(object):
+    
+        def __init__(self, id, name, registry, image):
+            self.id = id
+            self.name = name
+            self.registry = registry
+            self.image = image
+            self.description = None
+            self.members = []
+            self.all_archs = []
+            self.container_by_tags_by_arch = {} 
+
+        def add(self, container):
+            self.members.append(container)
+
+            if not self.description:
+                self.description = container.description
+            
+            for arch in container.arch.split(','):
+                
+                if not arch in self.all_archs:
+                    self.all_archs.append(arch)
+                if not arch in self.container_by_tags_by_arch:
+                    self.container_by_tags_by_arch[arch]={}
+                self.container_by_tags_by_arch[arch][container.tag] = container
+        
+        @ property
+        def color(self):
+            try:
+                return self.members[0].color
+            except IndexError:
+                return '#000000'
+        
+    # Populate container families
+    for container in data['containers']:
+        container_family_id = base64.b64encode('{}\t{}\t{}'.format(container.name, container.registry, container.image).encode('utf8')).decode('utf8')
+        if container_family_id not in data['container_families']:
+            data['container_families'][container_family_id] = ContainerFamily(container_family_id, container.name, container.registry, container.image)
+        data['container_families'][container_family_id].add(container)    
+            
     return render(request, 'software.html', {'data': data})