diff --git a/authentication/source/java/ch/systemsx/cisd/authentication/DefaultSessionManager.java b/authentication/source/java/ch/systemsx/cisd/authentication/DefaultSessionManager.java
index 7879d1b8c7e498b91e203ddc0090166935741086..41f9aeaaea898d05cce102206d3a6a461d1a526b 100644
--- a/authentication/source/java/ch/systemsx/cisd/authentication/DefaultSessionManager.java
+++ b/authentication/source/java/ch/systemsx/cisd/authentication/DefaultSessionManager.java
@@ -19,6 +19,7 @@ package ch.systemsx.cisd.authentication;
 import java.io.File;
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
+import java.util.Collection;
 import java.util.Date;
 import java.util.LinkedHashMap;
 import java.util.Map;
@@ -116,8 +117,7 @@ public class DefaultSessionManager<T extends BasicSession> implements ISessionMa
          */
         boolean hasExpired(Long sessionExpirationTimeOrNull)
         {
-            long sessionExpirationTime = sessionExpirationTimeOrNull == null ?
-                    session.getSessionExpirationTime() : sessionExpirationTimeOrNull;
+            long sessionExpirationTime = sessionExpirationTimeOrNull == null ? session.getSessionExpirationTime() : sessionExpirationTimeOrNull;
             return System.currentTimeMillis() - lastActiveTime > sessionExpirationTime;
         }
     }
@@ -131,7 +131,7 @@ public class DefaultSessionManager<T extends BasicSession> implements ISessionMa
      */
     protected final Map<String, FullSession<T>> sessions =
             new LinkedHashMap<String, FullSession<T>>();
-    
+
     private final IAuthenticationService authenticationService;
 
     private final IRemoteHostProvider remoteHostProvider;
@@ -209,6 +209,17 @@ public class DefaultSessionManager<T extends BasicSession> implements ISessionMa
                         + tokenGenerator.getNewToken(now, TIMESTAMP_TOKEN_SEPARATOR);
         synchronized (sessions)
         {
+            int maxNumberOfSessions = getMaxNumberOfSessionsFor(user);
+            if (maxNumberOfSessions > 0)
+            {
+                int numberOfOpenSessions = getNumberOfOpenSessionsFor(user);
+                if (numberOfOpenSessions >= maxNumberOfSessions)
+                {
+                    throw new UserFailureException(numberOfOpenSessions + " open session(s) but only "
+                            + maxNumberOfSessions + " session(s) are allowed for user " + user + ".");
+                }
+            }
+
             final T session =
                     sessionFactory.create(sessionToken, user, principal, getRemoteHost(), now,
                             sessionExpirationPeriodMillis);
@@ -221,6 +232,25 @@ public class DefaultSessionManager<T extends BasicSession> implements ISessionMa
         }
     }
 
