diff --git a/.gitignore b/.gitignore
index 3792e187a50799c0892a02e0d25e3c3c15df6e98..b8535f8bc274fa59fc16aa2e6535687342e435ee 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,7 @@
 /bin/
 /target/
 /cargo/
+/screenshots/
 /.settings/
 /.externalToolBuilders/
 
diff --git a/src/main/java/org/olat/admin/user/SystemRolesAndRightsController.java b/src/main/java/org/olat/admin/user/SystemRolesAndRightsController.java
index 572dc4fe9cc51509bc31c612e0338163c2b74f45..6ac8f5d40a94de807539cd3bdcff452c0e046cb1 100644
--- a/src/main/java/org/olat/admin/user/SystemRolesAndRightsController.java
+++ b/src/main/java/org/olat/admin/user/SystemRolesAndRightsController.java
@@ -27,6 +27,7 @@ package org.olat.admin.user;
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Date;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
@@ -46,6 +47,7 @@ import org.olat.core.gui.components.form.flexible.elements.FormLink;
 import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement;
 import org.olat.core.gui.components.form.flexible.elements.SingleSelection;
 import org.olat.core.gui.components.form.flexible.elements.SpacerElement;
+import org.olat.core.gui.components.form.flexible.elements.StaticTextElement;
 import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
 import org.olat.core.gui.components.form.flexible.impl.FormEvent;
 import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
@@ -60,6 +62,9 @@ import org.olat.core.id.Organisation;
 import org.olat.core.id.OrganisationRef;
 import org.olat.core.id.Roles;
 import org.olat.core.id.RolesByOrganisation;
+import org.olat.core.util.Formatter;
+import org.olat.user.UserLifecycleManager;
+import org.olat.user.UserModule;
 import org.springframework.beans.factory.annotation.Autowired;
 
 /**
@@ -82,6 +87,12 @@ import org.springframework.beans.factory.annotation.Autowired;
  */
 public class SystemRolesAndRightsController extends FormBasicController {
 	
+	private StaticTextElement lastLoginEl;
+	private StaticTextElement inactivationDateEl;
+	private StaticTextElement reactivationDateEl;
+	private StaticTextElement daysInactivationEl;
+	private StaticTextElement daysDeletionEl;
+	
 	private SpacerElement rolesSep;
 	private SingleSelection statusEl;
 	private SingleSelection anonymousEl;
@@ -110,10 +121,14 @@ public class SystemRolesAndRightsController extends FormBasicController {
 	@Autowired
 	private DB dbInstance;
 	@Autowired
+	private UserModule userModule;
+	@Autowired
 	private BaseSecurity securityManager;
 	@Autowired
 	private OrganisationService organisationService;
 	@Autowired
+	private UserLifecycleManager userLifecycleManager;
+	@Autowired
 	private UserBulkChangeManager userBulkChangeManager;
 	
 	/**
@@ -182,10 +197,27 @@ public class SystemRolesAndRightsController extends FormBasicController {
 		formLayout.add(rolesCont);
 		
 		initFormRoles();
-		
+		initFormStatus(ureq, formLayout, iAmAdmin, iAmUserManager);
+	}
+
+	private void initFormRoles() {
+		for(Organisation organisation:organisations) {
+			initFormRoles(rolesCont, organisation);
+		}
+		List<Organisation> upgradeableToOrganisations = new ArrayList<>(manageableOrganisations);
+		upgradeableToOrganisations.removeAll(organisations);
+		if(!upgradeableToOrganisations.isEmpty()) {
+			addToOrganisationButton = uifactory.addFormLink("rightsForm.add.to.organisation", rolesCont, Link.BUTTON);
+		}
+
+		rolesSep = uifactory.addSpacerElement("rolesSep", rolesCont, false);
+	}
+	
+	private void initFormStatus(UserRequest ureq, FormItemContainer formLayout, boolean iAmAdmin, boolean iAmUserManager) {
 		FormLayoutContainer statusCont = FormLayoutContainer.createDefaultFormLayout("statusc", getTranslator());
 		formLayout.add(statusCont);
 		
+		// status
 		statusEl = uifactory.addRadiosVertical("status", "rightsForm.status", statusCont, statusKeys.keys(), statusKeys.values());
 		statusEl.addActionListener(FormEvent.ONCHANGE);
 		sendLoginDeniedEmailEl = uifactory.addCheckboxesHorizontal("rightsForm.sendLoginDeniedEmail", statusCont, new String[]{"y"}, new String[]{translate("rightsForm.sendLoginDeniedEmail")});
@@ -195,24 +227,18 @@ public class SystemRolesAndRightsController extends FormBasicController {
 		statusEl.setVisible(iAmAdmin || iAmUserManager);
 		sendLoginDeniedEmailEl.setVisible(false);
 		
+		// life cycle information
+		lastLoginEl = uifactory.addStaticTextElement("rightsForm.last.login", "", statusCont);
+		inactivationDateEl = uifactory.addStaticTextElement("rightsForm.inactivation.date", "", statusCont);
+		reactivationDateEl = uifactory.addStaticTextElement("rightsForm.reactivation.date", "", statusCont);
+		daysInactivationEl = uifactory.addStaticTextElement("rightsForm.days.inactivation", "", statusCont);
+		daysDeletionEl = uifactory.addStaticTextElement("rightsForm.days.deletion", "", statusCont);
+		
 		FormLayoutContainer buttonGroupLayout = FormLayoutContainer.createButtonLayout("buttonGroupLayout", getTranslator());
 		statusCont.add(buttonGroupLayout);
 		uifactory.addFormCancelButton("cancel", buttonGroupLayout, ureq, getWindowControl());
 		uifactory.addFormSubmitButton("submit", buttonGroupLayout);
 	}
-
-	private void initFormRoles() {
-		for(Organisation organisation:organisations) {
-			initFormRoles(rolesCont, organisation);
-		}
-		List<Organisation> upgradeableToOrganisations = new ArrayList<>(manageableOrganisations);
-		upgradeableToOrganisations.removeAll(organisations);
-		if(!upgradeableToOrganisations.isEmpty()) {
-			addToOrganisationButton = uifactory.addFormLink("rightsForm.add.to.organisation", rolesCont, Link.BUTTON);
-		}
-
-		rolesSep = uifactory.addSpacerElement("rolesSep", rolesCont, false);
-	}
 	
 	private void initFormRoles(FormItemContainer formLayout, Organisation organisation) {
 		boolean admin = managerRoles.hasRoleInParentLine(organisation, OrganisationRoles.administrator)
@@ -357,6 +383,29 @@ public class SystemRolesAndRightsController extends FormBasicController {
 		setStatus(editedIdentity.getStatus());
 		wrapper.getRolesEl().setVisible(!isAnonymous());
 		rolesSep.setVisible(!isAnonymous());
+		
+		Formatter formatter = Formatter.getInstance(getLocale());
+		lastLoginEl.setValue(formatter.formatDateAndTime(editedIdentity.getLastLogin()));
+		
+		Date inactivationDate = editedIdentity.getInactivationDate();
+		inactivationDateEl.setValue(formatter.formatDate(inactivationDate));
+		inactivationDateEl.setVisible(inactivationDate != null);
+		
+		Date reactivationDate = editedIdentity.getReactivationDate();
+		reactivationDateEl.setValue(formatter.formatDate(reactivationDate));
+		reactivationDateEl.setVisible(reactivationDate != null);
+		
+		Date now = new Date();
+		long daysBeforeDeactivation = userLifecycleManager.getDaysUntilDeactivation(editedIdentity, now);
+		daysInactivationEl.setValue(Long.toString(daysBeforeDeactivation));
+		daysInactivationEl.setVisible(userModule.isUserAutomaticDeactivation()
+				&& (editedIdentity.getStatus().equals(Identity.STATUS_ACTIV)
+						|| editedIdentity.getStatus().equals(Identity.STATUS_PENDING)
+						|| editedIdentity.getStatus().equals(Identity.STATUS_LOGIN_DENIED)));
+		
+		long daysBeforeDeletion = userLifecycleManager.getDaysUntilDeletion(editedIdentity, now);
+		daysDeletionEl.setValue(Long.toString(daysBeforeDeletion));
+		daysDeletionEl.setVisible(userModule.isUserAutomaticDeletion() && editedIdentity.getInactivationDate() != null);
 	}
 	
 	private void setStatus(Integer status) {
diff --git a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_de.properties
index 8ea86bd3ded7c979fe169a1775dcb853a804180a..0fde36b33dd7065b3359c7e889a92723aca5df59 100644
--- a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_de.properties
@@ -93,8 +93,13 @@ poolsmanager=Poolverwalter
 repocoach=Kursbetreuer
 rightForm.error.anonymous.no.roles=Anonyme G\u00E4ste k\u00F6nnen keine Systemrollen wahrnehmen
 rightsForm.add.to.organisation=Zur Organisation hinzuf\u00FCgen
+rightsForm.days.deletion=Tage bis l\u00F6schen
+rightsForm.days.inactivation=Tage bis inaktivieren
 rightsForm.guest=Benutzertyp
+rightsForm.inactivation.date=Inaktivierungsdatum
 rightsForm.isLoginDenied=Login gesperrt
+rightsForm.last.login=Letzter Login
+rightsForm.reactivation.date=Reaktivierungsdatum
 rightsForm.roles=Rollen
 rightsForm.roles.for=Rollen f\u00FCr "{0}"
 rightsForm.sendLoginDeniedEmail=Benutzer \u00FCber Loginsperre informieren
diff --git a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_en.properties
index 0abd707398232444f1b9f1dae2f7afef70daa71e..ee23fc6ade76e7b130e38a36e19a87d75db23124 100644
--- a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_en.properties
@@ -93,8 +93,13 @@ poolsmanager=Question bank manager
 repocoach=Course coach
 rightForm.error.anonymous.no.roles=Anonymous guests cannot exercise system roles
 rightsForm.add.to.organisation=Add to organisation
+rightsForm.days.deletion=Days until deletion
+rightsForm.days.inactivation=Days until deactivation
 rightsForm.guest=User type
+rightsForm.inactivation.date=Inactivation date
 rightsForm.isLoginDenied=Login locked
+rightsForm.last.login=Last login
+rightsForm.reactivation.date=Reactivation date
 rightsForm.roles=Roles
 rightsForm.roles.for=Roles for "{0}"
 rightsForm.sendLoginDeniedEmail=Notify user about login denied change
diff --git a/src/main/java/org/olat/admin/user/imp/TransientIdentity.java b/src/main/java/org/olat/admin/user/imp/TransientIdentity.java
index eaa0276b2a0c61f4f5199b30b3c6d34561778e6d..f7356fc82fa573ba6eaa6b79157748327c0c7755 100644
--- a/src/main/java/org/olat/admin/user/imp/TransientIdentity.java
+++ b/src/main/java/org/olat/admin/user/imp/TransientIdentity.java
@@ -136,6 +136,11 @@ public class TransientIdentity implements Identity, User {
 		return null;
 	}
 
+	@Override
+	public Date getReactivationDate() {
+		return null;
+	}
+
 	@Override
 	public boolean equalsByPersistableKey(Persistable persistable) {
 		return super.equals(persistable);
diff --git a/src/main/java/org/olat/admin/user/imp/UpdateIdentity.java b/src/main/java/org/olat/admin/user/imp/UpdateIdentity.java
index 4667a5496ceb6d74d6f6e08f44e66c0d5888f540..030ef16a307b9b6bbd868af75ab92e627753c2aa 100644
--- a/src/main/java/org/olat/admin/user/imp/UpdateIdentity.java
+++ b/src/main/java/org/olat/admin/user/imp/UpdateIdentity.java
@@ -123,6 +123,11 @@ public class UpdateIdentity implements Identity {
 		return identity.getInactivationDate();
 	}
 
+	@Override
+	public Date getReactivationDate() {
+		return identity.getReactivationDate();
+	}
+
 	@Override
 	public int hashCode() {
 		return identity.hashCode();
diff --git a/src/main/java/org/olat/basesecurity/IdentityImpl.java b/src/main/java/org/olat/basesecurity/IdentityImpl.java
index 6b4a09d1412f4d889b5a035f6edee2ee18a9b906..4b25aa9a138bcf47214bc45c2f96cd544ee11c41 100644
--- a/src/main/java/org/olat/basesecurity/IdentityImpl.java
+++ b/src/main/java/org/olat/basesecurity/IdentityImpl.java
@@ -220,6 +220,7 @@ public class IdentityImpl implements Identity, IdentityRef, CreateInfo, Persista
 		this.inactivationEmailDate = inactivationEmailDate;
 	}
 
+	@Override
 	public Date getReactivationDate() {
 		return reactivationDate;
 	}
diff --git a/src/main/java/org/olat/basesecurity/manager/IdentityPowerSearchQueriesImpl.java b/src/main/java/org/olat/basesecurity/manager/IdentityPowerSearchQueriesImpl.java
index 0aad97bc76c1031833b973f34ee039d7406a4127..42a9c327e55e9404b5937f4dd2b2026282db6f0d 100644
--- a/src/main/java/org/olat/basesecurity/manager/IdentityPowerSearchQueriesImpl.java
+++ b/src/main/java/org/olat/basesecurity/manager/IdentityPowerSearchQueriesImpl.java
@@ -97,7 +97,8 @@ public class IdentityPowerSearchQueriesImpl implements IdentityPowerSearchQuerie
 		  .append(" ident.creationDate as ident_cDate,")
 		  .append(" ident.lastLogin as ident_lDate,")
 		  .append(" ident.status as ident_Status,")
-		  .append(" ident.inactivationDate as ident_iDate,");
+		  .append(" ident.inactivationDate as ident_iDate,")
+		  .append(" ident.reactivationDate as ident_rDate,");
 		writeUserProperties("user", sb, userPropertyHandlers);
 		sb.append(" user.key as ident_user_id")
 		  .append(" from ").append(IdentityImpl.class.getCanonicalName()).append(" as ident ")
@@ -121,13 +122,15 @@ public class IdentityPowerSearchQueriesImpl implements IdentityPowerSearchQuerie
 			Date lastLogin = (Date)rawObject[pos++];
 			Integer status = (Integer)rawObject[pos++];
 			Date inactivationDate = (Date)rawObject[pos++];
+			Date reactivationDate = (Date)rawObject[pos++];
 
 			String[] userProperties = new String[numOfProperties];
 			for(int i=0; i<numOfProperties; i++) {
 				userProperties[i] = (String)rawObject[pos++];
 			}
 
-			rows.add(new IdentityPropertiesRow(identityKey, creationDate, lastLogin, status, inactivationDate,
+			rows.add(new IdentityPropertiesRow(identityKey, creationDate, lastLogin, status,
+					inactivationDate, reactivationDate,
 					userPropertyHandlers, userProperties, locale));
 		}
 		return rows;
diff --git a/src/main/java/org/olat/basesecurity/model/IdentityPropertiesRow.java b/src/main/java/org/olat/basesecurity/model/IdentityPropertiesRow.java
index 08caed5c22d67d12185141f66867d276460f85df..140f68cd3e8c82723980953a107b08c4daf2525a 100644
--- a/src/main/java/org/olat/basesecurity/model/IdentityPropertiesRow.java
+++ b/src/main/java/org/olat/basesecurity/model/IdentityPropertiesRow.java
@@ -24,6 +24,7 @@ import java.util.List;
 import java.util.Locale;
 
 import org.olat.core.id.Identity;
+import org.olat.core.id.IdentityLifecycle;
 import org.olat.user.UserPropertiesRow;
 import org.olat.user.propertyhandlers.UserPropertyHandler;
 
@@ -33,12 +34,13 @@ import org.olat.user.propertyhandlers.UserPropertyHandler;
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  *
  */
-public class IdentityPropertiesRow extends UserPropertiesRow {
+public class IdentityPropertiesRow extends UserPropertiesRow implements IdentityLifecycle {
 	
 	private final Integer status;
 	private final Date lastLogin;
 	private final Date creationDate;
 	private final Date inactivationDate;
+	private final Date reactivationDate;
 	
 	public IdentityPropertiesRow(Identity identity, List<UserPropertyHandler> userPropertyHandlers, Locale locale) {
 		super(identity, userPropertyHandlers, locale);
@@ -46,30 +48,42 @@ public class IdentityPropertiesRow extends UserPropertiesRow {
 		lastLogin = identity.getLastLogin();
 		creationDate = identity.getCreationDate();
 		inactivationDate = identity.getInactivationDate();
+		reactivationDate = identity.getReactivationDate();
 	}
 	
 	public IdentityPropertiesRow(Long identityKey, Date creationDate, Date lastLogin, Integer status,
-			Date inactivationDate, List<UserPropertyHandler> userPropertyHandlers, String[] identityProps, Locale locale) {
+			Date inactivationDate, Date reactivationDate, List<UserPropertyHandler> userPropertyHandlers,
+			String[] identityProps, Locale locale) {
 		super(identityKey, userPropertyHandlers, identityProps, locale);
 		this.status = status;
 		this.creationDate = creationDate;
 		this.lastLogin = lastLogin;	
 		this.inactivationDate = inactivationDate;
+		this.reactivationDate = reactivationDate;
 	}
 	
+	@Override
 	public Integer getStatus() {
 		return status;
 	}
 
+	@Override
 	public Date getCreationDate() {
 		return creationDate;
 	}
 
+	@Override
 	public Date getLastLogin() {
 		return lastLogin;
 	}
-	
+
+	@Override
 	public Date getInactivationDate() {
 		return inactivationDate;
 	}
+
+	@Override
+	public Date getReactivationDate() {
+		return reactivationDate;
+	}
 }
diff --git a/src/main/java/org/olat/core/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/core/_i18n/LocalStrings_pt_BR.properties
index 2a3ac544bc9c0d7862babc4b5ab7f9df5a68528f..605ebae25e5585ec204b5ba220946b2397d41c07 100644
--- a/src/main/java/org/olat/core/_i18n/LocalStrings_pt_BR.properties
+++ b/src/main/java/org/olat/core/_i18n/LocalStrings_pt_BR.properties
@@ -1,4 +1,4 @@
-#Tue May 26 15:02:54 CEST 2020
+#Thu Sep 24 14:17:41 CEST 2020
 alert=Favor selecionar no m\u00EDnimo um objeto para sua a\u00E7\u00E3o.
 back=Voltar
 calendar.choose=Escolha uma data do mini calend\u00E1rio
@@ -49,6 +49,7 @@ info.header=Informa\u00E7\u00E3o
 info.saved=Suas modifica\u00E7\u00F5es foram salvas.
 input.toolong=Sua entrada \u00E9 muito longa.
 legend=Legend
+lock.same.user.different.window=Talvez voc\u00EA tenha aberto uma segunda janela?
 logout=Logout
 module.change.warning=Para ativar as suas altera\u00E7\u00F5es, o OpenOlat precisa ser reiniciado
 move.down=Mover para baixo
@@ -59,6 +60,7 @@ new=Novo
 new.form.mandatory=Este campo \u00E9 obrigat\u00F3rio.
 next=Pr\u00F3ximo
 no=N\u00E3o
+noTransOnlyParam={0}
 off=des.
 ok=OK
 on=lig.
@@ -125,5 +127,6 @@ warn.header=Aviso
 warn.notdispatched=Esta p\u00E1gina foi modificada. Favor considerar poss\u00EDveis mensagens.
 warn.reload=Favor n\u00E3o usar a tecla `Atualizar` ou `Voltar` do seu browser.
 warning.invalid.csrf=Incompatibilidade do CSRF
+warning.multi.window=Voc\u00EA abriu a mesma janela v\u00E1rias vezes.
 welcome=Bemvindo
 yes=Sim
diff --git a/src/main/java/org/olat/core/commons/controllers/linkchooser/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/core/commons/controllers/linkchooser/_i18n/LocalStrings_pt_BR.properties
index 2bc852c8b6e1bf9a6aa3bfdc487e44c61ae07b01..0eadf4d5aeb765992d71ec5deab04559f431ed8c 100644
--- a/src/main/java/org/olat/core/commons/controllers/linkchooser/_i18n/LocalStrings_pt_BR.properties
+++ b/src/main/java/org/olat/core/commons/controllers/linkchooser/_i18n/LocalStrings_pt_BR.properties
@@ -1,4 +1,4 @@
-#Fri Dec 11 19:45:49 CET 2009
+#Thu Sep 24 14:17:49 CEST 2020
 closewindow.manually=Voc\u00EA pode agora fechar esta janela
 error.notsupportedcharset=Este documento n\u00E3o pode ser salvo porque essa fonte n\u00E3o \u00E9 suportada\: fonte \u00E9 "{0}". Suportados s\u00E3o os seguintes\: <br><br>{1})
 error.pageeditedby=Esta p\u00E1gina \u00E9 sendo editada pelo usu\u00E1rio {0}. Por favor, tente novamente mais tarde.
@@ -8,5 +8,6 @@ filechooser.upload.title=Carregar arquivo
 linkchooser.select.title=Selecionar link
 linkchooser.tabbedpane.label.filechooser=Link de arquivo
 linkchooser.tabbedpane.label.internallinkchooser=Link do curso
+linkchooser.tabbedpane.label.internaltoolchooser=Link da ferramenta do curso
 selectfile=Escolher
 upload.error.incorrect.filetype=O documento carregado tem o tipo errado de arquivo ({0}). Os tipos de arquivo permitidos s\u00E3o\: {1}
diff --git a/src/main/java/org/olat/core/commons/modules/bc/commands/CmdDownloadZip.java b/src/main/java/org/olat/core/commons/modules/bc/commands/CmdDownloadZip.java
index 6d3e747ad590bd63ccfde5c2ec21656bb99c23c0..53112a9385fe49438f40b34fe9a575fa72fee87e 100644
--- a/src/main/java/org/olat/core/commons/modules/bc/commands/CmdDownloadZip.java
+++ b/src/main/java/org/olat/core/commons/modules/bc/commands/CmdDownloadZip.java
@@ -47,6 +47,7 @@ import org.olat.core.util.vfs.VFSContainer;
 import org.olat.core.util.vfs.VFSItem;
 import org.olat.core.util.vfs.VFSLeaf;
 import org.olat.core.util.vfs.VFSManager;
+import org.olat.core.util.vfs.filters.VFSSystemItemFilter;
 
 /**
  * 
@@ -194,7 +195,7 @@ public class CmdDownloadZip implements FolderCommand {
 				}
 				
 				for (VFSItem item:vfsFiles) {
-					ZipUtil.addToZip(item, "", zout);
+					ZipUtil.addToZip(item, "", zout, new VFSSystemItemFilter(), false);
 				}
 				zout.flush();
 			} catch (IOException e) {
diff --git a/src/main/java/org/olat/core/commons/modules/bc/commands/CmdZip.java b/src/main/java/org/olat/core/commons/modules/bc/commands/CmdZip.java
index 87a48c3b13543e95a373138b3757729743bab030..f978c5319a4361118ed2e8060ae76d8236c98062 100644
--- a/src/main/java/org/olat/core/commons/modules/bc/commands/CmdZip.java
+++ b/src/main/java/org/olat/core/commons/modules/bc/commands/CmdZip.java
@@ -50,6 +50,7 @@ import org.olat.core.util.vfs.VFSConstants;
 import org.olat.core.util.vfs.VFSContainer;
 import org.olat.core.util.vfs.VFSItem;
 import org.olat.core.util.vfs.VFSLeaf;
+import org.olat.core.util.vfs.filters.VFSSystemItemFilter;
 import org.springframework.beans.factory.annotation.Autowired;
 
 /**
@@ -170,7 +171,7 @@ public class CmdZip extends FormBasicController implements FolderCommand {
 				vfsFiles.add(item);
 			}
 		}
-		if (!ZipUtil.zip(vfsFiles, (VFSLeaf)zipFile, true)) {
+		if (!ZipUtil.zip(vfsFiles, (VFSLeaf)zipFile, new VFSSystemItemFilter(), false)) {
 			// cleanup zip file
 			zipFile.delete();				
 			status = FolderCommandStatus.STATUS_FAILED;
diff --git a/src/main/java/org/olat/core/commons/services/vfs/manager/VFSRepositoryServiceImpl.java b/src/main/java/org/olat/core/commons/services/vfs/manager/VFSRepositoryServiceImpl.java
index 97abe2954304ae54890554bd92b0e9e12c2990e0..3dcd03012819a2f770ae11c48cf56d2da6acc5d8 100644
--- a/src/main/java/org/olat/core/commons/services/vfs/manager/VFSRepositoryServiceImpl.java
+++ b/src/main/java/org/olat/core/commons/services/vfs/manager/VFSRepositoryServiceImpl.java
@@ -623,6 +623,8 @@ public class VFSRepositoryServiceImpl implements VFSRepositoryService, GenericEv
 		VFSMetadata currentMetadata = metadataDao.getMetadata(metadata.getRelativePath(), newName, (item instanceof VFSContainer));
 		if(currentMetadata != null && !currentMetadata.equals(metadata)) {
 			metadata.copyValues(currentMetadata, false);
+			deleteThumbnailsOfMetadata(currentMetadata);
+			deleteRevisionsOfMetadata(currentMetadata);
 			metadataDao.removeMetadata(currentMetadata);
 		}
 		
diff --git a/src/main/java/org/olat/core/commons/services/vfs/ui/management/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/core/commons/services/vfs/ui/management/_i18n/LocalStrings_pt_BR.properties
index 86162ea9972f8fad9049118cbddc8509624d5047..30f259ebfe685c2476e84c4f2af0b44be07188a9 100644
--- a/src/main/java/org/olat/core/commons/services/vfs/ui/management/_i18n/LocalStrings_pt_BR.properties
+++ b/src/main/java/org/olat/core/commons/services/vfs/ui/management/_i18n/LocalStrings_pt_BR.properties
@@ -1,7 +1,8 @@
-#Tue May 26 15:17:59 CEST 2020
+#Thu Sep 24 14:18:03 CEST 2020
 vfs.overview.action=A\u00E7\u00E3o
 vfs.overview.amount=Montante
 vfs.overview.files=Arquivos
+vfs.overview.files.note=* N\u00E3o incluindo arquivos exclu\u00EDdos, vers\u00F5es ou miniaturas
 vfs.overview.fileslink=Mostrar arquivos grandes
 vfs.overview.name=Nome
 vfs.overview.size=Tamanho
diff --git a/src/main/java/org/olat/core/gui/media/ZippedContainerMediaResource.java b/src/main/java/org/olat/core/gui/media/ZippedContainerMediaResource.java
index c329fa1add0ca57fd4d914911bbb689be5e279e0..3c60ea92b7611d0220ec0e7edb62f7833261d331 100644
--- a/src/main/java/org/olat/core/gui/media/ZippedContainerMediaResource.java
+++ b/src/main/java/org/olat/core/gui/media/ZippedContainerMediaResource.java
@@ -30,6 +30,7 @@ import org.olat.core.logging.Tracing;
 import org.olat.core.util.StringHelper;
 import org.olat.core.util.ZipUtil;
 import org.olat.core.util.vfs.VFSContainer;
+import org.olat.core.util.vfs.filters.VFSRevisionsAndThumbnailsFilter;
 
 /**
  * 
@@ -42,10 +43,12 @@ public class ZippedContainerMediaResource implements MediaResource {
 	private static final Logger log = Tracing.createLoggerFor(ZippedContainerMediaResource.class);
 	
 	private final String filename;
+	private final boolean withMetadata;
 	private final VFSContainer unzipContainer;
 	
-	public ZippedContainerMediaResource(String filename, VFSContainer unzipContainer) {
+	public ZippedContainerMediaResource(String filename, VFSContainer unzipContainer, boolean withMetadata) {
 		this.filename = filename;
+		this.withMetadata = withMetadata;
 		this.unzipContainer = unzipContainer;
 	}
 
@@ -91,7 +94,7 @@ public class ZippedContainerMediaResource implements MediaResource {
 		hres.setHeader("Content-Description", urlEncodedLabel);
 	
 		try(OutputStream out=hres.getOutputStream()) {
-			ZipUtil.zip(unzipContainer, out);
+			ZipUtil.zip(unzipContainer, out, new VFSRevisionsAndThumbnailsFilter(), withMetadata);
 		} catch (IOException e) {
 			log.error("", e);
 		}
diff --git a/src/main/java/org/olat/core/id/Identity.java b/src/main/java/org/olat/core/id/Identity.java
index caaff6eadfcc26827e0d64fa348f7fec98725369..e9c00e5034b0c06bd88163ab32467c7aa7e6d87f 100644
--- a/src/main/java/org/olat/core/id/Identity.java
+++ b/src/main/java/org/olat/core/id/Identity.java
@@ -36,7 +36,7 @@ import org.olat.basesecurity.IdentityRef;
  *
  * @author Mike Stock
  */
-public interface Identity extends CreateInfo, IdentityRef, Persistable {
+public interface Identity extends CreateInfo, IdentityRef, IdentityLifecycle, Persistable {
 
 	// status = 1..99    User with this status are visible (e.g. user search)
 	//          100..199 User with this status are invisible (e.g. user search)
@@ -71,16 +71,17 @@ public interface Identity extends CreateInfo, IdentityRef, Persistable {
 	 */
 	public User getUser();
 	
-	/**
-	 * @return Last date when the user logged in.
-	 */
-	public Date getLastLogin();
 
 	/**
 	 * @return Current identity status 
 	 */
+	@Override
 	public Integer getStatus();
 	
-	public Date getInactivationDate();
+	/**
+	 * @return Last date when the user logged in.
+	 */
+	@Override
+	public Date getLastLogin();
 	
 }
\ No newline at end of file
diff --git a/src/main/java/org/olat/core/id/IdentityLifecycle.java b/src/main/java/org/olat/core/id/IdentityLifecycle.java
new file mode 100644
index 0000000000000000000000000000000000000000..ddcf44e3cf664959850532c692c455c8fb721ccf
--- /dev/null
+++ b/src/main/java/org/olat/core/id/IdentityLifecycle.java
@@ -0,0 +1,49 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.core.id;
+
+import java.util.Date;
+
+/**
+ * 
+ * Initial date: 21 sept. 2020<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public interface IdentityLifecycle {
+	
+	/**
+	 * @return Current identity status 
+	 */
+	public Integer getStatus();
+	
+	public Date getCreationDate();
+	
+	/**
+	 * @return Last date when the user logged in.
+	 */
+	public Date getLastLogin();
+	
+
+	public Date getInactivationDate();
+	
+	public Date getReactivationDate();
+
+}
diff --git a/src/main/java/org/olat/core/logging/LogRealTimeViewerController.java b/src/main/java/org/olat/core/logging/LogRealTimeViewerController.java
index ca31df99c578128358ae34e17fee45d48b21d11d..bb426cca1bc6e2b95e161a305f88582e1eeae00f 100644
--- a/src/main/java/org/olat/core/logging/LogRealTimeViewerController.java
+++ b/src/main/java/org/olat/core/logging/LogRealTimeViewerController.java
@@ -57,6 +57,7 @@ public class LogRealTimeViewerController extends BasicController {
 	private final Level level;
 	private String loggingPackage;
 	private boolean collectLog = true;
+	private final String appenderName;
 	private final LogWriter writer = new LogWriter();
 	
 	private Link stopLink;
@@ -80,6 +81,8 @@ public class LogRealTimeViewerController extends BasicController {
 		super(ureq, control);
 		this.level = level;
 		this.loggingPackage = loggingPackage;
+		appenderName = "LogRealTimeApppender-" + getIdentity().getKey();
+		
 		logViewerVC = createVelocityContainer("logviewer");
 		logViewerVC.contextPut("loggingPackage", loggingPackage);
 
@@ -108,7 +111,7 @@ public class LogRealTimeViewerController extends BasicController {
 		WriterAppender appender = WriterAppender.newBuilder()
 				.setLayout(layout)
 				.setTarget(writer)
-				.setName("LogRealTimeApppender")
+				.setName(appenderName)
 				.build();
 		appender.start();
 		config.addAppender(appender);
@@ -118,10 +121,7 @@ public class LogRealTimeViewerController extends BasicController {
 		refList.addAll(currentRefs);
 		refList.add(ref);
 		
-		AppenderRef[] refs = refList.toArray(new AppenderRef[refList.size()]);
-		LoggerConfig loggerConfig = LoggerConfig.createLogger(false, level, loggingPackage, "true", refs, null, config, null);
-		loggerConfig.addAppender(appender, level, null);
-		config.addLogger(loggingPackage, loggerConfig);
+		currentLoggerConfig.addAppender(appender, level, null);
 		ctx.updateLoggers();
 	}
 
@@ -131,7 +131,10 @@ public class LogRealTimeViewerController extends BasicController {
 	}
 	
 	private void removeConfiguration() {
-		Tracing.resetLevelForAllLoggers();
+		final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
+		final Configuration config = ctx.getConfiguration();
+		LoggerConfig currentLoggerConfig = config.getLoggerConfig(loggingPackage);
+		currentLoggerConfig.removeAppender(appenderName);
 	}
 
 	@Override
diff --git a/src/main/java/org/olat/core/util/IPUtils.java b/src/main/java/org/olat/core/util/IPUtils.java
index d42a273b7bef4bc0ffe9d7881f3d1ff26f1f1687..3fe3dbfc7f3497f15c01a25f3b1d1361c5efe4fc 100644
--- a/src/main/java/org/olat/core/util/IPUtils.java
+++ b/src/main/java/org/olat/core/util/IPUtils.java
@@ -51,13 +51,17 @@ public class IPUtils {
 		ipWithMask = ipWithMask.trim();
 		int maskIndex = ipWithMask.indexOf('/');
 		if(maskIndex > 0) {
-			long bits = Long.parseLong(ipWithMask.substring(maskIndex + 1));
-			long subnet = ipToLong(textToNumericFormatV4(ipWithMask.substring(0, maskIndex)));
-			long ip = ipToLong(textToNumericFormatV4(address));
-			
-			long mask = -1 << (32 - bits);
-			if ((subnet & mask) == (ip & mask)) {
-				allOk = true;
+			try {
+				long bits = Long.parseLong(ipWithMask.substring(maskIndex + 1));
+				long subnet = ipToLong(textToNumericFormatV4(ipWithMask.substring(0, maskIndex)));
+				long ip = ipToLong(textToNumericFormatV4(address));
+				
+				long mask = -1 << (32 - bits);
+				if ((subnet & mask) == (ip & mask)) {
+					allOk = true;
+				}
+			} catch(Exception e) {
+				log.warn("Range not valid: {} for IP: {}", ipWithMask, address);
 			}
 		}
 		return allOk;
diff --git a/src/main/java/org/olat/core/util/ZipUtil.java b/src/main/java/org/olat/core/util/ZipUtil.java
index c34e63cb2b97dea5ede94b2f5cc4d12ae5d01cbe..c04a98aef047a96e750a64550526d978d8056d3b 100644
--- a/src/main/java/org/olat/core/util/ZipUtil.java
+++ b/src/main/java/org/olat/core/util/ZipUtil.java
@@ -68,6 +68,8 @@ import org.olat.core.util.vfs.VFSLeaf;
 import org.olat.core.util.vfs.VFSLockApplicationType;
 import org.olat.core.util.vfs.VFSLockManager;
 import org.olat.core.util.vfs.VFSManager;
+import org.olat.core.util.vfs.filters.VFSAllItemsFilter;
+import org.olat.core.util.vfs.filters.VFSItemFilter;
 import org.olat.core.util.vfs.filters.VFSSystemItemFilter;
 
 /**
@@ -543,10 +545,11 @@ public class ZipUtil {
 	 * @param files		Filenames to add to ZIP, relative to root
 	 * @param root		Base path.
 	 * @param target	Target ZIP file.
-	 * @param compress to compress ot just store
-	 * @return true if successfull, false otherwise.
+	 * @param filter    Filter to accept files in the ZIP
+	 * @param withMetadata Add metadata as shadow file
+	 * @return true if successful, false otherwise.
 	 */
-	public static boolean zip(Set<String> files, File root, File target, boolean compress) {
+	public static boolean zip(Set<String> files, File root, File target, VFSItemFilter filter, boolean withMetadata) {
 		//	Create a buffer for reading the files
 		if (target.exists()) return false;
 		List<VFSItem> vfsFiles = new ArrayList<>();
@@ -558,8 +561,8 @@ public class ZipUtil {
 			}
 			vfsFiles.add(item);
 		}
-		return zip(vfsFiles, new LocalFileImpl(target), compress);
-	} // zip
+		return zip(vfsFiles, new LocalFileImpl(target), filter, withMetadata);
+	}
 	
 	/**
 	 * Add the set of files residing in root to the ZIP file named target.
@@ -568,11 +571,11 @@ public class ZipUtil {
 	 * @param files		Filenames to add to ZIP, relative to root
 	 * @param root		Base path.
 	 * @param target	Target ZIP file.
-	 * @param compress to compress ot just store
-	 * @return true if successfull, false otherwise.
+	 * @param withMetadata Add metadata as shadow file
+	 * @return true if successful, false otherwise.
 	 */
-	public static boolean zip(Set<String> files, File root, File target) {
-		return zip(files, root, target, true);
+	public static boolean zip(Set<String> files, File root, File target, boolean withMetadata) {
+		return zip(files, root, target, VFSAllItemsFilter.ACCEPT_ALL, withMetadata);
 	}
 	
 	/**
@@ -583,9 +586,9 @@ public class ZipUtil {
 	 * @param outputFile The output ZIP file
 	 * @return true if successful
 	 */
-	public static boolean zip(VFSContainer container, File outputFile) {
+	public static boolean zip(VFSContainer container, File outputFile, VFSItemFilter filter, boolean withMetadata) {
 		try(OutputStream out = new FileOutputStream(outputFile)) {
-			zip(container, out);
+			zip(container, out, filter, withMetadata);
 			return true;
 		} catch(IOException e) {
 			handleIOException("", e);
@@ -601,11 +604,11 @@ public class ZipUtil {
 	 * @param out The output stream
 	 * @return true if successful
 	 */
-	public static boolean zip(VFSContainer container, OutputStream out) {
+	public static boolean zip(VFSContainer container, OutputStream out, VFSItemFilter filter, boolean withMetadata) {
 		try(ZipOutputStream zipOut = new ZipOutputStream(new BufferedOutputStream(out, FileUtils.BSIZE))) {
 			List<VFSItem> items=container.getItems(new VFSSystemItemFilter());
 			for(VFSItem item:items) {
-				addToZip(item, "", zipOut);
+				addToZip(item, "", zipOut, filter, withMetadata);
 			}
 			return true;
 		} catch(IOException e) {
@@ -614,7 +617,7 @@ public class ZipUtil {
 		}
 	}
 	
-	public static boolean zip(List<VFSItem> vfsFiles, VFSLeaf target, boolean compress) {
+	public static boolean zip(List<VFSItem> vfsFiles, VFSLeaf target, VFSItemFilter filter, boolean withMetadata) {
 		boolean success = true;
 		
 		String zname = target.getName();
@@ -624,9 +627,9 @@ public class ZipUtil {
 
 		try(OutputStream out = target.getOutputStream(false);
 				ZipOutputStream zipOut = new ZipOutputStream(new BufferedOutputStream(out, FileUtils.BSIZE))) {
-			zipOut.setLevel(compress?9:0);
+			zipOut.setLevel(9);
 			for (VFSItem item:vfsFiles) {
-				success = addToZip(item, "", zipOut);
+				success = addToZip(item, "", zipOut, filter, withMetadata);
 			}
 			zipOut.flush();
 		} catch (IOException e) {
@@ -636,39 +639,43 @@ public class ZipUtil {
 		return success;
 	}
 	
-	public static boolean addToZip(VFSItem vfsItem, String currentPath, ZipOutputStream out) {
+	public static boolean addToZip(VFSItem vfsItem, String currentPath, ZipOutputStream out, VFSItemFilter filter, boolean withMetadata) {
 		boolean success = true;
 		try {
+			if(filter == null) {
+				filter = VFSAllItemsFilter.ACCEPT_ALL;
+			}
+			
 			// The separator / is the separator defined by the ZIP standard
 			String itemName = currentPath.length() == 0 ?
 					vfsItem.getName() : currentPath + "/" + vfsItem.getName();
+			if(filter.accept(vfsItem)) {
+				if (vfsItem instanceof VFSContainer ) {
+					out.putNextEntry(new ZipEntry(itemName + "/"));
+					out.closeEntry();
 					
-			if (vfsItem instanceof VFSContainer) {
-				out.putNextEntry(new ZipEntry(itemName + "/"));
-				out.closeEntry();
-				
-				List<VFSItem> items = ((VFSContainer)vfsItem).getItems();
-				for (VFSItem item:items) {
-					if (!addToZip(item, itemName, out)) {
-						success = false;
-						break;
+					List<VFSItem> items = ((VFSContainer)vfsItem).getItems();
+					for (VFSItem item:items) {
+						if (!addToZip(item, itemName, out, filter, withMetadata)) {
+							success = false;
+							break;
+						}
 					}
-				}
-				
-			} else {
-				VFSLeaf leaf = (VFSLeaf)vfsItem;
-				ZipEntry entry = new ZipEntry(itemName);
-				out.putNextEntry(entry);
-				copyShielded(leaf, out);
-				out.closeEntry();
-				
-				if(leaf.canMeta() == VFSConstants.YES) {
-					byte[] metadata = MetaInfoReader.toBinaries(leaf.getMetaInfo());
-					if(metadata != null && metadata.length > 0) {
-						ZipEntry metaEntry = new ZipEntry("._oo_meta_".concat(itemName));
-						out.putNextEntry(metaEntry);
-						out.write(metadata);
-						out.closeEntry();
+				} else {
+					VFSLeaf leaf = (VFSLeaf)vfsItem;
+					ZipEntry entry = new ZipEntry(itemName);
+					out.putNextEntry(entry);
+					copyShielded(leaf, out);
+					out.closeEntry();
+					
+					if(withMetadata && leaf.canMeta() == VFSConstants.YES) {
+						byte[] metadata = MetaInfoReader.toBinaries(leaf.getMetaInfo());
+						if(metadata != null && metadata.length > 0) {
+							ZipEntry metaEntry = new ZipEntry(currentPath + "/._oo_meta_".concat(vfsItem.getName()));
+							out.putNextEntry(metaEntry);
+							out.write(metadata);
+							out.closeEntry();
+						}
 					}
 				}
 			}
@@ -689,16 +696,16 @@ public class ZipUtil {
 	 * 
 	 * @param rootFile
 	 * @param targetZipFile
-	 * @param compress to compress or just store (if already compressed)
+	 * @param withMetadata A metadata as shadow file
 	 * @return true = success, false = exception/error
 	 */
-	public static boolean zipAll(File rootFile, File targetZipFile, boolean compress) {
+	public static boolean zipAll(File rootFile, File targetZipFile, boolean withMetadata) {
 		Set<String> fileSet = new HashSet<>();
 		String[] files = rootFile.list();
 		for (int i = 0; i < files.length; i++) {
 			fileSet.add(files[i]);
 		}		
-		return zip(fileSet, rootFile, targetZipFile, compress);
+		return zip(fileSet, rootFile, targetZipFile, VFSAllItemsFilter.ACCEPT_ALL, withMetadata);
 	}
 	
 	/**
@@ -832,17 +839,6 @@ public class ZipUtil {
 		}
 	}
 	
-	/**
-	 * Zip all files under a certain root directory. (with compression)
-	 * 
-	 * @param rootFile
-	 * @param targetZipFile
-	 * @return true = success, false = exception/error
-	 */
-	public static boolean zipAll(File rootFile, File targetZipFile) {
-		return zipAll(rootFile, targetZipFile, true);
-	}
-	
 	/**
 	 * Unzip files from stream into target dir and do NOTHING ELSE!!!
 	 * See OLAT-6213
diff --git a/src/main/java/org/olat/core/util/mail/ui/EMailIdentity.java b/src/main/java/org/olat/core/util/mail/ui/EMailIdentity.java
index 69af87462bcedb96ecbc107ac2957d1ca4beb16c..e9be3a72b8e5a0b1676b8e8cb6d9c6d35e726b97 100644
--- a/src/main/java/org/olat/core/util/mail/ui/EMailIdentity.java
+++ b/src/main/java/org/olat/core/util/mail/ui/EMailIdentity.java
@@ -88,6 +88,11 @@ public class EMailIdentity implements Identity {
 	public Date getInactivationDate() {
 		return null;
 	}
+	
+	@Override
+	public Date getReactivationDate() {
+		return null;
+	}
 
 	private class EMailUser implements User, ModifiedInfo {
 
diff --git a/src/main/java/org/olat/core/util/vfs/filters/VFSAllItemsFilter.java b/src/main/java/org/olat/core/util/vfs/filters/VFSAllItemsFilter.java
new file mode 100644
index 0000000000000000000000000000000000000000..8a24adb105459c6047172155a53be3fcfb8009f4
--- /dev/null
+++ b/src/main/java/org/olat/core/util/vfs/filters/VFSAllItemsFilter.java
@@ -0,0 +1,23 @@
+package org.olat.core.util.vfs.filters;
+
+import org.olat.core.util.vfs.VFSItem;
+
+/**
+ * 
+ * Initial date: 24 sept. 2020<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class VFSAllItemsFilter implements VFSItemFilter {
+	
+	public static final VFSItemFilter ACCEPT_ALL = new VFSAllItemsFilter();
+	
+	private VFSAllItemsFilter() {
+		//
+	}
+
+	@Override
+	public boolean accept(VFSItem vfsItem) {
+		return true;
+	}
+}
diff --git a/src/main/java/org/olat/core/util/vfs/filters/VFSRevisionsAndThumbnailsFilter.java b/src/main/java/org/olat/core/util/vfs/filters/VFSRevisionsAndThumbnailsFilter.java
new file mode 100644
index 0000000000000000000000000000000000000000..b81534ba2a5393e9b9a5c4e5a3276e267c088c0a
--- /dev/null
+++ b/src/main/java/org/olat/core/util/vfs/filters/VFSRevisionsAndThumbnailsFilter.java
@@ -0,0 +1,19 @@
+package org.olat.core.util.vfs.filters;
+
+import org.olat.core.util.vfs.VFSItem;
+
+/**
+ * Accept all files but thumbnails and revisions.
+ * 
+ * Initial date: 24 sept. 2020<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class VFSRevisionsAndThumbnailsFilter implements VFSItemFilter {
+
+	@Override
+	public boolean accept(VFSItem vfsItem) {
+		String name = vfsItem.getName();
+		return !name.startsWith("._oo_th_") && !name.startsWith("._oo_vr_");
+	}
+}
diff --git a/src/main/java/org/olat/course/assessment/ui/mode/AssessmentModeEditController.java b/src/main/java/org/olat/course/assessment/ui/mode/AssessmentModeEditController.java
index b8a710260d5b7c258dad33782979e26b0d18ce89..de59c36f8a2d15da37a0c9215b3027263b5c1481 100644
--- a/src/main/java/org/olat/course/assessment/ui/mode/AssessmentModeEditController.java
+++ b/src/main/java/org/olat/course/assessment/ui/mode/AssessmentModeEditController.java
@@ -27,6 +27,7 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 import java.util.stream.Collectors;
+import java.util.StringTokenizer;
 
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.form.flexible.FormItem;
@@ -592,8 +593,31 @@ public class AssessmentModeEditController extends FormBasicController {
 			if(ipsMultiselect.getSelectedKeys().size() < 1) {
 				ipsMultiselect.setErrorKey("form.legende.mandatory", null);
 				allOk &= false;
+			} else {
+				allOk &= validIpList(ipListEl.getValue());
+			}
+		}
+		return allOk;
+	}
+	
+	/**
+	 * Try to begin some validation of the list but the list allowed
+	 * a lot of possibilities.
+	 * 
+	 * @param ipList The list of IPs
+	 * @return true if valid
+	 */
+	private boolean validIpList(String ipList) {
+		boolean allOk = true;
+		
+		for(StringTokenizer tokenizer = new StringTokenizer(ipList, "\n\r", false); tokenizer.hasMoreTokens(); ) {
+			String ipRange = tokenizer.nextToken();
+			if(StringHelper.containsNonWhitespace(ipRange) && ipRange.startsWith("/")) {
+				ipListEl.setErrorKey("error.ip.range.cannot.start.slash", new String[] { ipRange } );
+				allOk &= false;
 			}
 		}
+		
 		return allOk;
 	}
 
diff --git a/src/main/java/org/olat/course/assessment/ui/mode/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/assessment/ui/mode/_i18n/LocalStrings_de.properties
index 1bdfda03b1d0c88a9787cab03a388998f9750be0..7393dc4bb22258681d7889d1980167bec814b940 100644
--- a/src/main/java/org/olat/course/assessment/ui/mode/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/course/assessment/ui/mode/_i18n/LocalStrings_de.properties
@@ -58,6 +58,7 @@ error.atleastone=Bitte w\u00E4hlen Sie mindestens ein Pr\u00FCfungskonfiguration
 error.course.element.mandatory=Bitte w\u00E4hlen Sie die entsprechenden Kursbausteine.
 error.in.assessment=Sie d\u00FCrfen kein Pr\u00FCfungen l\u00F6schen die gerade gestartet sind.
 error.ip.range=Sie sind nicht im richtigen Netzwerk.
+error.ip.range.cannot.start.slash=Eine Adresse IP darf nicht mit einem Slash (/) anfangen: {0}
 error.ip.range.desc=Diese Pr\u00FCfung kann nur in den daf\u00FCr vorgesehenen Netzwerken durchgef\u00FChrt werden, bitte kontaktieren Sie Ihren Pr\u00FCfungsverantwortlichen. Ihre IP-Adresse lautet: {0}
 error.safe.exam=Bitte benutzen Sie den Safe Exam Browser.
 error.safe.exam.desc=Sie verwenden entweder nicht den <a href\="http://safeexambrowser.org" target\="_blank">Safe Exam Browser</a> oder eine falsche Safe Exam Browser Konfigurationsdatei. Bitte verwenden Sie ausschliesslich die von Ihrem Pr\u00FCfungsverantwortlichen bereitgestellte Safe Exam Browser Konfigurationsdatei f\u00FCr Ihr Betriebssystem. 
diff --git a/src/main/java/org/olat/course/assessment/ui/mode/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/course/assessment/ui/mode/_i18n/LocalStrings_en.properties
index 556b01e8f0488ff3ac690d9a1bd628dfd8af9415..dc0d7233583dc0b2a87fec6a26f048fc1e8d0ad9 100644
--- a/src/main/java/org/olat/course/assessment/ui/mode/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/course/assessment/ui/mode/_i18n/LocalStrings_en.properties
@@ -61,6 +61,7 @@ error.curriculum.missing=You must choose at least one curriculum element.
 error.group.missing=You must choose at least one group.
 error.in.assessment=You cannot delete an assessment which is running.
 error.ip.range=You are not in the right network.
+error.ip.range.cannot.start.slash=An IP cannot start with a slash: {0}
 error.ip.range.desc=The exam can only be taken in the registered networks, please contact your exam manager. Your IP address is\: {0}
 error.safe.exam=Please, use the Safe Exam Browser.
 error.safe.exam.desc=You are either not using the <a href\="http\://safeexambrowser.org" target\="_blank">Safe Exam Browser</a> or a wrong Safe Exam Browser configuration file. Please use the configuration file specific to your operating system that was made available by your exam manager. 
diff --git a/src/main/java/org/olat/course/export/CourseExportMediaResource.java b/src/main/java/org/olat/course/export/CourseExportMediaResource.java
index 134aa58d03f7977444961201c5c3f0e212730a51..a3a29f91505fdecd537c014efd35130b12f5f6d5 100644
--- a/src/main/java/org/olat/course/export/CourseExportMediaResource.java
+++ b/src/main/java/org/olat/course/export/CourseExportMediaResource.java
@@ -48,6 +48,7 @@ import org.olat.core.util.tree.TreeVisitor;
 import org.olat.core.util.vfs.LocalFolderImpl;
 import org.olat.core.util.vfs.VFSContainer;
 import org.olat.core.util.vfs.VFSManager;
+import org.olat.core.util.vfs.filters.VFSRevisionsAndThumbnailsFilter;
 import org.olat.course.CourseFactory;
 import org.olat.course.ICourse;
 import org.olat.course.PersistingCourseImpl;
@@ -391,7 +392,7 @@ public class CourseExportMediaResource implements MediaResource, StreamingOutput
 			String nodeDirectory = ZipUtil.concat(ICourse.EXPORTED_DATA_FOLDERNAME, courseNode.getIdent());
 			zout.putNextEntry(new ZipEntry(ZipUtil.concat(nodeDirectory, "oonode.zip")));
 			
-			ZipUtil.zip(nodeContainer, fOut);
+			ZipUtil.zip(nodeContainer, fOut, new VFSRevisionsAndThumbnailsFilter(), true);
 			
 			zout.closeEntry();
 		} catch (IOException e) {
diff --git a/src/main/java/org/olat/course/nodes/BCCourseNode.java b/src/main/java/org/olat/course/nodes/BCCourseNode.java
index 2cf38dcdc345bd41fffb64f8baeba965fb7b649e..644b83efdf8c41d2939067b9e81f3b81bddcdc7c 100644
--- a/src/main/java/org/olat/course/nodes/BCCourseNode.java
+++ b/src/main/java/org/olat/course/nodes/BCCourseNode.java
@@ -51,6 +51,7 @@ import org.olat.core.util.vfs.NamedContainerImpl;
 import org.olat.core.util.vfs.VFSContainer;
 import org.olat.core.util.vfs.VFSItem;
 import org.olat.core.util.vfs.VFSManager;
+import org.olat.core.util.vfs.filters.VFSRevisionsAndThumbnailsFilter;
 import org.olat.core.util.vfs.filters.VFSSystemItemFilter;
 import org.olat.course.CourseModule;
 import org.olat.course.ICourse;
@@ -202,7 +203,7 @@ public class BCCourseNode extends AbstractAccessableCourseNode {
 		File fNodeExportDir = new File(exportDirectory, getIdent());
 		fNodeExportDir.mkdirs();
 		File outputFile = new File(fNodeExportDir, "oonode.zip");
-		ZipUtil.zip(nodeContainer, outputFile);
+		ZipUtil.zip(nodeContainer, outputFile, new VFSRevisionsAndThumbnailsFilter(), true);
 	}
 
 	@Override
diff --git a/src/main/java/org/olat/course/nodes/CheckListCourseNode.java b/src/main/java/org/olat/course/nodes/CheckListCourseNode.java
index 1a7ddfac05478d99108bf14dc0806541d2145f3a..6c6a6ca33bd5b9cb07f10574002a3c9d72314589 100644
--- a/src/main/java/org/olat/course/nodes/CheckListCourseNode.java
+++ b/src/main/java/org/olat/course/nodes/CheckListCourseNode.java
@@ -54,6 +54,7 @@ import org.olat.core.util.resource.OresHelper;
 import org.olat.core.util.vfs.VFSContainer;
 import org.olat.core.util.vfs.VFSItem;
 import org.olat.core.util.vfs.VFSLeaf;
+import org.olat.core.util.vfs.filters.VFSSystemItemFilter;
 import org.olat.course.ICourse;
 import org.olat.course.assessment.AssessmentManager;
 import org.olat.course.assessment.CourseAssessmentService;
@@ -302,7 +303,7 @@ public class CheckListCourseNode extends AbstractAccessableCourseNode {
 						} else {
 							usedNames.add(checkbox.getTitle());
 						}
-						ZipUtil.addToZip(item, path, exportStream);
+						ZipUtil.addToZip(item, path, exportStream, new VFSSystemItemFilter(), false);
 					}
 				}
 			}
diff --git a/src/main/java/org/olat/course/nodes/DialogCourseNode.java b/src/main/java/org/olat/course/nodes/DialogCourseNode.java
index e427085f1ad7609747e271f98bc34db1ff261094..5d81b57d53500f62d113f08fc6b617d083bde81e 100644
--- a/src/main/java/org/olat/course/nodes/DialogCourseNode.java
+++ b/src/main/java/org/olat/course/nodes/DialogCourseNode.java
@@ -51,6 +51,7 @@ import org.olat.core.util.vfs.VFSContainer;
 import org.olat.core.util.vfs.VFSItem;
 import org.olat.core.util.vfs.callbacks.FullAccessCallback;
 import org.olat.core.util.vfs.filters.VFSLeafFilter;
+import org.olat.core.util.vfs.filters.VFSSystemItemFilter;
 import org.olat.course.CourseModule;
 import org.olat.course.ICourse;
 import org.olat.course.condition.Condition;
@@ -307,7 +308,7 @@ public class DialogCourseNode extends AbstractAccessableCourseNode {
 		
 		VFSContainer forumContainer =  depm.getDialogContainer(element);
 		for(VFSItem item: forumContainer.getItems(new VFSLeafFilter())) {
-			ZipUtil.addToZip(item, exportDirName, exportStream);
+			ZipUtil.addToZip(item, exportDirName, exportStream, new VFSSystemItemFilter(), false);
 		}
 		
 		try {
diff --git a/src/main/java/org/olat/course/nodes/GTACourseNode.java b/src/main/java/org/olat/course/nodes/GTACourseNode.java
index dd2ed3532eb5732d522fe7e115b0473e7b11ddcd..ba1fa7cd762e0a97f3215d61940b0766b5a9f6f0 100644
--- a/src/main/java/org/olat/course/nodes/GTACourseNode.java
+++ b/src/main/java/org/olat/course/nodes/GTACourseNode.java
@@ -620,7 +620,7 @@ public class GTACourseNode extends AbstractAccessableCourseNode {
 			if (solutions.exists()) {
 				String solutionDirName = dirName + "/solutions";
 				for(VFSItem solution:solutions.getItems(new VFSSystemItemFilter())) {
-					ZipUtil.addToZip(solution, solutionDirName, exportStream);
+					ZipUtil.addToZip(solution, solutionDirName, exportStream, new VFSSystemItemFilter(), false);
 				}
 			}
 		}
diff --git a/src/main/java/org/olat/course/nodes/ProjectBrokerCourseNode.java b/src/main/java/org/olat/course/nodes/ProjectBrokerCourseNode.java
index 8a9dbcad3813663e9bb3d845039eb23cc8eda022..5609e7cbc4a625d6f9dc70f14104c35aeae0008a 100644
--- a/src/main/java/org/olat/course/nodes/ProjectBrokerCourseNode.java
+++ b/src/main/java/org/olat/course/nodes/ProjectBrokerCourseNode.java
@@ -635,7 +635,7 @@ public class ProjectBrokerCourseNode extends AbstractAccessableCourseNode {
 					if (!VFSManager.isDirectoryAndNotEmpty(userFolder))
 						continue;
 					String path = exportDirName + "/dropboxes/" + themaItem.getName();
-					ZipUtil.addToZip(userFolder, path, exportStream);
+					ZipUtil.addToZip(userFolder, path, exportStream, new VFSSystemItemFilter(), false);
 				}
 			}
 		}
@@ -650,7 +650,7 @@ public class ProjectBrokerCourseNode extends AbstractAccessableCourseNode {
 					if (!VFSManager.isDirectoryAndNotEmpty(userFolder))
 						continue;
 					String path = exportDirName + "/returnboxes/" + themaItem.getName();
-					ZipUtil.addToZip(userFolder, path, exportStream);
+					ZipUtil.addToZip(userFolder, path, exportStream, new VFSSystemItemFilter(), false);
 				}
 			}
 		}
diff --git a/src/main/java/org/olat/course/nodes/TACourseNode.java b/src/main/java/org/olat/course/nodes/TACourseNode.java
index 2e6f0a9944f687652b08aa86573fafa43488b113..e46877bde855ab16af49cbe1b6f54d5aa1517a29 100644
--- a/src/main/java/org/olat/course/nodes/TACourseNode.java
+++ b/src/main/java/org/olat/course/nodes/TACourseNode.java
@@ -516,7 +516,7 @@ public class TACourseNode extends GenericCourseNode {
 			if (solutionDir.exists()) {
 				for(VFSItem child:solutionDir.getItems(new VFSSystemItemFilter())) {
 					dataFound = true;
-					ZipUtil.addToZip(child, dirName + "/solutions", exportStream);
+					ZipUtil.addToZip(child, dirName + "/solutions", exportStream, new VFSSystemItemFilter(), false);
 				}
 			}
 				
@@ -527,7 +527,7 @@ public class TACourseNode extends GenericCourseNode {
 				for (VFSItem file:dropBoxContent) {
 					if((dropboxNames == null || dropboxNames.contains(file.getName())) && VFSManager.isDirectoryAndNotEmpty(file)){
 						dataFound = true;
-						ZipUtil.addToZip(file, dirName + "/dropboxes", exportStream);
+						ZipUtil.addToZip(file, dirName + "/dropboxes", exportStream, new VFSSystemItemFilter(), false);
 					}
 				}
 			}
@@ -542,7 +542,7 @@ public class TACourseNode extends GenericCourseNode {
 					VFSItem item = taskfolderDir.resolve(assignedTask);
 					if(item != null) {
 						// copy choosen task to user folder
-						ZipUtil.addToZip(item, dirName + "/taskfolders/" + identity.getName(), exportStream);
+						ZipUtil.addToZip(item, dirName + "/taskfolders/" + identity.getName(), exportStream, new VFSSystemItemFilter(), false);
 						dataFound = true;
 					}
 				}
@@ -555,7 +555,7 @@ public class TACourseNode extends GenericCourseNode {
 				for (VFSItem file : returnBoxContent) {
 					if((dropboxNames == null || dropboxNames.contains(file.getName())) && VFSManager.isDirectoryAndNotEmpty(file)){
 						dataFound = true;
-						ZipUtil.addToZip(file, dirName + "/returnboxes", exportStream);
+						ZipUtil.addToZip(file, dirName + "/returnboxes", exportStream, new VFSSystemItemFilter(), false);
 					}
 				}
 			}
diff --git a/src/main/java/org/olat/course/nodes/gta/GTAManager.java b/src/main/java/org/olat/course/nodes/gta/GTAManager.java
index 1544d6661f747cd64204809c525023bfb749a814..c1d552dbd8b220657ed88bcf8ecc958ee6e8ce67 100644
--- a/src/main/java/org/olat/course/nodes/gta/GTAManager.java
+++ b/src/main/java/org/olat/course/nodes/gta/GTAManager.java
@@ -232,7 +232,7 @@ public interface GTAManager {
 	 * @param by The role of the doer
 	 * @return true if the status is done
 	 */
-	public boolean syncAssessmentEntry(Task task, GTACourseNode cNode, UserCourseEnvironment assessedUserCourseEnv, Identity doerIdentity, Role by);
+	public boolean syncAssessmentEntry(Task task, GTACourseNode cNode, UserCourseEnvironment assessedUserCourseEnv, boolean incrementUserAttempts, Identity doerIdentity, Role by);
 	
 	/**
 	 * Are users already processing this task?
diff --git a/src/main/java/org/olat/course/nodes/gta/manager/GTAManagerImpl.java b/src/main/java/org/olat/course/nodes/gta/manager/GTAManagerImpl.java
index 61e473327487f20a6f0977cdbac1212d84355dff..926115ed67296f45777ab9eb1fec24dd41b7c379 100644
--- a/src/main/java/org/olat/course/nodes/gta/manager/GTAManagerImpl.java
+++ b/src/main/java/org/olat/course/nodes/gta/manager/GTAManagerImpl.java
@@ -1025,7 +1025,7 @@ public class GTAManagerImpl implements GTAManager {
 					task = dbInstance.getCurrentEntityManager().merge(task);
 				}	
 				dbInstance.commit();
-				syncAssessmentEntry(task, cNode, null, doerIdentity, Role.user);
+				syncAssessmentEntry(task, cNode, null, false, doerIdentity, Role.user);
 				response = new AssignmentResponse(task, Status.ok);
 			}
 		} else {
@@ -1033,7 +1033,7 @@ public class GTAManagerImpl implements GTAManager {
 				((TaskImpl)currentTask).setTaskStatus(TaskProcess.submit);
 			}
 			currentTask = dbInstance.getCurrentEntityManager().merge(currentTask);
-			syncAssessmentEntry(currentTask, cNode, null, doerIdentity, Role.user);
+			syncAssessmentEntry(currentTask, cNode, null, false, doerIdentity, Role.user);
 			response = new AssignmentResponse(currentTask, Status.ok);
 		}
 		
@@ -1156,7 +1156,7 @@ public class GTAManagerImpl implements GTAManager {
 				TaskImpl task = createTask(taskName, reloadedTasks, nextStep, businessGroup, identity, cNode);
 				task.setAssignmentDate(new Date());
 				dbInstance.getCurrentEntityManager().persist(task);
-				syncAssessmentEntry(task, cNode, null, doerIdentity, Role.user);
+				syncAssessmentEntry(task, cNode, null, false, doerIdentity, Role.user);
 				response = new AssignmentResponse(task, Status.ok);
 			}
 			dbInstance.commit();
@@ -1169,7 +1169,7 @@ public class GTAManagerImpl implements GTAManager {
 				}
 			}
 			currentTask = dbInstance.getCurrentEntityManager().merge(currentTask);
-			syncAssessmentEntry(currentTask, cNode, null, doerIdentity, Role.user);
+			syncAssessmentEntry(currentTask, cNode, null, false, doerIdentity, Role.user);
 			response = new AssignmentResponse(currentTask, Status.ok);
 		}
 		return response;
@@ -1421,7 +1421,7 @@ public class GTAManagerImpl implements GTAManager {
 		taskImpl.setTaskStatus(nextStep);
 		TaskImpl mergedTask = dbInstance.getCurrentEntityManager().merge(taskImpl);
 		dbInstance.commit();//make the thing definitive
-		syncAssessmentEntry(mergedTask, cNode, null, doerIdentity, by);
+		syncAssessmentEntry(mergedTask, cNode, null, incrementUserAttempts, doerIdentity, by);
 		return mergedTask;
 	}
 	
@@ -1650,7 +1650,7 @@ public class GTAManagerImpl implements GTAManager {
 		taskImpl.setTaskStatus(newStatus);
 		syncDates(taskImpl, newStatus);
 		taskImpl = dbInstance.getCurrentEntityManager().merge(taskImpl);
-		syncAssessmentEntry(taskImpl, cNode, null, doerIdentity, by);
+		syncAssessmentEntry(taskImpl, cNode, null, incrementUserAttempts, doerIdentity, by);
 		
 		// mark the publishers
 		OLATResource resource = taskImpl.getTaskList().getEntry().getOlatResource();
@@ -1701,7 +1701,7 @@ public class GTAManagerImpl implements GTAManager {
 		taskImpl = dbInstance.getCurrentEntityManager().merge(taskImpl);
 		//log date
 		createAndPersistTaskRevisionDate(taskImpl, iteration, newStatus);
-		syncAssessmentEntry(taskImpl, cNode, null, doerIdentity, by);
+		syncAssessmentEntry(taskImpl, cNode, null, incrementUserAttempts, doerIdentity, by);
 		return taskImpl;
 	}
 
@@ -1769,7 +1769,7 @@ public class GTAManagerImpl implements GTAManager {
 
 	@Override
 	public boolean syncAssessmentEntry(Task taskImpl, GTACourseNode cNode,
-			UserCourseEnvironment assessedUserCourseEnv, Identity doerIdentity, Role by) {
+			UserCourseEnvironment assessedUserCourseEnv, boolean incrementUserAttempts, Identity doerIdentity, Role by) {
 		if(taskImpl == null || taskImpl.getTaskStatus() == null || cNode == null) return false;
 		
 		TaskList taskList = getTaskList(taskImpl);
@@ -1788,7 +1788,7 @@ public class GTAManagerImpl implements GTAManager {
 				}
 				AssessmentEvaluation scoreEvaluation = courseAssessmentService.getAssessmentEvaluation(cNode, userCourseEnv);
 				AssessmentEvaluation newScoreEvaluation = new AssessmentEvaluation(scoreEvaluation, assessmentStatus);
-	 			courseAssessmentService.saveScoreEvaluation(cNode, doerIdentity, newScoreEvaluation, userCourseEnv, false, by);
+	 			courseAssessmentService.saveScoreEvaluation(cNode, doerIdentity, newScoreEvaluation, userCourseEnv, incrementUserAttempts, by);
 	 			if(doerIdentity != null && doerIdentity.equals(assessedIdentity)) {
 	 				currentAssessmentStatus = scoreEvaluation.getAssessmentStatus();
 	 			}
@@ -1805,7 +1805,7 @@ public class GTAManagerImpl implements GTAManager {
 			AssessmentEvaluation scoreEvaluation = courseAssessmentService.getAssessmentEvaluation(cNode, userCourseEnv);
 			currentAssessmentStatus = scoreEvaluation.getAssessmentStatus();
 			AssessmentEvaluation newScoreEvaluation = new AssessmentEvaluation(scoreEvaluation, assessmentStatus);
- 			courseAssessmentService.saveScoreEvaluation(cNode, doerIdentity, newScoreEvaluation, userCourseEnv, false, by);
+ 			courseAssessmentService.saveScoreEvaluation(cNode, doerIdentity, newScoreEvaluation, userCourseEnv, incrementUserAttempts, by);
 		}
 		return currentAssessmentStatus != assessmentStatus;
 	}
diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GTAParticipantController.java b/src/main/java/org/olat/course/nodes/gta/ui/GTAParticipantController.java
index 113a79aac89cfdc3e5a293dbd9144caa8c1bb879..43ae2950c992395ff04884989492e69757b64bd1 100644
--- a/src/main/java/org/olat/course/nodes/gta/ui/GTAParticipantController.java
+++ b/src/main/java/org/olat/course/nodes/gta/ui/GTAParticipantController.java
@@ -619,7 +619,7 @@ public class GTAParticipantController extends GTAAbstractController implements A
 				
 				if(gtaManager.firstStep(gtaNode) == TaskProcess.solution) {
 					assignedTask = gtaManager.ensureTaskExists(assignedTask, assessedGroup, assessedIdentity, courseEntry, gtaNode);
-					gtaManager.syncAssessmentEntry(assignedTask, gtaNode, userCourseEnv, getIdentity(), Role.user);
+					gtaManager.syncAssessmentEntry(assignedTask, gtaNode, userCourseEnv, false, getIdentity(), Role.user);
 				}
 			} else {
 				VelocityContainer waitVC = createVelocityContainer("no_solutions_foryou");
diff --git a/src/main/java/org/olat/course/nodes/st/STCourseNodeRunController.java b/src/main/java/org/olat/course/nodes/st/STCourseNodeRunController.java
index 5f8d1cb374c5b7d9622a6d3c8408b0ee0118c833..2a453b5e5f47a52196907bbc0903bd0343c46b28 100644
--- a/src/main/java/org/olat/course/nodes/st/STCourseNodeRunController.java
+++ b/src/main/java/org/olat/course/nodes/st/STCourseNodeRunController.java
@@ -129,7 +129,7 @@ public class STCourseNodeRunController extends BasicController {
 				.withFilter(AccessibleFilter.create())
 				.build()
 				.getNodeById(stCourseNode.getIdent());
-		int chdCnt = courseTreeNode.getChildCount();
+		int chdCnt = courseTreeNode == null ? 0 : courseTreeNode.getChildCount();
 		for (int i = 0; i < chdCnt; i++) {
 			INode childNode = courseTreeNode.getChildAt(i);
 			if (childNode instanceof CourseTreeNode) {
@@ -141,7 +141,7 @@ public class STCourseNodeRunController extends BasicController {
 					Controller childPeekViewController = null;
 					boolean accessible = childCourseTreeNode.isAccessible();
 					if (displayType.equals(STCourseNodeEditController.CONFIG_VALUE_DISPLAY_PEEKVIEW)) {
-						if (peekviewChildNodes.size() == 0) {
+						if (peekviewChildNodes.isEmpty()) {
 							// Special case: no child nodes configured. This is the case when
 							// the node has been configured before it had any children. We just
 							// use the first children as they appear in the list
diff --git a/src/main/java/org/olat/course/run/preview/PreviewIdentity.java b/src/main/java/org/olat/course/run/preview/PreviewIdentity.java
index 7eaa1570696c97060ae9beccf7f97f9526f08103..47b6c2ae51a66ab4a8e25793575ad7b8e7a22e21 100644
--- a/src/main/java/org/olat/course/run/preview/PreviewIdentity.java
+++ b/src/main/java/org/olat/course/run/preview/PreviewIdentity.java
@@ -164,6 +164,11 @@ public final class PreviewIdentity implements Identity, User {
 		return null;
 	}
 
+	@Override
+	public Date getReactivationDate() {
+		return null;
+	}
+
 	@Override
 	public boolean equalsByPersistableKey(Persistable persistable) {
 		return equals(persistable);
diff --git a/src/main/java/org/olat/course/statistic/ExportManager.java b/src/main/java/org/olat/course/statistic/ExportManager.java
index a67dd704a8a9847119189e2851901ece10309d98..63a36cbc8260bb09eb40a7911ebfb49c9e0c9527 100644
--- a/src/main/java/org/olat/course/statistic/ExportManager.java
+++ b/src/main/java/org/olat/course/statistic/ExportManager.java
@@ -152,16 +152,18 @@ public class ExportManager {
 		
 		File outFile = new File(dir, filename);
 		// trigger the course log exporter - it will store the file to outFile
-		log.info("createLogFile: start exporting course log file "+outFile.getAbsolutePath());
+		log.info("createLogFile: start exporting course log file {}", outFile);
 		courseLogExporter.exportCourseLog(outFile, oresID, begin, end, resourceAdminAction, anonymize, isAdministrativeUser);
-		log.info("createLogFile: finished exporting course log file "+outFile.getAbsolutePath());
+		log.info("createLogFile: finished exporting course log file {}", outFile);
 		return outFile;
 	}
 	
 	private void saveFile(String targetDir, String zipName, File tmpDir, List<File> files, String email, String emailI18nSubkey, Locale locale) {
 		File zipFile = new File(targetDir, zipName);
-		Set<String> filenames = files.stream().map(File::getName).collect(Collectors.toSet());
-		if (ZipUtil.zip(filenames, tmpDir, zipFile)) {
+		Set<String> filenames = files.stream()
+				.map(File::getName)
+				.collect(Collectors.toSet());
+		if (ZipUtil.zip(filenames, tmpDir, zipFile, false)) {
 			sendEMail(email, locale, emailI18nSubkey);
 		}
 		FileUtils.deleteDirsAndFiles(tmpDir, true, true);
diff --git a/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_pt_BR.properties
index b1969e9ce7ea433ef2fc6b64858eb0d9f968ed30..4355a2e950576815ee3588315a4bc3a0a02ac02f 100644
--- a/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_pt_BR.properties
+++ b/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_pt_BR.properties
@@ -1,4 +1,4 @@
-#Tue May 26 15:24:24 CEST 2020
+#Thu Sep 24 14:18:24 CEST 2020
 accept=Confirmar
 action=A\u00E7\u00E3o
 add.member=Adicionar membro
@@ -74,6 +74,7 @@ msg.alleastone.editable.group=Voc\u00EA deve selecionar pelo menos um grupo que
 msg.alleasttwo.editable.group=Voc\u00EA deve selecionar pelo menos um grupo em que tenha a fun\u00E7\u00E3o de treinador.
 msg.atleastone=Deve haver no m\u00EDnimo um propriet\u00E1rio neste grupo de projeto.
 msg.only.editable.group=Voc\u00EA deve selecionar grupos onde voc\u00EA tem a fun\u00E7\u00E3o de treinador.
+msg.send.ok=Sua mensagem foi enviada com sucesso.
 my.groups=Meus grupos
 my.groups.alt=Trabalhar com seus grupos
 nomembers=Nenhum membro encontrado que se enquadra nos crit\u00E9rios estabelecidos.
@@ -162,6 +163,7 @@ table.header.graduate=Admitir
 table.header.group.full=Completo
 table.header.groups=Grupo
 table.header.identifier=Identificador
+table.header.identity.status=Status
 table.header.key=ID
 table.header.lastName=\u00DAltimo nome
 table.header.lastTime=\u00DAltima visita
diff --git a/src/main/java/org/olat/group/ui/run/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/group/ui/run/_i18n/LocalStrings_pt_BR.properties
index 5b79e5e5844a3734f8b2a20777912ee737514206..eddc474bd355406673e2c68e10cf05007a0a9f2c 100644
--- a/src/main/java/org/olat/group/ui/run/_i18n/LocalStrings_pt_BR.properties
+++ b/src/main/java/org/olat/group/ui/run/_i18n/LocalStrings_pt_BR.properties
@@ -1,4 +1,4 @@
-#Wed May 27 00:02:54 CEST 2020
+#Thu Sep 24 20:15:48 CEST 2020
 businessgroup.contact.bodytext=<p></p>---<p>Ir imediatamente para o grupo "{0}"\: {1}</p>
 businessgroup.contact.subject=Mensagem para grupo {0}
 contact.all.coaches=Todos os treinadores (coaches) de grupo
diff --git a/src/main/java/org/olat/gui/control/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/gui/control/_i18n/LocalStrings_pt_BR.properties
index fe270411ba05ad884b51c988a0d3aae771b3ed25..990de91d1beacaeeb9001356816af858249d6d65 100644
--- a/src/main/java/org/olat/gui/control/_i18n/LocalStrings_pt_BR.properties
+++ b/src/main/java/org/olat/gui/control/_i18n/LocalStrings_pt_BR.properties
@@ -1,6 +1,6 @@
-#Wed Nov 04 23:14:08 CET 2015
-
+#Thu Sep 24 14:18:39 CEST 2020
 command.closeprinting=Fechar visualiza\u00E7\u00E3o de impress\u00E3o
+contact.to=Suporte
 footer.ajax.hover=Modo AJAX est\u00E1 ativo, o que significa respostas r\u00E1pidas no OLAT.
 footer.login=Entrar
 logged.in.invitee=(convidado)
@@ -19,6 +19,7 @@ topnav.login.alt=Entrar no servidor OLAT
 topnav.logout=Sair do OLAT
 topnav.logout.alt=Sair do servidor OLAT
 topnav.my.menu.configurations=Configura\u00E7\u00E3o
+topnav.my.menu.help=Ajuda
 topnav.my.menu.label={0}
 topnav.my.menu.systems=Sistema
 topnav.my.menu.tools=Ferramentas pessoais
diff --git a/src/main/java/org/olat/ims/qti/editor/QTIEditorPackageImpl.java b/src/main/java/org/olat/ims/qti/editor/QTIEditorPackageImpl.java
index 771c827b7c95c76cd50a8984568e013ff6921a73..1898f50112477b5f08c66aa71057fc2874ffe9a8 100644
--- a/src/main/java/org/olat/ims/qti/editor/QTIEditorPackageImpl.java
+++ b/src/main/java/org/olat/ims/qti/editor/QTIEditorPackageImpl.java
@@ -58,6 +58,7 @@ import org.olat.core.util.vfs.NamedContainerImpl;
 import org.olat.core.util.vfs.VFSContainer;
 import org.olat.core.util.vfs.VFSItem;
 import org.olat.core.util.vfs.callbacks.VFSSecurityCallback;
+import org.olat.core.util.vfs.filters.VFSAllItemsFilter;
 import org.olat.core.util.xml.XMLParser;
 import org.olat.core.util.xml.XStreamHelper;
 import org.olat.fileresource.FileResourceManager;
@@ -303,7 +304,7 @@ public class QTIEditorPackageImpl implements QTIEditorPackage {
 		files.add(ImsRepositoryResolver.QTI_FILE);
 		files.add("media");
 		files.add("changelog");
-		return ZipUtil.zip(files, packageDir, fOut, false);
+		return ZipUtil.zip(files, packageDir, fOut, VFSAllItemsFilter.ACCEPT_ALL, false);
 	}
 	
 	/**
diff --git a/src/main/java/org/olat/ims/qti/qpool/QTIExportProcessor.java b/src/main/java/org/olat/ims/qti/qpool/QTIExportProcessor.java
index 9400329e66e4682e6f4d15ff4459248ac79b2832..40ea29e5d038ac09a1a206065ef0d13573b8a472 100644
--- a/src/main/java/org/olat/ims/qti/qpool/QTIExportProcessor.java
+++ b/src/main/java/org/olat/ims/qti/qpool/QTIExportProcessor.java
@@ -49,6 +49,7 @@ import org.olat.core.util.vfs.VFSContainer;
 import org.olat.core.util.vfs.VFSItem;
 import org.olat.core.util.vfs.VFSLeaf;
 import org.olat.core.util.vfs.VFSManager;
+import org.olat.core.util.vfs.filters.VFSSystemItemFilter;
 import org.olat.core.util.xml.XMLParser;
 import org.olat.ims.qti.QTIConstants;
 import org.olat.ims.qti.editor.QTIEditHelper;
@@ -84,7 +85,7 @@ public class QTIExportProcessor {
 		List<VFSItem> items = container.getItems();
 		addMetadata(fullItem, rootDir, zout);
 		for(VFSItem item:items) {
-			ZipUtil.addToZip(item, rootDir, zout);
+			ZipUtil.addToZip(item, rootDir, zout, new VFSSystemItemFilter(), false);
 		}
 	}
 	
diff --git a/src/main/java/org/olat/ims/qti/repository/handlers/QTIHandler.java b/src/main/java/org/olat/ims/qti/repository/handlers/QTIHandler.java
index d25ab9f9fbf98b00c4614ad8c4b7e211333ad1ca..8aaf95ba116351f62d4c35c5d92af7e5e8bdeb21 100644
--- a/src/main/java/org/olat/ims/qti/repository/handlers/QTIHandler.java
+++ b/src/main/java/org/olat/ims/qti/repository/handlers/QTIHandler.java
@@ -106,7 +106,7 @@ public abstract class QTIHandler extends FileHandler {
 		File fResourceFileroot = FileResourceManager.getInstance().getFileResourceRootImpl(resource).getBasefile();
 		File zipDir = new File(fResourceFileroot, FileResourceManager.ZIPDIR);
 		FileResource.copyResource(file, filename, zipDir);
-		ZipUtil.zipAll(zipDir, new File(fResourceFileroot, "qti.zip"));
+		ZipUtil.zipAll(zipDir, new File(fResourceFileroot, "qti.zip"), false);
 		RepositoryEntry re = CoreSpringFactory.getImpl(RepositoryService.class).create(initialAuthor, null, "", displayname, description,
 				resource, RepositoryEntryStatusEnum.preparation, organisation);
 		DBFactory.getInstance().commit();
@@ -124,7 +124,7 @@ public abstract class QTIHandler extends FileHandler {
 
 		File targetDir = new File(targetRootDir, FileResourceManager.ZIPDIR);
 		FileResource.copyResource(sourceFile, sourceFile.getName(), targetDir, new ChangeLogFilter());
-		ZipUtil.zipAll(targetDir, new File(targetRootDir, "qti.zip"));
+		ZipUtil.zipAll(targetDir, new File(targetRootDir, "qti.zip"), false);
 		return target;
 	}
 	
diff --git a/src/main/java/org/olat/ims/qti21/ui/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/ims/qti21/ui/_i18n/LocalStrings_pt_BR.properties
index 0782eac332e9c3916941f5e07a0169ee08cf991c..23bbdc87517e54fa2f20602a59c11c7879efb301 100644
--- a/src/main/java/org/olat/ims/qti21/ui/_i18n/LocalStrings_pt_BR.properties
+++ b/src/main/java/org/olat/ims/qti21/ui/_i18n/LocalStrings_pt_BR.properties
@@ -1,4 +1,4 @@
-#Tue May 26 15:37:35 CEST 2020
+#Thu Sep 24 14:23:44 CEST 2020
 actualPoints=$org.olat.modules.iq\:actualPoints
 admin.menu.title=QTI 2.1
 admin.menu.title.alt=Defini\u00E7\u00F5es do QTI 2.1
@@ -80,6 +80,8 @@ confirm.suspend.test=$org.olat.modules.iq\:confirmSuspend
 confirmation=Confirma\u00E7\u00E3o
 correct.solution=Solu\u00E7\u00E3o correta
 correction=Grau
+correction.alternatives=Alternativa
+correction.readonly=Ver corre\u00E7\u00E3o somente leitura
 correction.workflow=Workflow de corre\u00E7\u00E3o
 correction.workflow.anonymous=An\u00F4nimo
 countdown.running=Limite de tempo {1} segundos\: <strong>{0} segundos restantes</strong>
@@ -140,6 +142,10 @@ interaction.order.drag.msg=Arraste itens n\u00E3o utilizados daqui ...
 interaction.order.drop.msg=Solte e ordene os itens selecionados aqui ...
 interaction.order.source=Fonte
 interaction.order.target=Alvo
+invalidate=Invalidar
+invalidate.overwrite=Invalidar e transferir o resultado
+invalidate.test.confirm.text=Quer marcar esta sess\u00E3o de teste como inv\u00E1lida? Os dados n\u00E3o ser\u00E3o exclu\u00EDdos.
+invalidate.test.confirm.title=Invalidar
 item.comment=Coment\u00E1rio
 kprim.minus=Falso
 kprim.plus=Verdadeiro
@@ -189,6 +195,9 @@ question.progress.noMaxScore=$org.olat.modules.iq\:noMaxScore
 question.progress.score=$org.olat.modules.iq\:actualPoints
 question.title=Pergunta {0}
 questions=N\u00FAmero de perguntas no teste
+reopen.assessment=Reabrir avalia\u00E7\u00E3o
+reopen.assessment.text=Esta avalia\u00E7\u00E3o j\u00E1 est\u00E1 encerrada. Quer reabri-la para corrigir o teste?
+reopen.assessment.title=Reabrir avalia\u00E7\u00E3o encerrada
 reset.data=Resetar dados
 reset.test.data.acknowledge=Eu entendo que os dados ser\u00E3o exclu\u00EDdos definitivamente.
 reset.test.data.text=Deseja realmente redefinir os dados de avalia\u00E7\u00E3o do teste? Os resultados de <strong>{0} usu\u00E1rios</strong> ser\u00E3o exclu\u00EDdos definitivamente.
@@ -222,11 +231,19 @@ results.title.failed=Desculpe, voc\u00EA falhou no teste.
 results.title.for=para {0}
 results.title.generic=Estes s\u00E3o os resultados do seu teste
 results.title.passed=Voc\u00EA passou no teste\!
+results.visibility.correction=Visibilidade dos resultados ap\u00F3s a corre\u00E7\u00E3o
+results.visibility.correction.not.visible=N\u00E3o vis\u00EDvel
+results.visibility.correction.visible=Vis\u00EDvel
 retrievetest.confirm.text=$org.olat.ims.qti\:retrievetest.confirm.text
 retrievetest.confirm.text.plural=$org.olat.ims.qti.statistics.ui\:retrievetest.confirm.text.plural
 retrievetest.confirm.title=$org.olat.ims.qti.statistics.ui\:retrievetest.confirm.title
 retrievetest.nothing.todo=$org.olat.ims.qti.statistics.ui\:retrievetest.nothing.todo
 retry.item=Tente novamente
+revalidate=Marcar como v\u00E1lido
+revalidate.overwrite=Marcar como v\u00E1lido e transferir o resultado
+revalidate.test=Marque novamente como v\u00E1lido
+revalidate.test.confirm.text=Quer marcar novamente esta sess\u00E3o de teste como v\u00E1lida?
+revalidate.test.confirm.title=$\:revalidate.test
 review.responses=Revise suas respostas
 review.responses.desc=Voc\u00EA pode rever suas respostas de algumas (ou todas) perguntas. Estes s\u00E3o listados abaixo.
 score.cut=$org.olat.ims.qti\:score.cut
@@ -249,6 +266,8 @@ table.header.corrected=Corrigido
 table.header.correction=$\:correction
 table.header.duration=Dura\u00E7\u00E3o
 table.header.finalScore=Pontua\u00E7\u00E3o final
+table.header.id=ID
+table.header.invalidate=Invalidar
 table.header.itemSessions=\# quest\u00F5es
 table.header.lastModified=Data
 table.header.manualScore=Pontua\u00E7\u00E3o manual
@@ -276,8 +295,11 @@ upload.explanation=Selecione um arquivo do seu computador para fazer o upload
 validate.xml.signature=Validar recibo de teste
 validate.xml.signature.file=Arquivo XML
 validate.xml.signature.ok=O recibo do teste e os resultados foram validados com sucesso.
+warning.assignment.done=A classifica\u00E7\u00E3o deste teste j\u00E1 foi conclu\u00EDda. Se esta sess\u00E3o de teste for marcada como inv\u00E1lida, todas as corre\u00E7\u00F5es existentes ser\u00E3o perdidas.
+warning.assignment.inProcess=A pontua\u00E7\u00E3o da prova j\u00E1 come\u00E7ou. Se esta sess\u00E3o de teste for marcada como inv\u00E1lida, todas as corre\u00E7\u00F5es existentes ser\u00E3o perdidas.
 warning.download.log=N\u00E3o h\u00E1 um arquivo de log para este teste.
 warning.reset.assessmenttest.data=Os resultados do teste foram redefinidos por um administrador ou propriet\u00E1rio do curso. Voc\u00EA n\u00E3o pode continuar o teste e precisa reinici\u00E1-lo.
 warning.reset.test.data.nobody=N\u00E3o h\u00E1 nenhum participante que os dados possam ser resetados.
+warning.suspended.ended.assessmenttest=Voc\u00EA j\u00E1 interrompeu ou finalizou o teste, provavelmente em outra janela. Por favor, feche esta janela agora.
 warning.xml.signature.notok=A assinatura e os resultados n\u00E3o podem ser validados um ao outro.
 warning.xml.signature.session.not.found=Resultados de testes n\u00E3o podem ser encontrados.
diff --git a/src/main/java/org/olat/ims/qti21/ui/assessment/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/ims/qti21/ui/assessment/_i18n/LocalStrings_pt_BR.properties
index ef952030c571d869408d854b0e2be50459155b3d..fe554b792f67302332ff0a5def063f373c3caefa 100644
--- a/src/main/java/org/olat/ims/qti21/ui/assessment/_i18n/LocalStrings_pt_BR.properties
+++ b/src/main/java/org/olat/ims/qti21/ui/assessment/_i18n/LocalStrings_pt_BR.properties
@@ -1,4 +1,4 @@
-#Tue May 26 15:40:50 CEST 2020
+#Thu Sep 24 14:23:53 CEST 2020
 anonymous.user=Examinando
 assessed.identity=Usu\u00E1rio avaliado
 back.overview=Voltar ao menu principal
@@ -26,8 +26,10 @@ override.score=Substituir pontua\u00E7\u00E3o
 overview.tests=Vis\u00E3o geral e fechamento
 previous.item=Quest\u00E3o anterior
 previous.user=Usu\u00E1rio anterior
+reopen.assessment.title=$org.olat.ims.qti21.ui\:reopen.assessment.title
 save.back=Salvar e voltar \u00E0 vis\u00E3o geral
 save.next=Salvar e pr\u00F3xima pergunta
+save.next.identity=Salvar e pr\u00F3ximo participante
 save.tests=Salvar resultados como conclu\u00EDdos
 score=Pontua\u00E7\u00E3o
 show.rubric=Mostrar descri\u00E7\u00E3o
diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/ims/qti21/ui/editor/_i18n/LocalStrings_pt_BR.properties
index f5644ca97006ea57d08866375c09264fdaf1bcee..8522a75963688a56dfdf989b5ff91e2a46915dfe 100644
--- a/src/main/java/org/olat/ims/qti21/ui/editor/_i18n/LocalStrings_pt_BR.properties
+++ b/src/main/java/org/olat/ims/qti21/ui/editor/_i18n/LocalStrings_pt_BR.properties
@@ -1,4 +1,4 @@
-#Tue May 26 16:08:00 CEST 2020
+#Thu Sep 24 14:32:31 CEST 2020
 MULTIPLE=M\u00FAltipla escolha
 SINGLE=Escolha \u00FAnica
 add=Adicionar
@@ -45,6 +45,7 @@ error.cardinality.answer="Escolha \u00FAnica" permite apenas uma resposta corret
 error.double=$org.olat.ims.qti21.ui\:error.double
 error.import.question=Houve um erro inesperado durante a importa\u00E7\u00E3o de uma pergunta
 error.integer=$org.olat.ims.qti21.ui\:error.integer
+error.integer.positive=Ele precisa de um n\u00FAmero entre 0 e 2147483647.
 error.lock=Este teste / question\u00E1rio est\u00E1 sendo editado pelo usu\u00E1rio {0} no momento e, portanto, est\u00E1 bloqueado.
 error.lock.same.user=$\:error.lock $org.olat.core\:lock.same.user.different.window
 error.lock.title=Teste bloqueado
@@ -86,8 +87,11 @@ fib.tolerance.mode.exact=Exato
 fib.tolerance.mode.exact.help=A solu\u00E7\u00E3o correlaciona-se exatamente com a solu\u00E7\u00E3o inserida em "Solu\u00E7\u00E3o"
 fib.tolerance.mode.relative=Relativo
 fib.tolerance.mode.relative.help=A solu\u00E7\u00E3o \u00E9 aceita at\u00E9 um limite inferior e um limite superior. O limite \u00E9 um n\u00FAmero relativo em porcentagem. Exemplo\: Solu\u00E7\u00E3o 20, limite inferior 10, limite superior 10 & rarr; Todas as solu\u00E7\u00F5es entre 18 e 22 s\u00E3o corretas, j\u00E1 que o limite inferior significa menos 10% (20-2) e o limite superior mais 10% (20 + 2).
+fib.tolerance.mode.relative.low.example=Toler\u00E2ncia inferior em porcentagem, exemplo 15
+fib.tolerance.mode.relative.up.example=Toler\u00E2ncia superior em porcentagem, exemplo 15
 fib.tolerance.up=Limite superior
 file=Arquivo
+force.inherited.max.attempts=Herdar o n\u00FAmero de tentativas para todos os subelementos (se\u00E7\u00F5es, perguntas)
 form.choice=Escolha
 form.drawing=Desenho
 form.essay=Reda\u00E7\u00E3o
@@ -298,6 +302,10 @@ warning.custom.operator=Esta quest\u00E3o cont\u00E9m uma extens\u00E3o espec\u0
 warning.feedback.cutvalue=O feedback \u00E9 baseado no valor de corte. Voc\u00EA precisa defini-lo primeiro.
 warning.in.use=O recurso j\u00E1 \u00E9 usado para fins de avalia\u00E7\u00E3o. A edi\u00E7\u00E3o \u00E9 limitada.
 warning.item.session.control.attempts=Esta limita\u00E7\u00E3o pode ter um impacto no n\u00FAmero de tentativas por perguntas. <br/>Verifique as configura\u00E7\u00F5es para as perguntas novamente.
+warning.item.session.control.attempts.all.items.defined=Todas as quest\u00F5es j\u00E1 definiram o n\u00FAmero de tentativas e anulam este valor.
+warning.item.session.control.attempts.all.sections.defined=Todas as se\u00E7\u00F5es j\u00E1 definiram o n\u00FAmero de tentativas e anulam este valor.
+warning.item.session.control.attempts.items.defined=Algumas perguntas definiram o n\u00FAmero de tentativas e substitu\u00EDram este valor.
+warning.item.session.control.attempts.sections.defined=Certas se\u00E7\u00F5es definiram o n\u00FAmero de tentativas e substitu\u00EDram este valor.
 warning.templates=Esta quest\u00E3o cont\u00E9m alguns modelos que n\u00E3o s\u00E3o compat\u00EDveis com o editor OpenOlat.
 warning.text.after.interaction=Esta quest\u00E3o tem texto ap\u00F3s o elemento de intera\u00E7\u00E3o. Isso n\u00E3o \u00E9 compat\u00EDvel com o editor OpenOlat e o texto ser\u00E1 perdido ap\u00F3s a convers\u00E3o.
 warning.unsupported.feedbacks=Esta quest\u00E3o cont\u00E9m coment\u00E1rios que n\u00E3o s\u00E3o compat\u00EDveis com o editor OpenOlat. Eles podem ser perdidos ap\u00F3s a convers\u00E3o.
diff --git a/src/main/java/org/olat/ims/qti21/ui/report/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/ims/qti21/ui/report/_i18n/LocalStrings_pt_BR.properties
new file mode 100644
index 0000000000000000000000000000000000000000..144970981a86764323b01105b6490c1eecb78dd1
--- /dev/null
+++ b/src/main/java/org/olat/ims/qti21/ui/report/_i18n/LocalStrings_pt_BR.properties
@@ -0,0 +1,31 @@
+#Thu Sep 24 14:58:24 CEST 2020
+admin.menu.report.question.title=Perguntas para testes
+admin.menu.report.question.title.alt=Perguntas para testes
+report.course.displayname=T\u00EDtulo do curso
+report.course.externalref=Refer\u00EAncia do curso
+report.course.id=ID do curso
+report.explain=Relat\u00F3rio\: testes selecionados incluindo todas as quest\u00F5es contidas
+report.question.author=Criador da pergunta (propriet\u00E1rio)
+report.question.context=N\u00EDvel
+report.question.correction.time=$org.olat.modules.qpool.ui\:question.correctionTime
+report.question.identifier=ID da quest\u00E3o
+report.question.keywords=Palavras-chave
+report.question.license=$org.olat.modules.qpool.ui\:rights.license
+report.question.master.author=Criador (ID mestre do propriet\u00E1rio)
+report.question.master.identifier=ID mestre da pergunta
+report.question.master.keywords=Palavras-chave (ID mestre da pergunta)
+report.question.taxonomy.level=Assunto
+report.question.taxonomy.path=Caminho do assunto
+report.question.title=T\u00EDtulo da pergunta
+report.question.to.course=Reportar quest\u00F5es
+report.question.topic=T\u00F3pico
+report.question.type=Tipo
+report.test.author=Criador do teste (propriet\u00E1rio)
+report.test.displayname=T\u00EDtulo do teste do recurso did\u00E1tico
+report.test.externalref=Refer\u00EAncia do teste
+report.test.id=ID de teste (recurso did\u00E1tico)
+search=Busca
+search.author=Autor / propriet\u00E1rio
+search.empty=N\u00E3o foram encontrados testes que atendessem aos seus crit\u00E9rios.
+search.text=T\u00EDtulo / Ref. Ext / ID
+warning.at.least.one.test=Voc\u00EA deve escolher pelo menos um teste.
diff --git a/src/main/java/org/olat/modules/appointments/ui/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/modules/appointments/ui/_i18n/LocalStrings_pt_BR.properties
new file mode 100644
index 0000000000000000000000000000000000000000..3e43939685e3373357ebb88996b5b1e4692b66a0
--- /dev/null
+++ b/src/main/java/org/olat/modules/appointments/ui/_i18n/LocalStrings_pt_BR.properties
@@ -0,0 +1,166 @@
+#Thu Sep 24 20:01:49 CEST 2020
+add.appointment=Adicionar compromisso
+add.appointment.button=Adicionar
+add.appointment.recurring=Adicionar compromissos recorrentes
+add.appointment.single=Adicionar compromissos \u00FAnico
+add.appointment.title=Adicionar compromisso
+add.topic=Adicionar compromissos
+add.topic.title=$\:add.topic
+add.user=Adicionar usu\u00E1rio
+add.user.title=$\:add.user
+appointment.delete.participations={0} participantes selecionaram este compromisso. Esses participantes devem ser remarcados?
+appointment.details=Detalhes
+appointment.end=Fim
+appointment.free.participations=Participantes dispon\u00EDveis
+appointment.id=ID
+appointment.init.value=Este valor inicial \u00E9 definido para todos os compromissos. Ele pode ser editado separadamente em cada compromisso posteriormente.
+appointment.last=\u00DAltima consulta
+appointment.location=Localiza\u00E7\u00E3o
+appointment.max.participations=N\u00FAmero m\u00E1ximo de participantes
+appointment.next=Pr\u00F3ximo compromisso
+appointment.number.of.participations=No. participantes
+appointment.select=Selecione o compromisso
+appointment.selected=Compromisso selecionado
+appointment.start=Iniciar
+appointment.status=Status
+appointment.status.confirmed=Confirmado
+appointment.status.planned=N\u00E3o confirmado
+appointments=Compromissos
+appointments.confirmable={0} compromissos precisam ser confirmados.
+appointments.confirmable.none=Nenhum compromisso precisa ser confirmado.
+appointments.confirmable.one=Um compromisso deve ser confirmado.
+appointments.finding.confirmed=Um encontro foi confirmado. Voc\u00EA n\u00E3o est\u00E1 neste compromisso.
+appointments.free=Restam {0} compromissos.
+appointments.free.no=N\u00E3o h\u00E1 marca\u00E7\u00F5es gratuitas.
+appointments.free.one=Resta um compromisso.
+appointments.open=Mostrar compromissos
+appointments.recurring=Compromissos recorrentes
+appointments.recurring.days.of.week=Dias da semana
+appointments.recurring.first=Primeiro compromisso
+appointments.recurring.last=\u00DAltimo compromisso
+appointments.select=Selecione os compromissos
+appointments.select.multi.message=Selecione os compromissos desejados.
+appointments.select.one.message=Selecione o compromisso desejado.
+appointments.selected=Voc\u00EA tem {0} compromissos selecionados.
+appointments.selected.not.confirmed=Nenhum compromisso foi confirmado ainda.
+appointments.total=Existem {0} compromissos dispon\u00EDveis.
+appointments.total.one=H\u00E1 um compromisso dispon\u00EDvel.
+condition.accessibility.title=Acesso
+config.confirmation=Confirma\u00E7\u00E3o pelo treinador
+config.multi.participation=Sele\u00E7\u00E3o de v\u00E1rios compromissos
+confirm=Confirmar
+confirm.appointment.delete=Tem certeza de que deseja excluir este compromisso?
+confirm.appointment.delete.title=Excluir compromisso
+confirm.participation.self=Tem certeza de que deseja se inscrever para este compromisso ({0})? Nenhum outro compromisso pode ser escolhido posteriormente.
+confirm.participation.self.multi=Tem certeza de que deseja se inscrever para este compromisso ({0})? A nomea\u00E7\u00E3o n\u00E3o pode ser recusada posteriormente.
+confirm.participation.self.title=Selecione o compromisso
+confirm.topic.delete=Tem certeza de que deseja excluir todos os compromissos?
+confirm.topic.delete.title=Excluir compromissos
+delete=Excluir
+delete.topic=Excluir
+edit.appointment.button=Salvar
+edit.appointment.title=Editar compromisso
+edit.groups=Restri\u00E7\u00F5es de participa\u00E7\u00E3o
+edit.topic=Editar t\u00F3pico
+edit.topic.title=Editar t\u00F3pico
+email.organizer.recipients=Organizadores
+email.organizer.subject=Compromisso "{0}"
+email.title=Nova mensagem
+error.config.not.changeable=A configura\u00E7\u00E3o n\u00E3o pode mais ser alterada. Ele foi redefinido para os valores originais.
+error.first.after.start=A \u00FAltima consulta n\u00E3o deve ser antes da primeira.
+error.not.as.many.participations.left=Nem tantos usu\u00E1rios podem ser adicionados a este compromisso.
+error.positiv.number=Precisa ser um n\u00FAmero inteiro positivo.
+error.rebook=A remarca\u00E7\u00E3o dos participantes falhou.
+error.select.appointment=Voc\u00EA tem que selecionar um compromisso.
+error.select.participant=Voc\u00EA tem que selecionar um participante.
+error.start.after.end=A data de t\u00E9rmino n\u00E3o deve ser anterior \u00E0 data de in\u00EDcio.
+error.too.much.participations=J\u00E1 existem {0} participa\u00E7\u00F5es.
+error.user.remove.atleastone=Voc\u00EA deve selecionar pelo menos um usu\u00E1rio.
+filter.all=Mostrar tudo
+filter.future=Futuro
+filter.participated=Selecionados
+finding.confirmation.empty.table=Nenhum participante p\u00F4de selecionar este compromisso.
+finding.confirmation.info=Deseja realmente confirmar este compromisso?<br><br>Na lista abaixo voc\u00EA pode ver quais participantes escolheram este compromisso. Voc\u00EA pode adicionar mais participantes ao compromisso ou remover participantes do compromisso.
+full.day=Dia inteiro
+full.day.lower=dia inteiro
+groups.business.groups=Participantes do grupo
+groups.course=Participantes do curso
+groups.curriculum=Participantes do curr\u00EDculo
+groups.info=Aqui voc\u00EA pode restringir o acesso aos compromissos para grupos ou usu\u00E1rios individuais. Se voc\u00EA n\u00E3o selecionar nada, todos os usu\u00E1rios ter\u00E3o acesso aos compromissos.
+groups.title=Restri\u00E7\u00F5es de grupo
+groups.users.add=Adicionar
+groups.users.add.title=Adicionar usu\u00E1rio
+groups.users.empty.table=Nenhum usu\u00E1rio foi selecionado.
+groups.users.remove=Remover
+groups.users.remove.confirm.text=Tem certeza de que deseja remover os usu\u00E1rios selecionados?
+groups.users.remove.confirm.title=Remover usu\u00E1rio
+groups.users.title=Restri\u00E7\u00F5es de usu\u00E1rios
+groups.users.username=Nome do usu\u00E1rio
+mail.appointments.deleted.body=Caro {0} <br><br>Os seguintes compromissos foram exclu\u00EDdos.<br><br>{1}
+mail.appointments.deleted.subject=Compromissos exclu\u00EDdos
+mail.confirmed.body=Caro {0} <br><br>O seguinte compromisso foi confirmado.<br><br>{1}
+mail.confirmed.subject=Compromisso "{0}" confirmado
+mail.day=Data\: {0} (dia inteiro)
+mail.deleted.body=Caro {0} <br><br>O seguinte compromisso foi recusado.<br><br>{1}
+mail.deleted.subject=Compromisso "{0}" recusado
+mail.end=Fim\: {0}
+mail.location=Localiza\u00E7\u00E3o\: {0}
+mail.participation.created.body=Caro {0} <br><br>Voc\u00EA foi adicionado ao seguinte compromisso.<br><br>{1}
+mail.participation.created.subject=Adicionado ao compromisso "{0}"
+mail.participation.deleted.body=Caro {0} <br><br>Voc\u00EA foi removido do seguinte compromisso.<br><br>{1}
+mail.participation.deleted.subject=Removido do compromisso "{0}"
+mail.rebooked.body=Caro {0} <br><br>O seguinte compromisso foi marcado novamente.<br><br><b>Compromisso anterior</b><br>{1}<br><b>Novo compromisso</b><br> {2}
+mail.rebooked.subject=Compromisso remarcado
+mail.start=In\u00EDcio\: {0}
+mail.topic=T\u00F3pico\: {0}
+mail.unconfirmed.body=Caro {0} <br><br>O seguinte compromisso foi reaberto.<br><br>{1}
+mail.unconfirmed.subject=Compromisso "{0}" reaberto
+no.appointments=Sem compromissos dispon\u00EDveis.
+no.topics=Sem compromissos dispon\u00EDveis.
+notification.new.participation={1} inscrito em "{0}".
+notifications.header=Compromissos no curso "{0}"
+notifications.title=Agendamento de consulta no curso "{0}"
+organizer=Organizador
+organizer.separator=,
+organizer.with=com
+participants=Participantes
+participation.created.by=<i>Voc\u00EA foi adicionado a este compromisso por {0}.</i>
+participation.not.created=Voc\u00EA n\u00E3o foi adicionado ao compromisso.
+participations.free=Restam {0} lugares.
+participations.free.one=Resta um lugar.
+participations.not.created=Os usu\u00E1rios n\u00E3o foram adicionados ao compromisso.
+participations.number.of={0} participantes
+participations.number.of.one={0} participante
+participations.selected.many.many={0} participantes selecionaram {1} compromissos.
+participations.selected.many.one={0} participantes selecionaram um compromisso.
+participations.selected.one.many=Um participante selecionou {0} compromissos.
+participations.selected.one.one=Um participante selecionou um compromisso.
+rebook=Reagendar
+remove.user=Remover usu\u00E1rio
+remove.user.appointments=Compromisso
+remove.user.change=Remover
+remove.user.delete=Excluir
+remove.user.no.appointments=$\:remove.user.appointments
+remove.user.no.appointments.text=<i>N\u00E3o h\u00E1 compromissos com vagas livres suficientes.</i>
+remove.user.participation=Participantes
+remove.user.rebook=Reagendar
+remove.user.title=Remover usu\u00E1rio
+save.back=Salvar e voltar
+select=Selecionar
+table.empty.appointments=N\u00E3o h\u00E1 compromissos dispon\u00EDveis.
+table.header.delete=<i class\='o_icon o_icon-lg o_icon_delete'> </i>
+table.header.id=ID
+table.header.organizer=Organizador
+table.header.participation=Compromisso
+topic.coach.confirmation=Confirma\u00E7\u00E3o pelo treinador
+topic.configuration=Configura\u00E7\u00E3o
+topic.description=Descri\u00E7\u00E3o
+topic.description.closed=Mostrar descri\u00E7\u00E3o dos compromissos
+topic.description.opened=Esconder a descri\u00E7\u00E3o dos compromissos
+topic.multi.participation=Sele\u00E7\u00E3o de v\u00E1rios compromissos
+topic.title=T\u00EDtulo
+topic.type=Tipo
+topic.type.enrollment=Inscri\u00E7\u00E3o
+topic.type.finding=Encontrar compromisso
+unconfirm=Reabrir
+unconfirmed=n\u00E3o confirmado
diff --git a/src/main/java/org/olat/modules/bigbluebutton/ui/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/modules/bigbluebutton/ui/_i18n/LocalStrings_pt_BR.properties
index 81876d1ffdc6ed9a153416cbb003732add42b320..8e9f0c25f5c8ca6188e9392f08fece988829f642 100644
--- a/src/main/java/org/olat/modules/bigbluebutton/ui/_i18n/LocalStrings_pt_BR.properties
+++ b/src/main/java/org/olat/modules/bigbluebutton/ui/_i18n/LocalStrings_pt_BR.properties
@@ -1,4 +1,4 @@
-#Tue May 26 17:54:06 CEST 2020
+#Thu Sep 24 20:15:52 CEST 2020
 account.configuration=Configura\u00E7\u00E3o
 add.daily.meeting=Adicionar reuni\u00E3o recorrente di\u00E1ria
 add.meeting=Adicionar reuni\u00E3o
@@ -22,16 +22,23 @@ bigbluebutton.module.enabled=M\u00F3dulo "BigBlueButton"
 bigbluebutton.module.enabled.for=Ativar para
 bigbluebutton.module.enabled.for.courses=Cursos
 bigbluebutton.module.enabled.for.groups=Grupos
+bigbluebutton.recording.handler=Manipulador de grava\u00E7\u00E3o
 bigbluebutton.servers=Servidores
 bigbluebutton.servers.empty=Voc\u00EA n\u00E3o configurou um servidor.
 bigbluebutton.title=Configura\u00E7\u00E3o do servi\u00E7o BigBlueButton Web Conferencing
 calendar.open=Mostrar reservas de salas
 calendar.title=Calend\u00E1rio
 check=Verifique a conex\u00E3o
+collaboration.access=Gerenciar reuni\u00F5es BigBlueButton
+collaboration.access.all=Todos os membros
+collaboration.access.owners.coaches=Propriet\u00E1rios resp. treinadores
+collaboration.access.title=Configure o gerenciamento do BigBlueButton
 confirm.delete.meeting=Voc\u00EA realmente deseja excluir a reuni\u00E3o "{0}"?
 confirm.delete.meeting.title=Excluir reuni\u00E3o "{0}"
 confirm.delete.meetings=Deseja realmente excluir as {0} reuni\u00F5es online ({1})?
 confirm.delete.meetings.title=Excluir {0} reuni\u00F5es online
+confirm.delete.recording=Tem certeza de que deseja excluir a grava\u00E7\u00E3o "{0}"? A grava\u00E7\u00E3o exclu\u00EDda n\u00E3o pode ser recuperada.
+confirm.delete.recording.title=Excluir grava\u00E7\u00E3o "{0}"
 confirm.delete.server=Deseja realmente excluir o servidor "{0}"? <strong>Todas as reuni\u00F5es e grava\u00E7\u00F5es tamb\u00E9m ser\u00E3o exclu\u00EDdas.</strong>
 confirm.delete.server.title=Excluir servidor "{0}"
 confirm.delete.template=Deseja realmente excluir o modelo de sala "{0}"?
@@ -58,6 +65,8 @@ error.duration=A dura\u00E7\u00E3o da reuni\u00E3o \u00E9 muito longa. Dura\u00E
 error.end.past=A reuni\u00E3o online n\u00E3o pode ser planejada no passado.
 error.first.date.in.past=A data da primeira reuni\u00E3o n\u00E3o pode estar no passado.
 error.formatError=O formato de "{0}" n\u00E3o \u00E9 v\u00E1lido.
+error.identifier.in.use=O nome j\u00E1 est\u00E1 em uso. Por favor escolha outro.
+error.identifier.url.not.valid=O URL n\u00E3o ser\u00E1 v\u00E1lido. Remova caracteres especiais como $,? e espa\u00E7os.
 error.illegalOperation=Opera\u00E7\u00E3o n\u00E3o \u00E9 permitida.
 error.invalid.meeting=A reuni\u00E3o foi criada com outra configura\u00E7\u00E3o e n\u00E3o pode mais ser aberta.
 error.invalidField=O valor de "{0}" n\u00E3o \u00E9 v\u00E1lido.
@@ -77,23 +86,39 @@ error.unkown=Erro desconhecido
 error.url.invalid=URL de servidor inv\u00E1lido
 filter.all.instances=Todos os OpenOlats
 filter.this.instance=Este OpenOlat
+layout.standard=Padr\u00E3o
+layout.webcam=Reuni\u00E3o de webcam
 meeting.configure.button=V\u00E1 e configure a sala
 meeting.create.button=Abrir a reuni\u00E3o
 meeting.create.intro=A reuni\u00E3o ainda n\u00E3o foi aberta. Os participantes n\u00E3o podem entrar na sala de aula para uma reuni\u00E3o.
+meeting.creator=Criador
 meeting.day=Data da reuni\u00E3o
 meeting.deleted=Reuni\u00E3o exclu\u00EDda com sucesso.
 meeting.description=Descri\u00E7\u00E3o
 meeting.disclaimer.privacy=<strong>Datenschutzhinweis</strong><p>Im Rahmen der Online-Lehre ist es unumg\u00E4nglich personenbezogene Daten \u00FCber Sie zu verarbeiten. N\u00E4here Informationen \u00FCber die Verarbeitung und die M\u00F6glichkeit der Nutzung von Aliasnamen zum Schutz Ihrer Daten finden Sie unter\: <a href="https\://www.uibk.ac.at/datenschutz/besucherinnen-von-lv/">https\://www.uibk.ac.at/datenschutz/besucherinnen-von-lv/</a></p><strong>Hinweise für Studierende</strong><p>Jegliche \u00FCber ein Ansehen hinausgehende Verwendung der zur Verf\u00FCgung gestellten Aufnahmen (herunterladen, kopieren, ver\u00F6ffentlichen, etc.) f\u00FCr den eigenen Gebrauch, kann ohne Einwilligung der Rechteinhaber rechtliche Folgen nach sich ziehen.</p>
 meeting.end=Data final
 meeting.ended=A reuni\u00E3o j\u00E1 terminou.
+meeting.external.users=Acessar usu\u00E1rios externos
+meeting.external.users.empty=O acesso ao URL para usu\u00E1rios externos est\u00E1 desativado
+meeting.external.users.help=Para permitir que usu\u00E1rios externos acessem a reuni\u00E3o por meio de um URL, voc\u00EA pode definir uma refer\u00EAncia de reuni\u00E3o aqui. Voc\u00EA pode ent\u00E3o compartilhar o URL gerado, por exemplo via email. A refer\u00EAncia deve ser uma palavra \u00FAnica sem caracteres especiais.
 meeting.followupTime=Acompanhamento (min.)
 meeting.go.button=V\u00E1 para a sala de reuni\u00E3o
+meeting.guest=Convidados
+meeting.guest.join.button=Junte-se \u00E0 reuni\u00E3o online
+meeting.guest.on=permitidos
+meeting.guest.pseudo=Seu nome
+meeting.guest.pseudo.explain=Por favor, digite seu nome e pressione o bot\u00E3o para entrar na reuni\u00E3o online.
 meeting.join.button=Junte-se \u00E0 reuni\u00E3o
+meeting.layout=Layout
 meeting.leadTime=Tempo de prepara\u00E7\u00E3o (min.)
 meeting.leadTime.explain=O tempo de prepara\u00E7\u00E3o \u00E9 relevante apenas para moderadores.
+meeting.main.presenter=Apresentador principal
 meeting.name=Nome
 meeting.permanent=Tipo
 meeting.permanent.on=Permanente
+meeting.publishing=Publicar grava\u00E7\u00E3o
+meeting.publishing.auto=Autom\u00E1tico
+meeting.publishing.manual=Manual
 meeting.recurring.end=Data final recorrente
 meeting.recurring.start=Iniciar data recorrente
 meeting.register.button=Registro
@@ -105,6 +130,7 @@ meeting.start.button=Iniciar a reuni\u00E3o
 meeting.successfully.registered=Registrado com sucesso.
 meeting.template=Modelo de sala
 meeting.templates=Modelo
+meeting.url.external.users=Link para usu\u00E1rios externos
 meeting.welcome=Mensagem de boas-vindas
 meetings.admin.title=Configura\u00E7\u00E3o
 meetings.content=Conte\u00FAdo
@@ -112,6 +138,7 @@ meetings.past=Reuni\u00F5es antigas
 meetings.title=Reuni\u00F5es
 meetings.upcoming=Pr\u00F3ximas reuni\u00F5es
 minutes={0} min.
+native.recording.handler=Nativo
 no.contents=Esta reuni\u00E3o n\u00E3o tem nenhum conte\u00FAdo
 no.meeting.configured=Nenhuma reuni\u00E3o foi configurada ainda.
 no.recordings=N\u00E3o h\u00E1 grava\u00E7\u00E3o dispon\u00EDvel para esta reuni\u00E3o on-line no momento.
@@ -119,6 +146,7 @@ no.shared.contents=Nenhuma reuni\u00E3o futura agendada.
 no.template=Sem modelo
 no.template.configured=N\u00E3o h\u00E1 modelos de sala ativos dispon\u00EDveis.
 no.upcoming.meetings=Voc\u00EA n\u00E3o tem nenhuma reuni\u00E3o futura.
+opencast.recording.handler=Opencast
 option.accountid=ID da conta
 option.accountid.explain=O ID da conta \u00E9 opcional. Se o ID da conta n\u00E3o for especificado, a conta do usu\u00E1rio acima ser\u00E1 usada.
 option.adminlogin=Usu\u00E1rio
@@ -139,6 +167,13 @@ option.recordingurl=URL de grava\u00E7\u00E3o
 option.single.meeting=Reuni\u00F5es compartilhadas
 option.single.meeting.perdate=Criar uma sala de reuni\u00E3o por data
 option.single.meeting.single=Criar apenas uma sala de reuni\u00E3o por elemento ou grupo do curso
+publish.recording=Publicar
+publish.to=Publicar
+publish.to.all=Todos os participantes da reuni\u00E3o (sem convidados)
+publish.to.coach=Propriet\u00E1rios e treinadores
+publish.to.guest=Convidados
+publish.to.list=publicar em\:
+publish.to.participant=Participantes do curso / grupo
 recording.browser.infos=As grava\u00E7\u00F5es s\u00F3 podem ser visualizadas no Google Chrome ou Firefox.
 recording.type.podcast=Podcast
 recording.type.presentation=Apresenta\u00E7\u00E3o
@@ -159,6 +194,7 @@ table.header.breakout.recording.meetings=\# Breakout Grava\u00E7\u00E3o
 table.header.capacity.factor=Capacidade
 table.header.day.week=Dia
 table.header.enabled=Ativo
+table.header.external.users=Usu\u00E1rios externos
 table.header.listener.count=\# Ouvintes
 table.header.load=Carregar
 table.header.max.concurrent.meetings=Salas
@@ -169,6 +205,7 @@ table.header.moderator.count=\# Moderador
 table.header.number.meetings=\# Encontros
 table.header.participant.count=\# Participantes
 table.header.permanent=Permanente
+table.header.publish=Publicar
 table.header.recording.end=Fim
 table.header.recording.meetings=\# Grava\u00E7\u00F5es
 table.header.recording.name=Nome
@@ -193,6 +230,7 @@ template.description=Descri\u00E7\u00E3o
 template.enabled=Ativar modelo de sala
 template.explain.max.participants=M\u00E1x. n\u00FAmero de participantes\: {0} ({1} salas dispon\u00EDveis
 template.explain.max.participants.with.webcams.mod=M\u00E1x. n\u00FAmero de participantes\: {0}, apenas moderador com webcam ({1} salas dispon\u00EDveis)
+template.external.enabled=Aberto para usu\u00E1rios externos
 template.lock=Para participantes bloqueados...
 template.lockSettingsDisableCam=desativar webcam
 template.lockSettingsDisableMic=desativar microfone
@@ -216,10 +254,12 @@ undelete=Reativar
 view=Mostrar
 view.template=Modelo de sala "{0}"
 warning.at.least.one.meeting=Voc\u00EA deve selecionar pelo menos uma reuni\u00E3o.
+warning.meeting.permission.denied=Voc\u00EA n\u00E3o tem permiss\u00E3o para acessar a reuni\u00E3o online. Por favor, tente novamente mais tarde.
 warning.meeting.started=Voc\u00EA n\u00E3o pode mais editar uma reuni\u00E3o iniciada.
 warning.no.access=Voc\u00EA n\u00E3o pode acessar a reuni\u00E3o ainda.
 warning.no.meeting=A reuni\u00E3o foi exclu\u00EDda.
 warning.not.registered.shared.documents=Somente as pessoas que participaram da reuni\u00E3o podem abrir os documentos compartilhados.
+warning.recording.not.found=A grava\u00E7\u00E3o n\u00E3o pode ser encontrada.
 warning.template.in.use=O modelo de sala n\u00E3o pode ser exclu\u00EDdo porque \u00E9 usado por reuni\u00F5es online. Exclua a reuni\u00E3o online correspondente ou desative o modelo da sala.
 wizard.dates.title=Datas
 wizard.meeting.title=Configura\u00E7\u00E3o
diff --git a/src/main/java/org/olat/modules/cp/CPOfflineReadableManager.java b/src/main/java/org/olat/modules/cp/CPOfflineReadableManager.java
index e4f453e01521341068a8beaa1e463472d9bad68d..a9b1e4a05849d9c144a9611c1538b47cd7bcaeb5 100644
--- a/src/main/java/org/olat/modules/cp/CPOfflineReadableManager.java
+++ b/src/main/java/org/olat/modules/cp/CPOfflineReadableManager.java
@@ -53,6 +53,7 @@ import org.olat.core.util.StringHelper;
 import org.olat.core.util.WebappHelper;
 import org.olat.core.util.ZipUtil;
 import org.olat.core.util.vfs.LocalFileImpl;
+import org.olat.core.util.vfs.filters.VFSAllItemsFilter;
 import org.olat.fileresource.FileResourceManager;
 import org.olat.modules.cp.CPManifestTreeModel.UserObject;
 
@@ -306,10 +307,9 @@ public class CPOfflineReadableManager {
 		for (int i = 0; i < cpFiles.length; i++) {
 			allFilesInUnzippedDir.add(cpFiles[i]);
 		}
-		boolean zipResult = ZipUtil.zip(allFilesInUnzippedDir, unzippedDir, targetZip, true);
-
-		if(!targetZip.exists()){
-			log.warn("targetZip does not exists after zipping. zip-result is: "+ zipResult);
+		boolean zipResult = ZipUtil.zip(allFilesInUnzippedDir, unzippedDir, targetZip, VFSAllItemsFilter.ACCEPT_ALL, false);
+		if(!targetZip.exists()) {
+			log.warn("targetZip does not exists after zipping. zip-result is: {}", zipResult);
 		}
 	}
 
diff --git a/src/main/java/org/olat/modules/edusharing/ui/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/modules/edusharing/ui/_i18n/LocalStrings_pt_BR.properties
index 5c77e9b21dc6df5de2c1b6e7e3048dc97b6cd301..9419316c71134ed45c6e63f25f84e20f1cb9cde0 100644
--- a/src/main/java/org/olat/modules/edusharing/ui/_i18n/LocalStrings_pt_BR.properties
+++ b/src/main/java/org/olat/modules/edusharing/ui/_i18n/LocalStrings_pt_BR.properties
@@ -1,6 +1,7 @@
-#Mon Feb 04 18:28:41 CET 2019
+#Thu Sep 24 20:05:24 CEST 2020
 admin.app.id=ID do aplicativo
 admin.client.test=Teste
+admin.course.node.enabled=Elemento de curso
 admin.desc=O Edu-sharing \u00E9 um software para plataformas de aprendizagem em rede, trocando conte\u00FAdo de aprendizagem, metadados e ferramentas e tornando-as pesquis\u00E1veis em uma nuvem educacional e utiliz\u00E1veis em todos os sistemas conectados. Mais informa\u00E7\u00F5es podem ser encontradas no <a href\="https\://edu-sharing.com/" target\=_blank>site</a> de edu-sharing. <br/><br/> A configura\u00E7\u00E3o acontece em quatro etapas\:<br/>1. Insira e salve os valores de configura\u00E7\u00E3o.<br/>2. Gere e salve as chaves.<br/>3. Importe e salve a chave p\u00FAblica de compartilhamento de compartilhamento de edu.<br/>4. No compartilhamento de edu\: Conecte o OpenOlat como um aplicativo. URL com metadados\: {0} <br/>
 admin.enable.confirm.message=Voc\u00EA realmente deseja ativar o m\u00F3dulo "edu-sharing"? Por favor, note que os dados pessoais do usu\u00E1rio, como nome de usu\u00E1rio, primeiro nome, sobrenome e endere\u00E7o de e-mail podem ser transferidos para o "edu-sharing"
 admin.enable.confirm.title=Ativar m\u00F3dulo
diff --git a/src/main/java/org/olat/modules/forms/ui/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/modules/forms/ui/_i18n/LocalStrings_pt_BR.properties
index d6bb0d7a1f5b8353e18655f032c1d3829bab622f..9b942b46b0756a6f01a8026d14da568bc63341e5 100644
--- a/src/main/java/org/olat/modules/forms/ui/_i18n/LocalStrings_pt_BR.properties
+++ b/src/main/java/org/olat/modules/forms/ui/_i18n/LocalStrings_pt_BR.properties
@@ -1,4 +1,4 @@
-#Tue May 26 20:11:03 CEST 2020
+#Thu Sep 24 20:15:53 CEST 2020
 add.formcontainer=Recipiente
 add.formdisclaimer=Termos de uso
 add.formfileupload=Enviar arquivo
diff --git a/src/main/java/org/olat/modules/glossary/GlossaryManagerImpl.java b/src/main/java/org/olat/modules/glossary/GlossaryManagerImpl.java
index c4ec7fb5b3d3f673695ae6b359e1e72507b2fa13..e3d967d0fddf41a0c9609661999060addc7eeb51 100644
--- a/src/main/java/org/olat/modules/glossary/GlossaryManagerImpl.java
+++ b/src/main/java/org/olat/modules/glossary/GlossaryManagerImpl.java
@@ -172,7 +172,7 @@ public class GlossaryManagerImpl implements GlossaryManager {
 		String exportFileName = repoEntry.getDisplayname();
 		exportFileName = StringHelper.transformDisplayNameToFileSystemName(exportFileName);
 		VFSContainer glossaryRoot = getGlossaryRootFolder(res);
-		return new ZippedContainerMediaResource(exportFileName, glossaryRoot);
+		return new ZippedContainerMediaResource(exportFileName, glossaryRoot, false);
 	}
 	
 	
diff --git a/src/main/java/org/olat/modules/grading/ui/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/modules/grading/ui/_i18n/LocalStrings_pt_BR.properties
index 80fa93bb10233e62bf9c54e698cc05378ee8fdf4..3c8875a4bf651466b373616e324d349fc22b2eb9 100644
--- a/src/main/java/org/olat/modules/grading/ui/_i18n/LocalStrings_pt_BR.properties
+++ b/src/main/java/org/olat/modules/grading/ui/_i18n/LocalStrings_pt_BR.properties
@@ -1,4 +1,4 @@
-#Tue May 26 20:11:14 CEST 2020
+#Thu Sep 24 20:06:34 CEST 2020
 absence.grader.title=Adicione uma licen\u00E7a de aus\u00EAncia para "{0}"
 add.grader=Adicionar revisor
 admin.menu.title=Revisor
@@ -71,11 +71,18 @@ grading.enabled=Ativar fluxo de trabalho de revis\u00E3o
 grading.infos.configuration=Configura\u00E7\u00E3o
 grading.infos.graders=Revisores
 grading.my.assignments.title=Minhas tarefas de revis\u00E3o
+grading.real.correction.time.administrator=$org.olat.admin.user\:role.administrator
+grading.real.correction.time.author=$org.olat.admin.user\:role.author
+grading.real.correction.time.grader=Avaliador
+grading.real.correction.time.learnresourcemanager=$org.olat.admin.user\:role.learnresourcemanager
+grading.real.correction.time.visibility=Visibilidade dos minutos reais de corre\u00E7\u00E3o
 grading.repo.enabled=Ativar revis\u00E3o
 info.grader.activated=O revisor "{0}" foi ativado com sucesso.
 mail.grader.to.entry.body=Voc\u00EA \u00E9 um revisor agora
 mail.grader.to.entry.subject=Como revisor
 mail.notification.body=Nova atribui\u00E7\u00E3o de revis\u00E3o para $coursetitle
+mail.notification.participant.body=Seus \u00FAltimos resultados est\u00E3o vis\u00EDveis em\: $courseurl
+mail.notification.participant.subject=Novos resultados
 mail.notification.subject=Nova tarefa de revis\u00E3o
 mail.reminder1.body=Primeiro lembrete para a atribui\u00E7\u00E3o de $coursetitle
 mail.reminder1.subject=Primeiro lembrete
@@ -84,6 +91,8 @@ mail.reminder2.subject=Segundo lembrete e \u00FAltimo
 mail.to.grader.body=Texto para revisor
 mail.to.grader.subject=Assunto para revisor
 notification.body=Texto para notifica\u00E7\u00E3o
+notification.participant.body=Texto para notifica\u00E7\u00E3o ao participante
+notification.participant.subject=Assunto para notifica\u00E7\u00E3o ao participante
 notification.subject=Assunto para notifica\u00E7\u00E3o
 passed.false=$org.olat.course.assessment\:passed.false
 passed.false.label=N\u00E3o passou
diff --git a/src/main/java/org/olat/modules/opencast/ui/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/modules/opencast/ui/_i18n/LocalStrings_pt_BR.properties
new file mode 100644
index 0000000000000000000000000000000000000000..cb941db3b23473b5cefbea8bc285c411003ac337
--- /dev/null
+++ b/src/main/java/org/olat/modules/opencast/ui/_i18n/LocalStrings_pt_BR.properties
@@ -0,0 +1,18 @@
+#Thu Sep 24 20:16:37 CEST 2020
+admin.api.password=Senha API
+admin.api.url=URL API
+admin.api.url.example=https\://admin.opencast.example.com/api
+admin.api.username=Usu\u00E1rio da API
+admin.auth.delegate.roles=Fun\u00E7\u00F5es de autoriza\u00E7\u00E3o
+admin.auth.delegate.type=Autoriza\u00E7\u00E3o do administrador
+admin.auth.delegate.type.none=Nenhum
+admin.auth.delegate.type.roles=Fun\u00E7\u00F5es
+admin.auth.delegate.type.user=Usu\u00E1rio
+admin.bbb.enabled=Grava\u00E7\u00F5es BigBlueButton
+admin.check.api.connection=Verifique a conex\u00E3o API
+admin.course.node.enabled=Elemento do curso
+admin.enabled=M\u00F3dulo "Opencast"
+admin.lti.key=Chave LTI
+admin.lti.secret=Segredo LTI
+admin.lti.sign.url=URL de assinatura LTI
+admin.lti.sign.url.example=http\://localhost\:8080/lti
diff --git a/src/main/java/org/olat/modules/sharedfolder/SharedFolderManager.java b/src/main/java/org/olat/modules/sharedfolder/SharedFolderManager.java
index 241435b4cb6dec8bc64109f443a76432172ab21b..e2191d6e3802428542346c95b023c1bd523ea151 100644
--- a/src/main/java/org/olat/modules/sharedfolder/SharedFolderManager.java
+++ b/src/main/java/org/olat/modules/sharedfolder/SharedFolderManager.java
@@ -93,7 +93,7 @@ public class SharedFolderManager {
 		VFSContainer sharedFolder = getSharedFolder(res);
 		// do intermediate commit to avoid transaction timeout
 		DBFactory.getInstance().intermediateCommit();
-		return new ZippedContainerMediaResource(exportFileName, sharedFolder);
+		return new ZippedContainerMediaResource(exportFileName, sharedFolder, true);
 	}
 
 	public boolean exportSharedFolder(String sharedFolderSoftkey, File exportedDataDir) {
diff --git a/src/main/java/org/olat/modules/webFeed/dispatching/FeedMediaDispatcher.java b/src/main/java/org/olat/modules/webFeed/dispatching/FeedMediaDispatcher.java
index f45c717b478b869cd958c55d4636dde65df030b6..2519d1985759b267bfeb6d409e08ba0d64e19c46 100644
--- a/src/main/java/org/olat/modules/webFeed/dispatching/FeedMediaDispatcher.java
+++ b/src/main/java/org/olat/modules/webFeed/dispatching/FeedMediaDispatcher.java
@@ -20,6 +20,7 @@
 package org.olat.modules.webFeed.dispatching;
 
 import java.io.IOException;
+import java.util.HashMap;
 import java.util.List;
 
 import javax.servlet.http.HttpServletRequest;
@@ -411,6 +412,7 @@ public class FeedMediaDispatcher implements Dispatcher, GenericEventListener {
 				hasAccess = reSecurity.canLaunch();
 			} else {
 				IdentityEnvironment ienv = new IdentityEnvironment(identity, roles);
+				ienv.setAttributes(new HashMap<>());
 				UserCourseEnvironment userCourseEnv = new UserCourseEnvironmentImpl(ienv, course.getCourseEnvironment(), null, null, null, null,
 						reSecurity.isCourseCoach() || reSecurity.isGroupCoach(), reSecurity.isEntryAdmin(), reSecurity.isCourseParticipant() || reSecurity.isGroupParticipant(),
 						false);
@@ -422,6 +424,8 @@ public class FeedMediaDispatcher implements Dispatcher, GenericEventListener {
 						.getNodeById(pathNodeId);
 				if (treeNode != null && treeNode.isAccessible()) {
 					hasAccess = true;
+				} else {
+					log.info("Course element not found or access denied. Path::{}", path);
 				}
 			}
 		}
diff --git a/src/main/java/org/olat/modules/webFeed/manager/FeedManagerImpl.java b/src/main/java/org/olat/modules/webFeed/manager/FeedManagerImpl.java
index 4df75d6162c9d19633067669af88a895b4797f02..8f70ca9aa10442da7dce75fb53b05d4bcf1c488b 100644
--- a/src/main/java/org/olat/modules/webFeed/manager/FeedManagerImpl.java
+++ b/src/main/java/org/olat/modules/webFeed/manager/FeedManagerImpl.java
@@ -64,6 +64,7 @@ import org.olat.core.util.vfs.VFSContainer;
 import org.olat.core.util.vfs.VFSItem;
 import org.olat.core.util.vfs.VFSLeaf;
 import org.olat.core.util.vfs.VFSMediaResource;
+import org.olat.core.util.vfs.filters.VFSSystemItemFilter;
 import org.olat.fileresource.FileResourceManager;
 import org.olat.fileresource.types.BlogFileResource;
 import org.olat.fileresource.types.FeedFileResource;
@@ -832,7 +833,7 @@ public class FeedManagerImpl extends FeedManager {
 			if (oldArchive != null) {
 				oldArchive.delete();
 			}
-			ZipUtil.zip(feedContainer.getItems(), rootContainer.createChildLeaf(zipFileName), false);
+			ZipUtil.zip(feedContainer.getItems(), rootContainer.createChildLeaf(zipFileName), new VFSSystemItemFilter(), false);
 			return (VFSLeaf) rootContainer.resolve(zipFileName);
 		});
 
diff --git a/src/main/java/org/olat/modules/wiki/WikiToCPResource.java b/src/main/java/org/olat/modules/wiki/WikiToCPResource.java
index 7e3d92e6eeeea858460fee61e4a1aadf196cf1be..5614cd6ce86fb3f71f50b3dabe61744ea8862d77 100644
--- a/src/main/java/org/olat/modules/wiki/WikiToCPResource.java
+++ b/src/main/java/org/olat/modules/wiki/WikiToCPResource.java
@@ -21,6 +21,7 @@ package org.olat.modules.wiki;
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
 import java.util.List;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipOutputStream;
@@ -39,6 +40,7 @@ import org.olat.core.util.StringHelper;
 import org.olat.core.util.ZipUtil;
 import org.olat.core.util.vfs.VFSContainer;
 import org.olat.core.util.vfs.VFSItem;
+import org.olat.core.util.vfs.filters.VFSAllItemsFilter;
 import org.olat.modules.cp.CPOfflineReadableManager;
 
 /**
@@ -127,19 +129,19 @@ public class WikiToCPResource implements MediaResource {
 		// create the ims manifest
 		String manifest = export.createIMSManifest(wiki, identity);
 		zout.putNextEntry(new ZipEntry("imsmanifest.xml"));
-		IOUtils.write(manifest, zout, "UTF-8");
+		IOUtils.write(manifest, zout, StandardCharsets.UTF_8);
 		zout.closeEntry();
 
 		VFSContainer mediaContainer = WikiManager.getInstance().getMediaFolder(ores);
 		List<VFSItem> images = mediaContainer.getItems();
 		for (VFSItem image:images) {
-			ZipUtil.addToZip(image, "", zout);
+			ZipUtil.addToZip(image, "", zout, VFSAllItemsFilter.ACCEPT_ALL, false);
 		}
 
 		// create the javascript mapping file
 		String jsContent = export.createJsMappingContent(wiki);
 		zout.putNextEntry(new ZipEntry("mapping.js"));
-		IOUtils.write(jsContent, zout, "UTF-8");
+		IOUtils.write(jsContent, zout, StandardCharsets.UTF_8);
 		zout.closeEntry();
 		
 		
@@ -147,7 +149,7 @@ public class WikiToCPResource implements MediaResource {
 		for (WikiPage page: pages) {
 			String htmlPage = export.wikiPageToHtml(page);
 			zout.putNextEntry(new ZipEntry(page.getPageId() + ".html"));
-			IOUtils.write(htmlPage, zout, "UTF-8");
+			IOUtils.write(htmlPage, zout, StandardCharsets.UTF_8);
 			zout.closeEntry();
 		}
 		
diff --git a/src/main/java/org/olat/modules/wiki/WikiToZipUtils.java b/src/main/java/org/olat/modules/wiki/WikiToZipUtils.java
index d451ed34cb16969b09b19d79be8837c58b59d8af..8e2ef3063bf86602e0d152673916c611893dd64f 100644
--- a/src/main/java/org/olat/modules/wiki/WikiToZipUtils.java
+++ b/src/main/java/org/olat/modules/wiki/WikiToZipUtils.java
@@ -42,6 +42,7 @@ import org.olat.core.util.ZipUtil;
 import org.olat.core.util.vfs.VFSContainer;
 import org.olat.core.util.vfs.VFSItem;
 import org.olat.core.util.vfs.VFSLeaf;
+import org.olat.core.util.vfs.filters.VFSAllItemsFilter;
 import org.olat.core.util.vfs.filters.VFSSystemItemFilter;
 
 /**
@@ -116,7 +117,7 @@ public class WikiToZipUtils {
 		}
 		VFSLeaf zipFile = (VFSLeaf)rootContainer.resolve("wiki.zip");
 		if(rootContainer.resolve("wiki.zip") != null) zipFile.delete();
-		ZipUtil.zip(filesTozip, rootContainer.createChildLeaf("wiki.zip"), true);
+		ZipUtil.zip(filesTozip, rootContainer.createChildLeaf("wiki.zip"), VFSAllItemsFilter.ACCEPT_ALL, false);
 		return (VFSLeaf)rootContainer.resolve("wiki.zip");
 	}
 	
@@ -135,7 +136,7 @@ public class WikiToZipUtils {
 					exportStream.closeEntry();
 				}
 				for(VFSItem wikiItem:items) {
-					ZipUtil.addToZip(wikiItem, currentPath, exportStream);
+					ZipUtil.addToZip(wikiItem, currentPath, exportStream, VFSAllItemsFilter.ACCEPT_ALL, false);
 				}
 			}
 		}
diff --git a/src/main/java/org/olat/user/UserLifecycleManager.java b/src/main/java/org/olat/user/UserLifecycleManager.java
index 690c52ed6dad00b6df407151e1b85317c049eeeb..e498a15eb70266660929903cbfed502285269b6b 100644
--- a/src/main/java/org/olat/user/UserLifecycleManager.java
+++ b/src/main/java/org/olat/user/UserLifecycleManager.java
@@ -19,9 +19,11 @@
  */
 package org.olat.user;
 
+import java.util.Date;
 import java.util.Set;
 
 import org.olat.core.id.Identity;
+import org.olat.core.id.IdentityLifecycle;
 
 /**
  * 
@@ -32,7 +34,9 @@ import org.olat.core.id.Identity;
 public interface UserLifecycleManager {
 	
 
-
+	public long getDaysUntilDeactivation(IdentityLifecycle identity, Date referenceDate);
+	
+	public long getDaysUntilDeletion(IdentityLifecycle identity, Date referenceDate);
 	
 	/**
 	 * Check if there are identities to deactivate.
diff --git a/src/main/java/org/olat/user/UserModule.java b/src/main/java/org/olat/user/UserModule.java
index a091d0f12c6ac1d8045fe067ee415d32a3d320ae..7047134033d116172626767c5ace5cb467fcbfd9 100644
--- a/src/main/java/org/olat/user/UserModule.java
+++ b/src/main/java/org/olat/user/UserModule.java
@@ -128,6 +128,8 @@ public class UserModule extends AbstractSpringModule {
 	private boolean mailAfterDeactivation;
 	@Value("${user.days.before.mail.automatic.deactivation:30}")
 	private int numberOfDayBeforeDeactivationMail;
+	@Value("${user.days.reactivation.period:30}")
+	private int numberOfDayReactivationPeriod;
 	
 	@Value("${user.automatic.deletion:false}")
 	private boolean userAutomaticDeletion;
@@ -479,6 +481,14 @@ public class UserModule extends AbstractSpringModule {
 		setIntProperty(USER_NUM_OF_DAYS_BEFORE_MAIL_AUTOMATIC_DEACTIVATION, days, true);
 	}
 	
+	public int getNumberOfDayReactivationPeriod() {
+		return numberOfDayReactivationPeriod;
+	}
+
+	public void setNumberOfDayReactivationPeriod(int numberOfDayReactivationPeriod) {
+		this.numberOfDayReactivationPeriod = numberOfDayReactivationPeriod;
+	}
+
 	public boolean isUserAutomaticDeletion() {
 		return userAutomaticDeletion;
 	}
diff --git a/src/main/java/org/olat/user/manager/UserDataExportServiceImpl.java b/src/main/java/org/olat/user/manager/UserDataExportServiceImpl.java
index ed56d25f2f9d854d50b05d26f366d5d4b8c28df0..6af91f93bd8092b9f2d37d206c3c561a6a1c0aed 100644
--- a/src/main/java/org/olat/user/manager/UserDataExportServiceImpl.java
+++ b/src/main/java/org/olat/user/manager/UserDataExportServiceImpl.java
@@ -184,7 +184,7 @@ public class UserDataExportServiceImpl implements UserDataExportService {
 		// make zip
 		File[] files = archiveDirectory.listFiles(SystemFileFilter.DIRECTORY_FILES);
 		Set<String> filenames = Arrays.stream(files).map(File::getName).collect(Collectors.toSet());
-		ZipUtil.zip(filenames, archiveDirectory, archive);
+		ZipUtil.zip(filenames, archiveDirectory, archive, false);
 		// delete the temporary files
 		for(File file:files) {
 			FileUtils.deleteDirsAndFiles(file, true, true);
diff --git a/src/main/java/org/olat/user/manager/lifecycle/UserLifecycleManagerImpl.java b/src/main/java/org/olat/user/manager/lifecycle/UserLifecycleManagerImpl.java
index a980694995ca9d34c35cf86d43e6187de61ce8b0..3a31677b883f02cac2764d1d7ff72624b7722101 100644
--- a/src/main/java/org/olat/user/manager/lifecycle/UserLifecycleManagerImpl.java
+++ b/src/main/java/org/olat/user/manager/lifecycle/UserLifecycleManagerImpl.java
@@ -45,6 +45,7 @@ import org.olat.core.CoreSpringFactory;
 import org.olat.core.commons.persistence.DB;
 import org.olat.core.gui.translator.Translator;
 import org.olat.core.id.Identity;
+import org.olat.core.id.IdentityLifecycle;
 import org.olat.core.id.User;
 import org.olat.core.id.UserConstants;
 import org.olat.core.logging.Tracing;
@@ -95,7 +96,31 @@ public class UserLifecycleManagerImpl implements UserLifecycleManager {
 	@Autowired
 	private RepositoryDeletionModule repositoryDeletionModule;
 	
+	@Override
+	public long getDaysUntilDeactivation(IdentityLifecycle identity, Date referenceDate) {
+		long days;
+		Date reactivationDate = identity.getReactivationDate();
+		if(reactivationDate != null ) {
+			days = userModule.getNumberOfDayReactivationPeriod() - CalendarUtils.numOfDays(referenceDate, reactivationDate);
+		} else {
+			Date lastLogin = identity.getLastLogin();
+			if(lastLogin == null) {
+				lastLogin = identity.getCreationDate();
+			}
+			days = userModule.getNumberOfInactiveDayBeforeDeactivation() - CalendarUtils.numOfDays(referenceDate, lastLogin);
+		}
+		return days > 0l ? days : 1l;
+	}
 
+	@Override
+	public long getDaysUntilDeletion(IdentityLifecycle identity, Date referenceDate) {
+		if(identity == null || identity.getInactivationDate() == null) return -1;
+		
+		Date inactivationDate = identity.getInactivationDate();
+		long days = userModule.getNumberOfInactiveDayBeforeDeletion() - CalendarUtils.numOfDays(referenceDate, inactivationDate);
+		return days > 0l ? days : 1l;
+	}
+	
 	public List<Identity> getReadyToInactivateIdentities(Date loginDate, Date reactivationDateLimit) {
 		StringBuilder sb = new StringBuilder(512);
 		sb.append("select ident from ").append(IdentityImpl.class.getName()).append(" as ident")
@@ -185,7 +210,8 @@ public class UserLifecycleManagerImpl implements UserLifecycleManager {
 	public void inactivateIdentities(Set<Identity> vetoed) {
 		int numOfDaysBeforeDeactivation = userModule.getNumberOfInactiveDayBeforeDeactivation();
 		int numOfDaysBeforeEmail = userModule.getNumberOfDayBeforeDeactivationMail();
-		Date reactivationDatebefore = getDate(30);
+		int numOfDaysReactivation = userModule.getNumberOfDayReactivationPeriod();
+		Date reactivationDatebefore = getDate(numOfDaysReactivation);
 		boolean sendMailBeforeDeactivation = userModule.isMailBeforeDeactivation() && numOfDaysBeforeEmail > 0;
 		if(sendMailBeforeDeactivation) {
 			int days = numOfDaysBeforeDeactivation - numOfDaysBeforeEmail;
diff --git a/src/main/java/org/olat/user/ui/admin/UserSearchTableController.java b/src/main/java/org/olat/user/ui/admin/UserSearchTableController.java
index cc5d0c143ad03fc0d7eb7e325f2254723684bbd2..c79a83f3c6ac79c7cc9bd0228549aebc3315ddfd 100644
--- a/src/main/java/org/olat/user/ui/admin/UserSearchTableController.java
+++ b/src/main/java/org/olat/user/ui/admin/UserSearchTableController.java
@@ -50,6 +50,7 @@ import org.olat.core.gui.components.form.flexible.elements.FlexiTableFilter;
 import org.olat.core.gui.components.form.flexible.elements.FormLink;
 import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
 import org.olat.core.gui.components.form.flexible.impl.FormEvent;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.DateFlexiCellRenderer;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiColumnModel;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiColumnModel;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel;
@@ -83,6 +84,7 @@ import org.olat.core.util.mail.ContactList;
 import org.olat.core.util.mail.ContactMessage;
 import org.olat.core.util.resource.OresHelper;
 import org.olat.modules.co.ContactFormController;
+import org.olat.user.UserLifecycleManager;
 import org.olat.user.UserManager;
 import org.olat.user.UserModule;
 import org.olat.user.propertyhandlers.UserPropertyHandler;
@@ -146,6 +148,8 @@ public class UserSearchTableController extends FormBasicController implements Ac
 	@Autowired
 	private OrganisationService organisationService;
 	@Autowired
+	private UserLifecycleManager userLifecycleManager;
+	@Autowired
 	private UserBulkChangeManager userBulkChangesManager;
 	
 	public UserSearchTableController(UserRequest ureq, WindowControl wControl, TooledStackedPanel stackPanel,
@@ -172,13 +176,12 @@ public class UserSearchTableController extends FormBasicController implements Ac
 		previousLink.setTitle(translate("command.previous"));
 		nextLink = LinkFactory.createToolLink("nextelement","", this, "o_icon_next_toolbar");
 		nextLink.setTitle(translate("command.next"));
-		
-		
+
 		FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel();
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(UserCols.status, new IdentityStatusCellRenderer(getTranslator())));
 		if(isAdministrativeUser) {
 			columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, UserCols.id));
 		}
-		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(UserCols.status, new IdentityStatusCellRenderer(getTranslator())));
 
 		int colPos = USER_PROPS_OFFSET;
 		for (UserPropertyHandler userPropertyHandler : userPropertyHandlers) {
@@ -191,20 +194,20 @@ public class UserSearchTableController extends FormBasicController implements Ac
 			colPos++;
 		}
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(UserCols.creationDate));
-		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, UserCols.lastLogin));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(settings.isLifecycleColumnsDefault(), UserCols.lastLogin));
 
-		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, UserCols.inactivationDate));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(settings.isLifecycleColumnsDefault(), UserCols.inactivationDate, new DateFlexiCellRenderer(getLocale())));
 		if(userModule.isUserAutomaticDeactivation()) {
-			columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, UserCols.daysToInactivation));
+			columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(settings.isLifecycleColumnsDefault(), UserCols.daysToInactivation));
 		}
 		if(userModule.isUserAutomaticDeletion()) {
-			columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, UserCols.daysToDeletion));
+			columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(settings.isLifecycleColumnsDefault(), UserCols.daysToDeletion));
 		}
 		if(settings.isVCard()) {
 			columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("table.header.vcard", translate("table.identity.vcard"), "vcard"));
 		}
 		
-		tableModel = new UserSearchTableModel(new EmptyDataSource(), columnsModel, userModule);
+		tableModel = new UserSearchTableModel(new EmptyDataSource(), columnsModel, userModule, userLifecycleManager);
 		tableEl = uifactory.addTableElement(getWindowControl(), "table", tableModel, 25, false, getTranslator(), formLayout);
 		tableEl.setCustomizeColumns(true);
 		tableEl.setEmtpyTableMessageKey("error.no.user.found");
diff --git a/src/main/java/org/olat/user/ui/admin/UserSearchTableModel.java b/src/main/java/org/olat/user/ui/admin/UserSearchTableModel.java
index a4a5cc2adc9b0133a3987022fae64bf42b644224..2bea35d5d0916921d8c158cb4ce8a8074edb8af5 100644
--- a/src/main/java/org/olat/user/ui/admin/UserSearchTableModel.java
+++ b/src/main/java/org/olat/user/ui/admin/UserSearchTableModel.java
@@ -29,6 +29,7 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTable
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataSourceDelegate;
 import org.olat.core.id.Identity;
 import org.olat.modules.lecture.ui.TeacherRollCallController;
+import org.olat.user.UserLifecycleManager;
 import org.olat.user.UserModule;
 
 /**
@@ -41,11 +42,13 @@ public class UserSearchTableModel extends DefaultFlexiTableDataSourceModel<Ident
 	
 	private final Date now;
 	private final UserModule userModule;
+	private final UserLifecycleManager lifecycleManager;
 	
 	public UserSearchTableModel(FlexiTableDataSourceDelegate<IdentityPropertiesRow> source,
-			FlexiTableColumnModel columnModel, UserModule userModule) {
+			FlexiTableColumnModel columnModel, UserModule userModule, UserLifecycleManager lifecycleManager) {
 		super(source, columnModel);
 		this.userModule = userModule;
+		this.lifecycleManager = lifecycleManager;
 		now = CalendarUtils.startOfDay(new Date());
 	}
 
@@ -75,28 +78,21 @@ public class UserSearchTableModel extends DefaultFlexiTableDataSourceModel<Ident
 				&& (userRow.getStatus().equals(Identity.STATUS_ACTIV)
 						|| userRow.getStatus().equals(Identity.STATUS_PENDING)
 						|| userRow.getStatus().equals(Identity.STATUS_LOGIN_DENIED))) {
-			Date lastLogin = userRow.getLastLogin();
-			if(lastLogin == null) {
-				lastLogin = userRow.getCreationDate();
-			}
-			long days = userModule.getNumberOfInactiveDayBeforeDeactivation() - CalendarUtils.numOfDays(now, lastLogin);
-			return days > 0l ? days : 1l;
+			return lifecycleManager.getDaysUntilDeactivation(userRow, now);
 		}
 		return null;
 	}
 	
 	private Long getDaysToDeletion(IdentityPropertiesRow userRow) {
 		if(userModule.isUserAutomaticDeletion() && userRow.getInactivationDate() != null) {
-			Date inactivationDate = userRow.getInactivationDate();
-			long days = userModule.getNumberOfInactiveDayBeforeDeletion() - CalendarUtils.numOfDays(now, inactivationDate);
-			return days > 0l ? days : 1l;
+			return lifecycleManager.getDaysUntilDeletion(userRow, now);
 		}
 		return null;
 	}
 	
 	@Override
 	public DefaultFlexiTableDataSourceModel<IdentityPropertiesRow> createCopyWithEmptyList() {
-		return new UserSearchTableModel(null, getTableColumnModel(), userModule);
+		return new UserSearchTableModel(null, getTableColumnModel(), userModule, lifecycleManager);
 	}
 	
 	public enum UserCols implements FlexiSortableColumnDef {
diff --git a/src/main/java/org/olat/user/ui/admin/UserSearchTableSettings.java b/src/main/java/org/olat/user/ui/admin/UserSearchTableSettings.java
index 7d0833683ccc01f9e3e649943ef790fcd17decee..555d2f2ea3297857d8b2a968a14256016a153614 100644
--- a/src/main/java/org/olat/user/ui/admin/UserSearchTableSettings.java
+++ b/src/main/java/org/olat/user/ui/admin/UserSearchTableSettings.java
@@ -33,31 +33,37 @@ public class UserSearchTableSettings {
 	private final boolean bulkOrganisationMove;
 	private final boolean statusFilter;
 	private final boolean tableSearch;
+	private final boolean lifecycleColumns;
 	
-	private UserSearchTableSettings(boolean vCard, boolean bulkMail, boolean bulkOrganisationMove, boolean bulkDelete, boolean statusFilter, boolean tableSearch) {
+	private UserSearchTableSettings(boolean vCard, boolean lifecycleColumns, boolean bulkMail, boolean bulkOrganisationMove, boolean bulkDelete, boolean statusFilter, boolean tableSearch) {
 		this.vCard = vCard;
 		this.bulkMail = bulkMail;
 		this.bulkDelete = bulkDelete;
 		this.bulkOrganisationMove = bulkOrganisationMove;
 		this.statusFilter = statusFilter;
 		this.tableSearch = tableSearch;
+		this.lifecycleColumns = lifecycleColumns;
 	}
 	
 	/**
 	 * @return The table seetings with only the search enabled
 	 */
 	public static UserSearchTableSettings minimal() {
-		return new UserSearchTableSettings(false, false, false, false, false, true);
+		return new UserSearchTableSettings(false, false, false, false, false, false, true);
 	}
 	
 	public static UserSearchTableSettings withVCard(boolean bulkMail, boolean bulkOrganisationMove, boolean bulkDelete, boolean statusFilter, boolean tableSearch) {
-		return new UserSearchTableSettings(false, bulkMail, bulkOrganisationMove, bulkDelete, statusFilter, tableSearch);
+		return new UserSearchTableSettings(false, false, bulkMail, bulkOrganisationMove, bulkDelete, statusFilter, tableSearch);
 	}
 	
 	public boolean isVCard() {
 		return vCard;
 	}
 	
+	public boolean isLifecycleColumnsDefault() {
+		return lifecycleColumns;
+	}
+	
 	public boolean isTableSearch() {
 		return tableSearch;
 	}
diff --git a/src/main/java/org/olat/user/ui/admin/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/user/ui/admin/_i18n/LocalStrings_de.properties
index 7f3a49c6227445b6a4cfd49a3e3e1d27a5b675e7..7d8bda2c7466dadbd7ea70f7bd67ee3fedfc2fde 100644
--- a/src/main/java/org/olat/user/ui/admin/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/user/ui/admin/_i18n/LocalStrings_de.properties
@@ -137,4 +137,4 @@ table.identity.creationdate=Erstellt
 table.identity.days.deletion=Tage bis l\u00F6schen
 table.identity.days.inactivation=Tage bis inaktivieren
 table.identity.inactivation.date=Inaktivierungsdatum
-table.identity.lastlogin=letzter Login
+table.identity.lastlogin=Letzter Login
diff --git a/src/test/java/org/olat/core/commons/services/vfs/manager/VFSVersioningTest.java b/src/test/java/org/olat/core/commons/services/vfs/manager/VFSVersioningTest.java
index 79cd6d193f0ce6988d0e1d56183845db8a6d00b3..f3324dadee171d92873224f69c1123aaf6e1b695 100644
--- a/src/test/java/org/olat/core/commons/services/vfs/manager/VFSVersioningTest.java
+++ b/src/test/java/org/olat/core/commons/services/vfs/manager/VFSVersioningTest.java
@@ -171,6 +171,48 @@ public class VFSVersioningTest extends OlatTestCase {
 		Assert.assertEquals(id2, revisions.get(2).getAuthor());
 	}
 	
+	@Test
+	public void addVersionsDeleteRename() throws IOException {
+		versionsModule.setMaxNumberOfVersions(3);
+		waitForCondition(new SetMaxNumberOfVersions(versionsModule, 3l), 2000);
+		
+		Identity id2 = JunitTestHelper.createAndPersistIdentityAsRndUser("vers-2");
+		
+		//create a file
+		VFSContainer rootTest = VFSManager.olatRootContainer("/test_" + UUID.randomUUID(), null);
+		String filename = "orig_" + UUID.randomUUID().toString() + ".txt";
+		VFSLeaf file = rootTest.createChildLeaf(filename);
+		int byteCopied = copyTestTxt(file);
+		Assert.assertFalse(byteCopied == 0);
+		
+		//save a first version
+		for(int i=0; i<2; i++) {
+			InputStream inv = new ByteArrayInputStream(("Hello version " + i).getBytes());
+			vfsRepositoryService.addVersion(file, id2, "Version " + (1 +i), inv);
+			inv.close();
+		}
+
+		VFSItem retrievedFile = rootTest.resolve(filename);
+		VFSMetadata metadata = vfsRepositoryService.getMetadataFor(retrievedFile);
+		List<VFSRevision> revisions = vfsRepositoryService.getRevisions(metadata);
+		Assert.assertNotNull(revisions);
+		Assert.assertEquals(2, revisions.size());
+		
+		// delete the file
+		retrievedFile.delete();
+		
+		// new file
+		String newFilename = "new_" + UUID.randomUUID().toString() + ".txt";
+		VFSLeaf newFile = rootTest.createChildLeaf(newFilename);
+		int newByteCopied = copyTestTxt(newFile);
+		Assert.assertFalse(newByteCopied == 0);
+		
+		// rename new file to old name
+		newFile.rename(filename);
+		dbInstance.commit();
+		
+	}
+	
 	@Test
 	public void addVersions_overflow_lowLevel_deactivated() throws IOException {
 		versionsModule.setMaxNumberOfVersions(0);
diff --git a/src/test/java/org/olat/selenium/page/LoginPage.java b/src/test/java/org/olat/selenium/page/LoginPage.java
index 960059dbb66d78037de12a26123371cf9fcfe9e5..b600dd7859db266991490a84e79855dc55a51f6a 100644
--- a/src/test/java/org/olat/selenium/page/LoginPage.java
+++ b/src/test/java/org/olat/selenium/page/LoginPage.java
@@ -170,8 +170,6 @@ public class LoginPage {
 			try {
 				OOGraphene.waitElementDisappears(disclaimerXPath, 10, browser);
 			} catch (Exception e) {
-				// TODO Auto-generated catch block
-				e.printStackTrace();
 				OOGraphene.takeScreenshot("Login disclaimer", browser);
 				throw e;
 			}
diff --git a/src/test/java/org/olat/selenium/page/course/CourseEditorPageFragment.java b/src/test/java/org/olat/selenium/page/course/CourseEditorPageFragment.java
index 73e66f0fba97a202a48e03feb5df3776d31f6d89..4098a610d10781293f92c7fb75a2a22b2d7784c7 100644
--- a/src/test/java/org/olat/selenium/page/course/CourseEditorPageFragment.java
+++ b/src/test/java/org/olat/selenium/page/course/CourseEditorPageFragment.java
@@ -403,31 +403,20 @@ public class CourseEditorPageFragment {
 		OOGraphene.waitBusy(browser);
 		//popup
 		By referenceableEntriesBy = By.className("o_sel_search_referenceable_entries");
-		OOGraphene.waitElement(referenceableEntriesBy, 1, browser);
+		OOGraphene.waitElement(referenceableEntriesBy, browser);
 		WebElement popup = browser.findElement(referenceableEntriesBy);
 		popup.findElement(By.cssSelector("a.o_sel_repo_popup_my_resources")).click();
 		OOGraphene.waitBusy(browser);
 		
 		//find the row
-		WebElement selectRow = null;
-		List<WebElement> rows = popup.findElements(By.cssSelector("div.o_segments_content table.o_table tr"));
-		for(WebElement row:rows) {
-			String text = row.getText();
-			if(text.contains(resourceTitle)) {
-				selectRow = row;
-				break;
-			}
-		}
-		Assert.assertNotNull(selectRow);
-		
-		//find the select in the row
-		selectRow.findElement(By.xpath("//a[contains(@onclick,'rtbSelectLink')]")).click();
+		By rowBy = By.xpath("//div[contains(@class,'')]//div[contains(@class,'o_segments_content')]//table[contains(@class,'o_table')]//tr/td/a[text()[contains(.,'" + resourceTitle + "')]]");
+		OOGraphene.waitElement(rowBy, browser);
+		browser.findElement(rowBy).click();
 		OOGraphene.waitBusy(browser);
 		
 		//double check that the resource is selected (search the preview link)
 		By previewLink = By.xpath("//a/span[text()[contains(.,'" + resourceTitle + "')]]");
-		browser.findElement(previewLink);
-
+		OOGraphene.waitElement(previewLink, browser);
 		return this;
 	}
 	
diff --git a/src/test/java/org/olat/selenium/page/qpool/QuestionMetadataPage.java b/src/test/java/org/olat/selenium/page/qpool/QuestionMetadataPage.java
index 9ab8225d65c34cd11cea8f712222eda05e0c1b62..d4a5b034e98f31be1b0865eaef2b3823a706af6d 100644
--- a/src/test/java/org/olat/selenium/page/qpool/QuestionMetadataPage.java
+++ b/src/test/java/org/olat/selenium/page/qpool/QuestionMetadataPage.java
@@ -80,6 +80,7 @@ public class QuestionMetadataPage {
 		if(taxonomy != null) {
 			By taxonomyBy = By.cssSelector("div.o_sel_qpool_metadata_taxonomy select");
 			new Select(browser.findElement(taxonomyBy)).selectByVisibleText(taxonomy);
+			OOGraphene.waitBusy(browser);
 		}
 		
 		if(level != null) {
diff --git a/src/test/resources/arquillian.xml b/src/test/resources/arquillian.xml
index f656a58437d8e95cd593cd1915c1e90663339a3b..ab4a692ae8e99e13cdcf23e1c7a04ca3eab14732 100644
--- a/src/test/resources/arquillian.xml
+++ b/src/test/resources/arquillian.xml
@@ -30,7 +30,7 @@
 		-->
 		<property name="firefoxDriverVersion">${webdriver.firefox.version:v0.27.0}</property>
 		<property name="firefoxUserPreferences">src/test/profile/firefox/prefs.js</property>
-		<property name="chromeDriverVersion">${webdriver.chrome.version:84.0.4147.30}</property>
+		<property name="chromeDriverVersion">${webdriver.chrome.version:85.0.4183.87}</property>
 		<property name="chromeArguments">${webdriver.chrome.arguments}</property>
 		<property name="chromeExperimentalOption">{
 			"prefs":{"credentials_enable_service": false, "profile.password_manager_enabled": false }