+    private int getNumberOfOpenSessionsFor(String user)
+    {
+        int count = 0;
+        Collection<FullSession<T>> values = sessions.values();
+        for (FullSession<T> session : values)
+        {
+            if (session.getSession().getUserName().equals(user))
+            {
+                count++;
+            }
+        }
+        return count;
+    }
+
+    protected int getMaxNumberOfSessionsFor(String user)
+    {
+        return 0;
+    }
+
     private ISessionMonitor getSessionMonitor()
     {
         if (sessionMonitor == null)
diff --git a/authentication/sourceTest/java/ch/systemsx/cisd/authentication/DefaultSessionManagerTest.java b/authentication/sourceTest/java/ch/systemsx/cisd/authentication/DefaultSessionManagerTest.java
index a51ea5a87fe5ca5d39479a9997a9ffc190df18f0..78ed2c035dfb0d7a263d661c437f97504bc80f4a 100644
--- a/authentication/sourceTest/java/ch/systemsx/cisd/authentication/DefaultSessionManagerTest.java
+++ b/authentication/sourceTest/java/ch/systemsx/cisd/authentication/DefaultSessionManagerTest.java
@@ -20,12 +20,16 @@ import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertTrue;
 import static org.testng.AssertJUnit.fail;
 
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.regex.Pattern;
 
 import org.apache.commons.lang3.StringUtils;
 import org.apache.log4j.Level;
 import org.jmock.Expectations;
 import org.jmock.Mockery;
+import org.jmock.Sequence;
 import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Listeners;
@@ -72,6 +76,8 @@ public class DefaultSessionManagerTest
 
     private IPrincipalProvider principalProvider;
 
+    private Sequence sequence;
+
     private void assertExceptionMessageForInvalidSessionToken(final UserFailureException ex)
     {
         final String message = ex.getMessage();
@@ -88,6 +94,7 @@ public class DefaultSessionManagerTest
         authenticationService = context.mock(IAuthenticationService.class);
         remoteHostProvider = context.mock(IRemoteHostProvider.class);
         principalProvider = context.mock(IPrincipalProvider.class);
+        sequence = context.sequence("sequence");
         context.checking(new Expectations()
             {
                 {
@@ -98,12 +105,27 @@ public class DefaultSessionManagerTest
         logRecorder = new BufferedAppender("%-5p %c - %m%n", Level.DEBUG);
     }
 
-    @SuppressWarnings(
-    { "unchecked", "rawtypes" })
     private ISessionManager<BasicSession> createSessionManager(int sessionExpiration)
+    {
+        return createSessionManager(sessionExpiration, new HashMap<>());
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    private ISessionManager<BasicSession> createSessionManager(int sessionExpiration,
+            Map<String, Integer> maxNumberOfSessionByUser)
     {
         return new DefaultSessionManager(sessionFactory, prefixGenerator, authenticationService,
-                remoteHostProvider, sessionExpiration, 0, true);
+                remoteHostProvider, sessionExpiration, 0, true)
+            {
+
+                @Override
+                protected int getMaxNumberOfSessionsFor(String user)
+                {
+                    Integer maxNumber = maxNumberOfSessionByUser.get(user);
+                    return maxNumber == null ? 0 : maxNumber;
+                }
+
+            };
     }
 
     @AfterMethod
@@ -169,6 +191,92 @@ public class DefaultSessionManagerTest
         context.assertIsSatisfied();
     }
 
+    @Test
+    public void testUnlimitedNumberOfSessions()
+    {
+        final String user = "bla";
+        context.checking(new Expectations()
+            {
+                {
+                    allowing(remoteHostProvider).getRemoteHost();
+                    will(returnValue(REMOTE_HOST));
+
+                    for (int i = 0; i < 3; i++)
+                    {
+                        one(authenticationService).tryGetAndAuthenticateUser(user, "blub");
+                        will(returnValue(principal));
+
+                        one(sessionFactory).create(with(any(String.class)), with(equal(user)),
+                                with(equal(principal)), with(equal(REMOTE_HOST)),
+                                with(any(Long.class)), with(any(Integer.class)));
+                        BasicSession session =
+                                new BasicSession(user + "-" + (i + 1), user, principal, REMOTE_HOST, 42L, 0);
+                        will(returnValue(session));
+                        inSequence(sequence);
+
+                        one(prefixGenerator).createPrefix(session);
+                        will(returnValue("[USER:'" + user + "', HOST:'remote-host']"));
+                    }
+
+                }
+            });
+
+        assertEquals("bla-1", sessionManager.tryToOpenSession("bla", "blub"));
+        assertEquals("bla-2", sessionManager.tryToOpenSession("bla", "blub"));
+        assertEquals("bla-3", sessionManager.tryToOpenSession("bla", "blub"));
+
+        context.assertIsSatisfied();
+    }
+
+    @Test
+    public void testLimitedNumberOfSession()
+    {
+        final String user = "bla";
+        context.checking(new Expectations()
+            {
+                {
+                    one(authenticationService).check();
+
+                    allowing(remoteHostProvider).getRemoteHost();
+                    will(returnValue(REMOTE_HOST));
+
+                    exactly(3).of(authenticationService).tryGetAndAuthenticateUser(user, "blub");
+                    will(returnValue(principal));
+
+                    for (int i = 0; i < 2; i++)
+                    {
+                        one(sessionFactory).create(with(any(String.class)), with(equal(user)),
+                                with(equal(principal)), with(equal(REMOTE_HOST)),
+                                with(any(Long.class)), with(any(Integer.class)));
+                        BasicSession session =
+                                new BasicSession(user + "-" + (i + 1), user, principal, REMOTE_HOST, 42L, 0);
+                        will(returnValue(session));
+                        inSequence(sequence);
+
+                        one(prefixGenerator).createPrefix(session);
+                        will(returnValue("[USER:'" + user + "', HOST:'remote-host']"));
+                    }
+
+                    one(prefixGenerator).createPrefix("bla", REMOTE_HOST);
+                    will(returnValue("[USER:'bla', HOST:'remote-host']"));
+                }
+            });
+        sessionManager = createSessionManager(SESSION_EXPIRATION_PERIOD_MINUTES, Collections.singletonMap("bla", 2));
+
+        assertEquals("bla-1", sessionManager.tryToOpenSession("bla", "blub"));
+        assertEquals("bla-2", sessionManager.tryToOpenSession("bla", "blub"));
+        try
+        {
+            assertEquals("bla-3", sessionManager.tryToOpenSession("bla", "blub"));
+            fail("UserFailureException expected");
+        } catch (UserFailureException e)
+        {
+            assertEquals("2 open session(s) but only 2 session(s) are allowed for user bla.", e.getMessage());
+        }
+
+        context.assertIsSatisfied();
+    }
+
     @Test
     public void testSuccessfulAuthenticationWithEmailAddress()
     {
diff --git a/datastore_server/build.gradle b/datastore_server/build.gradle
index 8bacacef8fd90f58b54e7a9b7fa1687ae45de76c..8c4931600ae7b8dc8f02c7d3cdcf2761888eec40 100644
--- a/datastore_server/build.gradle
+++ b/datastore_server/build.gradle
@@ -10,6 +10,7 @@ apply from: '../gradle/javaproject.gradle'
 
 configurations.create('testRuntimeFirst')
 configurations.create('testRuntimeSecond')
+configurations.create('datastoreExecRuntime')
 
 dependencies {
 
@@ -35,6 +36,19 @@ dependencies {
 
 	runtime 'bioformats:bioformats:5.9.2'
 
+	// eln-lims Jython APIs dependencies
+	datastoreExecRuntime files("../openbis_standard_technologies/dist/core-plugins/eln-lims/1/dss/reporting-plugins/eln-lims-api/lib/zip4j_1.3.2.jar"),
+			files("../openbis_standard_technologies/dist/core-plugins/eln-lims/1/dss/reporting-plugins/eln-lims-api/lib/plasmapper.jar"),
+			files("../openbis_standard_technologies/dist/core-plugins/eln-lims/1/dss/reporting-plugins/eln-lims-api/lib/htmlcleaner-2.16.jar"),
+			files("../openbis_standard_technologies/dist/core-plugins/eln-lims/1/dss/reporting-plugins/exports-api/lib/docx4j-3.3.3.jar"),
+			files("../openbis_standard_technologies/dist/core-plugins/eln-lims/1/dss/reporting-plugins/exports-api/lib/docxbuilder.jar"),
+			files("../openbis_standard_technologies/dist/core-plugins/eln-lims/1/dss/reporting-plugins/exports-api/lib/jsoup-1.11.3.jar"),
+			files("../openbis_standard_technologies/dist/core-plugins/eln-lims/1/dss/reporting-plugins/exports-api/lib/serializer-2.7.2.jar"),
+			files("../openbis_standard_technologies/dist/core-plugins/eln-lims/1/dss/reporting-plugins/exports-api/lib/slf4j-api-1.7.21.jar"),
+			files("../openbis_standard_technologies/dist/core-plugins/eln-lims/1/dss/reporting-plugins/exports-api/lib/xalan-2.7.2.jar"),
+			files("../openbis_standard_technologies/dist/core-plugins/eln-lims/1/dss/reporting-plugins/zenodo-exports-api/lib/job-scheduler.jar"),
+			files("../openbis_standard_technologies/dist/core-plugins/eln-lims/1/dss/reporting-plugins/password-reset-api/lib/persistentkeyvaluestore.jar")
+
 	testCompile (project(path: ':openbis', configuration: 'tests')) {
 		exclude group: 'google', module: 'gwt-user'
 	}
@@ -73,7 +87,7 @@ sourceSets {
 		}
 
 		compileClasspath += sourceSets.main.compileClasspath
-		runtimeClasspath += sourceSets.main.runtimeClasspath
+		runtimeClasspath += sourceSets.main.runtimeClasspath + configurations.datastoreExecRuntime
 	}
 }
 
diff --git a/integration-tests/test_archiving.py b/integration-tests/test_archiving.py
index a039e94ad930b38965878b5d1d1ae72c98db2c62..346dedbbdd53691c25899fcc81b909423e27d0f0 100644
--- a/integration-tests/test_archiving.py
+++ b/integration-tests/test_archiving.py
@@ -27,6 +27,7 @@ class TestCase(systemtest.testcase.TestCase):
         
         openbisController = self.createOpenbisController()
         openbisController.createTestDatabase("openbis")
+        openbisController.asProperties['max-number-of-sessions-per-user'] = '0'
         
         openbisController.allUp()
         
diff --git a/integration-tests/test_obis.py b/integration-tests/test_obis.py
index 03a14dfef81894f32f28004bc6575946ea4e2808..ddf3dc7ce8d5470a8ec0b07aeb4a881e80a16224 100755
--- a/integration-tests/test_obis.py
+++ b/integration-tests/test_obis.py
@@ -45,6 +45,8 @@ class TestCase(systemtest.testcase.TestCase):
         self.installObis()
         self.openbisController = self.createOpenbisController()
         self.openbisController.createTestDatabase("openbis")
+        self.openbisController.asProperties['max-number-of-sessions-per-user'] = '0'
+
         self.openbisController.allUp()
 
         tmpdir = os.path.abspath('obis_data_' + str(randrange(100000)))
diff --git a/integration-tests/test_openbis_sync_big.py b/integration-tests/test_openbis_sync_big.py
index 8b47544bcb3d8936d92dde565d7bebc0b17d5cf7..2ca1e90159d474a2989b70b9d2503741a7824db6 100755
--- a/integration-tests/test_openbis_sync_big.py
+++ b/integration-tests/test_openbis_sync_big.py
@@ -410,6 +410,7 @@ class TestCase(systemtest.testcase.TestCase):
         openbis_data_source.enableProjectSamples()
         openbis_data_source.setDummyAuthentication()
         openbis_data_source.setDataStoreServerProperty("host-address", "https://localhost")
+        openbis_data_source.asProperties['max-number-of-sessions-per-user'] = '0'
         openbis_data_source.dssProperties['database.kind'] = openbis_data_source.databaseKind
         openbis_data_source.createTestDatabase('openbis')
         openbis_data_source.createTestDatabase('pathinfo')
@@ -426,6 +427,7 @@ class TestCase(systemtest.testcase.TestCase):
         openbis_harvester.enableProjectSamples()
         openbis_harvester.setDummyAuthentication()
         openbis_harvester.setDataStoreServerProperty("host-address", "https://localhost")
+        openbis_harvester.asProperties['max-number-of-sessions-per-user'] = '0'
         openbis_harvester.dssProperties['database.kind'] = openbis_harvester.databaseKind
         openbis_harvester.enableCorePlugin("openbis-sync")
         util.copyFromTo(self.getTemplatesFolder(), openbis_harvester.installPath, "harvester-config.txt")
diff --git a/js-test/servers/common/openBIS-server/etc/service.properties b/js-test/servers/common/openBIS-server/etc/service.properties
index 288dbe25af96844bc75fedd71f67aec354afe95c..e750d54ee21c229eb671293f286e32e326a26be4 100644
--- a/js-test/servers/common/openBIS-server/etc/service.properties
+++ b/js-test/servers/common/openBIS-server/etc/service.properties
@@ -130,6 +130,7 @@ trusted-cross-origin-domains=*
 # ---------------------------------------------------------------------------
 # The time after which an inactive session is expired by the service (in minutes).
 session-timeout = 720
+max-number-of-sessions-per-user = 0
 
 # ---------------------------------------------------------------------------
 # Business rules configuration
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/SingleSignOnServlet.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/SingleSignOnServlet.java
index dd45e86850433efcc9ddaddbbc062192444d829e..a2ec8176f5403ac11ff0f02a23af4222be325b56 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/SingleSignOnServlet.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/SingleSignOnServlet.java
@@ -17,10 +17,10 @@
 package ch.ethz.sis.openbis.generic.server;
 
 import java.io.IOException;
-import java.util.Arrays;
-import java.util.Enumeration;
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Map.Entry;
 
 import javax.annotation.Resource;
 import javax.servlet.ServletContext;
@@ -51,6 +51,8 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.Session;
 @Controller
 public class SingleSignOnServlet extends AbstractServlet
 {
+    private static final String OPENBIS_COOKIE = "openbis";
+
     public static final String SERVLET_NAME = "ssos";
 
     public static final String SESSION_ID_KEY = "session-id-key";
@@ -108,15 +110,32 @@ public class SingleSignOnServlet extends AbstractServlet
     @RequestMapping({ SERVLET_NAME })
     protected void respondToRequest(HttpServletRequest request, HttpServletResponse response) throws Exception, IOException
     {
+        operationLog.info("handle sso event");
+        removeStaleSessions();
         String sessionId = getHeader(request, SESSION_ID_KEY, DEFAULT_SESSION_ID_KEY);
-        String sessionToken = sessionTokenBySessionId.get(sessionId);
-        String returnURL = request.getParameter("return");
-        if (returnURL != null)
+        synchronized (this)
         {
-            handleLogOut(request, response, sessionId, sessionToken, returnURL);
-        } else
+            String sessionToken = sessionTokenBySessionId.get(sessionId);
+            String returnURL = request.getParameter("return");
+            if (returnURL != null)
+            {
+                handleLogOut(request, response, sessionId, sessionToken, returnURL);
+            } else
+            {
+                handleLogIn(request, response, sessionId, sessionToken);
+            }
+        }
+    }
+
+    private void removeStaleSessions()
+    {
+        for (Entry<String, String> entry : new ArrayList<>(sessionTokenBySessionId.entrySet()))
         {
-            handleLogIn(request, response, sessionId, sessionToken);
+            String sessionToken = entry.getValue();
+            if (sessionManager.tryGetSession(sessionToken) == null)
+            {
+                sessionTokenBySessionId.remove(entry.getKey());
+            }
         }
     }
 
@@ -148,7 +167,7 @@ public class SingleSignOnServlet extends AbstractServlet
         applicationServerApi.registerUser(sessionToken);
         sessionTokenBySessionId.put(sessionId, sessionToken);
 
-        operationLog.info("Session token " + sessionToken + " created for SSO session id " + sessionId);
+        operationLog.info("Session token " + sessionToken + " created for SSO session id " + sessionId + " (" + sessionTokenBySessionId.size() + ")");
         redirectToApp(request, response, sessionToken);
     }
 
@@ -156,6 +175,7 @@ public class SingleSignOnServlet extends AbstractServlet
             throws IOException
     {
         operationLog.info("log out session id: " + sessionId);
+        sessionTokenBySessionId.remove(sessionId);
         if (sessionToken != null)
         {
             Session session = sessionManager.tryGetSession(sessionToken);
@@ -178,7 +198,7 @@ public class SingleSignOnServlet extends AbstractServlet
         String redirectUrl = configurer.getResolvedProps().getProperty(REDIRECT_URL_KEY, template.createText());
         operationLog.info("redirect to " + redirectUrl);
         removeOpenbisCookies(request, response);
-        Cookie cookie = new Cookie("openbis", sessionToken);
+        Cookie cookie = new Cookie(OPENBIS_COOKIE, sessionToken);
         cookie.setPath("/");
         response.addCookie(cookie);
         response.sendRedirect(redirectUrl);
@@ -189,7 +209,7 @@ public class SingleSignOnServlet extends AbstractServlet
         Cookie[] cookies = request.getCookies();
         for (Cookie cookie : cookies)
         {
-            if (cookie.getName().equals("openbis"))
+            if (cookie.getName().equals(OPENBIS_COOKIE))
             {
                 cookie.setValue("");
                 cookie.setPath("/");
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/OpenBisSessionManager.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/OpenBisSessionManager.java
index 4b91a77070c1684feb0f74f85605540ca55b45eb..5934df568036cf9b0dd5edb32385a2bf2bfe26f3 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/OpenBisSessionManager.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/OpenBisSessionManager.java
@@ -16,6 +16,9 @@
 
 package ch.systemsx.cisd.openbis.generic.server;
 
+import java.util.HashSet;
+import java.util.Set;
+
 import ch.systemsx.cisd.authentication.DefaultSessionManager;
 import ch.systemsx.cisd.authentication.IAuthenticationService;
 import ch.systemsx.cisd.authentication.ILogMessagePrefixGenerator;
@@ -36,14 +39,14 @@ public class OpenBisSessionManager extends DefaultSessionManager<Session> implem
 {
     private static final int DEFAULT_SESSION_EXPIRATION_PERIOD_FOR_NO_LOGIN = 10;
 
-    private static final int getSessionExpirationPeriodMinutesForNoLogin(String property)
+    private static final int parseAsIntOrReturnDefaultValue(String string, int defaultValue)
     {
         try
         {
-            return Integer.parseInt(property);
+            return Integer.parseInt(string);
         } catch (NumberFormatException ex)
         {
-            return DEFAULT_SESSION_EXPIRATION_PERIOD_FOR_NO_LOGIN;
+            return defaultValue;
         }
     }
 
@@ -51,12 +54,17 @@ public class OpenBisSessionManager extends DefaultSessionManager<Session> implem
 
     private String userForAnonymousLogin;
 
+    private int maxNumberOfSessionsPerUser;
+
+    private Set<String> usersWithUnrestrictedNumberOfSessions = new HashSet<>();
+
     public OpenBisSessionManager(ISessionFactory<Session> sessionFactory, ILogMessagePrefixGenerator<Session> prefixGenerator,
             IAuthenticationService authenticationService, IRemoteHostProvider remoteHostProvider, int sessionExpirationPeriodMinutes,
             String sessionExpirationPeriodMinutesForNoLogin, boolean tryEmailAsUserName, IDAOFactory daoFactory)
     {
         super(sessionFactory, prefixGenerator, authenticationService, remoteHostProvider, sessionExpirationPeriodMinutes,
-                getSessionExpirationPeriodMinutesForNoLogin(sessionExpirationPeriodMinutesForNoLogin), tryEmailAsUserName);
+                parseAsIntOrReturnDefaultValue(sessionExpirationPeriodMinutesForNoLogin, DEFAULT_SESSION_EXPIRATION_PERIOD_FOR_NO_LOGIN),
+                tryEmailAsUserName);
         this.daoFactory = daoFactory;
     }
 
@@ -68,6 +76,37 @@ public class OpenBisSessionManager extends DefaultSessionManager<Session> implem
                 sessionExpirationPeriodMinutesForNoLogin, false, daoFactory);
     }
 
+    @Override
+    protected int getMaxNumberOfSessionsFor(String user)
+    {
+        if (usersWithUnrestrictedNumberOfSessions.contains(user))
+        {
+            return 0;
+        }
+        PersonPE person = daoFactory.getPersonDAO().tryFindPersonByUserId(user);
+        if (person != null && person.isSystemUser())
+        {
+            return 0;
+        }
+        return maxNumberOfSessionsPerUser;
+    }
+
+    public void setMaxNumberOfSessionsPerUser(String number)
+    {
+        maxNumberOfSessionsPerUser = parseAsIntOrReturnDefaultValue(number, 1);
+    }
+
+    public void setUsersWithUnrestrictedNumberOfSessions(String users)
+    {
+        if (users.startsWith("${") == false)
+        {
+            for (String user : users.split(","))
+            {
+                usersWithUnrestrictedNumberOfSessions.add(user.trim());
+            }
+        }
+    }
+
     @Override
     public void updateAllSessions()
     {
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/public/resources/js/openbis.js b/openbis/source/java/ch/systemsx/cisd/openbis/public/resources/js/openbis.js
index 07704d7a495f5313e5ae0f287f922367dfe78f2c..4d485fede1580cbe0f689a84fe0ffd8e725ae80a 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/public/resources/js/openbis.js
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/public/resources/js/openbis.js
@@ -312,7 +312,7 @@ openbis.prototype.login = function(userId, userPassword, action) {
 		success: 
 			function(loginResponse) {
 				if(loginResponse.error){
-					alert("Login failed");
+					alert("Login failed: " + loginResponse.error.message);
 				}else{
 					openbisObj._internal.sessionToken = loginResponse.result;
 					openbisObj.rememberSession();
diff --git a/openbis/source/java/genericApplicationContext.xml b/openbis/source/java/genericApplicationContext.xml
index face9a10576a97b196023a4823b4613205d50c94..745156dc98404b2588278e8488df3c4015d956a5 100644
--- a/openbis/source/java/genericApplicationContext.xml
+++ b/openbis/source/java/genericApplicationContext.xml
@@ -151,6 +151,8 @@
 		<constructor-arg value="true" />
 		<constructor-arg ref="dao-factory" />
 		<property name="userForAnonymousLogin" value="${user-for-anonymous-login}" />
+		<property name="maxNumberOfSessionsPerUser" value="${max-number-of-sessions-per-user}" />
+		<property name="usersWithUnrestrictedNumberOfSessions" value="${users-with-unrestricted-number-of-sessions}" />
 	</bean>
 
 	<bean id="display-settings-provider"
diff --git a/openbis/source/java/service.properties b/openbis/source/java/service.properties
index 9094f3ce5928771f42d13cba4611a766ef4c289d..aba585ceb49aed9663e64929fdd1f2d26f29fea1 100644
--- a/openbis/source/java/service.properties
+++ b/openbis/source/java/service.properties
@@ -2,6 +2,7 @@ authentication-service = dummy-authentication-service
 
 # The time after which an inactive session is expired by the service (in minutes).
 session-timeout = 720 
+max-number-of-sessions-per-user = 0
 
 session-workspace-root-dir = targets/session-workspace
 
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/shared/util/SimplePropertyValidatorTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/shared/util/SimplePropertyValidatorTest.java
index 599b46bc2ae77f9706510f8e10557a81837b0876..19b825d9464490448c8b522e805ded4b401c6dd1 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/shared/util/SimplePropertyValidatorTest.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/shared/util/SimplePropertyValidatorTest.java
@@ -101,7 +101,7 @@ public class SimplePropertyValidatorTest
                     "M/d/yy HH:mm\n" +
                     "yyyy-MM-dd HH:mm:ss Z\n" +
                     "yyyy-MM-dd'T'HH:mm:ssX\n" +
-                    "yyyy-MM-dd HH:mm:ss ZZZ\n" +
+                    "yyyy-MM-dd HH:mm:ss Z\n" +
                     "yyyy-MM-dd'T'HH:mm:ssXXX]'.");
         }
     }
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/initialize-master-data.py b/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/initialize-master-data.py
index d76ed8acd11035a28bd2b1b8c72d737f68e93147..be96493467fe5f9cb9b1448029cf3e59c0af9876 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/initialize-master-data.py
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/initialize-master-data.py
@@ -25,9 +25,9 @@ helper = MasterDataRegistrationHelper(sys.path)
 api = CommonServiceProvider.getApplicationContext().getBean(ApplicationServerApi.INTERNAL_SERVICE_NAME)
 sessionToken = api.loginAsSystem()
 props = CustomASServiceExecutionOptions().withParameter('xls', helper.listXlsByteArrays()) \
-    .withParameter('xls_name', 'ELN-LIMS-LIFE-SCIENCES').withParameter('update_mode', 'IGNORE_EXISTING') \
+    .withParameter('xls_name', 'ELN-LIMS-LIFE-SCIENCES').withParameter('update_mode', 'UPDATE_IF_EXISTS') \
     .withParameter('scripts', helper.getAllScripts())
-result = api.executeCustomASService(sessionToken, CustomASServiceCode("xls-import-api"), props)
+result = api.executeCustomASService(sessionToken, CustomASServiceCode("xls-import-api"), props);
 print("======================== master-data xls ingestion result ========================")
 print(result)
 print("======================== master-data xls ingestion result ========================")
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/master-data/data-model.xls b/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/master-data/data-model.xls
index e2755043112873eaa41408f7a01ab4e152444d93..8b219a0b5747b886494c221c82bd3f3f1f470262 100644
Binary files a/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/master-data/data-model.xls and b/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/master-data/data-model.xls differ
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/initialize-master-data.py b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/initialize-master-data.py
index 078f2ae70bab91de09d7b2d35c21281433dc731d..e3eaee0601ed6c89d3e53f6372cf7ed6e572ce6a 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/initialize-master-data.py
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/initialize-master-data.py
@@ -16,7 +16,6 @@
 # MasterDataRegistrationTransaction Class
 from ch.ethz.sis.openbis.generic.server.asapi.v3 import ApplicationServerApi
 from ch.systemsx.cisd.openbis.generic.server import CommonServiceProvider
-from ch.systemsx.cisd.openbis.generic.server import ComponentNames
 from ch.ethz.sis.openbis.generic.asapi.v3.dto.service.id import CustomASServiceCode
 from ch.ethz.sis.openbis.generic.asapi.v3.dto.service import CustomASServiceExecutionOptions
 from ch.systemsx.cisd.openbis.generic.server.jython.api.v1.impl import MasterDataRegistrationHelper
@@ -26,18 +25,9 @@ helper = MasterDataRegistrationHelper(sys.path)
 api = CommonServiceProvider.getApplicationContext().getBean(ApplicationServerApi.INTERNAL_SERVICE_NAME)
 sessionToken = api.loginAsSystem()
 props = CustomASServiceExecutionOptions().withParameter('xls', helper.listXlsByteArrays())\
-    .withParameter('xls_name', 'ELN-LIMS').withParameter('update_mode', 'IGNORE_EXISTING')\
+    .withParameter('xls_name', 'ELN-LIMS').withParameter('update_mode', 'UPDATE_IF_EXISTS')\
     .withParameter('scripts', helper.getAllScripts())
 result = api.executeCustomASService(sessionToken, CustomASServiceCode("xls-import-api"), props);
-# Updating MULTILINE_VARCHAR to use "Word Processor" for all Properties
-daoFactory = CommonServiceProvider.getApplicationContext().getBean(ComponentNames.DAO_FACTORY);
-currentSession = daoFactory.getSessionFactory().getCurrentSession();
-SQL = "UPDATE property_types SET meta_data = cast(:meta_data AS jsonb) WHERE id IN (SELECT id FROM property_types WHERE daty_id = (SELECT id FROM data_types WHERE code = 'MULTILINE_VARCHAR'))";
-meta_data = "{ \"custom_widget\" : \"Word Processor\" }";
-sqlQuery = currentSession.createSQLQuery(SQL);
-sqlQuery.setParameter("meta_data", meta_data);
-sqlQuery.executeUpdate();
-#
 print("======================== master-data xls ingestion result ========================")
 print(result)
 print("======================== master-data xls ingestion result ========================")
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/master-data/data-model.xls b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/master-data/data-model.xls
index c061f53d70d87bbbb9cf15446655855d2d1bf0ce..16332eb71f3a9ddbf34d818a04319e5fb81200c1 100644
Binary files a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/master-data/data-model.xls and b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/master-data/data-model.xls differ
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/css/style.css b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/css/style.css
index aab016d67217035d3eccdf3be19dd960a8d226f4..febb7e52dbfb12562b6e7af2bf6f2ebd9bfdfd63 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/css/style.css
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/css/style.css
@@ -778,11 +778,17 @@ span.fancytree-custom-icon {
   box-sizing: initial !important;
 }
 
+.jexcel_toolbar {
+    position: sticky;
+    top: 0px;
+    z-index : 800;
+}
+
 .jcolor-content > table > tr > td {
     padding : 7px !important;
 }
 
+
 .jexcel > thead > tr > td {
-    position : relative !important;
     z-index : auto !important;
 }
\ No newline at end of file
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/config/Profile.js b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/config/Profile.js
index 8b1a0d7ebb7f7f357ea1016d155394606e58f0fd..b713b303923d04fa508d679c6db1851f4d2ce138 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/config/Profile.js
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/config/Profile.js
@@ -135,7 +135,6 @@ $.extend(DefaultProfile.prototype, {
 //				"ADMIN-BS-MBPR28.D.ETHZ.CH-E96954A7" : "http://localhost:8080/download"
 		}
 		this.singleSignOnUrlTemplate = null;
-		this.singleSignOnUrlLogoutTemplate = null;
 		this.singleSignOnLinkLabel = 'Single Sign On Login';
 		
         this.customWidgetSettings = {};
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/controllers/MainController.js b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/controllers/MainController.js
index 1294aec2ba78fe8eec0fbf4992a436edea3db223..a4c8633e158bed6a2a2c053e454cc75e19aeff45 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/controllers/MainController.js
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/controllers/MainController.js
@@ -96,9 +96,13 @@ function MainController(profile) {
 		if(data.result == null){
 			$("#username").focus();
 			var callback = function() {Util.unblockUI();};
-			Util.showUserError('The given username or password is not correct.', callback);
+			var msg = 'The given username or password is not correct.';
+			if (data.error && data.error.message) {
+				msg = data.error.message;
+			}
+			Util.showUserError(msg, callback);
 			this.serverFacade.doIfFileAuthenticationService((function() {
-	            this._enablePasswordResetLink();
+				this._enablePasswordResetLink();
 			}).bind(this));
 			return;
 		}
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/util/FormUtil.js b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/util/FormUtil.js
index 19a34eb8422cac3228815ef88103b4e019eafa83..7ed58572f255491f4f021d23a13582c4512fab74 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/util/FormUtil.js
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/util/FormUtil.js
@@ -274,15 +274,20 @@ var FormUtil = new function() {
 		return $component;
 	}
 	
-	this.getExperimentTypeDropdown = function(id, isRequired) {
+	this.getExperimentTypeDropdown = function(id, isRequired, defaultValue) {
 		var experimentTypes = this.profile.allExperimentTypes;
 		
-		var $component = $("<select>", {"id" : id, class : 'form-control'});
+		var $component = $("<select>", {"id" : id, class : "form-control"});
 		if (isRequired) {
-			$component.attr('required', '');
+			$component.attr("required", "");
 		}
-		
-		$component.append($("<option>").attr('value', '').attr('selected', '').text("Select an " + ELNDictionary.getExperimentDualName() + " type"));
+
+		var $emptyOption = $("<option>").attr("value", "").attr('disabled', '').text("Select an " + ELNDictionary.getExperimentDualName() + " type");
+		if (!defaultValue || defaultValue === "") {
+			$emptyOption.attr("selected", "");
+		}
+
+		$component.append($emptyOption);
 		for(var i = 0; i < experimentTypes.length; i++) {
 			var experimentType = experimentTypes[i];
 			if(profile.isExperimentTypeHidden(experimentType.code)) {
@@ -294,12 +299,22 @@ var FormUtil = new function() {
 			if(description !== "") {
 				label += " (" + description + ")";
 			}
-			
-			$component.append($("<option>").attr('value',experimentType.code).text(label));
+
+			var $option = $("<option>").attr("value", experimentType.code).text(label);
+			if (experimentType.code === defaultValue) {
+				$option.attr("selected", "");
+			}
+			$component.append($option);
 		}
 		Select2Manager.add($component);
 		return $component;
-	}
+	};
+
+	this.getInlineExperimentTypeDropdown = function(id, isRequired, defaultValue) {
+		var $wrapper = $("<span>", { class : "dropdown" });
+		$wrapper.append(this.getExperimentTypeDropdown(id, isRequired, defaultValue));
+		return $wrapper;
+	};
 	
 	this.getSpaceDropdown = function(id, isRequired) {
 		var spaces = this.profile.allSpaces;
@@ -351,7 +366,7 @@ var FormUtil = new function() {
 		
 		$component.attr('required', '');
 		
-		$component.append($("<option>").attr('value', '').attr('selected', '').attr('disabled', '').text('Select a dataset type'));
+		$component.append($("<option>").attr('value', '').attr('selected', '').text('Select a dataset type'));
 		
 		for (var i = 0; i < dataSetTypes.length; i++) {
 			var datasetType = dataSetTypes[i];
@@ -779,6 +794,8 @@ var FormUtil = new function() {
 		}
 		
 		$component.append($("<option>").attr('value', '').attr('selected', '').attr('disabled', '').text(alt));
+		$component.append($("<option>").attr('value', '').text('(empty)'));
+
 		for(var i = 0; i < terms.length; i++) {
 			$component.append($("<option>").attr('value',terms[i].code).text(terms[i].label));
 		}
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/util/JExcelEditorManager.js b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/util/JExcelEditorManager.js
index 2ccaf756822bc54ac1990f91246f2f71b7f048be..4c1ab4c4bf814f16365bc0b97ff969d0d85277be 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/util/JExcelEditorManager.js
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/util/JExcelEditorManager.js
@@ -4,16 +4,28 @@ var JExcelEditorManager = new function() {
 
     this.getOnChange = function(guid, propertyCode, entity) {
         var _this = this;
-        return function() {
+        return function(el, record, x, y, value) {
             var jExcelEditor = _this.jExcelEditors[guid];
             if(jExcelEditor) {
+                // Change column width
+                var columnWidth = parseInt(jExcelEditor.getWidth(x));
+                var td = el.children[1].children[0].children[2].children[y].children[parseInt(x)+1];
+                var columnScrollWidth = td.scrollWidth;
+
+                if(columnScrollWidth > columnWidth) {
+                    jExcelEditor.setWidth(x, columnScrollWidth + 10);
+                }
+
+                // Save Editor
                 var data = jExcelEditor.getData();
                 var style = jExcelEditor.getStyle();
                 var meta = jExcelEditor.getMeta();
+                var width = jExcelEditor.getWidth();
                 var jExcelEditorValue = {
                     data : data,
                     style : style,
-                    meta : meta
+                    meta : meta,
+                    width : width
                 }
                 entity.properties[propertyCode] = "<DATA>" + window.btoa(JSON.stringify(jExcelEditorValue)) + "</DATA>";
             }
@@ -108,7 +120,7 @@ var JExcelEditorManager = new function() {
 	    var data = [];
 	    var style = null;
 	    var meta = null;
-
+        var width = null;
 	    if(entity.properties && entity.properties[propertyCode]) {
 	        var jExcelEditorValueAsStringWithTags = entity.properties[propertyCode];
 	        var jExcelEditorValue = null;
@@ -120,6 +132,7 @@ var JExcelEditorManager = new function() {
 	            data = jExcelEditorValue.data;
 	            style = jExcelEditorValue.style;
 	            meta = jExcelEditorValue.meta;
+	            width = jExcelEditorValue.width;
 	        }
 	    }
 
@@ -137,6 +150,10 @@ var JExcelEditorManager = new function() {
                     onchangemeta: null
         };
 
+        if(width) {
+            options.colWidths = width;
+        }
+
         if(mode === FormMode.VIEW) {
             options.allowInsertRow = false;
             options.allowManualInsertRow = false;
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/ProjectForm/ProjectFormController.js b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/ProjectForm/ProjectFormController.js
index 96b88be43f7e8d24f7e437d969416bd90e98363e..e41f3e82aaab0443bcaf0bf87af6d5833fd43962 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/ProjectForm/ProjectFormController.js
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/ProjectForm/ProjectFormController.js
@@ -125,4 +125,12 @@ function ProjectFormController(mainController, mode, project) {
 			Util.showError("No DSS available.", function() {Util.unblockUI();});
 		}
 	}
+
+	this.getDefaultSpaceValue = function (key, callback) {
+		this._mainController.serverFacade.getSetting(key, callback);
+	};
+
+	this.setDefaultSpaceValue = function (key, value) {
+		this._mainController.serverFacade.setSetting(key, value);
+	};
 }
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/ProjectForm/ProjectFormView.js b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/ProjectForm/ProjectFormView.js
index 00426c6e9b8b7aca4cbfbc3fd293cdacd28ba00a..67397978ff96378c0be5e27ba058d66d09281d25 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/ProjectForm/ProjectFormView.js
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/ProjectForm/ProjectFormView.js
@@ -61,36 +61,47 @@ function ProjectFormView(projectFormController, projectFormModel) {
 		//
 		var toolbarModel = [];
 		if(this._projectFormModel.mode === FormMode.VIEW) {
-			var showSelectExperimentType = function() {
-				var $dropdown = FormUtil.getExperimentTypeDropdown("experimentTypeDropdown", true);
-				Util.showDropdownAndBlockUI("experimentTypeDropdown", $dropdown);
-				
-				$("#experimentTypeDropdown").on("change", function(event) {
-					var experimentTypeCode = $("#experimentTypeDropdown")[0].value;
-					_this._projectFormController.createNewExperiment(experimentTypeCode);
-				});
-				
-				$("#experimentTypeDropdownCancel").on("click", function(event) { 
-					Util.unblockUI();
-				});
-			}
+			var experimentKindName = ELNDictionary.getExperimentKindName(projectIdentifier);
 			if (_this._allowedToCreateExperiments()) {
 				//Create Experiment
-				var isDefaultExperimentPressent = mainController.profile.getExperimentTypeForExperimentTypeCode("DEFAULT_EXPERIMENT") != null;
-				if(isDefaultExperimentPressent) {
-					var $createExpBtn = FormUtil.getButtonWithIcon("glyphicon-plus", function() {
-						if(profile.isInventorySpace(_this._projectFormModel.project.spaceCode)) {
+				var isDefaultExperimentPresent = mainController.profile.getExperimentTypeForExperimentTypeCode("DEFAULT_EXPERIMENT") != null;
+				if(isDefaultExperimentPresent) {
+					var newExperimentTypeDropdownId = "new-experiment-type-dropdown";
+					var defaultValueKey = entityPath.text() + "-FORM-" + newExperimentTypeDropdownId;
+
+					this._projectFormController.getDefaultSpaceValue(defaultValueKey, function (settingsValue) {
+						var defaultValue;
+						if (settingsValue) {
+							defaultValue = settingsValue;
+						} else if (profile.isInventorySpace(_this._projectFormModel.project.spaceCode)) {
 							var experimentType = profile.getExperimentTypeForExperimentTypeCode(_this._projectFormModel.project.spaceCode);
-							if(experimentType) {
-								_this._projectFormController.createNewExperiment(_this._projectFormModel.project.spaceCode);
+							if (experimentType) {
+								defaultValue = _this._projectFormModel.project.spaceCode;
 							} else {
-								showSelectExperimentType();
+								defaultValue = "";
 							}
 						} else {
-							_this._projectFormController.createNewExperiment("DEFAULT_EXPERIMENT");
+							defaultValue = "DEFAULT_EXPERIMENT";
+						}
+
+						$("option[value=" + defaultValue + "]").prop("selected", true);
+					});
+
+					var $experimentTypeDropdown = FormUtil.getInlineExperimentTypeDropdown(newExperimentTypeDropdownId, true);
+					var $createExpBtn = FormUtil.getButtonWithIcon("glyphicon-plus", function() {
+						var experimentTypeCode = $("#" + newExperimentTypeDropdownId)[0].value;
+
+						if (experimentTypeCode && experimentTypeCode !== "") {
+							_this._projectFormController.createNewExperiment(experimentTypeCode);
 						}
 					});
-					toolbarModel.push({ component : $createExpBtn, tooltip: "Create " + ELNDictionary.getExperimentKindName(projectIdentifier) });
+
+					toolbarModel.push({ component: $createExpBtn, tooltip: "Create " + experimentKindName });
+					toolbarModel.push({ component: $experimentTypeDropdown, tooltip: "Type of the " + experimentKindName + " to create" });
+
+					$experimentTypeDropdown.change(function(event) {
+						_this._projectFormController.setDefaultSpaceValue(defaultValueKey, $(event.target).val());
+					});
 				}
 			}
 			if(_this._allowedToEdit()) {
@@ -142,8 +153,22 @@ function ProjectFormView(projectFormController, projectFormModel) {
                 toolbarModel.push({ component : $freezeButton, tooltip: isEntityFrozenTooltip });
             }
 
+			var showSelectExperimentType = function() {
+				var $dropdown = FormUtil.getExperimentTypeDropdown("experimentTypeDropdown", true);
+				Util.showDropdownAndBlockUI("experimentTypeDropdown", $dropdown);
+
+				$("#experimentTypeDropdown").on("change", function(event) {
+					var experimentTypeCode = $("#experimentTypeDropdown")[0].value;
+					_this._projectFormController.createNewExperiment(experimentTypeCode);
+				});
+
+				$("#experimentTypeDropdownCancel").on("click", function(event) {
+					Util.unblockUI();
+				});
+			};
+
 			//Operations
-			var $operationsMenu = FormUtil.getOperationsMenu([{ label: "Create " + ELNDictionary.getExperimentKindName(projectIdentifier), event: function() {
+			var $operationsMenu = FormUtil.getOperationsMenu([{ label: "Create " + experimentKindName, event: function() {
 				showSelectExperimentType();
 			}}]);
 			toolbarModel.push({ component : $operationsMenu, tooltip: "Extra operations" });
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/SampleForm/SampleFormView.js b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/SampleForm/SampleFormView.js
index a4b303cd98b51654a4aa5817221b0ef10342324e..f6b3bcf2857e4c4d2b8e96ffa4a9b9143964d8da 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/SampleForm/SampleFormView.js
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/SampleForm/SampleFormView.js
@@ -361,6 +361,7 @@ function SampleFormView(sampleFormController, sampleFormModel) {
                                     sample = results.objects[rIdx];
                                 }
                             }
+                            _this._sampleFormModel.sample.properties = sample.properties;
 
                             if(_this._sampleFormModel.views.header) {
                                 _this._sampleFormModel.views.header.empty();
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/SideMenu/SideMenuWidgetView.js b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/SideMenu/SideMenuWidgetView.js
index c7f77e5c4cd57151ba75599ade67fbfcd3b60f52..ecd57517a2c01f717c852ea89b205c396594b486 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/SideMenu/SideMenuWidgetView.js
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/views/SideMenu/SideMenuWidgetView.js
@@ -107,12 +107,7 @@ function SideMenuWidgetView(sideMenuWidgetController, sideMenuWidgetModel) {
         
         var logoutButton = FormUtil.getButtonWithIcon("glyphicon-off", function() {
             $('body').addClass('bodyLogin');
-            var logoutTemplate = mainController.profile.singleSignOnUrlLogoutTemplate;
-            if (logoutTemplate) {
-                window.location = logoutTemplate.replace("${host}", window.location.hostname);
-            } else {
-                mainController.serverFacade.logout();
-            }
+            mainController.serverFacade.logout();
          });
         
         var $searchForm = $("<form>", { "onsubmit": "return false;" })
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jexcel/VERSION.txt b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jexcel/VERSION.txt
index 4e48a183b1e04b13e790490acc20f37e0b25afd3..ba5b1b9b6e69d49a787cdf726c7f9f53f98e6279 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jexcel/VERSION.txt
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jexcel/VERSION.txt
@@ -1 +1 @@
-3.4.1 from Master 2019.08.08
\ No newline at end of file
+3.4.4 from Master 2019.08.27
\ No newline at end of file
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jexcel/jexcel.css b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jexcel/jexcel.css
index 55d0153866db4889f77742f1f0984696bbf9eb29..8ee0a9794bca5a00ed1026ceb7c6dc11a8564b8d 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jexcel/jexcel.css
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jexcel/jexcel.css
@@ -1,5 +1,5 @@
 /**
- * (c) jExcel v3.4.1
+ * (c) jExcel v3.4.4
  * 
  * Author: Paul Hodel <paul.hodel@gmail.com>
  * Website: https://bossanova.uk/jexcel/
@@ -76,6 +76,11 @@
     z-index:2000;
 }
 
+.with-toolbar .jexcel > thead > tr > td
+{
+    top:42px;
+}
+
 .jexcel > thead.draggable > tr > td::before
 {
     content:'\00a0';
@@ -635,44 +640,21 @@
     background-color:#ddd;
 }
 
-/*.copying
-{
-    border-top:1px solid #ccc !important;
-    border-left:1px solid #ccc !important;
-    border-right:1px solid #fff !important;
-    border-bottom:1px solid #fff !important;
-}
-
-.copying-top
-{
-    border-top:1px solid transparent !important;
-}
-
-.copying-bottom
+.jexcel_hidden_index tr > td:first-child, .jexcel_hidden_index colgroup > col:first-child
 {
-    border-bottom:1px solid transparent !important;
-}
-
-.copying-left
-{
-    border-left:1px solid transparent !important;
-}
-
-.copying-right
-{
-    border-right:1px solid transparent !important;
+    display:none;
 }
 
-.copying
+.jexcel_border
 {
-    background: linear-gradient(white, white) padding-box, repeating-linear-gradient(-45deg, black 0, black 25%, transparent 0, transparent 50%) 0 / .6em .6em !important;
-    animation: ants 12s linear infinite;
+    position:absolute;
+    border:1px solid transparent;
+    pointer-events: none;
 }
 
-@keyframes ants
+.jexcel_copying
 {
-    to
-    {
-        background-position: 50% 50%
-    }
-}*/
+    border:1px solid transparent;
+    border-image: url('data:image/gif;base64,R0lGODlhCgAKAJECAAAAAP///////wAAACH/C05FVFNDQVBFMi4wAwEAAAAh/wtYTVAgRGF0YVhNUDw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OEI5RDc5MTFDNkE2MTFFM0JCMDZEODI2QTI4MzJBOTIiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6OEI5RDc5MTBDNkE2MTFFM0JCMDZEODI2QTI4MzJBOTIiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuZGlkOjAyODAxMTc0MDcyMDY4MTE4MDgzQzNDMjA5MzREQ0ZDIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjAyODAxMTc0MDcyMDY4MTE4MDgzQzNDMjA5MzREQ0ZDIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+Af/+/fz7+vn49/b19PPy8fDv7u3s6+rp6Ofm5eTj4uHg397d3Nva2djX1tXU09LR0M/OzczLysnIx8bFxMPCwcC/vr28u7q5uLe2tbSzsrGwr66trKuqqainpqWko6KhoJ+enZybmpmYl5aVlJOSkZCPjo2Mi4qJiIeGhYSDgoGAf359fHt6eXh3dnV0c3JxcG9ubWxramloZ2ZlZGNiYWBfXl1cW1pZWFdWVVRTUlFQT05NTEtKSUhHRkVEQ0JBQD8+PTw7Ojk4NzY1NDMyMTAvLi0sKyopKCcmJSQjIiEgHx4dHBsaGRgXFhUUExIREA8ODQwLCgkIBwYFBAMCAQAAIfkEBQoAAgAsAAAAAAoACgAAAhWEERkn7W3ei7KlagMWF/dKgYeyGAUAIfkEBQoAAgAsAAAAAAoACgAAAg+UYwLJ7RnQm7QmsCyVKhUAIfkEBQoAAgAsAAAAAAoACgAAAhCUYgLJHdiinNSAVfOEKoUCACH5BAUKAAIALAAAAAAKAAoAAAIRVISAdusPo3RAzYtjaMIaUQAAIfkEBQoAAgAsAAAAAAoACgAAAg+MDiem7Q8bSLFaG5il6xQAIfkEBQoAAgAsAAAAAAoACgAAAg+UYRLJ7QnQm7SmsCyVKhUAIfkEBQoAAgAsAAAAAAoACgAAAhCUYBLJDdiinNSEVfOEKoECACH5BAUKAAIALAAAAAAKAAoAAAIRFISBdusPo3RBzYsjaMIaUQAAOw==') 8% repeat;
+    pointer-events: none;
+}
\ No newline at end of file
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jexcel/jexcel.js b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jexcel/jexcel.js
index eb9fd03d45440fc121bae03209cdf633dc6a8265..db91aa915d0188ac02cd4b84a1371e6981d07f93 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jexcel/jexcel.js
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/lib/jexcel/jexcel.js
@@ -1,5 +1,5 @@
 /**
- * (c) jExcel v3.4.1
+ * (c) jExcel v3.4.4
  * 
  * Author: Paul Hodel <paul.hodel@gmail.com>
  * Website: https://bossanova.uk/jexcel/
@@ -111,10 +111,14 @@ var jexcel = (function(el, options) {
         meta: null,
         // Style
         style:null,
+        // Execute formulas
+        parseFormulas:true,
+        autoIncrement:true,
         // Event handles
         onload:null,
         onchange:null,
         onbeforechange:null,
+        onafterchanges:null,
         onbeforeinsertrow: null,
         oninsertrow:null,
         onbeforeinsertcolumn: null,
@@ -175,7 +179,7 @@ var jexcel = (function(el, options) {
             noCellsSelected: 'No cells selected',
         },
         // About message
-        about:"jExcel CE Spreadsheet\nVersion 3.4.1\nAuthor: Paul Hodel <paul.hodel@gmail.com>\nWebsite: https://jexcel.net/v3",
+        about:"jExcel CE Spreadsheet\nVersion 3.4.4\nAuthor: Paul Hodel <paul.hodel@gmail.com>\nWebsite: https://jexcel.net/v3",
     };
 
     // Loading initial configuration from user
@@ -220,6 +224,7 @@ var jexcel = (function(el, options) {
     obj.style = [];
     obj.meta = [];
     obj.data = null;
+    obj.border = {};
 
     // Internal controllers
     obj.cursor = null;
@@ -516,9 +521,6 @@ var jexcel = (function(el, options) {
         // Fullscreen
         if (obj.options.fullscreen == true) {
             el.classList.add('fullscreen');
-            if (obj.options.toolbar) {
-                el.classList.add('with-toolbar');
-            }
         } else {
             // Overflow
             if (obj.options.tableOverflow == true) {
@@ -533,6 +535,11 @@ var jexcel = (function(el, options) {
             }
         }
 
+        // With toolbars
+        if (obj.options.toolbar) {
+            el.classList.add('with-toolbar');
+        }
+
         // Actions
         if (obj.options.columnDrag == true) {
             obj.thead.classList.add('draggable');
@@ -830,7 +837,7 @@ var jexcel = (function(el, options) {
                 td.appendChild(img);
             }
         } else {
-            if ((''+value).substr(0,1) == '=') {
+            if ((''+value).substr(0,1) == '=' && obj.options.parseFormulas == true) {
                 value = obj.executeFormula(value, i, j)
             }
             if (obj.options.columns[i].mask) {
@@ -1469,6 +1476,13 @@ var jexcel = (function(el, options) {
                 }
             }
 
+            // On edition end
+            if (! obj.ignoreEvents) {
+                if (typeof(obj.options.oneditionend) == 'function') {
+                    obj.options.oneditionend(el, cell, x, y, value, save);
+                }
+            }
+
             // Update values
             var ignoreEvents = obj.ignoreEvents ? true : false;
             var ignoreHistory = obj.ignoreHistory ? true : false;
@@ -1508,6 +1522,13 @@ var jexcel = (function(el, options) {
 
             // Restore value
             cell.innerHTML = obj.edition[1];
+
+            // On edition end
+            if (! obj.ignoreEvents) {
+                if (typeof(obj.options.oneditionend) == 'function') {
+                    obj.options.oneditionend(el, cell, x, y, value, save);
+                }
+            }
         }
 
         // Remove editor class
@@ -1515,14 +1536,37 @@ var jexcel = (function(el, options) {
 
         // Finish edition
         obj.edition = null;
+    }
 
-        // On edition end
-        if (! obj.ignoreEvents) {
-            if (typeof(obj.options.oneditionend) == 'function') {
-                obj.options.oneditionend(el, cell, x, y, value);
-            }
-        }
-    },
+    /**
+     * Get the cell object
+     * 
+     * @param object cell
+     * @return string value
+     */
+    obj.getCell = function(cell) {
+        // Convert in case name is excel liked ex. A10, BB92
+        cell = jexcel.getIdFromColumnName(cell, true);
+        var x = cell[0];
+        var y = cell[1];
+
+        return obj.records[y][x];
+    }
+
+    /**
+     * Get label
+     * 
+     * @param object cell
+     * @return string value
+     */
+    obj.getLabel = function(cell) {
+        // Convert in case name is excel liked ex. A10, BB92
+        cell = jexcel.getIdFromColumnName(cell, true);
+        var x = cell[0];
+        var y = cell[1];
+
+        return obj.records[y][x].innerHTML;
+    }
 
     /**
      * Get the value from a cell
@@ -1638,6 +1682,13 @@ var jexcel = (function(el, options) {
 
         // Update table with custom configurations if applicable
         obj.updateTable();
+
+        // On after change
+        if (! obj.ignoreEvents) {
+            if (typeof(obj.options.onafterchanges) == 'function') {
+                obj.options.onafterchanges(el, records, value);
+            }
+        }
     }
 
     /**
@@ -1664,6 +1715,13 @@ var jexcel = (function(el, options) {
 
         // Update table with custom configurations if applicable
         obj.updateTable();
+
+        // On after change
+        if (! obj.ignoreEvents) {
+            if (typeof(obj.options.onafterchanges) == 'function') {
+                obj.options.onafterchanges(el, records, value);
+            }
+        }
     }
 
     /**
@@ -1689,6 +1747,13 @@ var jexcel = (function(el, options) {
                 records:records,
                 selection:obj.selectedCell,
             });
+
+            // On after change
+            if (! obj.ignoreEvents) {
+                if (typeof(obj.options.onafterchanges) == 'function') {
+                    obj.options.onafterchanges(el, records);
+                }
+            }
         }
     }
 
@@ -1710,7 +1775,7 @@ var jexcel = (function(el, options) {
                     var val = obj.options.onbeforechange(el, obj.records[y][x], x, y, value);
 
                     // If you return something this will overwrite the value
-                    if (val != 'undefined') {
+                    if (val != undefined) {
                         value = val;
                     }
                 }
@@ -1776,13 +1841,9 @@ var jexcel = (function(el, options) {
                     }
                 } else {
                     // Update data and cell
-                    if (obj.options.columns[x].autoCasting != false) { 
-                        obj.options.data[y][x] = (value && Number(value) == value) ? Number(value) : value;
-                    } else {
-                        obj.options.data[y][x] = value;
-                    }
+                    obj.options.data[y][x] = value;
                     // Label
-                    if (('' + value).substr(0,1) == '=') {
+                    if (('' + value).substr(0,1) == '='  && obj.options.parseFormulas == true) {
                         value = obj.executeFormula(value, x, y);
                     }
                     if (obj.options.columns[x].mask) {
@@ -1881,7 +1942,7 @@ var jexcel = (function(el, options) {
                         var value = data[posy][posx];
                     }
 
-                    if (value && t0 == t1) {
+                    if (value && t0 == t1 && obj.options.autoIncrement == true) {
                         if (obj.options.columns[i].type == 'text' || obj.options.columns[i].type == 'number') {
                             if ((''+value).substr(0,1) == '=') {
                                 var tokens = value.match(/([A-Z]+[0-9]+)/g);
@@ -1943,6 +2004,42 @@ var jexcel = (function(el, options) {
 
         // Update table with custom configuration if applicable
         obj.updateTable();
+
+        // On after change
+        if (! obj.ignoreEvents) {
+            if (typeof(obj.options.onafterchanges) == 'function') {
+                obj.options.onafterchanges(el, records);
+            }
+        }
+    }
+
+    obj.setBorder = function(x1, y1, x2, y2, border) {
+        if (! obj.border[border]) {
+            obj.border[border] = document.createElement('div');
+            obj.border[border].classList.add('jexcel_border');
+            if (border == 'copying') {
+                obj.border[border].classList.add('jexcel_copying');
+            } else {
+                obj.border[border].style.borderColor = border;
+                //obj.border[border].style.backgroundColor = 'rgba(0,0,0,0.1)';
+            }
+            el.appendChild(obj.border[border]);
+        }
+
+        // Get last cell
+        var first = obj.records[x1][y1].getBoundingClientRect();
+        var x1 = first.left;
+        var y1 = first.top;
+
+        var last = obj.records[x2][y2].getBoundingClientRect();
+        var w1 = (last.left + last.width) - first.left - 2;
+        var h1 = (last.top + last.height) - first.top - 2;
+
+        // Place the corner in the correct place
+        obj.border[border].style.top = y1 + 'px';
+        obj.border[border].style.left = x1 + 'px';
+        obj.border[border].style.width = w1 + 'px';
+        obj.border[border].style.height = h1 + 'px';
     }
 
     /**
@@ -2510,18 +2607,26 @@ var jexcel = (function(el, options) {
     /**
      * Get the row height
      * 
-     * @param row - row number (first column is: 0)
+     * @param row - row number (first row is: 0)
      * @return height - current row height
      */
     obj.getHeight = function(row) {
         if (! row) {
+            // Get height of all rows
+            var data = [];
+            for (var j = 0; j < obj.rows.length; j++) {
+                var h = obj.rows[j].style.height;
+                if (h) {
+                    data[j] = h;
+                }
+            }
         } else {
-            // In case the column is an object
+            // In case the row is an object
             if (typeof(row) == 'object') {
                 row = $(row).getAttribute('data-y');
             }
 
-            data = obj.rows[row].getAttribute('height')
+            var data = obj.rows[row].style.height;
         }
 
         return data;
@@ -3941,14 +4046,14 @@ var jexcel = (function(el, options) {
      * Show index column
      */
     obj.showIndex = function() {
-        obj.colgroupContainer.children[0].width = 40;
+        obj.table.classList.remove('jexcel_hidden_index');
     }
 
     /**
      * Hide index column
      */
     obj.hideIndex = function() {
-        obj.colgroupContainer.children[0].width = 0;
+        obj.table.classList.add('jexcel_hidden_index');
     }
 
     /**
@@ -4108,11 +4213,13 @@ var jexcel = (function(el, options) {
             tokensUpdate(tokens);
         }
 
+        // String
+        var evalstring = '';
+
         // Get tokens
         var tokens = expression.match(/([A-Z]+[0-9]+)/g);
 
         if (tokens) {
-            var evalstring = "";
             for (var i = 0; i < tokens.length; i++) {
                 // Keep chain
                 if (! obj.formula[tokens[i]]) {
@@ -4125,8 +4232,6 @@ var jexcel = (function(el, options) {
 
                 // Do not calculate again
                 if (eval('typeof(' + tokens[i] + ') == "undefined"')) {
-                    // Declaretion
-                    evalstring += "var " + tokens[i] + " = null;";
                     // Coords
                     var position = jexcel.getIdFromColumnName(tokens[i], 1);
                     // Get value
@@ -4142,32 +4247,24 @@ var jexcel = (function(el, options) {
                         value = obj.executeFormula(value, position[0], position[1]);
                     }
                     // Type!
-                    if ((''+value).trim() == '' || value != Number(value)) {
-                        // Trying any formatted number
-                        var number = ('' + value);
-                        var decimal = obj.options.columns[position[0]].decimal || '.';
-                        number = number.split(decimal);
-                        number[0] = number[0].match(/[+-]?[0-9]/g);
-                        if (number[0]) {
-                            number[0] = number[0].join('');
-                        } 
-                        if (number[1]) {
-                            number[1] = number[1].match(/[0-9]*/g).join('');
-                        }
-                        // Got a valid number
-                        if (number[0] && Number(number[0]) >= 0) {
-                            if (! number[1]) {
-                                evalstring += "var " + tokens[i] + " = " + number[0] + ".00;";
+                    if ((''+value).trim() == '') {
+                        // Null
+                        evalstring += "var " + tokens[i] + " = null;";
+                    } else {
+                        if (value == Number(value)) {
+                            // Number
+                            evalstring += "var " + tokens[i] + " = " + value + ";";
+                        } else {
+                            // Trying any formatted number
+                            var number = null;
+                            if (number = obj.parseNumber(value, position[0])) {
+                                // Render as number
+                                evalstring += "var " + tokens[i] + " = " + number + ";";
                             } else {
-                                evalstring += "var " + tokens[i] + " = " + number[0] + '.' + number[1] + ";";
+                                // Render as string
+                                evalstring += "var " + tokens[i] + " = '" + value + "';";
                             }
-                        } else {
-                            // Render as string
-                            evalstring += "var " + tokens[i] + " = '" + value + "';";
                         }
-                    } else {
-                        // Number
-                        evalstring += "var " + tokens[i] + " = " + value + ";";
                     }
                 }
             }
@@ -4185,6 +4282,38 @@ var jexcel = (function(el, options) {
         return res;
     }
 
+    /**
+     * Trying to extract a number from a string
+     **/
+    obj.parseNumber = function(value, columnNumber) {
+        // Decimal point
+        var decimal = columnNumber && obj.options.columns[columnNumber].decimal ? obj.options.columns[columnNumber].decimal : '.';
+
+        // Parse both parts of the number
+        var number = ('' + value);
+        number = number.split(decimal);
+        number[0] = number[0].match(/[+-]?[0-9]/g);
+        if (number[0]) {
+            number[0] = number[0].join('');
+        } 
+        if (number[1]) {
+            number[1] = number[1].match(/[0-9]*/g).join('');
+        }
+
+        // Is a valid number 
+        if (number[0] && Number(number[0]) >= 0) {
+            if (! number[1]) {
+                var value = Number(number[0] + '.00');
+            } else {
+                var value = Number(number[0] + '.' + number[1]);
+            }
+        } else {
+            var value = null;
+        }
+
+        return value;
+    }
+
     /**
      * Get row number
      */
@@ -4908,6 +5037,9 @@ var jexcel = (function(el, options) {
                 } else if (quantyOfPages - obj.pageNumber < 5) {
                     var startNumber = quantyOfPages - 9;
                     var finalNumber = quantyOfPages;
+                    if (startNumber < 1) {
+                        startNumber = 1;
+                    }
                 } else {
                     var startNumber = obj.pageNumber - 4;
                     var finalNumber = obj.pageNumber + 5;
@@ -5081,9 +5213,7 @@ var jexcel = (function(el, options) {
                 obj.textarea.value = str;
             }
             obj.textarea.select();
-            jexcel.copyControls.enabled = false;
             document.execCommand("copy");
-            jexcel.copyControls.enabled = true;
         }
 
         // Keep data
@@ -5091,24 +5221,6 @@ var jexcel = (function(el, options) {
         // Keep non visible information
         obj.hashString = obj.hash(obj.textarea.value); 
 
-        // Highlight
-        /*for (var i = 0; i < obj.highlighted.length; i++) {
-            obj.highlighted[i].classList.add('copying');
-
-            if (obj.highlighted[i].classList.contains('highlight-top')) {
-                obj.highlighted[i].classList.add('copying-top');
-            }
-            if (obj.highlighted[i].classList.contains('highlight-right')) {
-                obj.highlighted[i].classList.add('copying-right');
-            }
-            if (obj.highlighted[i].classList.contains('highlight-bottom')) {
-                obj.highlighted[i].classList.add('copying-bottom');
-            }
-            if (obj.highlighted[i].classList.contains('highlight-left')) {
-                obj.highlighted[i].classList.add('copying-left');
-            }
-        }*/
-
         return str;
     }
 
@@ -5165,7 +5277,7 @@ var jexcel = (function(el, options) {
                         var columnName = jexcel.getColumnNameFromId([colIndex, rowIndex]);
                         newStyle[columnName] = style[styleIndex];
                         oldStyle[columnName] = obj.getStyle(columnName);
-                        obj.records[rowIndex][colIndex].style = style[styleIndex];
+                        obj.records[rowIndex][colIndex].setAttribute('style', style[styleIndex]);
                         styleIndex++
                     }
                     i++;
@@ -5198,13 +5310,13 @@ var jexcel = (function(el, options) {
                 oldStyle:oldStyle,
             });
 
+            // Update table
+            obj.updateTable();
+
             // Paste event
             if (typeof(obj.options.onpaste) == 'function') {
                 obj.options.onpaste(el, records);
             }
-
-            // Update table
-            obj.updateTable();
         }
     }
 
@@ -5872,8 +5984,6 @@ jexcel.destroy = function(element, destroyEventHandlers) {
             document.removeEventListener("mousemove", jexcel.mouseMoveControls);
             document.removeEventListener("mouseover", jexcel.mouseOverControls);
             document.removeEventListener("dblclick", jexcel.doubleClickControls);
-            document.removeEventListener("copy", jexcel.copyControls);
-            document.removeEventListener("cut", jexcel.cutControls);
             document.removeEventListener("paste", jexcel.pasteControls);
             document.removeEventListener("contextmenu", jexcel.contextMenuControls);
             document.removeEventListener("touchstart", jexcel.touchStartControls);
@@ -5891,8 +6001,6 @@ jexcel.build = function() {
     document.addEventListener("mousemove", jexcel.mouseMoveControls);
     document.addEventListener("mouseover", jexcel.mouseOverControls);
     document.addEventListener("dblclick", jexcel.doubleClickControls);
-    document.addEventListener("copy", jexcel.copyControls);
-    document.addEventListener("cut", jexcel.cutControls);
     document.addEventListener("paste", jexcel.pasteControls);
     document.addEventListener("contextmenu", jexcel.contextMenuControls);
     document.addEventListener("touchstart", jexcel.touchStartControls);
@@ -6158,6 +6266,25 @@ jexcel.keyDownControls = function(e) {
                             // Ctrl + Z
                             jexcel.current.undo();
                             e.preventDefault();
+                        } else if (e.which == 67) {
+                            // Ctrl + C
+                            jexcel.current.copy(true);
+                            e.preventDefault();
+                        } else if (e.which == 67) {
+                            // Ctrl + C
+                            jexcel.current.copy(true);
+                            e.preventDefault();
+                        } else if (e.which == 88) {
+                            // Ctrl + X
+                            if (jexcel.current.options.editable == true) {
+                                jexcel.cutControls();
+                            } else {
+                                jexcel.copyControls();
+                            }
+                            e.preventDefault();
+                        } else if (e.which == 86) {
+                            // Ctrl + V
+                            jexcel.pasteControls();
                         }
                     } else {
                         if (jexcel.current.selectedCell) {
@@ -6177,6 +6304,9 @@ jexcel.keyDownControls = function(e) {
                                             // Start edition
                                             jexcel.current.openEditor(jexcel.current.records[rowId][columnId], true);
                                         }
+                                    } else if (e.keyCode == 113) {
+                                        // Start edition with current content F2
+                                        jexcel.current.openEditor(jexcel.current.records[rowId][columnId], false);
                                     } else if ((e.keyCode == 8) ||
                                                (e.keyCode >= 48 && e.keyCode <= 57) ||
                                                (e.keyCode >= 65 && e.keyCode <= 90) ||
@@ -6188,9 +6318,6 @@ jexcel.keyDownControls = function(e) {
                                         if (jexcel.current.options.columns[columnId].type == 'calendar') {
                                             e.preventDefault();
                                         }
-                                    } else if (e.keyCode == 113) {
-                                        // Start edition with current content F2
-                                        jexcel.current.openEditor(jexcel.current.records[rowId][columnId], false);
                                     }
                                 }
                             }
@@ -6789,11 +6916,13 @@ jexcel.cutControls = function(e) {
 jexcel.pasteControls = function(e) {
     if (jexcel.current && jexcel.current.selectedCell) {
         if (! jexcel.current.edition) {
-            if (e.clipboardData) {
-                if (jexcel.current.options.editable == true) {
+            if (jexcel.current.options.editable == true) {
+                if (e && e.clipboardData) {
                     jexcel.current.paste(jexcel.current.selectedCell[0], jexcel.current.selectedCell[1], e.clipboardData.getData('text'));
+                    e.preventDefault();
+                } else if (window.clipboardData) {
+                    jexcel.current.paste(jexcel.current.selectedCell[0], jexcel.current.selectedCell[1], window.clipboardData.getData('text'));
                 }
-                e.preventDefault();
             }
         }
     }
@@ -6871,8 +7000,6 @@ jexcel.touchEndControls = function(e) {
     }
 }
 
-jexcel.copyControls.enabled = true;
-
 /**
  * Jquery Support
  */
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/dss/reporting-plugins/rc-exports-api/plugin.properties b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/dss/reporting-plugins/rc-exports-api/plugin.properties
index 3b491463420d4b44d08eefafbf5d543a7b2ef812..682300955e379a9321d06d8acf2b2a456c0399c6 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/dss/reporting-plugins/rc-exports-api/plugin.properties
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/dss/reporting-plugins/rc-exports-api/plugin.properties
@@ -1,8 +1,8 @@
 label = Research Collection Exports API
 class = ch.systemsx.cisd.openbis.dss.generic.server.plugins.jython.JythonIngestionService
 script-path = rcExports.py
-limit-data-size-megabytes = 4000
-service-document-url=https://test.research-collection.ethz.ch/swordv2/servicedocument
 realm=SWORD2
-user=youruser
-password=yourpassword
\ No newline at end of file
+limit-data-size-megabytes=${rc-exports-api-limit-data-size-megabytes:4000}
+service-document-url=${rc-exports-api-service-document-url:https://test.research-collection.ethz.ch/swordv2/servicedocument}
+user=${rc-exports-api-user}
+password=${rc-exports-api-password}
\ No newline at end of file
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/dss/reporting-plugins/zenodo-exports-api/plugin.properties b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/dss/reporting-plugins/zenodo-exports-api/plugin.properties
index 46637e2ba22178234ec544460bef0591959e8a9a..cc77ea6f8cfc5d2c91b4292696d89990276b2b7b 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/dss/reporting-plugins/zenodo-exports-api/plugin.properties
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/dss/reporting-plugins/zenodo-exports-api/plugin.properties
@@ -1,7 +1,6 @@
 label = Zenodo Exports API
 class = ch.systemsx.cisd.openbis.dss.generic.server.plugins.jython.JythonIngestionService
 script-path = zenodoExports.py
-service-document-url=https://test.research-collection.ethz.ch/swordv2/servicedocument
-limit-data-size-megabytes = 50000
-zenodoUrl=https://localhost
-accessToken=
\ No newline at end of file
+limit-data-size-megabytes=${zenodo-exports-api-limit-data-size-megabytes:4000}
+zenodoUrl=${zenodo-exports-api-zenodoUrl:https://localhost}
+accessToken=${zenodo-exports-api-accessToken}
\ No newline at end of file
diff --git a/openbis_standard_technologies/dist/server/service.properties b/openbis_standard_technologies/dist/server/service.properties
index 0e38ec4f10eea30ad869f6b8a5e1f88fb63a0d93..bcbe9b8b1c22a17b32e8edca36d1c8986073f95d 100644
--- a/openbis_standard_technologies/dist/server/service.properties
+++ b/openbis_standard_technologies/dist/server/service.properties
@@ -173,6 +173,14 @@ session-timeout = 720
 # Session time (in minutes) in case of presents of file etc/nologin.html. Should be < 30. 
 #session-timeout-no-login = 10
 
+# Maximum number of sessions allowed per user. Zero means unlimited number of sessions. Default value is 1.
+# max-number-of-sessions-per-user = 1
+
+# Comma separated list of users allowed to have unlimited number of sessions. Default: Empty list.
+# Note: The DSS (user 'etlserver' by default, see property 'username' of DSS service.properties)
+# should be added to this list.
+# users-with-unrestricted-number-of-sessions = 
+
 # ---------------------------------------------------------------------------
 # Business rules configuration
 # ---------------------------------------------------------------------------
diff --git a/pybis/src/python/pybis/__init__.py b/pybis/src/python/pybis/__init__.py
index 4aa2b995675dc04f0874952732c359ada99bdd0f..b2c5fe70dd5b62fe2b565da8abc8041646f66371 100644
--- a/pybis/src/python/pybis/__init__.py
+++ b/pybis/src/python/pybis/__init__.py
@@ -1,7 +1,7 @@
 name = 'pybis'
 __author__ = 'Swen Vermeul'
 __email__ = 'swen@ethz.ch'
-__version__ = '1.9.1'
+__version__ = '1.9.2'
 
 from . import pybis
 from .pybis import Openbis
diff --git a/pybis/src/python/setup.py b/pybis/src/python/setup.py
index 723fcda825c708e6a385739579d327aa8d44c80e..b7f8b9853da7d66554103c7c93286cd344a3eb3d 100644
--- a/pybis/src/python/setup.py
+++ b/pybis/src/python/setup.py
@@ -11,7 +11,7 @@ with open("README.md", "r", encoding="utf-8") as fh:
 
 setup(
     name='PyBIS',
-    version= '1.9.1',
+    version= '1.9.2',
     author='Swen Vermeul • ID SIS • ETH Zürich',
     author_email='swen@ethz.ch',
     description='openBIS connection and interaction, optimized for using with Jupyter',
diff --git a/screening/source/java/service.properties b/screening/source/java/service.properties
index 54ea1996dee1c979ffd2cda4c6cc582932af8687..c8f492aa0e35bdad5ae098dfcecb4d523f470f48 100644
--- a/screening/source/java/service.properties
+++ b/screening/source/java/service.properties
@@ -2,6 +2,7 @@ authentication-service = dummy-authentication-service
 
 # The time after which an inactive session is expired by the service (in minutes).
 session-timeout = 720 
+max-number-of-sessions-per-user = 0
 
 session-workspace-root-dir = targets/session-workspace
 
diff --git a/ui-test/resource/service.properties b/ui-test/resource/service.properties
index ca31420f298374fc16fb6baa90a4338d775ee5d3..c9a308a53d4b229aea6107a7e2f6d041a451ed3e 100644
--- a/ui-test/resource/service.properties
+++ b/ui-test/resource/service.properties
@@ -2,6 +2,7 @@ authentication-service = dummy-authentication-service
 
 # The time after which an inactive session is expired by the service (in minutes).
 session-timeout = 720 
+max-number-of-sessions-per-user = 0
 
 # Authorization
 # Supported: 'no-authorization' and 'active-authorization'