From 6cb3a1538f304c3c1005216c45aafe67296756b9 Mon Sep 17 00:00:00 2001
From: srosse <none@none>
Date: Wed, 19 Nov 2014 20:07:00 +0100
Subject: [PATCH] OO-1254: generate of the certificate is asynchronous

---
 .../org/olat/course/_spring/courseContext.xml |   2 +
 .../AssessedIdentitiesTableDataModel.java     |   6 +
 .../assessment/AssessmentMainController.java  |  39 ++-
 .../olat/course/certificate/Certificate.java  |   4 +-
 .../course/certificate/CertificateEvent.java  |  48 +++
 .../course/certificate/CertificateLight.java  |   4 +-
 .../course/certificate/CertificateStatus.java |  32 ++
 .../certificate/CertificatesManager.java      |   4 +
 .../olat/course/certificate/EmailStatus.java  |  33 ++
 .../_spring/certificateContext.xml            |   9 +
 .../_spring/certificateJms_activemq.xml       |  17 ++
 .../_spring/certificateJms_jndi.xml           |  15 +
 ...ker.java => CertificatePDFFormWorker.java} |   6 +-
 .../manager/CertificatePhantomWorker.java     |  29 +-
 .../manager/CertificatesManagerImpl.java      | 287 ++++++++++++++----
 .../model/AbstractCertificate.java            | 201 ++++++++++++
 .../certificate/model/CertificateImpl.java    | 133 +-------
 .../model/CertificateLightImpl.java           |  30 +-
 .../model/CertificateStandalone.java          | 135 +-------
 .../certificate/model/JmsCertificateWork.java |  98 ++++++
 ...ssessedIdentityCertificatesController.java |  43 ++-
 ...eAndEfficiencyStatementListController.java |  51 +++-
 .../ui/DownloadCertificateCellRenderer.java   |  24 +-
 .../ui/_content/certificate_overview.html     |  10 +-
 .../ui/_i18n/LocalStrings_de.properties       |   3 +-
 .../database/mysql/alter_10_0_0_to_10_1_0.sql |   5 +-
 .../database/mysql/setupDatabase.sql          |   5 +-
 .../oracle/alter_10_0_0_to_10_1_0.sql         |   5 +-
 .../database/oracle/setupDatabase.sql         |   7 +-
 .../postgresql/alter_10_0_0_to_10_1_0.sql     |   5 +-
 .../database/postgresql/setupDatabase.sql     |   5 +-
 .../resources/serviceconfig/olat.properties   |   2 +
 .../static/themes/light/modules/_icons.scss   |   1 +
 src/main/webapp/static/themes/light/theme.css |   2 +-
 .../themes/light/theme_ie_completions.css     |   2 +-
 .../manager/CertificatesManagerTest.java      | 167 +++++++++-
 .../org/olat/restapi/CertificationTest.java   |   3 +
 37 files changed, 1071 insertions(+), 401 deletions(-)
 create mode 100644 src/main/java/org/olat/course/certificate/CertificateEvent.java
 create mode 100644 src/main/java/org/olat/course/certificate/CertificateStatus.java
 create mode 100644 src/main/java/org/olat/course/certificate/EmailStatus.java
 create mode 100644 src/main/java/org/olat/course/certificate/_spring/certificateContext.xml
 create mode 100644 src/main/java/org/olat/course/certificate/_spring/certificateJms_activemq.xml
 create mode 100644 src/main/java/org/olat/course/certificate/_spring/certificateJms_jndi.xml
 rename src/main/java/org/olat/course/certificate/manager/{CertificateTemplateWorker.java => CertificatePDFFormWorker.java} (97%)
 create mode 100644 src/main/java/org/olat/course/certificate/model/AbstractCertificate.java
 create mode 100644 src/main/java/org/olat/course/certificate/model/JmsCertificateWork.java

diff --git a/src/main/java/org/olat/course/_spring/courseContext.xml b/src/main/java/org/olat/course/_spring/courseContext.xml
index 5f1c0a997bc..55642808310 100644
--- a/src/main/java/org/olat/course/_spring/courseContext.xml
+++ b/src/main/java/org/olat/course/_spring/courseContext.xml
@@ -11,6 +11,7 @@
 	<context:component-scan base-package="org.olat.course.certificate.manager" />
 
 	<import resource="classpath:/org/olat/course/assessment/_spring/assessmentContext.xml"/>
+	<import resource="classpath:/org/olat/course/certificate/_spring/certificateContext.xml"/>
 	<import resource="classpath:/org/olat/course/config/ui/courselayout/_spring/courseLayoutContext.xml"/>
 	<import resource="classpath:/org/olat/course/db/_spring/coursedbContext.xml"/>
 	<import resource="classpath:/org/olat/course/nodes/_spring/buildingblockContext.xml"/>
@@ -22,6 +23,7 @@
 	<import resource="classpath:/org/olat/course/nodes/vitero/_spring/buildingblockContext.xml"/>
 	<import resource="classpath:/org/olat/course/statistic/_spring/statisticContext.xml"/>
 	<import resource="classpath:/org/olat/course/statistic/_spring/statisticsJobContext.xml"/>
+	
 
 	<bean id="courseModule" class="org.olat.course.CourseModule" 
 		depends-on="userModule, triggerUserModuleInit, org.olat.core.util.WebappHelper, metaInfoFactory, fileresourceManager">
diff --git a/src/main/java/org/olat/course/assessment/AssessedIdentitiesTableDataModel.java b/src/main/java/org/olat/course/assessment/AssessedIdentitiesTableDataModel.java
index 81483e072e4..0e480ffc480 100644
--- a/src/main/java/org/olat/course/assessment/AssessedIdentitiesTableDataModel.java
+++ b/src/main/java/org/olat/course/assessment/AssessedIdentitiesTableDataModel.java
@@ -146,6 +146,12 @@ public class AssessedIdentitiesTableDataModel extends DefaultTableDataModel<Asse
 	public void setCertificates(Map<Long, CertificateLight> certificates) {
 		this.certificates = certificates;
 	}
+	
+	public void putCertificate(CertificateLight certificate) {
+		if(certificates != null) {
+			certificates.put(certificate.getIdentityKey(), certificate);
+		}
+	}
 
 	/**
 	 * @see org.olat.core.gui.components.table.TableDataModel#getColumnCount()
diff --git a/src/main/java/org/olat/course/assessment/AssessmentMainController.java b/src/main/java/org/olat/course/assessment/AssessmentMainController.java
index 447930a9282..952a0eef86d 100644
--- a/src/main/java/org/olat/course/assessment/AssessmentMainController.java
+++ b/src/main/java/org/olat/course/assessment/AssessmentMainController.java
@@ -28,7 +28,6 @@ package org.olat.course.assessment;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Date;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
@@ -89,6 +88,7 @@ import org.olat.core.logging.OLATSecurityException;
 import org.olat.core.logging.OLog;
 import org.olat.core.logging.Tracing;
 import org.olat.core.logging.activity.ActionType;
+import org.olat.core.util.coordinate.CoordinatorManager;
 import org.olat.core.util.event.GenericEventListener;
 import org.olat.core.util.resource.OresHelper;
 import org.olat.core.util.tree.TreeHelper;
@@ -97,6 +97,7 @@ import org.olat.course.ICourse;
 import org.olat.course.assessment.NodeTableDataModel.Cols;
 import org.olat.course.assessment.bulk.BulkAssessmentOverviewController;
 import org.olat.course.assessment.manager.UserCourseInformationsManager;
+import org.olat.course.certificate.CertificateEvent;
 import org.olat.course.certificate.CertificateLight;
 import org.olat.course.certificate.CertificatesManager;
 import org.olat.course.certificate.ui.CertificatesWizardController;
@@ -374,6 +375,8 @@ public class AssessmentMainController extends MainLayoutBasicController implemen
 		
 		// Register for assessment changed events
 		course.getCourseEnvironment().getAssessmentManager().registerForAssessmentChangeEvents(this, ureq.getIdentity());
+		CoordinatorManager.getInstance().getCoordinator().getEventBus()
+			.registerFor(this, getIdentity(), CertificatesManager.ORES_CERTIFICATE_EVENT);
 	}
 
 	/**
@@ -634,6 +637,21 @@ public class AssessmentMainController extends MainLayoutBasicController implemen
 		if ((event instanceof AssessmentChangedEvent) &&  event.getCommand().equals(AssessmentChangedEvent.TYPE_SCORE_EVAL_CHANGED)) {
 			AssessmentChangedEvent ace = (AssessmentChangedEvent) event;
 			doUpdateLocalCacheAndUserModelFromAssessmentEvent(ace);
+		} else if(event instanceof CertificateEvent) {
+			CertificateEvent ce = (CertificateEvent)event;
+			if(re.getOlatResource().getKey().equals(ce.getResourceKey())
+					&& localUserCourseEnvironmentCache.containsKey(ce.getOwnerKey())) {
+				updateCertificate(ce.getCertificateKey());
+			}
+		}
+	}
+	
+	private void updateCertificate(Long certificateKey) {
+		if (userListCtr != null 
+				&& userListCtr.getTableDataModel() instanceof AssessedIdentitiesTableDataModel) {
+			CertificateLight certificate = certificatesManager.getCertificateLightById(certificateKey);
+			((AssessedIdentitiesTableDataModel)userListCtr
+					.getTableDataModel()).putCertificate(certificate);
 		}
 	}
 	
@@ -962,7 +980,7 @@ public class AssessmentMainController extends MainLayoutBasicController implemen
 	}
 	
 	private Map<Long, CertificateLight> getCertificates(ICourse course) {
-		Map<Long, CertificateLight> certificates = new HashMap<>();
+		Map<Long, CertificateLight> certificates =  new ConcurrentHashMap<>();
 		OLATResource resource = course.getCourseEnvironment().getCourseGroupManager().getCourseResource();
 		List<CertificateLight> certificateList = certificatesManager.getCertificates(resource);
 		for(CertificateLight certificate:certificateList) {
@@ -981,18 +999,15 @@ public class AssessmentMainController extends MainLayoutBasicController implemen
 		TableGuiConfiguration tableConfig = new TableGuiConfiguration();
 		tableConfig.setTableEmptyMessage(translate("nodesoverview.nonodes"));
 		tableConfig.setDownloadOffered(false);
-		//fxdiff VCRP-4: assessment overview with max score
 		tableConfig.setSortingEnabled(true);
 		tableConfig.setDisplayTableHeader(true);
 		tableConfig.setDisplayRowCount(false);
 		tableConfig.setPageingEnabled(false);
-		//fxdiff VCRP-4: assessment overview with max score
 		tableConfig.setPreferencesOffered(true, "assessmentNodeList");
 		
 		nodeListCtr = new TableController(tableConfig, ureq, getWindowControl(), getTranslator());
 		listenTo(nodeListCtr);
 		
-		//fxdiff VCRP-4: assessment overview with max score
 		final IndentedNodeRenderer nodeRenderer = new IndentedNodeRenderer() {
 			@Override
 			public boolean isIndentationEnabled() {
@@ -1235,10 +1250,10 @@ public class AssessmentMainController extends MainLayoutBasicController implemen
 	}
 	
 	/**
-	 * @param hasAssessableNodes true: show menu, false: hide menu
+	 * @param assessableNodes true: show menu, false: hide menu
 	 * @return The tree model
 	 */
-	private TreeModel buildTreeModel(boolean hasAssessableNodes, boolean certificate) {
+	private TreeModel buildTreeModel(boolean assessableNodes, boolean certificate) {
 		GenericTreeNode root, gtn;
 
 		GenericTreeModel gtm = new GenericTreeModel();
@@ -1249,7 +1264,7 @@ public class AssessmentMainController extends MainLayoutBasicController implemen
 		gtm.setRootNode(root);
 
 		// show real menu only when there are some assessable nodes
-		if (hasAssessableNodes) {
+		if (assessableNodes) {
 			gtn = new GenericTreeNode();
 			gtn.setTitle(translate("menu.groupfocus"));
 			gtn.setUserObject(CMD_GROUPFOCUS);
@@ -1263,7 +1278,7 @@ public class AssessmentMainController extends MainLayoutBasicController implemen
 			root.addChild(gtn);
 		}
 		
-		if (hasAssessableNodes || certificate) {
+		if (assessableNodes || certificate) {
 			gtn = new GenericTreeNode();
 			gtn.setTitle(translate("menu.userfocus"));
 			gtn.setUserObject(CMD_USERFOCUS);
@@ -1271,7 +1286,7 @@ public class AssessmentMainController extends MainLayoutBasicController implemen
 			root.addChild(gtn);
 		}
 
-		if (hasAssessableNodes) {
+		if (assessableNodes) {
 			gtn = new GenericTreeNode();
 			gtn.setTitle(translate("menu.bulkfocus"));
 			gtn.setUserObject(CMD_BULKFOCUS);
@@ -1293,6 +1308,7 @@ public class AssessmentMainController extends MainLayoutBasicController implemen
 	/**
 	 * @see org.olat.core.gui.control.DefaultController#doDispose(boolean)
 	 */
+	@Override
 	protected void doDispose() {
 		// controllers disposed by BasicController
 		userListCtr = null;
@@ -1313,6 +1329,9 @@ public class AssessmentMainController extends MainLayoutBasicController implemen
 				log.debug("Interrupting assessment cache preload in course::" + course.getResourceableId() + " while in doDispose()");
 			}
 		}
+		
+		CoordinatorManager.getInstance().getCoordinator().getEventBus()
+			.deregisterFor(this, CertificatesManager.ORES_CERTIFICATE_EVENT);
 	}
 	
 	/**
diff --git a/src/main/java/org/olat/course/certificate/Certificate.java b/src/main/java/org/olat/course/certificate/Certificate.java
index df71bd342bb..1c8ccdd8b88 100644
--- a/src/main/java/org/olat/course/certificate/Certificate.java
+++ b/src/main/java/org/olat/course/certificate/Certificate.java
@@ -32,9 +32,11 @@ public interface Certificate extends CreateInfo {
 	
 	public Long getKey();
 	
+	public CertificateStatus getStatus();
+	
 	public String getUuid();
 	
-	public String getName();
+	//public String getName();
 	
 	public String getPath();
 	
diff --git a/src/main/java/org/olat/course/certificate/CertificateEvent.java b/src/main/java/org/olat/course/certificate/CertificateEvent.java
new file mode 100644
index 00000000000..bb12662d0de
--- /dev/null
+++ b/src/main/java/org/olat/course/certificate/CertificateEvent.java
@@ -0,0 +1,48 @@
+package org.olat.course.certificate;
+
+import org.olat.core.util.event.MultiUserEvent;
+
+/**
+ * 
+ * Initial date: 19.11.2014<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class CertificateEvent extends MultiUserEvent {
+
+	private static final long serialVersionUID = -1854321062161208157L;
+	private Long ownerKey;
+	private Long resourceKey;
+	private Long certificateKey;
+	
+	public CertificateEvent(Long ownerKey, Long certificateKey, Long resourceKey) {
+		super("certificate-update");
+		this.ownerKey = ownerKey;
+		this.resourceKey = resourceKey;
+		this.certificateKey = certificateKey;
+	}
+
+	public Long getOwnerKey() {
+		return ownerKey;
+	}
+
+	public void setOwnerKey(Long ownerKey) {
+		this.ownerKey = ownerKey;
+	}
+
+	public Long getResourceKey() {
+		return resourceKey;
+	}
+
+	public void setResourceKey(Long resourceKey) {
+		this.resourceKey = resourceKey;
+	}
+
+	public Long getCertificateKey() {
+		return certificateKey;
+	}
+
+	public void setCertificateKey(Long certificateKey) {
+		this.certificateKey = certificateKey;
+	}
+}
diff --git a/src/main/java/org/olat/course/certificate/CertificateLight.java b/src/main/java/org/olat/course/certificate/CertificateLight.java
index 4cbe0602a80..6f29478365a 100644
--- a/src/main/java/org/olat/course/certificate/CertificateLight.java
+++ b/src/main/java/org/olat/course/certificate/CertificateLight.java
@@ -29,7 +29,9 @@ import org.olat.core.id.CreateInfo;
  */
 public interface CertificateLight extends CreateInfo {
 	
-	public String getName();
+	public Long getKey();
+	
+	public CertificateStatus getStatus();
 	
 	public String getUuid();
 	
diff --git a/src/main/java/org/olat/course/certificate/CertificateStatus.java b/src/main/java/org/olat/course/certificate/CertificateStatus.java
new file mode 100644
index 00000000000..057441e925d
--- /dev/null
+++ b/src/main/java/org/olat/course/certificate/CertificateStatus.java
@@ -0,0 +1,32 @@
+/**
+ * <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.course.certificate;
+
+/**
+ * 
+ * Initial date: 19.11.2014<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public enum CertificateStatus {
+	pending,
+	ok,
+	error
+}
diff --git a/src/main/java/org/olat/course/certificate/CertificatesManager.java b/src/main/java/org/olat/course/certificate/CertificatesManager.java
index 9eb6221a7b3..6517e51d060 100644
--- a/src/main/java/org/olat/course/certificate/CertificatesManager.java
+++ b/src/main/java/org/olat/course/certificate/CertificatesManager.java
@@ -28,6 +28,7 @@ import org.olat.basesecurity.IdentityRef;
 import org.olat.core.commons.services.notifications.PublisherData;
 import org.olat.core.commons.services.notifications.SubscriptionContext;
 import org.olat.core.id.Identity;
+import org.olat.core.id.OLATResourceable;
 import org.olat.core.util.mail.MailerResult;
 import org.olat.core.util.resource.OresHelper;
 import org.olat.core.util.vfs.VFSLeaf;
@@ -45,6 +46,7 @@ import org.olat.resource.OLATResource;
 public interface CertificatesManager {
 
 	public static final String ORES_CERTIFICATE =  OresHelper.calculateTypeName(CertificatesManager.class);
+	public static final OLATResourceable ORES_CERTIFICATE_EVENT =  OresHelper.createOLATResourceableInstance("Certificate", 0l);
 	
 	public boolean isHTMLTemplateAllowed();
 	
@@ -93,6 +95,8 @@ public interface CertificatesManager {
 	
 	public Certificate getCertificateByUuid(String uuid);
 	
+	public CertificateLight getCertificateLightById(Long key);
+	
 	public VFSLeaf getCertificateLeaf(Certificate certificate);
 	
 
diff --git a/src/main/java/org/olat/course/certificate/EmailStatus.java b/src/main/java/org/olat/course/certificate/EmailStatus.java
new file mode 100644
index 00000000000..62d5bba6d87
--- /dev/null
+++ b/src/main/java/org/olat/course/certificate/EmailStatus.java
@@ -0,0 +1,33 @@
+/**
+ * <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.course.certificate;
+
+/**
+ * 
+ * Initial date: 19.11.2014<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public enum EmailStatus {
+	
+	ok,
+	error,
+
+}
diff --git a/src/main/java/org/olat/course/certificate/_spring/certificateContext.xml b/src/main/java/org/olat/course/certificate/_spring/certificateContext.xml
new file mode 100644
index 00000000000..23558cb5126
--- /dev/null
+++ b/src/main/java/org/olat/course/certificate/_spring/certificateContext.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://www.springframework.org/schema/beans 
+                        http://www.springframework.org/schema/beans/spring-beans.xsd">
+                        
+	<import resource="classpath:org/olat/course/certificate/_spring/certificateJms_${jms.provider}.xml" />
+                        
+</beans>
\ No newline at end of file
diff --git a/src/main/java/org/olat/course/certificate/_spring/certificateJms_activemq.xml b/src/main/java/org/olat/course/certificate/_spring/certificateJms_activemq.xml
new file mode 100644
index 00000000000..0df5e613c76
--- /dev/null
+++ b/src/main/java/org/olat/course/certificate/_spring/certificateJms_activemq.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://www.springframework.org/schema/beans 
+                        http://www.springframework.org/schema/beans/spring-beans.xsd">
+
+	<!-- JMS Stuff for ActiveMQ -->
+	<bean id="certificateConnectionFactory" class="org.apache.activemq.spring.ActiveMQConnectionFactory" lazy-init="true">
+		<property name="brokerURL" value="${certificate.broker.url}" /> 
+	</bean>
+
+	<bean id="certificateQueue" class="org.apache.activemq.command.ActiveMQQueue" lazy-init="true">
+		<constructor-arg value="olat/certificateQueue" />
+	</bean>
+	
+	
+</beans>
diff --git a/src/main/java/org/olat/course/certificate/_spring/certificateJms_jndi.xml b/src/main/java/org/olat/course/certificate/_spring/certificateJms_jndi.xml
new file mode 100644
index 00000000000..a0e3b73e13b
--- /dev/null
+++ b/src/main/java/org/olat/course/certificate/_spring/certificateJms_jndi.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://www.springframework.org/schema/beans 
+                        http://www.springframework.org/schema/beans/spring-beans.xsd">
+
+	<!-- JMS Stuff -->
+	<bean id="certificateConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean" lazy-init="true">
+        <property name="jndiName"><value>${jms.broker.jndi}</value></property>
+    </bean>
+    <bean id="certificateQueue" class="org.springframework.jndi.JndiObjectFactoryBean" lazy-init="true">
+		<property name="jndiName"><value>${certificate.broker.jndi}</value></property>
+	</bean>
+
+</beans>
diff --git a/src/main/java/org/olat/course/certificate/manager/CertificateTemplateWorker.java b/src/main/java/org/olat/course/certificate/manager/CertificatePDFFormWorker.java
similarity index 97%
rename from src/main/java/org/olat/course/certificate/manager/CertificateTemplateWorker.java
rename to src/main/java/org/olat/course/certificate/manager/CertificatePDFFormWorker.java
index 7dae2a57b3d..667f93f54ff 100644
--- a/src/main/java/org/olat/course/certificate/manager/CertificateTemplateWorker.java
+++ b/src/main/java/org/olat/course/certificate/manager/CertificatePDFFormWorker.java
@@ -54,10 +54,10 @@ import org.olat.user.propertyhandlers.UserPropertyHandler;
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  *
  */
-public class CertificateTemplateWorker {
+public class CertificatePDFFormWorker {
 
 	private static final OLog log = Tracing
-			.createLoggerFor(CertificateTemplateWorker.class);
+			.createLoggerFor(CertificatePDFFormWorker.class);
 	
 	private final Float score;
 	private final Boolean passed;
@@ -71,7 +71,7 @@ public class CertificateTemplateWorker {
 	private final UserManager userManager;
 	private final CertificatesManagerImpl certificatesManager;
 
-	public CertificateTemplateWorker(Identity identity, RepositoryEntry entry,
+	public CertificatePDFFormWorker(Identity identity, RepositoryEntry entry,
 			Float score, Boolean passed, Date dateCertification,
 			Date dateFirstCertification, Locale locale,
 			UserManager userManager, CertificatesManagerImpl certificatesManager) {
diff --git a/src/main/java/org/olat/course/certificate/manager/CertificatePhantomWorker.java b/src/main/java/org/olat/course/certificate/manager/CertificatePhantomWorker.java
index 42e93909450..38ab7e69b0b 100644
--- a/src/main/java/org/olat/course/certificate/manager/CertificatePhantomWorker.java
+++ b/src/main/java/org/olat/course/certificate/manager/CertificatePhantomWorker.java
@@ -58,7 +58,7 @@ import org.olat.user.propertyhandlers.UserPropertyHandler;
  */
 public class CertificatePhantomWorker {
 	private static final OLog log = Tracing
-			.createLoggerFor(CertificateTemplateWorker.class);
+			.createLoggerFor(CertificatePDFFormWorker.class);
 	
 	private final Float score;
 	private final Boolean passed;
@@ -109,17 +109,15 @@ public class CertificatePhantomWorker {
 		}
 		
 		CountDownLatch doneSignal = new CountDownLatch(1);
-		ProcessWorker worker = new ProcessWorker(cmds, doneSignal);
+		ProcessWorker worker = new ProcessWorker(cmds, htmlCertificateFile, doneSignal);
 		worker.start();
 
 		try {
-			doneSignal.await(3000, TimeUnit.MILLISECONDS);
+			doneSignal.await(30000, TimeUnit.MILLISECONDS);
 		} catch (InterruptedException e) {
 			log.error("", e);
 		}
 		
-		htmlCertificateFile.delete();
-		
 		worker.destroyProcess();
 		return certificateFile;
 	}
@@ -131,6 +129,7 @@ public class CertificatePhantomWorker {
 		try(Reader in = Files.newBufferedReader(templateFile.toPath(), Charset.forName("UTF-8"));
 			Writer output = new FileWriter(htmlCertificate)) {
 			result = certificatesManager.getVelocityEngine().evaluate(context, output, "mailTemplate", in);
+			output.flush();
 		} catch(Exception e) {
 			log.error("", e);
 		}
@@ -216,11 +215,11 @@ public class CertificatePhantomWorker {
 		cmds.add("--help");
 		
 		CountDownLatch doneSignal = new CountDownLatch(1);
-		ProcessWorker worker = new ProcessWorker(cmds, doneSignal);
+		ProcessWorker worker = new ProcessWorker(cmds, null, doneSignal);
 		worker.start();
 
 		try {
-			doneSignal.await(3000, TimeUnit.MILLISECONDS);
+			doneSignal.await(10000, TimeUnit.MILLISECONDS);
 		} catch (InterruptedException e) {
 			log.error("", e);
 		}
@@ -236,10 +235,12 @@ public class CertificatePhantomWorker {
 		private int exitValue = -1;
 		private final List<String> cmd;
 		private final CountDownLatch doneSignal;
+		private final File htmlCertificateFile;
 		
-		public ProcessWorker(List<String> cmd, CountDownLatch doneSignal) {
+		public ProcessWorker(List<String> cmd, File htmlCertificateFile, CountDownLatch doneSignal) {
 			this.cmd = cmd;
 			this.doneSignal = doneSignal;
+			this.htmlCertificateFile = htmlCertificateFile;
 		}
 		
 		public void destroyProcess() {
@@ -267,6 +268,10 @@ public class CertificatePhantomWorker {
 			} catch (IOException e) {
 				log.error ("Could not spawn convert sub process", e);
 				destroyProcess();
+			} finally {
+				if(htmlCertificateFile != null) {
+					htmlCertificateFile.delete();
+				}
 			}
 		}
 		
@@ -298,8 +303,8 @@ public class CertificatePhantomWorker {
 			} catch (IOException e) {
 				//
 			}
-
-			if (log.isDebug()) {
+			
+			if(log.isDebug()) {
 				log.debug("Error: " + errors.toString());
 				log.debug("Output: " + output.toString());
 			}
@@ -307,10 +312,10 @@ public class CertificatePhantomWorker {
 			try {
 				exitValue = proc.waitFor();
 				if (exitValue != 0) {
-					log.warn("Problem with PhantomJS?");
+					log.warn("Problem with PhantomJS? " + exitValue);
 				}
 			} catch (InterruptedException e) {
-				//
+				log.warn("Takes too long");
 			}
 		}
 	}
diff --git a/src/main/java/org/olat/course/certificate/manager/CertificatesManagerImpl.java b/src/main/java/org/olat/course/certificate/manager/CertificatesManagerImpl.java
index 345e5fe324f..28ed611d3bd 100644
--- a/src/main/java/org/olat/course/certificate/manager/CertificatesManagerImpl.java
+++ b/src/main/java/org/olat/course/certificate/manager/CertificatesManagerImpl.java
@@ -35,6 +35,18 @@ import java.util.Locale;
 import java.util.Properties;
 import java.util.UUID;
 
+import javax.annotation.Resource;
+import javax.jms.ConnectionFactory;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.ObjectMessage;
+import javax.jms.Queue;
+import javax.jms.QueueConnection;
+import javax.jms.QueueSender;
+import javax.jms.QueueSession;
+import javax.jms.Session;
 import javax.persistence.TypedQuery;
 
 import org.apache.velocity.app.VelocityEngine;
@@ -54,8 +66,10 @@ import org.olat.core.id.Roles;
 import org.olat.core.logging.OLog;
 import org.olat.core.logging.Tracing;
 import org.olat.core.util.FileUtils;
+import org.olat.core.util.StringHelper;
 import org.olat.core.util.Util;
 import org.olat.core.util.WebappHelper;
+import org.olat.core.util.coordinate.CoordinatorManager;
 import org.olat.core.util.i18n.I18nManager;
 import org.olat.core.util.mail.MailBundle;
 import org.olat.core.util.mail.MailManager;
@@ -70,14 +84,18 @@ import org.olat.course.CorruptedCourseException;
 import org.olat.course.CourseFactory;
 import org.olat.course.ICourse;
 import org.olat.course.certificate.Certificate;
+import org.olat.course.certificate.CertificateEvent;
 import org.olat.course.certificate.CertificateLight;
+import org.olat.course.certificate.CertificateStatus;
 import org.olat.course.certificate.CertificateTemplate;
 import org.olat.course.certificate.CertificatesManager;
+import org.olat.course.certificate.EmailStatus;
 import org.olat.course.certificate.RecertificationTimeUnit;
 import org.olat.course.certificate.model.CertificateImpl;
 import org.olat.course.certificate.model.CertificateInfos;
 import org.olat.course.certificate.model.CertificateStandalone;
 import org.olat.course.certificate.model.CertificateTemplateImpl;
+import org.olat.course.certificate.model.JmsCertificateWork;
 import org.olat.course.certificate.ui.CertificateController;
 import org.olat.course.config.CourseConfig;
 import org.olat.course.nodes.CourseNode;
@@ -88,10 +106,12 @@ import org.olat.group.model.SearchBusinessGroupParams;
 import org.olat.modules.vitero.model.GroupRole;
 import org.olat.repository.RepositoryEntry;
 import org.olat.repository.RepositoryManager;
+import org.olat.repository.RepositoryService;
 import org.olat.repository.model.RepositoryEntrySecurity;
 import org.olat.resource.OLATResource;
 import org.olat.user.UserManager;
 import org.olat.user.propertyhandlers.UserPropertyHandler;
+import org.springframework.beans.factory.DisposableBean;
 import org.springframework.beans.factory.InitializingBean;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
@@ -105,7 +125,7 @@ import uk.ac.reload.diva.util.ZipUtils;
  *
  */
 @Service("certificatesManager")
-public class CertificatesManagerImpl implements CertificatesManager, InitializingBean {
+public class CertificatesManagerImpl implements CertificatesManager, MessageListener, InitializingBean, DisposableBean {
 	
 	private static final OLog log = Tracing.createLoggerFor(CertificatesManagerImpl.class);
 
@@ -122,12 +142,23 @@ public class CertificatesManagerImpl implements CertificatesManager, Initializin
 	@Autowired
 	private BaseSecurity securityManager;
 	@Autowired
+	private RepositoryService repositoryService;
+	@Autowired
 	private RepositoryManager repositoryManager;
 	@Autowired
 	private NotificationsManager notificationsManager;
 	@Autowired
 	private BusinessGroupService businessGroupService;
-	
+	@Autowired
+	private CoordinatorManager coordinatorManager;
+
+	@Resource(name="certificateQueue")
+	private Queue jmsQueue;
+	private Session certificateSession;
+	private MessageConsumer consumer;
+	@Resource(name="certificateConnectionFactory")
+	private ConnectionFactory connectionFactory;
+	private QueueConnection connection;
 
 	private Boolean phantomAvailable;
 	private FileStorage usersStorage;
@@ -159,6 +190,51 @@ public class CertificatesManagerImpl implements CertificatesManager, Initializin
 		} catch(Exception e) {
 			log.error("", e);
 		}
+		
+		//start the queues
+		try {
+			startQueue();
+		} catch (JMSException e) {
+			log.error("", e);
+		}
+	}
+	
+	private void startQueue() throws JMSException {
+		connection = (QueueConnection)connectionFactory.createConnection();
+		connection.start();
+		log.info("springInit: JMS connection started with connectionFactory=" + connectionFactory);
+
+		//listen to the queue only if indexing node
+		certificateSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+		consumer = certificateSession.createConsumer(jmsQueue);
+		consumer.setMessageListener(this);
+	}
+
+	@Override
+	public void destroy() throws Exception {
+		closeJms();
+	}
+	
+	private void closeJms() {
+		if(consumer != null) {
+			try {
+				consumer.close();
+			} catch (JMSException e) {
+				log.error("", e);
+			}
+		}
+		if(connection != null) {
+			try {
+				certificateSession.close();
+				connection.close();
+			} catch (JMSException e) {
+				log.error("", e);
+			}
+		}
+	}
+	
+	private Queue getJmsQueue() {
+		return jmsQueue;
 	}
 
 	@Override
@@ -203,22 +279,40 @@ public class CertificatesManagerImpl implements CertificatesManager, Initializin
 	@Override
 	public VFSLeaf getCertificateLeaf(Certificate certificate) {
 		VFSContainer cerContainer = getCertificateRootContainer();
-		VFSItem cerItem = cerContainer.resolve(certificate.getPath());
+		VFSItem cerItem = null;
+		if(StringHelper.containsNonWhitespace(certificate.getPath())) {
+			cerItem = cerContainer.resolve(certificate.getPath());
+		}
 		return cerItem instanceof VFSLeaf ? (VFSLeaf)cerItem : null;
 	}
 	
 	private File getCertificateFile(Certificate certificate) {
 		File file = getCertificateRoot();
-		return new File(file, certificate.getPath());
+		if(StringHelper.containsNonWhitespace(certificate.getPath())) {
+			return new File(file, certificate.getPath());
+		}
+		return null;
 	}
 	
 	@Override
-	public Certificate getCertificateById(Long key) {
+	public CertificateImpl getCertificateById(Long key) {
 		StringBuilder sb = new StringBuilder();
 		sb.append("select cer from certificate cer")
 		  .append(" where cer.key=:certificateKey");
-		List<Certificate> certificates = dbInstance.getCurrentEntityManager()
-				.createQuery(sb.toString(), Certificate.class)
+		List<CertificateImpl> certificates = dbInstance.getCurrentEntityManager()
+				.createQuery(sb.toString(), CertificateImpl.class)
+				.setParameter("certificateKey", key)
+				.getResultList();
+		return certificates.isEmpty() ? null : certificates.get(0);
+	}
+	
+	@Override
+	public CertificateLight getCertificateLightById(Long key) {
+		StringBuilder sb = new StringBuilder();
+		sb.append("select cer from certificatelight cer")
+		  .append(" where cer.key=:certificateKey");
+		List<CertificateLight> certificates = dbInstance.getCurrentEntityManager()
+				.createQuery(sb.toString(), CertificateLight.class)
 				.setParameter("certificateKey", key)
 				.getResultList();
 		return certificates.isEmpty() ? null : certificates.get(0);
@@ -459,10 +553,15 @@ public class CertificatesManagerImpl implements CertificatesManager, Initializin
 		if(creationDate != null) {
 			certificate.setCreationDate(creationDate);
 		}
+		RepositoryEntry entry = repositoryService.loadByResourceKey(resource.getKey());
+		if(entry != null) {
+			certificate.setCourseTitle(entry.getDisplayname());
+		}
 		certificate.setLastModified(certificate.getCreationDate());
 		certificate.setIdentity(identity);
 		certificate.setUuid(UUID.randomUUID().toString());
 		certificate.setLast(true);
+		certificate.setStatus(CertificateStatus.ok);
 
 		String dir = usersStorage.generateDir();
 		try (InputStream in = Files.newInputStream(certificateFile.toPath())) {
@@ -472,12 +571,11 @@ public class CertificatesManagerImpl implements CertificatesManager, Initializin
 			File storedCertificateFile = new File(dirFile, "Certificate.pdf");
 			Files.copy(in, storedCertificateFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
 
-			certificate.setName(storedCertificateFile.getName());
 			certificate.setPath(dir + storedCertificateFile.getName());
 
-			Date dateFirstCertification = getDateFirstCertification(identity, resource);
+			Date dateFirstCertification = getDateFirstCertification(identity, resource.getKey());
 			if (dateFirstCertification != null) {
-				removeLastFlag(identity, resource);
+				removeLastFlag(identity, resource.getKey());
 			}
 
 			dbInstance.getCurrentEntityManager().persist(certificate);
@@ -500,6 +598,7 @@ public class CertificatesManagerImpl implements CertificatesManager, Initializin
 		certificate.setUuid(UUID.randomUUID().toString());
 		certificate.setLast(true);
 		certificate.setCourseTitle(courseTitle);
+		certificate.setStatus(CertificateStatus.ok);
 
 		String dir = usersStorage.generateDir();
 		try (InputStream in = Files.newInputStream(certificateFile.toPath())) {
@@ -509,8 +608,12 @@ public class CertificatesManagerImpl implements CertificatesManager, Initializin
 			File storedCertificateFile = new File(dirFile, "Certificate.pdf");
 			Files.copy(in, storedCertificateFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
 
-			certificate.setName(storedCertificateFile.getName());
 			certificate.setPath(dir + storedCertificateFile.getName());
+			
+			Date dateFirstCertification = getDateFirstCertification(identity, resourceKey);
+			if (dateFirstCertification != null) {
+				removeLastFlag(identity, resourceKey);
+			}
 
 			dbInstance.getCurrentEntityManager().persist(certificate);
 		} catch (Exception e) {
@@ -539,7 +642,7 @@ public class CertificatesManagerImpl implements CertificatesManager, Initializin
 		File certificateFile;
 		File dirFile = new File(WebappHelper.getTmpDir(), UUID.randomUUID().toString());	
 		if(template.getPath().toLowerCase().endsWith("pdf")) {
-			CertificateTemplateWorker worker = new CertificateTemplateWorker(identity, entry, 2.0f, true,
+			CertificatePDFFormWorker worker = new CertificatePDFFormWorker(identity, entry, 2.0f, true,
 					new Date(), new Date(), locale, userManager, this);
 			certificateFile = worker.fill(template, dirFile);
 		} else {
@@ -563,13 +666,13 @@ public class CertificatesManagerImpl implements CertificatesManager, Initializin
 	@Override
 	public Certificate generateCertificate(CertificateInfos certificateInfos, RepositoryEntry entry,
 			CertificateTemplate template, MailerResult result) {
-		Certificate certificate = persistCertificate(certificateInfos, entry, template, result);
+		Certificate certificate = persistCertificate(certificateInfos, entry, template);
 		markPublisherNews(null, entry.getOlatResource());
 		return certificate;
 	}
 
 	private Certificate persistCertificate(CertificateInfos certificateInfos, RepositoryEntry entry,
-			CertificateTemplate template, MailerResult result) {
+			CertificateTemplate template) {
 		OLATResource resource = entry.getOlatResource();
 		Identity identity = certificateInfos.getAssessedIdentity();
 		
@@ -586,52 +689,125 @@ public class CertificatesManagerImpl implements CertificatesManager, Initializin
 		certificate.setUuid(UUID.randomUUID().toString());
 		certificate.setLast(true);
 		certificate.setCourseTitle(entry.getDisplayname());
+		certificate.setStatus(CertificateStatus.pending);
 		
-		String dir = usersStorage.generateDir();
-		try {
-			File dirFile = new File(getCertificateRoot(), dir);
-			dirFile.mkdirs();
-			
-			Float score = certificateInfos.getScore();
-			Locale locale = I18nManager.getInstance().getLocaleOrDefault(null);
-			Boolean passed = certificateInfos.getPassed();
-			Date dateCertification = certificate.getCreationDate();
-			Date dateFirstCertification = getDateFirstCertification(identity, resource);
-
-			File certificateFile;
-			if(template == null || template.getPath().toLowerCase().endsWith("pdf")) {
-				CertificateTemplateWorker worker = new CertificateTemplateWorker(identity, entry, score, passed,
-						dateCertification, dateFirstCertification, locale, userManager, this);
-				certificateFile = worker.fill(template, dirFile);
-			} else {
-				CertificatePhantomWorker worker = new CertificatePhantomWorker(identity, entry, score, passed,
-						dateCertification, dateFirstCertification, locale, userManager, this);
-				certificateFile = worker.fill(template, dirFile);
-			}
+		dbInstance.getCurrentEntityManager().persist(certificate);
+		dbInstance.commit();
+		
+		//send message
+		sendJmsCertificateFile(certificate, template, certificateInfos.getScore(), certificateInfos.getPassed());
 
-			certificate.setName(certificateFile.getName());
-			certificate.setPath(dir + certificateFile.getName());
-			
-			if(dateFirstCertification != null) {
-				//not the first certification, reset the last of the others certificates
-				removeLastFlag(identity, resource);
+		return certificate;
+	}
+	
+	protected VelocityEngine getVelocityEngine() {
+		return velocityEngine;
+	}
+	
+	private void sendJmsCertificateFile(Certificate certificate, CertificateTemplate template, Float score, Boolean passed) {
+		QueueSender sender;
+		QueueSession session = null;
+		try  {
+			JmsCertificateWork workUnit = new JmsCertificateWork();
+			workUnit.setCertificateKey(certificate.getKey());
+			if(template != null) {
+				workUnit.setTemplateKey(template.getKey());
 			}
+			workUnit.setPassed(passed);
+			workUnit.setScore(score);
 			
-			dbInstance.getCurrentEntityManager().persist(certificate);
+			session = connection.createQueueSession(false, QueueSession.AUTO_ACKNOWLEDGE );
+			ObjectMessage message = session.createObjectMessage();
+			message.setObject(workUnit);
 
-			MailerResult newResult = sendCertificate(identity, entry, certificateFile);
-			if(result != null) {
-				result.append(newResult);
+			sender = session.createSender(getJmsQueue());
+			sender.send( message );
+		} catch (JMSException e) {
+			log.error("", e );
+		} finally {
+			if(session != null) {
+				try {
+					session.close();
+				} catch (JMSException e) {
+					//last hope
+				}
 			}
-			
-		} catch (Exception e) {
-			log.error("", e);
 		}
-		return certificate;
 	}
 	
-	protected VelocityEngine getVelocityEngine() {
-		return velocityEngine;
+	@Override
+	public void onMessage(Message message) {
+		if(message instanceof ObjectMessage) {
+			try {
+				ObjectMessage objMsg = (ObjectMessage)message;
+				JmsCertificateWork workUnit = (JmsCertificateWork)objMsg.getObject();
+				doCertificate(workUnit);
+				message.acknowledge();
+			} catch (JMSException e) {
+				log.error("", e);
+			} finally {
+				dbInstance.commitAndCloseSession();
+			}
+		}
+	}
+	
+	private void doCertificate(JmsCertificateWork workUnit) {
+		CertificateImpl certificate = getCertificateById(workUnit.getCertificateKey());
+		CertificateTemplate template = null;
+		if(workUnit.getTemplateKey() != null) {
+			template = getTemplateById(workUnit.getTemplateKey());
+		}
+		OLATResource resource = certificate.getOlatResource();
+		Identity identity = certificate.getIdentity();
+		RepositoryEntry entry = repositoryService.loadByResourceKey(resource.getKey());
+		
+		String dir = usersStorage.generateDir();
+		File dirFile = new File(getCertificateRoot(), dir);
+		dirFile.mkdirs();
+		
+		Float score = workUnit.getScore();
+		Locale locale = I18nManager.getInstance().getLocaleOrDefault(null);
+		Boolean passed = workUnit.getPassed();
+		Date dateCertification = certificate.getCreationDate();
+		Date dateFirstCertification = getDateFirstCertification(identity, resource.getKey());
+		
+		File certificateFile;
+		if(template == null || template.getPath().toLowerCase().endsWith("pdf")) {
+			CertificatePDFFormWorker worker = new CertificatePDFFormWorker(identity, entry, score, passed,
+					dateCertification, dateFirstCertification, locale, userManager, this);
+			certificateFile = worker.fill(template, dirFile);
+			if(certificateFile == null) {
+				certificate.setStatus(CertificateStatus.error);
+			} else {
+				certificate.setStatus(CertificateStatus.ok);
+			}
+		} else {
+			CertificatePhantomWorker worker = new CertificatePhantomWorker(identity, entry, score, passed,
+					dateCertification, dateFirstCertification, locale, userManager, this);
+			certificateFile = worker.fill(template, dirFile);
+			if(certificateFile == null) {
+				certificate.setStatus(CertificateStatus.error);
+			} else {
+				certificate.setStatus(CertificateStatus.ok);
+			}
+		}
+
+		certificate.setPath(dir + certificateFile.getName());
+		if(dateFirstCertification != null) {
+			//not the first certification, reset the last of the others certificates
+			removeLastFlag(identity, resource.getKey());
+		}
+		MailerResult result = sendCertificate(identity, entry, certificateFile);
+		if(result.isSuccessful()) {
+			certificate.setEmailStatus(EmailStatus.ok);
+		} else {
+			certificate.setEmailStatus(EmailStatus.error);
+		}
+		dbInstance.getCurrentEntityManager().merge(certificate);
+		dbInstance.commit();
+		
+		CertificateEvent event = new CertificateEvent(identity.getKey(), certificate.getKey(), resource.getKey());
+		coordinatorManager.getCoordinator().getEventBus().fireEventToListenersOf(event, ORES_CERTIFICATE_EVENT);
 	}
 	
 	private MailerResult sendCertificate(Identity to, RepositoryEntry entry, File certificateFile) {
@@ -653,30 +829,31 @@ public class CertificatesManagerImpl implements CertificatesManager, Initializin
 		return mailManager.sendMessage(bundle);
 	}
 	
-	private Date getDateFirstCertification(Identity identity, OLATResource resource) {
+	private Date getDateFirstCertification(Identity identity, Long resourceKey) {
 		StringBuilder sb = new StringBuilder();
 		sb.append("select cer.creationDate from certificate cer")
 		  .append(" where cer.olatResource.key=:resourceKey and cer.identity.key=:identityKey")
 		  .append(" order by cer.creationDate asc");
 		
 		List<Date> dates = dbInstance.getCurrentEntityManager().createQuery(sb.toString(), Date.class)
-				.setParameter("resourceKey", resource.getKey())
+				.setParameter("resourceKey", resourceKey)
 				.setParameter("identityKey", identity.getKey())
 				.setMaxResults(1)
 				.getResultList();
 		return dates.isEmpty() ? null : dates.get(0);
 	}
 	
-	private void removeLastFlag(Identity identity, OLATResource resource) {
+	private void removeLastFlag(Identity identity, Long resourceKey) {
 		StringBuilder sb = new StringBuilder();
 		sb.append("update certificate  cer set cer.last=false")
 		  .append(" where cer.olatResource.key=:resourceKey and cer.identity.key=:identityKey");
 		
 		dbInstance.getCurrentEntityManager().createQuery(sb.toString())
-				.setParameter("resourceKey", resource.getKey())
+				.setParameter("resourceKey", resourceKey)
 				.setParameter("identityKey", identity.getKey())
 				.executeUpdate();
 	}
+	
 
 	@Override
 	public List<CertificateTemplate> getTemplates() {
diff --git a/src/main/java/org/olat/course/certificate/model/AbstractCertificate.java b/src/main/java/org/olat/course/certificate/model/AbstractCertificate.java
new file mode 100644
index 00000000000..40de69289b6
--- /dev/null
+++ b/src/main/java/org/olat/course/certificate/model/AbstractCertificate.java
@@ -0,0 +1,201 @@
+/**
+ * <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.course.certificate.model;
+
+import java.util.Date;
+
+import javax.persistence.Column;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.MappedSuperclass;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+
+import org.hibernate.annotations.GenericGenerator;
+import org.olat.basesecurity.IdentityImpl;
+import org.olat.core.id.Identity;
+import org.olat.core.id.Persistable;
+import org.olat.course.certificate.Certificate;
+import org.olat.course.certificate.CertificateStatus;
+import org.olat.course.certificate.EmailStatus;
+
+/**
+ * 
+ * Initial date: 19.11.2014<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+@MappedSuperclass
+public abstract class AbstractCertificate implements Certificate, Persistable {
+
+	private static final long serialVersionUID = 2614314930775241116L;
+
+	@Id
+	@GeneratedValue(generator = "system-uuid")
+	@GenericGenerator(name = "system-uuid", strategy = "hilo")
+	@Column(name="id", nullable=false, unique=true, insertable=true, updatable=false)
+	private Long key;
+	
+	@Temporal(TemporalType.TIMESTAMP)
+	@Column(name="creationdate", nullable=false, insertable=true, updatable=false)
+	private Date creationDate;
+	@Temporal(TemporalType.TIMESTAMP)
+	@Column(name="lastmodified", nullable=false, insertable=true, updatable=true)
+	private Date lastModified;
+	
+	@Column(name="c_status", nullable=false, insertable=true, updatable=true)
+	private String statusString;
+	@Column(name="c_email_status", nullable=true, insertable=true, updatable=true)
+	private String emailStatusString;
+	
+	@Column(name="c_uuid", nullable=false, insertable=true, updatable=false)
+	private String uuid;
+
+	@Column(name="c_path", nullable=true, insertable=true, updatable=true)
+	private String path;
+	@Column(name="c_last", nullable=false, insertable=true, updatable=true)
+	private boolean last;
+	@Column(name="c_course_title", nullable=true, insertable=true, updatable=false)
+	private String courseTitle;
+	
+	@ManyToOne(targetEntity=IdentityImpl.class,fetch=FetchType.LAZY, optional=true)
+	@JoinColumn(name="fk_identity", nullable=false, insertable=true, updatable=false)
+	private Identity identity;
+	
+	@Override
+	public Long getKey() {
+		return key;
+	}
+	
+	public void setKey(Long key) {
+		this.key = key;
+	}
+
+	@Override
+	public Date getCreationDate() {
+		return creationDate;
+	}
+
+	public void setCreationDate(Date creationDate) {
+		this.creationDate = creationDate;
+	}
+
+	public Date getLastModified() {
+		return lastModified;
+	}
+
+	public void setLastModified(Date lastModified) {
+		this.lastModified = lastModified;
+	}
+	
+	public String getEmailStatusString() {
+		return emailStatusString;
+	}
+
+	public void setEmailStatusString(String emailStatusString) {
+		this.emailStatusString = emailStatusString;
+	}
+	
+	public EmailStatus getEmailStatus() {
+		return emailStatusString == null ? null : EmailStatus.valueOf(emailStatusString);
+	}
+	
+	public void setEmailStatus(EmailStatus emailStatus) {
+		if(emailStatus == null) {
+			emailStatusString = null;
+		} else {
+			emailStatusString = emailStatus.name();
+		}
+	}
+
+	public String getStatusString() {
+		return statusString;
+	}
+
+	public void setStatusString(String statusString) {
+		this.statusString = statusString;
+	}
+
+	@Override
+	public CertificateStatus getStatus() {
+		return CertificateStatus.valueOf(statusString);
+	}
+
+	public void setStatus(CertificateStatus status) {
+		this.statusString = status.name();
+	}
+	
+	@Override
+	public String getUuid() {
+		return uuid;
+	}
+
+	public void setUuid(String uuid) {
+		this.uuid = uuid;
+	}
+
+	@Override
+	public String getCourseTitle() {
+		return courseTitle;
+	}
+
+	public void setCourseTitle(String courseTitle) {
+		this.courseTitle = courseTitle;
+	}
+
+	public boolean isLast() {
+		return last;
+	}
+
+	public void setLast(boolean last) {
+		this.last = last;
+	}
+
+	@Override
+	public String getPath() {
+		return path;
+	}
+
+	public void setPath(String path) {
+		this.path = path;
+	}
+	
+	@Override
+	public Identity getIdentity() {
+		return identity;
+	}
+
+	public void setIdentity(Identity identity) {
+		this.identity = identity;
+	}
+
+	@Override
+	public int hashCode() {
+		return key == null ? -23984 : key.hashCode();
+	}
+	
+	@Override
+	public boolean equalsByPersistableKey(Persistable persistable) {
+		return equals(persistable);
+	}
+}
diff --git a/src/main/java/org/olat/course/certificate/model/CertificateImpl.java b/src/main/java/org/olat/course/certificate/model/CertificateImpl.java
index b6fa18668a8..312aef7dbcf 100644
--- a/src/main/java/org/olat/course/certificate/model/CertificateImpl.java
+++ b/src/main/java/org/olat/course/certificate/model/CertificateImpl.java
@@ -19,24 +19,13 @@
  */
 package org.olat.course.certificate.model;
 
-import java.util.Date;
-
 import javax.persistence.Column;
 import javax.persistence.Entity;
 import javax.persistence.FetchType;
-import javax.persistence.GeneratedValue;
-import javax.persistence.Id;
 import javax.persistence.JoinColumn;
 import javax.persistence.ManyToOne;
 import javax.persistence.Table;
-import javax.persistence.Temporal;
-import javax.persistence.TemporalType;
 
-import org.hibernate.annotations.GenericGenerator;
-import org.olat.basesecurity.IdentityImpl;
-import org.olat.core.id.Identity;
-import org.olat.core.id.Persistable;
-import org.olat.course.certificate.Certificate;
 import org.olat.resource.OLATResource;
 import org.olat.resource.OLATResourceImpl;
 
@@ -48,112 +37,18 @@ import org.olat.resource.OLATResourceImpl;
  */
 @Entity(name="certificate")
 @Table(name="o_cer_certificate")
-public class CertificateImpl implements Certificate, Persistable {
+public class CertificateImpl extends AbstractCertificate {
 
 	private static final long serialVersionUID = 2360631986446191873L;
 
-	@Id
-	@GeneratedValue(generator = "system-uuid")
-	@GenericGenerator(name = "system-uuid", strategy = "hilo")
-	@Column(name="id", nullable=false, unique=true, insertable=true, updatable=false)
-	private Long key;
-	
-	@Temporal(TemporalType.TIMESTAMP)
-	@Column(name="creationdate", nullable=false, insertable=true, updatable=false)
-	private Date creationDate;
-	@Temporal(TemporalType.TIMESTAMP)
-	@Column(name="lastmodified", nullable=false, insertable=true, updatable=true)
-	private Date lastModified;
-	
-	@Column(name="c_uuid", nullable=false, insertable=true, updatable=false)
-	private String uuid;
-
-	@Column(name="c_name", nullable=false, insertable=true, updatable=false)
-	private String name;
-	@Column(name="c_path", nullable=false, insertable=true, updatable=false)
-	private String path;
-	@Column(name="c_last", nullable=false, insertable=true, updatable=true)
-	private boolean last;
-	@Column(name="c_course_title", nullable=true, insertable=true, updatable=false)
-	private String courseTitle;
 	@Column(name="c_archived_resource_id", nullable=false, insertable=true, updatable=false)
 	private Long archivedResourceKey;
 	
 	@ManyToOne(targetEntity=OLATResourceImpl.class,fetch=FetchType.LAZY, optional=true)
 	@JoinColumn(name="fk_olatresource", nullable=false, insertable=true, updatable=true)
 	private OLATResource olatResource;
-	
-	@ManyToOne(targetEntity=IdentityImpl.class,fetch=FetchType.LAZY, optional=true)
-	@JoinColumn(name="fk_identity", nullable=false, insertable=true, updatable=false)
-	private Identity identity;
-
-	@Override
-	public Long getKey() {
-		return key;
-	}
-	
-	public void setKey(Long key) {
-		this.key = key;
-	}
-	
-	public Date getCreationDate() {
-		return creationDate;
-	}
-
-	public void setCreationDate(Date creationDate) {
-		this.creationDate = creationDate;
-	}
-
-	public Date getLastModified() {
-		return lastModified;
-	}
-
-	public void setLastModified(Date lastModified) {
-		this.lastModified = lastModified;
-	}
-	
-	public String getUuid() {
-		return uuid;
-	}
-
-	public void setUuid(String uuid) {
-		this.uuid = uuid;
-	}
 
 	@Override
-	public String getName() {
-		return name;
-	}
-
-	public void setName(String name) {
-		this.name = name;
-	}
-
-	@Override
-	public String getCourseTitle() {
-		return courseTitle;
-	}
-
-	public void setCourseTitle(String courseTitle) {
-		this.courseTitle = courseTitle;
-	}
-
-	public boolean isLast() {
-		return last;
-	}
-
-	public void setLast(boolean last) {
-		this.last = last;
-	}
-
-	public String getPath() {
-		return path;
-	}
-
-	public void setPath(String path) {
-		this.path = path;
-	}
-
 	public Long getArchivedResourceKey() {
 		return archivedResourceKey;
 	}
@@ -170,35 +65,15 @@ public class CertificateImpl implements Certificate, Persistable {
 		this.olatResource = olatResource;
 	}
 
-	public Identity getIdentity() {
-		return identity;
-	}
-
-	public void setIdentity(Identity identity) {
-		this.identity = identity;
-	}
-
-	@Override
-	public int hashCode() {
-		return key == null ? -23984 : key.hashCode();
-	}
-
 	@Override
 	public boolean equals(Object obj) {
 		if(this == obj) {
 			return true;
 		}
 		if(obj instanceof CertificateImpl) {
-			CertificateImpl prefs = (CertificateImpl)obj;
-			return key != null && key.equals(prefs.key);
+			CertificateImpl cert = (CertificateImpl)obj;
+			return getKey() != null && getKey().equals(cert.getKey());
 		}
 		return false;
 	}
-
-	@Override
-	public boolean equalsByPersistableKey(Persistable persistable) {
-		return equals(persistable);
-	}
-	
-
-}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/course/certificate/model/CertificateLightImpl.java b/src/main/java/org/olat/course/certificate/model/CertificateLightImpl.java
index 4b0038d2c0b..62bd7d85573 100644
--- a/src/main/java/org/olat/course/certificate/model/CertificateLightImpl.java
+++ b/src/main/java/org/olat/course/certificate/model/CertificateLightImpl.java
@@ -32,6 +32,7 @@ import javax.persistence.TemporalType;
 import org.hibernate.annotations.GenericGenerator;
 import org.olat.core.id.Persistable;
 import org.olat.course.certificate.CertificateLight;
+import org.olat.course.certificate.CertificateStatus;
 
 /**
  * 
@@ -54,11 +55,12 @@ public class CertificateLightImpl implements CertificateLight, Persistable {
 	@Temporal(TemporalType.TIMESTAMP)
 	@Column(name="creationdate", nullable=false, insertable=true, updatable=false)
 	private Date creationDate;
-
+	
+	@Column(name="c_status", nullable=false, insertable=true, updatable=true)
+	private String statusString;
+	
 	@Column(name="c_uuid", nullable=false, insertable=true, updatable=false)
 	private String uuid;
-	@Column(name="c_name", nullable=false, insertable=true, updatable=false)
-	private String name;
 	@Column(name="c_last", nullable=false, insertable=true, updatable=true)
 	private boolean last;
 	@Column(name="c_course_title", nullable=true, insertable=true, updatable=false)
@@ -86,23 +88,27 @@ public class CertificateLightImpl implements CertificateLight, Persistable {
 	public void setCreationDate(Date creationDate) {
 		this.creationDate = creationDate;
 	}
+	
+	public String getStatusString() {
+		return statusString;
+	}
 
-	@Override
-	public String getUuid() {
-		return uuid;
+	public void setStatusString(String statusString) {
+		this.statusString = statusString;
 	}
 
-	public void setUuid(String uuid) {
-		this.uuid = uuid;
+	@Override
+	public CertificateStatus getStatus() {
+		return CertificateStatus.valueOf(statusString);
 	}
 
 	@Override
-	public String getName() {
-		return name;
+	public String getUuid() {
+		return uuid;
 	}
 
-	public void setName(String name) {
-		this.name = name;
+	public void setUuid(String uuid) {
+		this.uuid = uuid;
 	}
 
 	@Override
diff --git a/src/main/java/org/olat/course/certificate/model/CertificateStandalone.java b/src/main/java/org/olat/course/certificate/model/CertificateStandalone.java
index 23c3b8d212b..2267fdd8c2d 100644
--- a/src/main/java/org/olat/course/certificate/model/CertificateStandalone.java
+++ b/src/main/java/org/olat/course/certificate/model/CertificateStandalone.java
@@ -19,24 +19,9 @@
  */
 package org.olat.course.certificate.model;
 
-import java.util.Date;
-
 import javax.persistence.Column;
 import javax.persistence.Entity;
-import javax.persistence.FetchType;
-import javax.persistence.GeneratedValue;
-import javax.persistence.Id;
-import javax.persistence.JoinColumn;
-import javax.persistence.ManyToOne;
 import javax.persistence.Table;
-import javax.persistence.Temporal;
-import javax.persistence.TemporalType;
-
-import org.hibernate.annotations.GenericGenerator;
-import org.olat.basesecurity.IdentityImpl;
-import org.olat.core.id.Identity;
-import org.olat.core.id.Persistable;
-import org.olat.course.certificate.Certificate;
 
 /**
  * 
@@ -46,108 +31,14 @@ import org.olat.course.certificate.Certificate;
  */
 @Entity(name="certificatestandalone")
 @Table(name="o_cer_certificate")
-public class CertificateStandalone implements Certificate, Persistable {
+public class CertificateStandalone extends AbstractCertificate {
 
 	private static final long serialVersionUID = 2360631986446191873L;
 
-	@Id
-	@GeneratedValue(generator = "system-uuid")
-	@GenericGenerator(name = "system-uuid", strategy = "hilo")
-	@Column(name="id", nullable=false, unique=true, insertable=true, updatable=false)
-	private Long key;
-	
-	@Temporal(TemporalType.TIMESTAMP)
-	@Column(name="creationdate", nullable=false, insertable=true, updatable=false)
-	private Date creationDate;
-	@Temporal(TemporalType.TIMESTAMP)
-	@Column(name="lastmodified", nullable=false, insertable=true, updatable=true)
-	private Date lastModified;
-	
-	@Column(name="c_uuid", nullable=false, insertable=true, updatable=false)
-	private String uuid;
-
-	@Column(name="c_name", nullable=false, insertable=true, updatable=false)
-	private String name;
-	@Column(name="c_path", nullable=false, insertable=true, updatable=false)
-	private String path;
-	@Column(name="c_last", nullable=false, insertable=true, updatable=true)
-	private boolean last;
-	@Column(name="c_course_title", nullable=true, insertable=true, updatable=false)
-	private String courseTitle;
 	@Column(name="c_archived_resource_id", nullable=false, insertable=true, updatable=false)
 	private Long archivedResourceKey;
-	
-	@ManyToOne(targetEntity=IdentityImpl.class,fetch=FetchType.LAZY, optional=true)
-	@JoinColumn(name="fk_identity", nullable=false, insertable=true, updatable=false)
-	private Identity identity;
 
 	@Override
-	public Long getKey() {
-		return key;
-	}
-	
-	public void setKey(Long key) {
-		this.key = key;
-	}
-	
-	public Date getCreationDate() {
-		return creationDate;
-	}
-
-	public void setCreationDate(Date creationDate) {
-		this.creationDate = creationDate;
-	}
-
-	public Date getLastModified() {
-		return lastModified;
-	}
-
-	public void setLastModified(Date lastModified) {
-		this.lastModified = lastModified;
-	}
-	
-	public String getUuid() {
-		return uuid;
-	}
-
-	public void setUuid(String uuid) {
-		this.uuid = uuid;
-	}
-
-	@Override
-	public String getName() {
-		return name;
-	}
-
-	public void setName(String name) {
-		this.name = name;
-	}
-
-	@Override
-	public String getCourseTitle() {
-		return courseTitle;
-	}
-
-	public void setCourseTitle(String courseTitle) {
-		this.courseTitle = courseTitle;
-	}
-
-	public boolean isLast() {
-		return last;
-	}
-
-	public void setLast(boolean last) {
-		this.last = last;
-	}
-
-	public String getPath() {
-		return path;
-	}
-
-	public void setPath(String path) {
-		this.path = path;
-	}
-
 	public Long getArchivedResourceKey() {
 		return archivedResourceKey;
 	}
@@ -156,35 +47,15 @@ public class CertificateStandalone implements Certificate, Persistable {
 		this.archivedResourceKey = archivedResourceKey;
 	}
 
-	public Identity getIdentity() {
-		return identity;
-	}
-
-	public void setIdentity(Identity identity) {
-		this.identity = identity;
-	}
-
-	@Override
-	public int hashCode() {
-		return key == null ? -23984 : key.hashCode();
-	}
-
 	@Override
 	public boolean equals(Object obj) {
 		if(this == obj) {
 			return true;
 		}
 		if(obj instanceof CertificateStandalone) {
-			CertificateStandalone prefs = (CertificateStandalone)obj;
-			return key != null && key.equals(prefs.key);
+			CertificateStandalone cert = (CertificateStandalone)obj;
+			return getKey() != null && getKey().equals(cert.getKey());
 		}
 		return false;
 	}
-
-	@Override
-	public boolean equalsByPersistableKey(Persistable persistable) {
-		return equals(persistable);
-	}
-	
-
 }
diff --git a/src/main/java/org/olat/course/certificate/model/JmsCertificateWork.java b/src/main/java/org/olat/course/certificate/model/JmsCertificateWork.java
new file mode 100644
index 00000000000..ab143554034
--- /dev/null
+++ b/src/main/java/org/olat/course/certificate/model/JmsCertificateWork.java
@@ -0,0 +1,98 @@
+/**
+ * <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.course.certificate.model;
+
+import java.io.Serializable;
+
+/**
+ * 
+ * Initial date: 19.11.2014<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class JmsCertificateWork implements Serializable {
+
+	private static final long serialVersionUID = 4462884019283948487L;
+	
+	private Float score;
+	private Boolean passed;
+	private Long templateKey;
+	private Long certificateKey;
+	
+	public JmsCertificateWork() {
+		//
+	}
+	
+	public JmsCertificateWork(Long certificateKey, Long templateKey, Float score, Boolean passed) {
+		this.score = score;
+		this.passed = passed;
+		this.templateKey = templateKey;
+		this.certificateKey = certificateKey;
+	}
+
+	public Float getScore() {
+		return score;
+	}
+
+	public void setScore(Float score) {
+		this.score = score;
+	}
+
+	public Boolean getPassed() {
+		return passed;
+	}
+
+	public void setPassed(Boolean passed) {
+		this.passed = passed;
+	}
+
+	public Long getTemplateKey() {
+		return templateKey;
+	}
+
+	public void setTemplateKey(Long templateKey) {
+		this.templateKey = templateKey;
+	}
+
+	public Long getCertificateKey() {
+		return certificateKey;
+	}
+
+	public void setCertificateKey(Long certificateKey) {
+		this.certificateKey = certificateKey;
+	}
+	
+	@Override
+	public int hashCode() {
+		return certificateKey == null ? 87580 : certificateKey.hashCode();
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if(this == obj) {
+			return true;
+		}
+		if(obj instanceof JmsCertificateWork) {
+			JmsCertificateWork work = (JmsCertificateWork)obj;
+			return certificateKey != null && certificateKey.equals(work.certificateKey);
+		}
+		return false;
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/course/certificate/ui/AssessedIdentityCertificatesController.java b/src/main/java/org/olat/course/certificate/ui/AssessedIdentityCertificatesController.java
index 3dcb9c612f6..15fc037d94a 100644
--- a/src/main/java/org/olat/course/certificate/ui/AssessedIdentityCertificatesController.java
+++ b/src/main/java/org/olat/course/certificate/ui/AssessedIdentityCertificatesController.java
@@ -35,10 +35,13 @@ import org.olat.core.gui.control.generic.modal.DialogBoxController;
 import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory;
 import org.olat.core.id.Identity;
 import org.olat.core.util.Formatter;
+import org.olat.core.util.coordinate.CoordinatorManager;
+import org.olat.core.util.event.GenericEventListener;
 import org.olat.core.util.mail.MailerResult;
 import org.olat.course.CourseFactory;
 import org.olat.course.ICourse;
 import org.olat.course.certificate.Certificate;
+import org.olat.course.certificate.CertificateEvent;
 import org.olat.course.certificate.CertificateTemplate;
 import org.olat.course.certificate.CertificatesManager;
 import org.olat.course.certificate.model.CertificateInfos;
@@ -56,7 +59,7 @@ import org.springframework.beans.factory.annotation.Autowired;
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  *
  */
-public class AssessedIdentityCertificatesController extends BasicController {
+public class AssessedIdentityCertificatesController extends BasicController implements GenericEventListener {
 	
 	private Link generateLink;
 	private final VelocityContainer mainVC;
@@ -88,8 +91,28 @@ public class AssessedIdentityCertificatesController extends BasicController {
 		}
 		loadList();
 		putInitialPanel(mainVC);
+		
+		CoordinatorManager.getInstance().getCoordinator().getEventBus()
+			.registerFor(this, getIdentity(), CertificatesManager.ORES_CERTIFICATE_EVENT);
 	}
 	
+	@Override
+	protected void doDispose() {
+		CoordinatorManager.getInstance().getCoordinator().getEventBus()
+			.deregisterFor(this, CertificatesManager.ORES_CERTIFICATE_EVENT);
+	}
+
+	@Override
+	public void event(Event event) {
+		if(event instanceof CertificateEvent) {
+			CertificateEvent ce = (CertificateEvent)event;
+			if(ce.getOwnerKey().equals(assessedUserCourseEnv.getIdentityEnvironment().getIdentity().getKey())
+					&& resource.getKey().equals(ce.getResourceKey())) {
+				loadList();
+			}
+		}
+	}
+
 	private void loadList() {
 		Identity assessedIdentity = assessedUserCourseEnv.getIdentityEnvironment().getIdentity();
 		List<Certificate> certificates = certificatesManager.getCertificates(assessedIdentity, resource);
@@ -98,7 +121,7 @@ public class AssessedIdentityCertificatesController extends BasicController {
 		for(Certificate certificate:certificates) {
 			String displayName = formatter.formatDateAndTime(certificate.getCreationDate());
 			String url = DownloadCertificateCellRenderer.getUrl(certificate);
-			Links links = new Links(url, displayName);
+			Links links = new Links(url, displayName, certificate.getStatus().name());
 			certificatesLink.add(links);
 			
 			if(canDelete) {
@@ -113,11 +136,6 @@ public class AssessedIdentityCertificatesController extends BasicController {
 		}
 		mainVC.contextPut("certificates", certificatesLink);
 	}
-	
-	@Override
-	protected void doDispose() {
-		//
-	}
 
 	@Override
 	protected void event(UserRequest ureq, Component source, Event event) {
@@ -195,23 +213,32 @@ public class AssessedIdentityCertificatesController extends BasicController {
 		MailerResult result = new MailerResult();
 		certificatesManager.generateCertificate(certificateInfos, courseEntry, template, result);
 		loadList();
+		showInfo("msg.certificate.pending");
 	}
 	
 	public static class Links {
 		private String url;
 		private String name;
+		private String status;
 		private Link delete;
 		
-		public Links(String url, String name) {
+		public Links(String url, String name, String status) {
 			this.url = url;
 			this.name = name;
+			this.status = status;
 		}
+		
 		public String getUrl() {
 			return url;
 		}
+		
 		public String getName() {
 			return name;
 		}
+		
+		public String getStatus() {
+			return status;
+		}
 
 		public String getDeleteName() {
 			return delete == null ? null : delete.getComponentName();
diff --git a/src/main/java/org/olat/course/certificate/ui/CertificateAndEfficiencyStatementListController.java b/src/main/java/org/olat/course/certificate/ui/CertificateAndEfficiencyStatementListController.java
index 322aeee5ba1..29bfee14aa7 100644
--- a/src/main/java/org/olat/course/certificate/ui/CertificateAndEfficiencyStatementListController.java
+++ b/src/main/java/org/olat/course/certificate/ui/CertificateAndEfficiencyStatementListController.java
@@ -53,6 +53,8 @@ import org.olat.core.gui.render.URLBuilder;
 import org.olat.core.gui.translator.Translator;
 import org.olat.core.id.Identity;
 import org.olat.core.util.Util;
+import org.olat.core.util.coordinate.CoordinatorManager;
+import org.olat.core.util.event.GenericEventListener;
 import org.olat.core.util.vfs.VFSContainer;
 import org.olat.course.CorruptedCourseException;
 import org.olat.course.assessment.EfficiencyStatement;
@@ -61,6 +63,7 @@ import org.olat.course.assessment.IdentityAssessmentEditController;
 import org.olat.course.assessment.bulk.PassedCellRenderer;
 import org.olat.course.assessment.model.UserEfficiencyStatementLight;
 import org.olat.course.assessment.portfolio.EfficiencyStatementArtefact;
+import org.olat.course.certificate.CertificateEvent;
 import org.olat.course.certificate.CertificateLight;
 import org.olat.course.certificate.CertificatesManager;
 import org.olat.course.certificate.ui.CertificateAndEfficiencyStatementListModel.CertificateAndEfficiencyStatement;
@@ -80,13 +83,13 @@ import org.springframework.beans.factory.annotation.Autowired;
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  *
  */
-public class CertificateAndEfficiencyStatementListController extends FormBasicController implements BreadcrumbPanelAware {
+public class CertificateAndEfficiencyStatementListController extends FormBasicController
+		implements BreadcrumbPanelAware, GenericEventListener {
 	
 	private static final String CMD_SHOW = "cmd.show";
 	private static final String CMD_LAUNCH_COURSE = "cmd.launch.course";
 	private static final String CMD_DELETE = "cmd.delete";
 	private static final String CMD_ARTEFACT = "cmd.artefact";
-	private static final String CMD_CERTIFICATE = "cmd.certificate";
 	
 	private FlexiTableElement tableEl;
 	private BreadcrumbPanel stackPanel;
@@ -118,6 +121,37 @@ public class CertificateAndEfficiencyStatementListController extends FormBasicCo
 		this.assessedIdentity = assessedIdentity;
 		
 		initForm(ureq);
+		
+		CoordinatorManager.getInstance().getCoordinator().getEventBus()
+			.registerFor(this, getIdentity(), CertificatesManager.ORES_CERTIFICATE_EVENT);
+	}
+	
+	@Override
+	protected void doDispose() {
+		CoordinatorManager.getInstance().getCoordinator().getEventBus()
+			.deregisterFor(this, CertificatesManager.ORES_CERTIFICATE_EVENT);
+	}
+
+	@Override
+	public void event(Event event) {
+		if(event instanceof CertificateEvent) {
+			CertificateEvent ce = (CertificateEvent)event;
+			if(getIdentity().getKey().equals(ce.getOwnerKey())) {
+				updateStatement(ce.getResourceKey(), ce.getCertificateKey());
+			}
+		}
+	}
+	
+	private void updateStatement(Long resourceKey, Long certificateKey) {
+		List<CertificateAndEfficiencyStatement> statements = tableModel.getObjects();
+		for(int i=statements.size(); i-->0; ) {
+			CertificateAndEfficiencyStatement statement = statements.get(i);
+			if(resourceKey.equals(statement.getResourceKey())) {
+				CertificateLight certificate = certificatesManager.getCertificateLightById(certificateKey);
+				statement.setCertificate(certificate);
+				break;
+			}
+		}
 	}
 
 	@Override
@@ -130,11 +164,12 @@ public class CertificateAndEfficiencyStatementListController extends FormBasicCo
 		FlexiTableColumnModel tableColumnModel = FlexiTableDataModelFactory.createFlexiTableColumnModel();
 		tableColumnModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.displayName.i18n(), Cols.displayName.ordinal()));
 		tableColumnModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.score.i18n(), Cols.score.ordinal()));
-		tableColumnModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.passed.i18n(), Cols.passed.ordinal(), new PassedCellRenderer()));
+		tableColumnModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.passed.i18n(), Cols.passed.ordinal(),
+				new PassedCellRenderer()));
 		tableColumnModel.addFlexiColumnModel(new StaticFlexiColumnModel("table.header.show",
 				translate("table.header.show"), CMD_SHOW));
-		tableColumnModel.addFlexiColumnModel(new StaticFlexiColumnModel(Cols.certificate.i18n(), Cols.certificate.ordinal(), CMD_CERTIFICATE,
-				true, Cols.certificate.name(), new StaticFlexiCellRenderer(CMD_CERTIFICATE, new DownloadCertificateCellRenderer(assessedIdentity))));
+		tableColumnModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.certificate.i18n(), Cols.certificate.ordinal(),
+				new DownloadCertificateCellRenderer(assessedIdentity)));
 		tableColumnModel.addFlexiColumnModel(new StaticFlexiColumnModel("table.header.launchcourse",
 				translate("table.header.launchcourse"), CMD_LAUNCH_COURSE));
 		tableColumnModel.addFlexiColumnModel(new StaticFlexiColumnModel("table.header.delete",
@@ -174,6 +209,7 @@ public class CertificateAndEfficiencyStatementListController extends FormBasicCo
 			CertificateAndEfficiencyStatement wrapper = resourceKeyToStatments.get(resourceKey);
 			if(wrapper == null) {
 				wrapper = new CertificateAndEfficiencyStatement();
+				wrapper.setDisplayName(certificate.getCourseTitle());
 				resourceKeyToStatments.put(resourceKey, wrapper);
 				statments.add(wrapper);
 			} else {
@@ -184,11 +220,6 @@ public class CertificateAndEfficiencyStatementListController extends FormBasicCo
 		
 		tableModel.setObjects(statments);
 	}
-	
-	@Override
-	protected void doDispose() {
-		//
-	}
 
 	@Override
 	protected void formOK(UserRequest ureq) {
diff --git a/src/main/java/org/olat/course/certificate/ui/DownloadCertificateCellRenderer.java b/src/main/java/org/olat/course/certificate/ui/DownloadCertificateCellRenderer.java
index af909497b51..0fe9f0beb59 100644
--- a/src/main/java/org/olat/course/certificate/ui/DownloadCertificateCellRenderer.java
+++ b/src/main/java/org/olat/course/certificate/ui/DownloadCertificateCellRenderer.java
@@ -35,6 +35,7 @@ import org.olat.core.util.Formatter;
 import org.olat.core.util.StringHelper;
 import org.olat.course.certificate.Certificate;
 import org.olat.course.certificate.CertificateLight;
+import org.olat.course.certificate.CertificateStatus;
 import org.olat.course.certificate.model.CertificateLightPack;
 import org.olat.user.UserManager;
 
@@ -59,10 +60,10 @@ public class DownloadCertificateCellRenderer implements CustomCellRenderer, Flex
 	@Override
 	public void render(StringOutput sb, Renderer renderer, Object val, Locale locale, int alignment, String action) {
 		if(val instanceof CertificateLight) {
-			generateUrl(sb, (CertificateLight)val, assessedIdentity, locale);
+			render(sb, (CertificateLight)val, assessedIdentity, locale);
 		} else if(val instanceof CertificateLightPack) {
 			CertificateLightPack pack = (CertificateLightPack)val;
-			generateUrl(sb, pack.getCertificate(), pack.getIdentity(), locale);		
+			render(sb, pack.getCertificate(), pack.getIdentity(), locale);		
 		}
 	}
 
@@ -70,18 +71,25 @@ public class DownloadCertificateCellRenderer implements CustomCellRenderer, Flex
 	public void render(Renderer renderer, StringOutput target, Object cellValue, int row, FlexiTableComponent source,
 			URLBuilder ubu, Translator translator) {
 		if(cellValue instanceof CertificateLight) {
-			generateUrl(target, (CertificateLight)cellValue, assessedIdentity, translator.getLocale());
+			render(target, (CertificateLight)cellValue, assessedIdentity, translator.getLocale());
 		} else if(cellValue instanceof CertificateLightPack) {
 			CertificateLightPack pack = (CertificateLightPack)cellValue;
-			generateUrl(target, pack.getCertificate(), pack.getIdentity(), translator.getLocale());	
+			render(target, pack.getCertificate(), pack.getIdentity(), translator.getLocale());	
 		}
 	}
 	
-	private void generateUrl(StringOutput sb, CertificateLight certificate, Identity identity, Locale locale) {
+	
+	private void render(StringOutput sb, CertificateLight certificate, Identity identity, Locale locale) {
 		String name = Formatter.getInstance(locale).formatDate(certificate.getCreationDate());
-		sb.append("<a href='").append(getUrl(certificate, identity))
-		  .append("' target='_blank'><i class='o_icon o_filetype_pdf'> </i> ")
-		  .append(name).append(".pdf").append("</a>");
+		if(CertificateStatus.pending.equals(certificate.getStatus())) {
+			sb.append("<span><i class='o_icon o_icon_pending o_icon-spin'> </i>").append(name).append(".pdf").append("</span>");
+		} else if(CertificateStatus.error.equals(certificate.getStatus())) {
+			sb.append("<span><i class='o_icon o_icon_error'> </i>").append(name).append(".pdf").append("</span>");
+		} else {
+			sb.append("<a href='").append(getUrl(certificate, identity))
+			  .append("' target='_blank'><i class='o_icon o_filetype_pdf'> </i> ")
+			  .append(name).append(".pdf").append("</a>");
+		}
 	}
 	
 	public static String getName(Certificate certificate) {
diff --git a/src/main/java/org/olat/course/certificate/ui/_content/certificate_overview.html b/src/main/java/org/olat/course/certificate/ui/_content/certificate_overview.html
index 3f5f16fe139..28a85c6a2e0 100644
--- a/src/main/java/org/olat/course/certificate/ui/_content/certificate_overview.html
+++ b/src/main/java/org/olat/course/certificate/ui/_content/certificate_overview.html
@@ -7,7 +7,15 @@
 			#else
 				<ul class="list-unstyled o_certificates">
 				#foreach($certificate in $certificates)
-					<li><a href="$certificate.url" target="_blank"><i class="o_icon o_filetype_pdf"> </i> $certificate.name</a> 
+					<li>
+					#if($certificate.status == "pending")
+						<span><i class="o_icon o_icon_pending o_icon-spin"> </i> $certificate.name</span>
+					#elseif($certificate.status == "ok")
+						<a href="$certificate.url" target="_blank"><i class="o_icon o_filetype_pdf"> </i> $certificate.name</a>
+					#elseif($certificate.status == "error")
+						<span><i class="o_icon o_icon_error"> </i> $certificate.name</span>
+					#end
+
 					#if($r.available($certificate.getDeleteName())) 
 						$r.render($certificate.getDeleteName())
 					#end
diff --git a/src/main/java/org/olat/course/certificate/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/certificate/ui/_i18n/LocalStrings_de.properties
index 079f71a16f0..999f3ef428a 100644
--- a/src/main/java/org/olat/course/certificate/ui/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/course/certificate/ui/_i18n/LocalStrings_de.properties
@@ -56,4 +56,5 @@ confirm.delete.certificate.text=Wollen Sie wirklich den Zertifikat l
 confirm.certificate.deleted=Der Zertifikate von {0} wurde gelöscht.
 certificates.wizard.title=Zertifikaten erstellen
 certificates.wizard.select=Benutzer auswählen
-certificates.wizard.overview=Ubersicht
\ No newline at end of file
+certificates.wizard.overview=Ubersicht
+msg.certificate.pending=Der Zertifikat wird in ein paar Sekunden erstellt.
\ No newline at end of file
diff --git a/src/main/resources/database/mysql/alter_10_0_0_to_10_1_0.sql b/src/main/resources/database/mysql/alter_10_0_0_to_10_1_0.sql
index d2fa87af94a..8c71525607c 100644
--- a/src/main/resources/database/mysql/alter_10_0_0_to_10_1_0.sql
+++ b/src/main/resources/database/mysql/alter_10_0_0_to_10_1_0.sql
@@ -15,9 +15,10 @@ create table o_cer_certificate (
    id bigint not null,
    creationdate datetime not null,
    lastmodified datetime not null,
+   c_status varchar(16) not null default 'pending',
+   c_email_status varchar(16),
    c_uuid varchar(36) not null,
-   c_name varchar(256) not null,
-   c_path varchar(1024) not null,
+   c_path varchar(1024),
    c_last boolean not null default 1,
    c_course_title varchar(255),
    c_archived_resource_id bigint not null,
diff --git a/src/main/resources/database/mysql/setupDatabase.sql b/src/main/resources/database/mysql/setupDatabase.sql
index 0708fb192a6..22d7a92a2b9 100644
--- a/src/main/resources/database/mysql/setupDatabase.sql
+++ b/src/main/resources/database/mysql/setupDatabase.sql
@@ -1076,9 +1076,10 @@ create table o_cer_certificate (
    id bigint not null,
    creationdate datetime not null,
    lastmodified datetime not null,
+   c_status varchar(16) not null default 'pending',
+   c_email_status varchar(16),
    c_uuid varchar(36) not null,
-   c_name varchar(256) not null,
-   c_path varchar(1024) not null,
+   c_path varchar(1024),
    c_last boolean not null default 1,
    c_course_title varchar(255),
    c_archived_resource_id bigint not null,
diff --git a/src/main/resources/database/oracle/alter_10_0_0_to_10_1_0.sql b/src/main/resources/database/oracle/alter_10_0_0_to_10_1_0.sql
index f5fb9ded1f5..26b280af8c6 100644
--- a/src/main/resources/database/oracle/alter_10_0_0_to_10_1_0.sql
+++ b/src/main/resources/database/oracle/alter_10_0_0_to_10_1_0.sql
@@ -14,9 +14,10 @@ create table o_cer_certificate (
    id number(20) not null,
    creationdate date not null,
    lastmodified date not null,
+   c_status varchar2(16 char) default 'pending' not null,
+   c_email_status varchar2(16 char),
    c_uuid varchar2(36 char) not null,
-   c_name varchar2(256 char) not null,
-   c_path varchar2(1024 char) not null,
+   c_path varchar2(1024 char),
    c_last number default 1 not null,
    c_course_title varchar2(255 char),
    c_archived_resource_id number(20) not null,
diff --git a/src/main/resources/database/oracle/setupDatabase.sql b/src/main/resources/database/oracle/setupDatabase.sql
index ed3cbe29bb5..3996f9b2e23 100644
--- a/src/main/resources/database/oracle/setupDatabase.sql
+++ b/src/main/resources/database/oracle/setupDatabase.sql
@@ -1110,11 +1110,12 @@ create table o_cer_certificate (
    id number(20) not null,
    creationdate date not null,
    lastmodified date not null,
+   c_status varchar2(16 char) default 'pending' not null,
+   c_email_status varchar2(16 char),
    c_uuid varchar2(36 char) not null,
-   c_name varchar2(256 char) not null,
-   c_path varchar2(1024 char) not null,
+   c_path varchar2(1024 char),
    c_last number default 1 not null,
-   c_course_title varchar(255),
+   c_course_title varchar2(255 char),
    c_archived_resource_id number(20) not null,
    fk_olatresource number(20),
    fk_identity number(20) not null,
diff --git a/src/main/resources/database/postgresql/alter_10_0_0_to_10_1_0.sql b/src/main/resources/database/postgresql/alter_10_0_0_to_10_1_0.sql
index 907efe8bf3b..e19b149045a 100644
--- a/src/main/resources/database/postgresql/alter_10_0_0_to_10_1_0.sql
+++ b/src/main/resources/database/postgresql/alter_10_0_0_to_10_1_0.sql
@@ -14,9 +14,10 @@ create table o_cer_certificate (
    id int8 not null,
    creationdate timestamp not null,
    lastmodified timestamp not null,
+   c_status varchar(16) not null default 'pending',
+   c_email_status varchar(16),
    c_uuid varchar(36) not null,
-   c_name varchar(256) not null,
-   c_path varchar(1024) not null,
+   c_path varchar(1024),
    c_last bool not null default true,
    c_course_title varchar(255),
    c_archived_resource_id int8 not null,
diff --git a/src/main/resources/database/postgresql/setupDatabase.sql b/src/main/resources/database/postgresql/setupDatabase.sql
index e9dfccbc13e..e678c844926 100644
--- a/src/main/resources/database/postgresql/setupDatabase.sql
+++ b/src/main/resources/database/postgresql/setupDatabase.sql
@@ -1077,9 +1077,10 @@ create table o_cer_certificate (
    id int8 not null,
    creationdate timestamp not null,
    lastmodified timestamp not null,
+   c_status varchar(16) not null default 'pending',
+   c_email_status varchar(16),
    c_uuid varchar(36) not null,
-   c_name varchar(256) not null,
-   c_path varchar(1024) not null,
+   c_path varchar(1024),
    c_last bool not null default true,
    c_course_title varchar(255),
    c_archived_resource_id int8 not null,
diff --git a/src/main/resources/serviceconfig/olat.properties b/src/main/resources/serviceconfig/olat.properties
index e78a0e233c5..bf830d37744 100644
--- a/src/main/resources/serviceconfig/olat.properties
+++ b/src/main/resources/serviceconfig/olat.properties
@@ -745,6 +745,7 @@ cluster.singleton.services = enabled
 jms.broker.url=vm://embedded?broker.persistent=false
 search.broker.url=vm://embedded?broker.persistent=false
 index.broker.url=vm://embedded?broker.persistent=false
+certificate.broker.url=vm://embedded?broker.persistent=false
 # Cluster (remote) jms.broker.url
 #jms.broker.url=failover:(tcp://localhost:61616?wireFormat.maxInactivityDuration=0)
 #search.broker.url=failover:(tcp://localhost:61616?wireFormat.maxInactivityDuration=0)
@@ -755,6 +756,7 @@ sysbus.broker.jndi=topic/sysbus
 search.broker.jndi=queue/searchQueue
 index.broker.jndi=queue/indexQueue
 exam.broker.jndi=queue/examQueue
+certificate.broker.jndi=queue/certificateQueue
 
 #####
 #query cache config for singlevm/cluster
diff --git a/src/main/webapp/static/themes/light/modules/_icons.scss b/src/main/webapp/static/themes/light/modules/_icons.scss
index 45503931a8f..9258c7237c2 100644
--- a/src/main/webapp/static/themes/light/modules/_icons.scss
+++ b/src/main/webapp/static/themes/light/modules/_icons.scss
@@ -148,6 +148,7 @@ $fa-css-prefix: "o_icon" !default;
 .o_icon_pageing:before { content: $fa-var-ellipsis-h;}
 .o_icon_passed:before { content: $fa-var-check-circle;}
 .o_icon_password:before { content: $fa-var-lock;}
+.o_icon_pending:before { content: $fa-var-spinner; }
 .o_icon_phone:before { content: $fa-var-phone;}
 .o_icon_post:before { content: $fa-var-comment-o; }
 .o_icon_preview:before { content: $fa-var-eye;}
diff --git a/src/main/webapp/static/themes/light/theme.css b/src/main/webapp/static/themes/light/theme.css
index 335a97624e6..cd5c98c7309 100644
--- a/src/main/webapp/static/themes/light/theme.css
+++ b/src/main/webapp/static/themes/light/theme.css
@@ -58,7 +58,7 @@ fieldset{padding:0;margin:0;border:0;min-width:0}legend{display:block;width:100%
 @media (max-width: 767px){.hidden-xs{display:none !important}}@media (min-width: 768px) and (max-width: 991px){.hidden-sm{display:none !important}}@media (min-width: 992px) and (max-width: 1199px){.hidden-md{display:none !important}}@media (min-width: 1200px){.hidden-lg{display:none !important}}.visible-print{display:none !important}@media print{.visible-print{display:block !important}table.visible-print{display:table}tr.visible-print{display:table-row !important}th.visible-print,td.visible-print{display:table-cell !important}}.visible-print-block{display:none !important}@media print{.visible-print-block{display:block !important}}
 .visible-print-inline{display:none !important}@media print{.visible-print-inline{display:inline !important}}
 .visible-print-inline-block{display:none !important}@media print{.visible-print-inline-block{display:inline-block !important}}
-@media print{.hidden-print{display:none !important}}body .modal{position:absolute;overflow:visible}body div.tooltip-inner{max-width:400px}body div.popover{max-width:450px}body .modal-body.alert{border-radius:0}body .progress{margin-bottom:0}.panel-body:nth-child(n+2){border-top:1px solid #ddd}.form-control-feedback{top:10px}.form-horizontal .has-feedback .form-control-feedback{top:10px}.btn.btn-primary.o_disabled{color:#fff !important}body .progress-bar[aria-valuenow="1"],body .progress-bar[aria-valuenow="2"]{min-width:1px}@font-face{font-family:'FontAwesome';src:url("../../font-awesome/fonts/fontawesome-webfont.eot?v=4.2.0");src:url("../../font-awesome/fonts/fontawesome-webfont.eot?#iefix&v=4.2.0") format("embedded-opentype"),url("../../font-awesome/fonts/fontawesome-webfont.woff?v=4.2.0") format("woff"),url("../../font-awesome/fonts/fontawesome-webfont.ttf?v=4.2.0") format("truetype"),url("../../font-awesome/fonts/fontawesome-webfont.svg?v=4.2.0#fontawesomeregular") format("svg");font-weight:normal;font-style:normal}.o_icon{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.o_icon-lg{font-size:1.33333em;line-height:0.75em;vertical-align:-15%}.o_icon-2x{font-size:2em}.o_icon-3x{font-size:3em}.o_icon-4x{font-size:4em}.o_icon-5x{font-size:5em}.o_icon-fw{width:1.28571em;text-align:center}.o_icon-ul{padding-left:0;margin-left:2.14286em;list-style-type:none}.o_icon-ul>li{position:relative}.o_icon-li{position:absolute;left:-2.14286em;width:2.14286em;top:0.14286em;text-align:center}.o_icon-li.o_icon-lg{left:-1.85714em}.o_icon-border{padding:.2em .25em .15em;border:solid 0.08em #eee;border-radius:.1em}.pull-right{float:right}.pull-left{float:left}.o_icon.pull-left{margin-right:.3em}.o_icon.pull-right{margin-left:.3em}.o_icon-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.o_icon-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.o_icon-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.o_icon-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.o_icon-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0);-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.o_icon-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .o_icon-rotate-90,:root .o_icon-rotate-180,:root .o_icon-rotate-270,:root .o_icon-flip-horizontal,:root .o_icon-flip-vertical{filter:none}.o_icon-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.o_icon-stack-1x,.o_icon-stack-2x{position:absolute;left:0;width:100%;text-align:center}.o_icon-stack-1x{line-height:inherit}.o_icon-stack-2x{font-size:2em}.o_icon-inverse{color:#fff}.o_icon_accessibility:before{content:"\f193"}.o_icon_actions:before{content:"\f085"}.o_icon_archive_tool:before{content:"\f019"}.o_icon_assessment_tool:before{content:"\f091"}.o_icon_attempt_limit:before{content:"\f021"}.o_icon_accept:before{content:"\f00c";color:#5cb85c}.o_icon_add:before{content:"\f055"}.o_icon_add_search:before{content:"\f00e"}.o_icon_audio:before{content:"\f028"}.o_icon_back:before{content:"\f053"}.o_icon_back_history:before{content:"\f1da"}.o_icon_bold:before{content:"\f032"}.o_icon_booking:before{content:"\f07a"}.o_icon_bookmark:before{content:"\f02e";color:#bc2d0c}.o_icon_bookmark_add:before{content:"\f097"}.o_icon_bookmark_header:before{content:"\f02e"}.o_icon_browse:before{content:"\f00e"}.o_icon_browsercheck:before{content:"\f164"}.o_icon_busy:before{content:"\f110"}.o_icon_calendar:before{content:"\f073"}.o_icon_calendar_enabled:before{content:"\f05d"}.o_icon_calendar_disabled:before{content:"\f10c"}.o_icon_calendar:before{content:"\f073"}.o_icon_caret:before{content:"\f0d7"}.o_icon_caret_right:before{content:"\f0da"}.o_icon_catalog:before{content:"\f0e8"}.o_icon_catalog_sub:before{content:"\f07b"}.o_icon_certificate:before{content:"\f0a3"}.o_icon_chat:before{content:"\f0e5"}.o_icon_check:before{content:"\f00c"}.o_icon_check_off:before{content:"\f096"}.o_icon_check_on:before{content:"\f046"}.o_icon_checkbox:before{content:"\f096"}.o_icon_checkbox_checked:before{content:"\f14a"}.o_icon_cleanup:before{content:"\f0f9"}.o_icon_close:before{content:"\f00d"}.o_icon_close_resource:before{content:"\f011"}.o_icon_close_tab:before{content:"\f00d"}.o_icon_close_tool:before{content:"\f00d"}.o_icon_close_tree:before{content:"\f0d7"}.o_icon_close_togglebox:before,.o_togglebox_wrapper .o_opener.o_in i:before{content:"\f0d7"}.o_icon_code:before{content:"\f121"}.o_icon_color_picker:before{content:"\f043"}.o_icon_copy:before{content:"\f0c5"}.o_icon_courseareas:before{content:"\f1db"}.o_icon_coursedb:before{content:"\f1c0"}.o_icon_courseeditor:before{content:"\f044"}.o_icon_coursefolder:before{content:"\f114"}.o_icon_courserun:before{content:"\f1b2"}.o_icon_comments:before{content:"\f086"}.o_icon_comments_none:before{content:"\f0e5"}.o_icon_content_popup:before{content:"\f08e"}.o_icon_correct_answer:before{content:"\f00c";color:#5cb85c}.o_icon_customize:before{content:"\f013"}.o_icon_delete_item:before{content:"\f1f8"}.o_icon_delete:before{content:"\f056";color:#A87E7E}.o_icon_details:before{content:"\f0eb"}.o_icon_dev:before{content:"\f188"}.o_icon_disabled:before{content:"\f10c"}.o_icon_download:before{content:"\f019"}.o_icon_edit:before{content:"\f044"}.o_icon_edit_file:before{content:"\f044"}.o_icon_edit_metadata:before{content:"\f013"}.o_icon_enabled:before{content:"\f111"}.o_icon_enlarge:before{content:"\f00e"}.o_icon_eportfolio_add:before{content:"\f12e"}.o_icon_eportfolio_link:before{content:"\f12e"}.o_icon_error:before{content:"\f06a";color:#d9534f}.o_icon_expenditure:before{content:"\f017"}.o_icon_export:before{content:"\f045"}.o_icon_external_link:before{content:"\f08e"}.o_icon_failed:before{content:"\f057"}.o_icon_filter:before{content:"\f0b0"}.o_icon_group:before,.o_BusinessGroup_icon:before{content:"\f0c0"}.o_icon_header:before{content:"\f1dc"}.o_icon_help:before{content:"\f059";cursor:help}.o_icon_home:before{content:"\f015"}.o_icon_impress:before{content:"\f05a"}.o_icon_important:before{content:"\f071";color:#f0ad4e}.o_icon_import:before{content:"\f093"}.o_icon_info:before{content:"\f05a";color:#5bc0de}.o_icon_info_msg:before{content:"\f06a";color:#d9534f}.o_icon_inline_editable:before{content:"\f044"}.o_icon_institution:before{content:"\f19c"}.o_icon_italic:before{content:"\f033"}.o_icon_landingpage:before{content:"\f140"}.o_icon_language:before{content:"\f0ac"}.o_icon_layout:before{content:"\f1c5"}.o_icon_link:before{content:"\f0c1"}.o_icon_link_extern:before{content:"\f08e"}.o_icon_list:before{content:"\f03a"}.o_icon_list_num :before{content:"\f0cb"}.o_icon_lifecycle:before{content:"\f073"}.o_icon_locked:before{content:"\f023"}.o_icon_login:before{content:"\f090"}.o_icon_logout:before{content:"\f08b"}.o_icon_mandatory:before{content:"\f069";color:#f0ad4e}.o_icon_managed:before{content:"\f079";color:#777}.o_icon_mail:before{content:"\f003"}.o_icon_math:before{content:"\f198"}.o_icon_membersmanagement:before{content:"\f0c0"}.o_icon_menuhandel:before{content:"\f0c9"}.o_icon_message:before{content:"\f0e0"}.o_icon_move:before{content:"\f047"}.o_icon_move_down:before{content:"\f103"}.o_icon_move_left:before{content:"\f100"}.o_icon_move_right:before{content:"\f101"}.o_icon_move_up:before{content:"\f102"}.o_icon_new:before{content:"\f069";color:#5cb85c}.o_icon_new_document:before{content:"\f15c"}.o_icon_new_folder:before{content:"\f07b"}.o_icon_news:before{content:"\f05a"}.o_icon_next:before{content:"\f138"}.o_icon_next_page:before{content:"\f101"}.o_icon_next_toolbar:before{content:"\f0da"}.o_icon_node_after:before{content:"\f175"}.o_icon_node_before:before{content:"\f176"}.o_icon_node_under:before{content:"\f112"}.o_icon_notes:before{content:"\f1e8"}.o_icon_notification:before{content:"\f09e"}.o_icon_open_tree:before{content:"\f0da"}.o_icon_open_togglebox:before,.o_togglebox_wrapper .o_opener i:before{content:"\f0da"}.o_icon_openolat:before,.o_icon_provider_olat:before{content:"\221E";font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-weight:bold}.o_icon_options:before{content:"\f205"}.o_icon_pageing:before{content:"\f141"}.o_icon_passed:before{content:"\f058"}.o_icon_password:before{content:"\f023"}.o_icon_phone:before{content:"\f095"}.o_icon_post:before{content:"\f0e5"}.o_icon_preview:before{content:"\f06e"}.o_icon_previous:before{content:"\f137"}.o_icon_previous_page:before{content:"\f100"}.o_icon_previous_toolbar:before{content:"\f0d9"}.o_icon_print:before{content:"\f02f"}.o_icon_private:before{content:"\f02f"}.o_icon_provider_adfs:before{content:"\f17a"}.o_icon_provider_facebook:before{content:"\f09a"}.o_icon_provider_google:before{content:"\f0d5"}.o_icon_provider_guest:before{content:"\f1ae"}.o_icon_provider_ldap:before{content:"\f19c"}.o_icon_provider_linkedin:before{content:"\f0e1"}.o_icon_provider_oauth:before{content:"\f0c2"}.o_icon_provider_shibboleth:before{content:"\f19c"}.o_icon_provider_twitter:before{content:"\f099"}.o_icon_publish:before{content:"\f064"}.o_icon_qrcode:before{content:"\f029"}.o_icon_quickview:before{content:"\f06e"}.o_icon_radio_off:before{content:"\f10c"}.o_icon_radio_on:before{content:"\f05d"}.o_icon_rating_on:before,.o_rating .o_rating_items.o_enabled .o_icon:hover:before{content:"\f005"}.o_icon_rating_off:before{content:"\f006"}.o_icon_read:before{content:"\f10c"}.o_icon_readonly:before{content:"\f044";color:red}.o_icon_readwrite:before{content:"\f044"}.o_icon_recycle:before{content:"\f1b8"}.o_icon_refresh:before{content:"\f021"}.o_icon_reject:before{content:"\f00d";color:#d9534f}.o_icon_remove:before{content:"\f00d"}.o_icon_reply:before{content:"\f112"}.o_icon_reply_with_quote:before{content:"\f122"}.o_icon_response_feedback:before{content:"\f021"}.o_icon_review:before{content:"\f06e"}.o_icon_rss:before{content:"\f09e"}.o_icon_rss_unsubscribe:before{content:"\f09e";color:#996633}.o_icon_search:before{content:"\f002"}.o_icon_settings:before{content:"\f085"}.o_icon_share:before{content:"\f064"}.o_icon_show_more:before{content:"\f150"}.o_icon_show_less:before{content:"\f151"}.o_icon_spacer:before{content:"\f07e"}.o_icon_split:before{content:"\f127"}.o_icon_sort:before{content:"\f0dc"}.o_icon_sort_asc:before{content:"\f0de"}.o_icon_sort_desc:before{content:"\f0dd"}.o_icon_sort_menu:before{content:"\f160"}.o_icon_start:before{content:"\f054"}.o_icon_status_available:before{content:"\f111";color:#063}.o_icon_status_chat:before{content:"\f075"}.o_icon_status_dnd:before{content:"\f192";color:#cc3}.o_icon_status_unavailable:before{content:"\f05c";color:#963}.o_icon_statistics_tool:before{content:"\f080"}.o_icon_table:before{content:"\f0ce"}.o_icon_table_large:before{content:"\f009"}.o_icon_tags:before{content:"\f02c"}.o_icon_timelimit:before{content:"\f1e2"}.o_icon_toggle:before{content:"\f111"}.o_icon_to_read:before{content:"\f111"}.o_icon_tool:before{content:"\f013"}.o_icon_tools:before{content:"\f0ad"}.o_icon_top:before{content:"\f077"}.o_icon_translation_item:before{content:"\f1c9"}.o_icon_translation_package:before{content:"\f115"}.o_icon_user:before{content:"\f007"}.o_icon_user_vip:before{content:"\f19d"}.o_icon_user_anonymous:before{content:"\f128"}.o_icon_upload:before{content:"\f093"}.o_icon_version:before{content:"\f1da"}.o_icon_video:before{content:"\f008"}.o_icon_warn:before{content:"\f071";color:#f0ad4e}.o_icon_wizard:before{content:"\f0d0"}.o_CourseModule_icon:before,.o_course_icon:before{content:"\f1b2"}.o_EPStructuredMapTemplate_icon:before{content:"\f12e"}.o_FileResource-BLOG_icon:before{content:"\f0a1"}.o_FileResource-IMSCP_icon:before{content:"\f187"}.o_FileResource-PODCAST_icon:before{content:"\f03d"}.o_FileResource-SHAREDFOLDER:before{content:"\f08e"}.o_FileResource-SCORMCP_icon:before{content:"\f187"}.o_FileResource-SURVEY_icon:before{content:"\f11a"}.o_FileResource-TEST_icon:before{content:"\f044"}.o_FileResource-WIKI_icon:before{content:"\f0ac"}.o_FileResource-SHAREDFOLDER_icon:before{content:"\f115"}.o_FileResource-GLOSSARY_icon:before{content:"\f19d"}.o_FileResource-PDF_icon:before{content:"\f1c1"}.o_FileResource-XLS_icon:before{content:"\f1c3"}.o_FileResource-PPT_icon:before{content:"\f1c4"}.o_FileResource-DOC_icon:before{content:"\f1c2"}.o_FileResource-ANIM_icon:before{content:"\f1c8"}.o_FileResource-IMAGE_icon:before{content:"\f1c5"}.o_FileResource-SOUND_icon:before{content:"\f1c7"}.o_FileResource-MOVIE_icon:before{content:"\f1c8"}.o_FileResource-FILE_icon:before{content:"\f016"}.o_CourseModule_icon_closed:before{content:"\f05e"}.o_sp_icon:before{content:"\f0f6"}.o_st_icon:before{content:"\f1b3"}.o_tu_icon:before{content:"\f08e"}.o_bc_icon:before{content:"\f115"}.o_lti_icon:before{content:"\f08e"}.o_cp_icon:before{content:"\f187"}.o_cp_item:before{content:"\f0f6"}.o_scorm_icon:before{content:"\f187"}.o_en_icon:before{content:"\f090"}.o_fo_icon:before{content:"\f0e6"}.o_co_icon:before{content:"\f003"}.o_infomsg_icon:before{content:"\f05a"}.o_cal_icon:before{content:"\f073"}.o_wiki_icon:before{content:"\f0ac"}.o_podcast_icon:before{content:"\f03d"}.o_blog_icon:before{content:"\f0a1"}.o_ep_icon:before{content:"\f12e"}.o_iqtest_icon:before{content:"\f044"}.o_iqself_icon:before{content:"\f044"}.o_iqsurv_icon:before{content:"\f11a"}.o_ta_icon:before{content:"\f0ae"}.o_ms_icon:before{content:"\f087"}.o_dialog_icon:before{content:"\f0c5"}.o_projectbroker_icon:before{content:"\f10c"}.o_ll_icon:before{content:"\f0c1"}.o_den_icon:before{content:"\f133"}.o_cmembers_icon:before{content:"\f0c0"}.o_cl_icon:before{content:"\f046"}.o_vc_icon:before{content:"\f108"}.o_vitero_icon:before{content:"\f108"}.o_openmeetings_icon:before{content:"\f108"}.o_portlet_infomsg_icon:before{content:"\f05a"}.o_portlet_quickstart_icon:before{content:"\f1d9"}.o_portlet_bookmark_icon:before{content:"\f02e"}.o_portlet_groups_icon:before{content:"\f0c0"}.o_portlet_notes_icon:before{content:"\f1e8"}.o_portlet_noti_icon:before{content:"\f09e"}.o_portlet_eff_icon:before{content:"\f0a3"}.o_portlet_repository_student_icon:before{content:"\f1b3"}.o_portlet_repository_teacher_icon:before{content:"\f19d"}.o_portlet_iframe_icon:before{content:"\f005"}.o_portlet_sysinfo_icon:before{content:"\f0e4"}.o_portlet_dyk_icon:before{content:"\f0eb"}.o_portlet_infomessages_icon:before{content:"\f0e5"}.o_portlet_cal_icon:before{content:"\f073"}.o_portlet_institutions_icon:before{content:"\f19c"}.o_portlet_links_icon:before{content:"\f0c1"}.o_portlet_shibboleth_icon:before{content:"\f090"}.o_icon_qpool:before{content:"\f19c"}.o_icon_pool_private:before{content:"\f096"}.o_icon_pool_public:before{content:"\f046"}.o_icon_pool_my_items:before{content:"\f007"}.o_icon_pool_favorits:before{content:"\f02e"}.o_icon_pool_collection:before{content:"\f03a"}.o_icon_pool_pool:before{content:"\f1e1"}.o_icon_pool_share:before{content:"\f0c0"}.o_forum_message_icon:before{content:"\f0e5"}.o_calendar_icon:before{content:"\f073"}.o_forum_status_thread_icon:before{content:"\f0e6"}.o_forum_status_sticky_closed_icon:before{content:"\f05e"}.o_forum_status_sticky_icon:before{content:"\f086"}.o_forum_status_closed_icon:before{content:"\f05e";color:#a94442}.o_forum_status_opened_icon:before{content:"\f05e";color:#3c763d}.o_forum_status_hidden_icon:before{content:"\f070";color:#a94442}.o_forum_status_visible_icon:before{content:"\f06e";color:#3c763d}.o_mi_qpool_import:before{content:"\f1c0"}.o_mi_qtisection:before{content:"\f1b3"}.o_mi_qtisc:before{content:"\f192"}.o_mi_qtimc:before{content:"\f046"}.o_mi_qtikprim:before{content:"\f14a"}.o_mi_qtifib:before{content:"\f141"}.o_mi_qtiessay:before{content:"\f036"}.o_black_led:before{content:"\f111";color:#428bca}.o_green_led:before{content:"\f111";color:#5cb85c}.o_yellow_led:before{content:"\f111";color:#f0ad4e}.o_red_led:before{content:"\f111";color:#d9534f}.o_ac_token_icon:before{content:"\f084"}.o_ac_free_icon:before{content:"\f06b"}.o_ac_group_icon:before{content:"\f0c0"}.o_ac_membersonly_icon:before{content:"\f023"}.o_ac_paypal_icon:before{content:"\f1f4"}.o_ac_status_canceled_icon:before{content:"\f068";color:#f0ad4e}.o_ac_status_error_icon:before{content:"\f00d";color:#d9534f}.o_ac_status_new_icon:before{content:"\f069";color:#428bca}.o_ac_status_succes_icon:before{content:"\f00c";color:#5cb85c}.o_ac_status_waiting_icon:before{content:"\f017";color:#428bca}.o_ac_order_status_new_icon:before{content:"\f069";color:#428bca}.o_ac_order_status_prepayment_icon:before{content:"\f0d6";color:#5bc0de}.o_ac_order_status_payed_icon:before{content:"\f00c";color:#5cb85c}.o_ac_order_status_canceled_icon:before{content:"\f068";color:#f0ad4e}.o_ac_order_status_error_icon:before{content:"\f00d";color:#d9534f}.o_ac_order_status_warning_icon:before{content:"\f12a";color:#f0ad4e}.o_scorm_org:before{content:"\f187"}.o_scorm_item:before{content:"\f016"}.o_scorm_completed:before,.o_scorm_passed:before{content:"\f058"}.o_scorm_failed:before{content:"\f071"}.o_scorm_incomplete:before{content:"\f071"}.o_scorm_not_attempted:before{background:none}.o_midpub:before{content:"\f058"}.o_midwarn:before{content:"\f071"}.o_midlock:before{content:"\f023"}.o_miderr:before{content:"\f071"}.o_middel:before{content:"\f12d"}.o_filetype_file:before,.o_filetype_ico:before{content:"\f016"}.o_filetype_folder:before{content:"\f114"}.o_filetype_folder_open:before{content:"\f115"}.o_filetype_zip:before,.o_filetype_gz:before,.o_filetype_tar:before,.o_filetype_tgz:before{content:"\f1c6"}.o_filetype_css:before,.o_filetype_js:before,.o_filetype_java:before,.o_filetype_numbers:before,.o_filetype_ods:before,.o_filetype_xml:before,.o_filetype_xsl:before{content:"\f1c9"}.o_filetype_bat_icon:before,.o_filetype_bat:before,.o_filetype_exe:before,.o_filetype_app:before,.o_filetype_sh:before{content:"\f1c9"}.o_filetype_xls:before,.o_filetype_xlsx:before{content:"\f1c3"}.o_filetype_png:before,.o_filetype_tiff:before,.o_filetype_webp:before,.o_filetype_gif:before,.o_filetype_ico:before,.o_filetype_jpeg:before,.o_filetype_bmp:before,.o_filetype_odg:before,.o_filetype_eps:before,.o_filetype_jpg:before{content:"\f1c5"}.o_filetype_psd:before,.o_filetype_avi:before,.o_filetype_dvi:before,.o_filetype_mp4:before,.o_filetype_m4v:before,.o_filetype_webm:before,.o_filetype_ogg:before,.o_filetype_video:before,.o_filetype_mov:before,.o_filetype_mpeg:before,.o_filetype_mpg:before,.o_filetype_qt:before,.o_filetype_ra:before,.o_filetype_ram:before,.o_filetype_swf:before,.o_filetype_flv:before{content:"\f1c8"}.o_filetype_midi:before,.o_filetype_audio:before,.o_filetype_mp3:before,.o_filetype_m3u:before,.o_filetype_wav:before{content:"\f1c7"}.o_filetype_ps:before,.o_filetype_pdf:before{content:"\f1c1"}.o_filetype_key:before,.o_filetype_odp:before,.o_filetype_ppt:before,.o_filetype_pptx:before{content:"\f1c4"}.o_filetype_odf:before,.o_filetype_rtf:before,.o_filetype_readme:before,.o_filetype_README:before,.o_filetype_log:before,.o_filetype_txt:before,.o_filetype_htm:before,.o_filetype_html:before{content:"\f0f6"}.o_filetype_odt:before,.o_filetype_pages:before,.o_filetype_doc:before,.o_filetype_docx:before{content:"\f1c2"}.o_icon_share_social:before{content:"\f14d"}.o_icon_apple:before{content:"\f179"}.o_icon_facebook:before{content:"\f082"}.o_icon_twitter:before{content:"\f081"}.o_icon_google:before{content:"\f0d4"}.o_icon_delicious:before{content:"\f1a5"}.o_icon_digg:before{content:"\f1a6"}.o_icon_mailto:before{content:"\f199"}.o_icon_link:before{content:"\f0c1"}.o_icon_yahoo:before{content:"\f19e"}a.o_icon:hover,a.o_icon:focus{text-decoration:none}img.o_emoticons_angel{background:url(../light/images/emoticons/smiley-angel.png);width:16px;height:16px}img.o_emoticons_angry{background:url(../light/images/emoticons/smiley-mad.png);width:16px;height:16px}img.o_emoticons_blushing{background:url(../light/images/emoticons/smiley-red.png);width:16px;height:16px}img.o_emoticons_confused{background:url(../light/images/emoticons/smiley-confuse.png);width:16px;height:16px}img.o_emoticons_cool{background:url(../light/images/emoticons/smiley-cool.png);width:16px;height:16px}img.o_emoticons_cry{background:url(../light/images/emoticons/smiley-cry.png);width:16px;height:16px}img.o_emoticons_devil{background:url(../light/images/emoticons/smiley-evil.png);width:16px;height:16px}img.o_emoticons_grin{background:url(../light/images/emoticons/smiley-grin.png);width:16px;height:16px}img.o_emoticons_kiss{background:url(../light/images/emoticons/smiley-kiss.png);width:16px;height:16px}img.o_emoticons_ohoh{background:url(../light/images/emoticons/smiley-eek.png);width:16px;height:16px}img.o_emoticons_sad{background:url(../light/images/emoticons/smiley-sad.png);width:16px;height:16px}img.o_emoticons_sick{background:url(../light/images/emoticons/smiley-sad-blue.png);width:16px;height:16px}img.o_emoticons_smile{background:url(../light/images/emoticons/smiley.png);width:16px;height:16px}img.o_emoticons_tongue{background:url(../light/images/emoticons/smiley-razz.png);width:16px;height:16px}img.o_emoticons_ugly{background:url(../light/images/emoticons/smiley-money.png);width:16px;height:16px}img.o_emoticons_weird{background:url(../light/images/emoticons/smiley-nerd.png);width:16px;height:16px}img.o_emoticons_wink{background:url(../light/images/emoticons/smiley-wink.png);width:16px;height:16px}img.o_emoticons_worried{background:url(../light/images/emoticons/smiley-roll-blue.png);width:16px;height:16px}img.o_emoticons_up{background:url(../light/images/emoticons/thumb-up.png);width:16px;height:16px}img.o_emoticons_down{background:url(../light/images/emoticons/thumb.png);width:16px;height:16px}.o_block_bottom,.o_block,.o_button_group,.o_block_with_datecomp .o_content,.o_course_run .o_toc .o_entry,.o_header_with_buttons,.o_search_result{margin-bottom:1em}.o_block_top,.o_block,.o_button_group,.o_block_with_datecomp .o_content,.o_course_run .o_toc .o_entry{margin-top:1em}.o_block_large_bottom,.o_block_large,.o_block_with_datecomp,.o_login .o_login_footer_wrapper,.o_portlet{margin-bottom:2em}.o_block_large_top,.o_block_large,.o_block_with_datecomp,.o_login .o_login_footer_wrapper,.o_portlet{margin-top:2em}.o_scrollblock{overflow-x:auto;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;-webkit-overflow-scrolling:touch}.o_button_group{text-align:center}.o_button_group a,.o_button_group input,.o_button_group button,.o_button_group .btn-group{margin-right:5px;margin-bottom:0.5em}.o_button_group a:last-child,.o_button_group input:last-child,.o_button_group button:last-child,.o_button_group .btn-group:last-child{margin-right:0}.o_button_group .btn-group a,.o_button_group .btn-group input,.o_button_group .btn-group button{margin-right:0;margin-bottom:0}.o_button_group .dropdown-menu{text-align:left}.o_button_group_left{text-align:left}.o_button_group_right{text-align:right}.o_button_group_top{margin-top:0}.o_header_with_buttons:before,.o_header_with_buttons:after{content:" ";display:table}.o_header_with_buttons:after{clear:both}.o_header_with_buttons h1,.o_header_with_buttons h3,.o_header_with_buttons h4,.o_header_with_buttons .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_header_with_buttons h2{display:inline-block}.o_header_with_buttons .o_button_group{margin-top:10px;margin-bottom:0;float:right}.panel-heading.o_header_with_buttons{margin-bottom:0}.o_xsmall{font-size:12px}.o_small,.o_comments .o_comment_wrapper h5,.o_comments .o_comment_wrapper .o_comment,.o_bc_meta,.tooltip,.o_noti,.o_block_with_datecomp .o_meta,.o_togglebox_wrapper div.o_togglebox_content .o_hide,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_state,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_score,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_bookings .o_label,.o_course_run .o_toc .o_entry{font-size:12px}.o_large{font-size:18px}.o_xlarge{font-size:18px}.o_disabled{color:#777 !important;cursor:default}.o_disabled:hover{color:#777 !important}.o_dimmed{opacity:0.4;filter:alpha(opacity=40)}.o_selected{font-weight:bold}.o_deleted{text-decoration:line-through}.o_clickable{cursor:pointer}.o_ochre{color:#c8a959}.o_blue{color:#12223F}.o_undecorated:hover,.o_undecorated:focus,.o_disabled:hover,#o_main_wrapper #o_toplink:hover,#o_footer_powered a:hover,#o_share a:hover,#o_share_social_container a:hover,.o_toolbar .o_tools_container a:hover,.o_button_toggle:hover,.o_im_message_group .o_im_from:hover,.o_noti .o_label:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_social .o_comments:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_title a:hover,.o_catalog .o_level .o_meta .o_title a:hover,.o_catalog .o_sublevels .o_sublevel .o_meta .o_title a:hover,.o_repo_details .o_social .o_comments:hover,.o_login .o_login_register:hover,.o_disabled:focus,#o_main_wrapper #o_toplink:focus,#o_footer_powered a:focus,#o_share a:focus,#o_share_social_container a:focus,.o_toolbar .o_tools_container a:focus,.o_button_toggle:focus,.o_im_message_group .o_im_from:focus,.o_noti .o_label:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_social .o_comments:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_title a:focus,.o_catalog .o_level .o_meta .o_title a:focus,.o_catalog .o_sublevels .o_sublevel .o_meta .o_title a:focus,.o_repo_details .o_social .o_comments:focus,.o_login .o_login_register:focus{text-decoration:none}.o_copy_code{overflow-x:auto;overflow-y:auto;font-family:Menlo,Monaco,Consolas,"Courier New",monospace;padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;white-space:nowrap;border-radius:4px}.o_nowrap{white-space:nowrap}.o_titled_wrapper .o_content{margin-top:20px}.o_video{display:inline-block;width:100% \9;max-width:100%;height:auto}.o_image{display:inline-block;width:100% \9;max-width:100%;height:auto}.o_with_hyphens{-webkit-hyphens:auto;-moz-hyphens:auto;-ms-hyphens:auto;hyphens:auto}h1{color:#428bca}h2{color:#428bca}h3{color:#428bca}h4,.o_cal .fc-header-title h2{color:#428bca}h5{color:#428bca}h5{color:#428bca}fieldset legend{color:#333}html{position:relative;min-height:100%}body{min-height:100%;margin-bottom:80px}#o_main_wrapper{background:#fff;z-index:3}#o_main_wrapper #o_main_container{background:#fff}#o_main_wrapper #o_main_container #o_main_left{float:left;z-index:2;position:relative;background:#fff}#o_main_wrapper #o_main_container #o_main_left #o_main_left_content{padding:0 0 0 15px}#o_main_wrapper #o_main_container #o_main_left #o_main_left_toggle{position:absolute;display:none;right:0;top:70px;margin-right:-30px;font-size:25px;line-height:35px;text-align:center;width:30px;height:35px;z-index:3;border:1px solid #ddd;border-left:none;border-bottom-right-radius:4px;border-top-right-radius:4px;background-color:#fbfbfb;-webkit-box-shadow:2px 0px 4px 1px rgba(0,0,0,0.15);box-shadow:2px 0px 4px 1px rgba(0,0,0,0.15);color:#428bca}#o_main_wrapper #o_main_container #o_main_left.o_offcanvas{background:#fbfbfb;-webkit-box-shadow:0px 0px 6px 1px rgba(0,0,0,0.2);box-shadow:0px 0px 6px 1px rgba(0,0,0,0.2);min-width:250px}#o_main_wrapper #o_main_container #o_main_left.o_offcanvas #o_main_left_content{padding:0 0 0 0}#o_main_wrapper #o_main_container #o_main_right{float:right;z-index:2;position:relative;background:inherit}#o_main_wrapper #o_main_container #o_main_right #o_main_right_content{padding:0 15px 0 0}#o_main_wrapper #o_main_container #o_main_center{position:relative;z-index:1;background:inherit}#o_main_wrapper #o_main_container #o_main_center h2:first-child{margin-top:0}@media screen and (max-width: 767px){#o_main_wrapper #o_main_container #o_main_center{margin-left:0 !important}}#o_main_wrapper #o_main_container #o_main_center #o_main_center_content{padding:0 15px}#o_main_wrapper #o_main_container #o_main_center #o_main_center_content #o_main_center_content_inner{padding-bottom:15px}#o_main_wrapper #o_toplink{position:absolute;bottom:0;right:15px;text-align:center;z-index:3}@media (max-width: 767px){#o_main_wrapper #o_main_container #o_main_center #o_main_center_content{padding:15px}}
+@media print{.hidden-print{display:none !important}}body .modal{position:absolute;overflow:visible}body div.tooltip-inner{max-width:400px}body div.popover{max-width:450px}body .modal-body.alert{border-radius:0}body .progress{margin-bottom:0}.panel-body:nth-child(n+2){border-top:1px solid #ddd}.form-control-feedback{top:10px}.form-horizontal .has-feedback .form-control-feedback{top:10px}.btn.btn-primary.o_disabled{color:#fff !important}body .progress-bar[aria-valuenow="1"],body .progress-bar[aria-valuenow="2"]{min-width:1px}@font-face{font-family:'FontAwesome';src:url("../../font-awesome/fonts/fontawesome-webfont.eot?v=4.2.0");src:url("../../font-awesome/fonts/fontawesome-webfont.eot?#iefix&v=4.2.0") format("embedded-opentype"),url("../../font-awesome/fonts/fontawesome-webfont.woff?v=4.2.0") format("woff"),url("../../font-awesome/fonts/fontawesome-webfont.ttf?v=4.2.0") format("truetype"),url("../../font-awesome/fonts/fontawesome-webfont.svg?v=4.2.0#fontawesomeregular") format("svg");font-weight:normal;font-style:normal}.o_icon{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.o_icon-lg{font-size:1.33333em;line-height:0.75em;vertical-align:-15%}.o_icon-2x{font-size:2em}.o_icon-3x{font-size:3em}.o_icon-4x{font-size:4em}.o_icon-5x{font-size:5em}.o_icon-fw{width:1.28571em;text-align:center}.o_icon-ul{padding-left:0;margin-left:2.14286em;list-style-type:none}.o_icon-ul>li{position:relative}.o_icon-li{position:absolute;left:-2.14286em;width:2.14286em;top:0.14286em;text-align:center}.o_icon-li.o_icon-lg{left:-1.85714em}.o_icon-border{padding:.2em .25em .15em;border:solid 0.08em #eee;border-radius:.1em}.pull-right{float:right}.pull-left{float:left}.o_icon.pull-left{margin-right:.3em}.o_icon.pull-right{margin-left:.3em}.o_icon-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.o_icon-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.o_icon-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.o_icon-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.o_icon-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0);-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.o_icon-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .o_icon-rotate-90,:root .o_icon-rotate-180,:root .o_icon-rotate-270,:root .o_icon-flip-horizontal,:root .o_icon-flip-vertical{filter:none}.o_icon-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.o_icon-stack-1x,.o_icon-stack-2x{position:absolute;left:0;width:100%;text-align:center}.o_icon-stack-1x{line-height:inherit}.o_icon-stack-2x{font-size:2em}.o_icon-inverse{color:#fff}.o_icon_accessibility:before{content:"\f193"}.o_icon_actions:before{content:"\f085"}.o_icon_archive_tool:before{content:"\f019"}.o_icon_assessment_tool:before{content:"\f091"}.o_icon_attempt_limit:before{content:"\f021"}.o_icon_accept:before{content:"\f00c";color:#5cb85c}.o_icon_add:before{content:"\f055"}.o_icon_add_search:before{content:"\f00e"}.o_icon_audio:before{content:"\f028"}.o_icon_back:before{content:"\f053"}.o_icon_back_history:before{content:"\f1da"}.o_icon_bold:before{content:"\f032"}.o_icon_booking:before{content:"\f07a"}.o_icon_bookmark:before{content:"\f02e";color:#bc2d0c}.o_icon_bookmark_add:before{content:"\f097"}.o_icon_bookmark_header:before{content:"\f02e"}.o_icon_browse:before{content:"\f00e"}.o_icon_browsercheck:before{content:"\f164"}.o_icon_busy:before{content:"\f110"}.o_icon_calendar:before{content:"\f073"}.o_icon_calendar_enabled:before{content:"\f05d"}.o_icon_calendar_disabled:before{content:"\f10c"}.o_icon_calendar:before{content:"\f073"}.o_icon_caret:before{content:"\f0d7"}.o_icon_caret_right:before{content:"\f0da"}.o_icon_catalog:before{content:"\f0e8"}.o_icon_catalog_sub:before{content:"\f07b"}.o_icon_certificate:before{content:"\f0a3"}.o_icon_chat:before{content:"\f0e5"}.o_icon_check:before{content:"\f00c"}.o_icon_check_off:before{content:"\f096"}.o_icon_check_on:before{content:"\f046"}.o_icon_checkbox:before{content:"\f096"}.o_icon_checkbox_checked:before{content:"\f14a"}.o_icon_cleanup:before{content:"\f0f9"}.o_icon_close:before{content:"\f00d"}.o_icon_close_resource:before{content:"\f011"}.o_icon_close_tab:before{content:"\f00d"}.o_icon_close_tool:before{content:"\f00d"}.o_icon_close_tree:before{content:"\f0d7"}.o_icon_close_togglebox:before,.o_togglebox_wrapper .o_opener.o_in i:before{content:"\f0d7"}.o_icon_code:before{content:"\f121"}.o_icon_color_picker:before{content:"\f043"}.o_icon_copy:before{content:"\f0c5"}.o_icon_courseareas:before{content:"\f1db"}.o_icon_coursedb:before{content:"\f1c0"}.o_icon_courseeditor:before{content:"\f044"}.o_icon_coursefolder:before{content:"\f114"}.o_icon_courserun:before{content:"\f1b2"}.o_icon_comments:before{content:"\f086"}.o_icon_comments_none:before{content:"\f0e5"}.o_icon_content_popup:before{content:"\f08e"}.o_icon_correct_answer:before{content:"\f00c";color:#5cb85c}.o_icon_customize:before{content:"\f013"}.o_icon_delete_item:before{content:"\f1f8"}.o_icon_delete:before{content:"\f056";color:#A87E7E}.o_icon_details:before{content:"\f0eb"}.o_icon_dev:before{content:"\f188"}.o_icon_disabled:before{content:"\f10c"}.o_icon_download:before{content:"\f019"}.o_icon_edit:before{content:"\f044"}.o_icon_edit_file:before{content:"\f044"}.o_icon_edit_metadata:before{content:"\f013"}.o_icon_enabled:before{content:"\f111"}.o_icon_enlarge:before{content:"\f00e"}.o_icon_eportfolio_add:before{content:"\f12e"}.o_icon_eportfolio_link:before{content:"\f12e"}.o_icon_error:before{content:"\f06a";color:#d9534f}.o_icon_expenditure:before{content:"\f017"}.o_icon_export:before{content:"\f045"}.o_icon_external_link:before{content:"\f08e"}.o_icon_failed:before{content:"\f057"}.o_icon_filter:before{content:"\f0b0"}.o_icon_group:before,.o_BusinessGroup_icon:before{content:"\f0c0"}.o_icon_header:before{content:"\f1dc"}.o_icon_help:before{content:"\f059";cursor:help}.o_icon_home:before{content:"\f015"}.o_icon_impress:before{content:"\f05a"}.o_icon_important:before{content:"\f071";color:#f0ad4e}.o_icon_import:before{content:"\f093"}.o_icon_info:before{content:"\f05a";color:#5bc0de}.o_icon_info_msg:before{content:"\f06a";color:#d9534f}.o_icon_inline_editable:before{content:"\f044"}.o_icon_institution:before{content:"\f19c"}.o_icon_italic:before{content:"\f033"}.o_icon_landingpage:before{content:"\f140"}.o_icon_language:before{content:"\f0ac"}.o_icon_layout:before{content:"\f1c5"}.o_icon_link:before{content:"\f0c1"}.o_icon_link_extern:before{content:"\f08e"}.o_icon_list:before{content:"\f03a"}.o_icon_list_num :before{content:"\f0cb"}.o_icon_lifecycle:before{content:"\f073"}.o_icon_locked:before{content:"\f023"}.o_icon_login:before{content:"\f090"}.o_icon_logout:before{content:"\f08b"}.o_icon_mandatory:before{content:"\f069";color:#f0ad4e}.o_icon_managed:before{content:"\f079";color:#777}.o_icon_mail:before{content:"\f003"}.o_icon_math:before{content:"\f198"}.o_icon_membersmanagement:before{content:"\f0c0"}.o_icon_menuhandel:before{content:"\f0c9"}.o_icon_message:before{content:"\f0e0"}.o_icon_move:before{content:"\f047"}.o_icon_move_down:before{content:"\f103"}.o_icon_move_left:before{content:"\f100"}.o_icon_move_right:before{content:"\f101"}.o_icon_move_up:before{content:"\f102"}.o_icon_new:before{content:"\f069";color:#5cb85c}.o_icon_new_document:before{content:"\f15c"}.o_icon_new_folder:before{content:"\f07b"}.o_icon_news:before{content:"\f05a"}.o_icon_next:before{content:"\f138"}.o_icon_next_page:before{content:"\f101"}.o_icon_next_toolbar:before{content:"\f0da"}.o_icon_node_after:before{content:"\f175"}.o_icon_node_before:before{content:"\f176"}.o_icon_node_under:before{content:"\f112"}.o_icon_notes:before{content:"\f1e8"}.o_icon_notification:before{content:"\f09e"}.o_icon_open_tree:before{content:"\f0da"}.o_icon_open_togglebox:before,.o_togglebox_wrapper .o_opener i:before{content:"\f0da"}.o_icon_openolat:before,.o_icon_provider_olat:before{content:"\221E";font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-weight:bold}.o_icon_options:before{content:"\f205"}.o_icon_pageing:before{content:"\f141"}.o_icon_passed:before{content:"\f058"}.o_icon_password:before{content:"\f023"}.o_icon_pending:before{content:"\f110"}.o_icon_phone:before{content:"\f095"}.o_icon_post:before{content:"\f0e5"}.o_icon_preview:before{content:"\f06e"}.o_icon_previous:before{content:"\f137"}.o_icon_previous_page:before{content:"\f100"}.o_icon_previous_toolbar:before{content:"\f0d9"}.o_icon_print:before{content:"\f02f"}.o_icon_private:before{content:"\f02f"}.o_icon_provider_adfs:before{content:"\f17a"}.o_icon_provider_facebook:before{content:"\f09a"}.o_icon_provider_google:before{content:"\f0d5"}.o_icon_provider_guest:before{content:"\f1ae"}.o_icon_provider_ldap:before{content:"\f19c"}.o_icon_provider_linkedin:before{content:"\f0e1"}.o_icon_provider_oauth:before{content:"\f0c2"}.o_icon_provider_shibboleth:before{content:"\f19c"}.o_icon_provider_twitter:before{content:"\f099"}.o_icon_publish:before{content:"\f064"}.o_icon_qrcode:before{content:"\f029"}.o_icon_quickview:before{content:"\f06e"}.o_icon_radio_off:before{content:"\f10c"}.o_icon_radio_on:before{content:"\f05d"}.o_icon_rating_on:before,.o_rating .o_rating_items.o_enabled .o_icon:hover:before{content:"\f005"}.o_icon_rating_off:before{content:"\f006"}.o_icon_read:before{content:"\f10c"}.o_icon_readonly:before{content:"\f044";color:red}.o_icon_readwrite:before{content:"\f044"}.o_icon_recycle:before{content:"\f1b8"}.o_icon_refresh:before{content:"\f021"}.o_icon_reject:before{content:"\f00d";color:#d9534f}.o_icon_remove:before{content:"\f00d"}.o_icon_reply:before{content:"\f112"}.o_icon_reply_with_quote:before{content:"\f122"}.o_icon_response_feedback:before{content:"\f021"}.o_icon_review:before{content:"\f06e"}.o_icon_rss:before{content:"\f09e"}.o_icon_rss_unsubscribe:before{content:"\f09e";color:#996633}.o_icon_search:before{content:"\f002"}.o_icon_settings:before{content:"\f085"}.o_icon_share:before{content:"\f064"}.o_icon_show_more:before{content:"\f150"}.o_icon_show_less:before{content:"\f151"}.o_icon_spacer:before{content:"\f07e"}.o_icon_split:before{content:"\f127"}.o_icon_sort:before{content:"\f0dc"}.o_icon_sort_asc:before{content:"\f0de"}.o_icon_sort_desc:before{content:"\f0dd"}.o_icon_sort_menu:before{content:"\f160"}.o_icon_start:before{content:"\f054"}.o_icon_status_available:before{content:"\f111";color:#063}.o_icon_status_chat:before{content:"\f075"}.o_icon_status_dnd:before{content:"\f192";color:#cc3}.o_icon_status_unavailable:before{content:"\f05c";color:#963}.o_icon_statistics_tool:before{content:"\f080"}.o_icon_table:before{content:"\f0ce"}.o_icon_table_large:before{content:"\f009"}.o_icon_tags:before{content:"\f02c"}.o_icon_timelimit:before{content:"\f1e2"}.o_icon_toggle:before{content:"\f111"}.o_icon_to_read:before{content:"\f111"}.o_icon_tool:before{content:"\f013"}.o_icon_tools:before{content:"\f0ad"}.o_icon_top:before{content:"\f077"}.o_icon_translation_item:before{content:"\f1c9"}.o_icon_translation_package:before{content:"\f115"}.o_icon_user:before{content:"\f007"}.o_icon_user_vip:before{content:"\f19d"}.o_icon_user_anonymous:before{content:"\f128"}.o_icon_upload:before{content:"\f093"}.o_icon_version:before{content:"\f1da"}.o_icon_video:before{content:"\f008"}.o_icon_warn:before{content:"\f071";color:#f0ad4e}.o_icon_wizard:before{content:"\f0d0"}.o_CourseModule_icon:before,.o_course_icon:before{content:"\f1b2"}.o_EPStructuredMapTemplate_icon:before{content:"\f12e"}.o_FileResource-BLOG_icon:before{content:"\f0a1"}.o_FileResource-IMSCP_icon:before{content:"\f187"}.o_FileResource-PODCAST_icon:before{content:"\f03d"}.o_FileResource-SHAREDFOLDER:before{content:"\f08e"}.o_FileResource-SCORMCP_icon:before{content:"\f187"}.o_FileResource-SURVEY_icon:before{content:"\f11a"}.o_FileResource-TEST_icon:before{content:"\f044"}.o_FileResource-WIKI_icon:before{content:"\f0ac"}.o_FileResource-SHAREDFOLDER_icon:before{content:"\f115"}.o_FileResource-GLOSSARY_icon:before{content:"\f19d"}.o_FileResource-PDF_icon:before{content:"\f1c1"}.o_FileResource-XLS_icon:before{content:"\f1c3"}.o_FileResource-PPT_icon:before{content:"\f1c4"}.o_FileResource-DOC_icon:before{content:"\f1c2"}.o_FileResource-ANIM_icon:before{content:"\f1c8"}.o_FileResource-IMAGE_icon:before{content:"\f1c5"}.o_FileResource-SOUND_icon:before{content:"\f1c7"}.o_FileResource-MOVIE_icon:before{content:"\f1c8"}.o_FileResource-FILE_icon:before{content:"\f016"}.o_CourseModule_icon_closed:before{content:"\f05e"}.o_sp_icon:before{content:"\f0f6"}.o_st_icon:before{content:"\f1b3"}.o_tu_icon:before{content:"\f08e"}.o_bc_icon:before{content:"\f115"}.o_lti_icon:before{content:"\f08e"}.o_cp_icon:before{content:"\f187"}.o_cp_item:before{content:"\f0f6"}.o_scorm_icon:before{content:"\f187"}.o_en_icon:before{content:"\f090"}.o_fo_icon:before{content:"\f0e6"}.o_co_icon:before{content:"\f003"}.o_infomsg_icon:before{content:"\f05a"}.o_cal_icon:before{content:"\f073"}.o_wiki_icon:before{content:"\f0ac"}.o_podcast_icon:before{content:"\f03d"}.o_blog_icon:before{content:"\f0a1"}.o_ep_icon:before{content:"\f12e"}.o_iqtest_icon:before{content:"\f044"}.o_iqself_icon:before{content:"\f044"}.o_iqsurv_icon:before{content:"\f11a"}.o_ta_icon:before{content:"\f0ae"}.o_ms_icon:before{content:"\f087"}.o_dialog_icon:before{content:"\f0c5"}.o_projectbroker_icon:before{content:"\f10c"}.o_ll_icon:before{content:"\f0c1"}.o_den_icon:before{content:"\f133"}.o_cmembers_icon:before{content:"\f0c0"}.o_cl_icon:before{content:"\f046"}.o_vc_icon:before{content:"\f108"}.o_vitero_icon:before{content:"\f108"}.o_openmeetings_icon:before{content:"\f108"}.o_portlet_infomsg_icon:before{content:"\f05a"}.o_portlet_quickstart_icon:before{content:"\f1d9"}.o_portlet_bookmark_icon:before{content:"\f02e"}.o_portlet_groups_icon:before{content:"\f0c0"}.o_portlet_notes_icon:before{content:"\f1e8"}.o_portlet_noti_icon:before{content:"\f09e"}.o_portlet_eff_icon:before{content:"\f0a3"}.o_portlet_repository_student_icon:before{content:"\f1b3"}.o_portlet_repository_teacher_icon:before{content:"\f19d"}.o_portlet_iframe_icon:before{content:"\f005"}.o_portlet_sysinfo_icon:before{content:"\f0e4"}.o_portlet_dyk_icon:before{content:"\f0eb"}.o_portlet_infomessages_icon:before{content:"\f0e5"}.o_portlet_cal_icon:before{content:"\f073"}.o_portlet_institutions_icon:before{content:"\f19c"}.o_portlet_links_icon:before{content:"\f0c1"}.o_portlet_shibboleth_icon:before{content:"\f090"}.o_icon_qpool:before{content:"\f19c"}.o_icon_pool_private:before{content:"\f096"}.o_icon_pool_public:before{content:"\f046"}.o_icon_pool_my_items:before{content:"\f007"}.o_icon_pool_favorits:before{content:"\f02e"}.o_icon_pool_collection:before{content:"\f03a"}.o_icon_pool_pool:before{content:"\f1e1"}.o_icon_pool_share:before{content:"\f0c0"}.o_forum_message_icon:before{content:"\f0e5"}.o_calendar_icon:before{content:"\f073"}.o_forum_status_thread_icon:before{content:"\f0e6"}.o_forum_status_sticky_closed_icon:before{content:"\f05e"}.o_forum_status_sticky_icon:before{content:"\f086"}.o_forum_status_closed_icon:before{content:"\f05e";color:#a94442}.o_forum_status_opened_icon:before{content:"\f05e";color:#3c763d}.o_forum_status_hidden_icon:before{content:"\f070";color:#a94442}.o_forum_status_visible_icon:before{content:"\f06e";color:#3c763d}.o_mi_qpool_import:before{content:"\f1c0"}.o_mi_qtisection:before{content:"\f1b3"}.o_mi_qtisc:before{content:"\f192"}.o_mi_qtimc:before{content:"\f046"}.o_mi_qtikprim:before{content:"\f14a"}.o_mi_qtifib:before{content:"\f141"}.o_mi_qtiessay:before{content:"\f036"}.o_black_led:before{content:"\f111";color:#428bca}.o_green_led:before{content:"\f111";color:#5cb85c}.o_yellow_led:before{content:"\f111";color:#f0ad4e}.o_red_led:before{content:"\f111";color:#d9534f}.o_ac_token_icon:before{content:"\f084"}.o_ac_free_icon:before{content:"\f06b"}.o_ac_group_icon:before{content:"\f0c0"}.o_ac_membersonly_icon:before{content:"\f023"}.o_ac_paypal_icon:before{content:"\f1f4"}.o_ac_status_canceled_icon:before{content:"\f068";color:#f0ad4e}.o_ac_status_error_icon:before{content:"\f00d";color:#d9534f}.o_ac_status_new_icon:before{content:"\f069";color:#428bca}.o_ac_status_succes_icon:before{content:"\f00c";color:#5cb85c}.o_ac_status_waiting_icon:before{content:"\f017";color:#428bca}.o_ac_order_status_new_icon:before{content:"\f069";color:#428bca}.o_ac_order_status_prepayment_icon:before{content:"\f0d6";color:#5bc0de}.o_ac_order_status_payed_icon:before{content:"\f00c";color:#5cb85c}.o_ac_order_status_canceled_icon:before{content:"\f068";color:#f0ad4e}.o_ac_order_status_error_icon:before{content:"\f00d";color:#d9534f}.o_ac_order_status_warning_icon:before{content:"\f12a";color:#f0ad4e}.o_scorm_org:before{content:"\f187"}.o_scorm_item:before{content:"\f016"}.o_scorm_completed:before,.o_scorm_passed:before{content:"\f058"}.o_scorm_failed:before{content:"\f071"}.o_scorm_incomplete:before{content:"\f071"}.o_scorm_not_attempted:before{background:none}.o_midpub:before{content:"\f058"}.o_midwarn:before{content:"\f071"}.o_midlock:before{content:"\f023"}.o_miderr:before{content:"\f071"}.o_middel:before{content:"\f12d"}.o_filetype_file:before,.o_filetype_ico:before{content:"\f016"}.o_filetype_folder:before{content:"\f114"}.o_filetype_folder_open:before{content:"\f115"}.o_filetype_zip:before,.o_filetype_gz:before,.o_filetype_tar:before,.o_filetype_tgz:before{content:"\f1c6"}.o_filetype_css:before,.o_filetype_js:before,.o_filetype_java:before,.o_filetype_numbers:before,.o_filetype_ods:before,.o_filetype_xml:before,.o_filetype_xsl:before{content:"\f1c9"}.o_filetype_bat_icon:before,.o_filetype_bat:before,.o_filetype_exe:before,.o_filetype_app:before,.o_filetype_sh:before{content:"\f1c9"}.o_filetype_xls:before,.o_filetype_xlsx:before{content:"\f1c3"}.o_filetype_png:before,.o_filetype_tiff:before,.o_filetype_webp:before,.o_filetype_gif:before,.o_filetype_ico:before,.o_filetype_jpeg:before,.o_filetype_bmp:before,.o_filetype_odg:before,.o_filetype_eps:before,.o_filetype_jpg:before{content:"\f1c5"}.o_filetype_psd:before,.o_filetype_avi:before,.o_filetype_dvi:before,.o_filetype_mp4:before,.o_filetype_m4v:before,.o_filetype_webm:before,.o_filetype_ogg:before,.o_filetype_video:before,.o_filetype_mov:before,.o_filetype_mpeg:before,.o_filetype_mpg:before,.o_filetype_qt:before,.o_filetype_ra:before,.o_filetype_ram:before,.o_filetype_swf:before,.o_filetype_flv:before{content:"\f1c8"}.o_filetype_midi:before,.o_filetype_audio:before,.o_filetype_mp3:before,.o_filetype_m3u:before,.o_filetype_wav:before{content:"\f1c7"}.o_filetype_ps:before,.o_filetype_pdf:before{content:"\f1c1"}.o_filetype_key:before,.o_filetype_odp:before,.o_filetype_ppt:before,.o_filetype_pptx:before{content:"\f1c4"}.o_filetype_odf:before,.o_filetype_rtf:before,.o_filetype_readme:before,.o_filetype_README:before,.o_filetype_log:before,.o_filetype_txt:before,.o_filetype_htm:before,.o_filetype_html:before{content:"\f0f6"}.o_filetype_odt:before,.o_filetype_pages:before,.o_filetype_doc:before,.o_filetype_docx:before{content:"\f1c2"}.o_icon_share_social:before{content:"\f14d"}.o_icon_apple:before{content:"\f179"}.o_icon_facebook:before{content:"\f082"}.o_icon_twitter:before{content:"\f081"}.o_icon_google:before{content:"\f0d4"}.o_icon_delicious:before{content:"\f1a5"}.o_icon_digg:before{content:"\f1a6"}.o_icon_mailto:before{content:"\f199"}.o_icon_link:before{content:"\f0c1"}.o_icon_yahoo:before{content:"\f19e"}a.o_icon:hover,a.o_icon:focus{text-decoration:none}img.o_emoticons_angel{background:url(../light/images/emoticons/smiley-angel.png);width:16px;height:16px}img.o_emoticons_angry{background:url(../light/images/emoticons/smiley-mad.png);width:16px;height:16px}img.o_emoticons_blushing{background:url(../light/images/emoticons/smiley-red.png);width:16px;height:16px}img.o_emoticons_confused{background:url(../light/images/emoticons/smiley-confuse.png);width:16px;height:16px}img.o_emoticons_cool{background:url(../light/images/emoticons/smiley-cool.png);width:16px;height:16px}img.o_emoticons_cry{background:url(../light/images/emoticons/smiley-cry.png);width:16px;height:16px}img.o_emoticons_devil{background:url(../light/images/emoticons/smiley-evil.png);width:16px;height:16px}img.o_emoticons_grin{background:url(../light/images/emoticons/smiley-grin.png);width:16px;height:16px}img.o_emoticons_kiss{background:url(../light/images/emoticons/smiley-kiss.png);width:16px;height:16px}img.o_emoticons_ohoh{background:url(../light/images/emoticons/smiley-eek.png);width:16px;height:16px}img.o_emoticons_sad{background:url(../light/images/emoticons/smiley-sad.png);width:16px;height:16px}img.o_emoticons_sick{background:url(../light/images/emoticons/smiley-sad-blue.png);width:16px;height:16px}img.o_emoticons_smile{background:url(../light/images/emoticons/smiley.png);width:16px;height:16px}img.o_emoticons_tongue{background:url(../light/images/emoticons/smiley-razz.png);width:16px;height:16px}img.o_emoticons_ugly{background:url(../light/images/emoticons/smiley-money.png);width:16px;height:16px}img.o_emoticons_weird{background:url(../light/images/emoticons/smiley-nerd.png);width:16px;height:16px}img.o_emoticons_wink{background:url(../light/images/emoticons/smiley-wink.png);width:16px;height:16px}img.o_emoticons_worried{background:url(../light/images/emoticons/smiley-roll-blue.png);width:16px;height:16px}img.o_emoticons_up{background:url(../light/images/emoticons/thumb-up.png);width:16px;height:16px}img.o_emoticons_down{background:url(../light/images/emoticons/thumb.png);width:16px;height:16px}.o_block_bottom,.o_block,.o_button_group,.o_block_with_datecomp .o_content,.o_course_run .o_toc .o_entry,.o_header_with_buttons,.o_search_result{margin-bottom:1em}.o_block_top,.o_block,.o_button_group,.o_block_with_datecomp .o_content,.o_course_run .o_toc .o_entry{margin-top:1em}.o_block_large_bottom,.o_block_large,.o_block_with_datecomp,.o_login .o_login_footer_wrapper,.o_portlet{margin-bottom:2em}.o_block_large_top,.o_block_large,.o_block_with_datecomp,.o_login .o_login_footer_wrapper,.o_portlet{margin-top:2em}.o_scrollblock{overflow-x:auto;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;-webkit-overflow-scrolling:touch}.o_button_group{text-align:center}.o_button_group a,.o_button_group input,.o_button_group button,.o_button_group .btn-group{margin-right:5px;margin-bottom:0.5em}.o_button_group a:last-child,.o_button_group input:last-child,.o_button_group button:last-child,.o_button_group .btn-group:last-child{margin-right:0}.o_button_group .btn-group a,.o_button_group .btn-group input,.o_button_group .btn-group button{margin-right:0;margin-bottom:0}.o_button_group .dropdown-menu{text-align:left}.o_button_group_left{text-align:left}.o_button_group_right{text-align:right}.o_button_group_top{margin-top:0}.o_header_with_buttons:before,.o_header_with_buttons:after{content:" ";display:table}.o_header_with_buttons:after{clear:both}.o_header_with_buttons h1,.o_header_with_buttons h3,.o_header_with_buttons h4,.o_header_with_buttons .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_header_with_buttons h2{display:inline-block}.o_header_with_buttons .o_button_group{margin-top:10px;margin-bottom:0;float:right}.panel-heading.o_header_with_buttons{margin-bottom:0}.o_xsmall{font-size:12px}.o_small,.o_comments .o_comment_wrapper h5,.o_comments .o_comment_wrapper .o_comment,.o_bc_meta,.tooltip,.o_noti,.o_block_with_datecomp .o_meta,.o_togglebox_wrapper div.o_togglebox_content .o_hide,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_state,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_score,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_bookings .o_label,.o_course_run .o_toc .o_entry{font-size:12px}.o_large{font-size:18px}.o_xlarge{font-size:18px}.o_disabled{color:#777 !important;cursor:default}.o_disabled:hover{color:#777 !important}.o_dimmed{opacity:0.4;filter:alpha(opacity=40)}.o_selected{font-weight:bold}.o_deleted{text-decoration:line-through}.o_clickable{cursor:pointer}.o_ochre{color:#c8a959}.o_blue{color:#12223F}.o_undecorated:hover,.o_undecorated:focus,.o_disabled:hover,#o_main_wrapper #o_toplink:hover,#o_footer_powered a:hover,#o_share a:hover,#o_share_social_container a:hover,.o_toolbar .o_tools_container a:hover,.o_button_toggle:hover,.o_im_message_group .o_im_from:hover,.o_noti .o_label:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_social .o_comments:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details:hover,.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_title a:hover,.o_catalog .o_level .o_meta .o_title a:hover,.o_catalog .o_sublevels .o_sublevel .o_meta .o_title a:hover,.o_repo_details .o_social .o_comments:hover,.o_login .o_login_register:hover,.o_disabled:focus,#o_main_wrapper #o_toplink:focus,#o_footer_powered a:focus,#o_share a:focus,#o_share_social_container a:focus,.o_toolbar .o_tools_container a:focus,.o_button_toggle:focus,.o_im_message_group .o_im_from:focus,.o_noti .o_label:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_social .o_comments:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_start:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_book:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_access .o_details:focus,.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_title a:focus,.o_catalog .o_level .o_meta .o_title a:focus,.o_catalog .o_sublevels .o_sublevel .o_meta .o_title a:focus,.o_repo_details .o_social .o_comments:focus,.o_login .o_login_register:focus{text-decoration:none}.o_copy_code{overflow-x:auto;overflow-y:auto;font-family:Menlo,Monaco,Consolas,"Courier New",monospace;padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;white-space:nowrap;border-radius:4px}.o_nowrap{white-space:nowrap}.o_titled_wrapper .o_content{margin-top:20px}.o_video{display:inline-block;width:100% \9;max-width:100%;height:auto}.o_image{display:inline-block;width:100% \9;max-width:100%;height:auto}.o_with_hyphens{-webkit-hyphens:auto;-moz-hyphens:auto;-ms-hyphens:auto;hyphens:auto}h1{color:#428bca}h2{color:#428bca}h3{color:#428bca}h4,.o_cal .fc-header-title h2{color:#428bca}h5{color:#428bca}h5{color:#428bca}fieldset legend{color:#333}html{position:relative;min-height:100%}body{min-height:100%;margin-bottom:80px}#o_main_wrapper{background:#fff;z-index:3}#o_main_wrapper #o_main_container{background:#fff}#o_main_wrapper #o_main_container #o_main_left{float:left;z-index:2;position:relative;background:#fff}#o_main_wrapper #o_main_container #o_main_left #o_main_left_content{padding:0 0 0 15px}#o_main_wrapper #o_main_container #o_main_left #o_main_left_toggle{position:absolute;display:none;right:0;top:70px;margin-right:-30px;font-size:25px;line-height:35px;text-align:center;width:30px;height:35px;z-index:3;border:1px solid #ddd;border-left:none;border-bottom-right-radius:4px;border-top-right-radius:4px;background-color:#fbfbfb;-webkit-box-shadow:2px 0px 4px 1px rgba(0,0,0,0.15);box-shadow:2px 0px 4px 1px rgba(0,0,0,0.15);color:#428bca}#o_main_wrapper #o_main_container #o_main_left.o_offcanvas{background:#fbfbfb;-webkit-box-shadow:0px 0px 6px 1px rgba(0,0,0,0.2);box-shadow:0px 0px 6px 1px rgba(0,0,0,0.2);min-width:250px}#o_main_wrapper #o_main_container #o_main_left.o_offcanvas #o_main_left_content{padding:0 0 0 0}#o_main_wrapper #o_main_container #o_main_right{float:right;z-index:2;position:relative;background:inherit}#o_main_wrapper #o_main_container #o_main_right #o_main_right_content{padding:0 15px 0 0}#o_main_wrapper #o_main_container #o_main_center{position:relative;z-index:1;background:inherit}#o_main_wrapper #o_main_container #o_main_center h2:first-child{margin-top:0}@media screen and (max-width: 767px){#o_main_wrapper #o_main_container #o_main_center{margin-left:0 !important}}#o_main_wrapper #o_main_container #o_main_center #o_main_center_content{padding:0 15px}#o_main_wrapper #o_main_container #o_main_center #o_main_center_content #o_main_center_content_inner{padding-bottom:15px}#o_main_wrapper #o_toplink{position:absolute;bottom:0;right:15px;text-align:center;z-index:3}@media (max-width: 767px){#o_main_wrapper #o_main_container #o_main_center #o_main_center_content{padding:15px}}
 #o_back_wrapper,#o_preview_wrapper{margin-top:10px}#o_back_wrapper.o_toolbar .o_breadcrumb .breadcrumb,#o_preview_wrapper.o_toolbar .o_breadcrumb .breadcrumb{font-size:14px}#o_footer_wrapper{position:absolute;bottom:0;width:100%;height:70px;overflow:hidden;background-color:#f5f5f5;color:#999;line-height:16px;font-size:12px}#o_footer_wrapper a{color:#999}#o_footer_wrapper a:hover{color:#000}#o_footer_container{position:relative;padding-top:10px;min-height:70px;background:#f5f5f5;z-index:1}#o_footer_user{position:absolute;left:15px;top:10px;z-index:1}#o_footer_user #o_counter{white-space:nowrap}#o_footer_user #o_username{white-space:nowrap;margin-right:1em}#o_footer_version{position:absolute;right:15px;top:10px;text-align:right;z-index:1}@media (max-width: 767px){#o_footer_version{padding-top:10px;text-align:left}}
 #o_footer_powered{position:absolute;top:30px;right:15px;z-index:1}#o_footer_powered img{opacity:0.6;filter:alpha(opacity=60)}#o_footer_powered img:hover{opacity:1;filter:alpha(opacity=100)}#o_footer_impressum{position:absolute;top:10px;width:100%;text-align:center;z-index:-1}#o_footer_impressum i{display:none}#o_footer_textline{position:absolute;top:30px;width:100%;text-align:center;z-index:-1}#o_share{margin-top:10px}#o_share a{opacity:0.6;filter:alpha(opacity=60)}#o_share a:hover{opacity:1;filter:alpha(opacity=100)}#o_share a,#o_share_social_container a{color:#999;margin:0 0.25em 0 0}#o_share a:hover,#o_share_social_container a:hover{color:#000}@media (max-width: 767px){#o_counter,#o_footer_version,#o_share{display:none}#o_footer_impressum{top:30px;text-align:left}#o_footer_textline{top:50px;text-align:left}#o_footer_powered{top:10px}#o_footer_powered a:after{content:"\221E";font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-weight:bold;font-size:14px}#o_footer_powered img{display:none}}#o_navbar_wrapper{z-index:4;border-top:1px solid #e7e7e7;box-shadow:inset 0 1px 0 rgba(255,255,255,0.1)}#o_navbar_wrapper #o_navbar_container{position:relative}.o_navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid #e7e7e7;background-color:#f8f8f8}.o_navbar:before,.o_navbar:after{content:" ";display:table}.o_navbar:after{clear:both}.o_navbar .o_navbar_tabs li{max-width:150px}.o_navbar .o_navbar_tabs li a{padding-right:30px}.o_navbar .o_navbar_tabs li a:first-child span{display:block;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.o_navbar .o_navbar_tabs .o_icon-fw{position:absolute;top:15px;left:0.5em;padding-top:3px;width:1em;height:1em;display:none}.o_navbar .o_navbar_tabs .o_navbar_tab_close{position:absolute;top:15px;right:0.5em;padding:0;width:1em;height:1em}.o_navbar .o_navbar_tabs .o_navbar_tab_close i:before{color:#d9534f}.o_navbar .o_navbar_tabs .o_navbar_tab_close:hover i:before{color:#c9302c}.o_navbar .o_custom_navbar-brand{background-position:5px 0;background-repeat:no-repeat;height:50px;width:120px}.o_navbar #o_navbar_langchooser{color:#777;padding:7px 15px}.o_navbar #o_navbar_langchooser form span+div{display:inline}.o_navbar #o_navbar_tools_permanent #o_navbar_print a,.o_navbar #o_navbar_tools_permanent #o_navbar_impress a,.o_navbar #o_navbar_tools_permanent #o_navbar_help a{color:#777;padding-right:0}.o_navbar #o_navbar_tools_permanent #o_navbar_login a{color:#f0ad4e}.o_navbar .o_navbar_tools li>a>span{display:none}@media (min-width: 768px){.o_navbar .o_navbar_tools li.o_portrait>a>span{display:inline}}.o_navbar #o_navbar_tools_personal .o_navbar_tool a,.o_navbar #o_navbar_tools_permanent .o_navbar_tool a{padding-right:5px}.o_navbar #o_navbar_tools_personal #o_navbar_my_menu a,.o_navbar #o_navbar_tools_permanent #o_navbar_my_menu a{padding-left:45px}.o_navbar #o_navbar_tools_personal #o_navbar_my_menu .o_portrait,.o_navbar #o_navbar_tools_permanent #o_navbar_my_menu .o_portrait{position:absolute;left:7px;top:10px}.o_navbar #o_navbar_tools_personal .o_logout,.o_navbar #o_navbar_tools_permanent .o_logout{color:#d9534f}.o_navbar.o_navbar-offcanvas .o_navbar_tab_close{top:10px;right:10px}.o_navbar.o_navbar-offcanvas .o_navbar-right a{padding:3px 20px;color:#777}.o_navbar.o_navbar-offcanvas .o_navbar-right a:hover,.o_navbar.o_navbar-offcanvas .o_navbar-right a:focus{color:#fff;background-color:transparent}.o_navbar.o_navbar-offcanvas .o_navbar-right a.o_logout{color:#d9534f}.o_navbar.o_navbar-offcanvas .o_navbar-right a.o_logout:hover,.o_navbar.o_navbar-offcanvas .o_navbar-right a.o_logout:focus{color:#c9302c}.o_navbar.o_navbar-offcanvas .o_navbar-right a .o_icon-lg{font-size:1.0em}.o_navbar.o_navbar-offcanvas .o_navbar-right .divider{height:1px;margin:9px 0;overflow:hidden;background-color:none}.o_navbar.o_navbar-offcanvas .o_navbar-right .dropdown-header{padding-left:15px}.o_navbar.o_navbar-offcanvas .o_navbar-right .dropdown-toggle{display:none}.o_navbar.o_navbar-offcanvas .o_navbar-right .dropdown-menu{box-shadow:none;position:relative;top:0;left:0;display:block;float:none;background-color:#222;color:#777;font-size:14px}.o_navbar.o_navbar-offcanvas .o_navbar-right .dropdown-menu .divider{background:none}.o_navbar.o_navbar-offcanvas .o_navbar-nav a{color:#777;text-shadow:none}.o_navbar.o_navbar-offcanvas .o_navbar-nav a:hover,.o_navbar.o_navbar-offcanvas .o_navbar-nav a:focus{background-color:transparent;color:#fff}.o_navbar.o_navbar-offcanvas .o_navbar-nav .active a,.o_navbar.o_navbar-offcanvas .o_navbar-nav .active a:hover,.o_navbar.o_navbar-offcanvas .o_navbar-nav .active a:focus{background-color:#090909;color:#fff}.o_navbar.o_navbar-offcanvas .o_navbar-nav .o_navbar-link{color:#777}.o_navbar.o_navbar-offcanvas .o_navbar-nav .o_navbar-link:hover{color:#fff}.o_navbar.o_navbar-offcanvas .o_navbar-nav .open .dropdown-menu>li>a{color:#777}.o_navbar.o_navbar-offcanvas .o_navbar-nav .open .dropdown-menu>li>a:hover,.o_navbar.o_navbar-offcanvas .o_navbar-nav .open .dropdown-menu>li>a:focus{color:#333;background-color:transparent}.o_navbar.o_navbar-offcanvas .o_navbar-nav .open .dropdown-menu>.active>a,.o_navbar.o_navbar-offcanvas .o_navbar-nav .open .dropdown-menu>.active>a:hover,.o_navbar.o_navbar-offcanvas .o_navbar-nav .open .dropdown-menu>.active>a:focus{color:#555;background-color:#e7e7e7}.o_navbar.o_navbar-offcanvas .o_navbar-nav .open .dropdown-menu>.disabled>a,.o_navbar.o_navbar-offcanvas .o_navbar-nav .open .dropdown-menu>.disabled>a:hover,.o_navbar.o_navbar-offcanvas .o_navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#ccc;background-color:transparent}#o_navbar_print a span,#o_navbar_impress a span,#o_navbar_help a span,#o_navbar_search_opener a span{display:none}body.o_dmz #o_navbar_print a span,body.o_dmz #o_navbar_impress a span,body.o_dmz #o_navbar_help a span,body.o_dmz #o_navbar_search_opener a span{display:inline}.o_navbar-collapse{max-height:340px;overflow-x:visible;padding-right:15px;padding-left:15px;-webkit-overflow-scrolling:touch}.o_navbar-collapse:before,.o_navbar-collapse:after{content:" ";display:table}.o_navbar-collapse:after{clear:both}.o_navbar-collapse.o_collapse{display:block !important;height:auto !important;padding-bottom:0;overflow:visible !important}.o_navbar-offcanvas .o_navbar-collapse{width:auto;box-shadow:none;margin-top:10px;margin-right:-15px;margin-left:-15px}.o_navbar-brand{float:left;font-size:18px;line-height:20px;height:50px;color:#777}.o_navbar-brand:hover,.o_navbar-brand:focus{text-decoration:none;color:#5e5e5e;background-color:transparent}.o_navbar-toggle{position:relative;margin-right:15px;margin-left:15px;padding:9px 10px;margin-top:8px;margin-bottom:8px;border:1px solid #ddd;border-radius:4px;background-color:transparent;background-image:none}.o_navbar-toggle:hover,.o_navbar-toggle:focus{outline:none;background-color:#ddd}.o_navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px;background-color:#888}.o_navbar-toggle .icon-bar+.icon-bar{margin-top:4px}#o_navbar_left-toggle{float:left}#o_navbar_right-toggle{float:right}.o_navbar-link{color:#777}.o_navbar-link:hover{color:#333}.o_navbar-nav{margin:7.5px -15px}.o_navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px;color:#777}.o_navbar-nav>li>a:hover,.o_navbar-nav>li>a:focus{color:#333;background-color:transparent}.o_navbar-nav>.active>a,.o_navbar-nav>.active>a:hover,.o_navbar-nav>.active>a:focus{color:#555;background-color:#e7e7e7}.o_navbar-nav>.disabled>a,.o_navbar-nav>.disabled>a:hover,.o_navbar-nav>.disabled>a:focus{color:#ccc;background-color:transparent}.o_navbar-nav>.open>a,.o_navbar-nav>.open>a:hover,.o_navbar-nav>.open>a:focus{background-color:#e7e7e7;color:#555}.o_collapse .o_navbar-nav{float:left;margin:0}.o_collapse .o_navbar-nav>li{float:left}.o_collapse .o_navbar-nav>li>a{padding-top:15px;padding-bottom:15px}.o_collapse .o_navbar-nav.o_navbar-right:last-child{margin-right:-15px}.o_collapse.o_navbar-collapse .o_navbar-left{float:left !important}.o_collapse.o_navbar-collapse .o_navbar-right{float:right !important}.o_navbar-form{margin-left:-15px;margin-right:-15px;padding:10px 15px;border-top:1px solid #e7e7e7;border-bottom:1px solid #e7e7e7;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);margin-top:8px;margin-bottom:8px}@media (max-width: 767px){.o_navbar-form .form-group{margin-bottom:5px}}
 .o_collapse .o_navbar-form{width:auto;border:0;margin-left:0;margin-right:0;padding-top:0;padding-bottom:0;-webkit-box-shadow:none;box-shadow:none}.o_collapse .o_navbar-form.o_navbar-right:last-child{margin-right:-15px}.o_navbar-nav>li>.dropdown-menu{margin-top:0;border-top-right-radius:0;border-top-left-radius:0}.o_navbar-fixed-bottom .o_navbar-nav>li>.dropdown-menu{border-bottom-right-radius:0;border-bottom-left-radius:0}.o_navbar-btn{margin-top:8px;margin-bottom:8px}.o_navbar-btn.btn-sm,.btn-group-sm>.o_navbar-btn.btn{margin-top:10px;margin-bottom:10px}.o_navbar-btn.btn-xs,.btn-group-xs>.o_navbar-btn.btn{margin-top:14px;margin-bottom:14px}.o_navbar-text{margin-top:15px;margin-bottom:15px;color:#777}.o_collapse .o_navbar-text{float:left;margin-left:15px;margin-right:15px}.o_collapse .o_navbar-text.o_navbar-right:last-child{margin-right:0}.o_dropdown_tab{position:relative}.o_dropdown_tab>a:first-child{padding-right:30px}.o_dropdown_tab>a:first-child .o_icon-fw{display:none;position:absolute;top:0;left:10px;padding-top:3px;line-height:20px}.o_dropdown_tab>a:first-child span{display:block;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.o_dropdown_tab .o_navbar_tab_close{position:absolute;top:0px;right:10px;padding-left:0px;padding-right:0px;color:#d9534f;background-color:inherit}.o_dropdown_tab .o_navbar_tab_close:focus,.o_dropdown_tab .o_navbar_tab_close:hover{color:#c9302c;background-color:inherit}#o_navbar_more .dropdown-menu .divider:last-child{display:none}@media (min-width: 768px){#o_navbar_more .dropdown-menu{max-width:300px}}@media (max-width: 767px){#o_navbar_more>li{position:inherit}#o_navbar_more .dropdown-menu{left:0px;right:0px}#o_navbar_more .dropdown-menu a,#o_navbar_more .dropdown-menu i{line-height:30px}#o_navbar_more .dropdown-menu .o_navbar_tab_close{line-height:inherit}}.o_toolbar{position:relative;margin-bottom:20px;margin-top:-10px;border:1px solid #e7e7e7}.o_toolbar:before,.o_toolbar:after{content:" ";display:table}.o_toolbar:after{clear:both}@media (min-width: 768px){.o_toolbar{border-top-right-radius:4px;border-top-left-radius:4px;border-bottom-right-radius:4px;border-bottom-left-radius:4px}}.o_toolbar .o_breadcrumb:before,.o_toolbar .o_breadcrumb:after{content:" ";display:table}.o_toolbar .o_breadcrumb:after{clear:both}.o_toolbar .o_breadcrumb .breadcrumb{margin-bottom:0;padding:5px 9px;font-size:11px;line-height:15px;border-radius:0;background:#f5f5f5;border-top-right-radius:4px;border-top-left-radius:4px}.o_toolbar .o_breadcrumb .breadcrumb .o_breadcrumb_close{float:right;position:relative;margin:0 0 0 15px;vertical-align:middle}.o_toolbar .o_breadcrumb .breadcrumb .o_breadcrumb_close a{line-height:15px;color:#d9534f}.o_toolbar .o_breadcrumb .breadcrumb .o_breadcrumb_close a:hover{color:#b52b27}.o_toolbar .o_breadcrumb .breadcrumb .o_breadcrumb_close a i{font-size:16px}.o_toolbar .o_breadcrumb .breadcrumb .o_breadcrumb_close a span{display:none}.o_toolbar .o_breadcrumb .breadcrumb .o_breadcrumb_close:before{content:none}.o_toolbar .o_tools_container{text-align:center;min-height:37px;position:realtive;background-color:#f8f8f8;border-bottom-right-radius:4px;border-bottom-left-radius:4px;border-top:1px solid #e7e7e7}.o_toolbar .o_tools_container:before,.o_toolbar .o_tools_container:after{content:" ";display:table}.o_toolbar .o_tools_container:after{clear:both}@media (max-width: 991px){.o_toolbar .o_tools_container{min-height:35px}}@media (max-width: 767px){.o_toolbar .o_tools_container{min-height:22px;text-align:left}}.o_toolbar .o_tools_container a{color:#777;display:inline-block}.o_toolbar .o_tools_container a:hover{color:#333}.o_toolbar .o_tools_container a.o_disabled{color:#aaa !important}.o_toolbar .o_tools_container a.o_disabled:hover{color:#aaa !important}.o_toolbar .o_tools_container a.active{color:#428bca;background-color:transparent}.o_toolbar .o_tools_container .dropdown-menu a{display:block}.o_toolbar .o_tools_container .dropdown-menu a.active{color:#428bca;background-color:transparent}.o_toolbar .o_tools{margin-top:8px;margin-bottom:5px}.o_toolbar .o_tool,.o_toolbar .o_text{position:relative;margin:0 10px}.o_toolbar .o_tool:first-child,.o_toolbar .o_text:first-child{margin-left:0}.o_toolbar .o_tool:last-child,.o_toolbar .o_text:last-child{margin-right:0}.o_toolbar .o_tool a i,.o_toolbar .o_tool .o_disabled i,.o_toolbar .o_text a i,.o_toolbar .o_text .o_disabled i{font-size:18px}.o_toolbar .o_tool a span,.o_toolbar .o_tool .o_disabled span,.o_toolbar .o_text a span,.o_toolbar .o_text .o_disabled span{display:block;font-size:12px}.o_toolbar .o_tool a span.badge,.o_toolbar .o_tool .o_disabled span.badge,.o_toolbar .o_text a span.badge,.o_toolbar .o_text .o_disabled span.badge{position:absolute;right:50%;top:-18px;margin-right:-12px;font-size:13px}@media (min-width: 767px) and (max-width: 991px){.o_toolbar .o_tool a i,.o_toolbar .o_tool .o_disabled i,.o_toolbar .o_text a i,.o_toolbar .o_text .o_disabled i{font-size:16px}.o_toolbar .o_tool a span,.o_toolbar .o_tool .o_disabled span,.o_toolbar .o_text a span,.o_toolbar .o_text .o_disabled span{font-size:11px}.o_toolbar .o_tool a span.badge,.o_toolbar .o_tool .o_disabled span.badge,.o_toolbar .o_text a span.badge,.o_toolbar .o_text .o_disabled span.badge{top:-16.5px;margin-right:-11px;font-size:12px}}@media (max-width: 767px){.o_toolbar .o_tool a i,.o_toolbar .o_tool .o_disabled i,.o_toolbar .o_text a i,.o_toolbar .o_text .o_disabled i{font-size:20px}.o_toolbar .o_tool a span,.o_toolbar .o_tool .o_disabled span,.o_toolbar .o_text a span,.o_toolbar .o_text .o_disabled span{display:none}.o_toolbar .o_tool a span.badge,.o_toolbar .o_tool .o_disabled span.badge,.o_toolbar .o_text a span.badge,.o_toolbar .o_text .o_disabled span.badge{display:block;position:relative;top:0;left:0}}.o_toolbar .o_tool .o_chelp,.o_toolbar .o_text .o_chelp{position:relative;top:-1em;vertical-align:top}.o_toolbar .o_tool_next,.o_toolbar .o_tool_previous{padding:0;margin-top:5px;border:1px solid #ccc;background-color:#eee}.o_toolbar .o_tool_next a,.o_toolbar .o_tool_previous a{color:#777}.o_toolbar .o_tool_next a:hover,.o_toolbar .o_tool_previous a:hover{color:#333}.o_toolbar .o_tool_next a.o_disabled,.o_toolbar .o_tool_previous a.o_disabled{color:#aaa !important}.o_toolbar .o_tool_next a.o_disabled:hover,.o_toolbar .o_tool_previous a.o_disabled:hover{color:#aaa !important}.o_toolbar .o_tool_next i,.o_toolbar .o_tool_previous i{font-size:21px}@media (min-width: 767px) and (max-width: 991px){.o_toolbar .o_tool_next,.o_toolbar .o_tool_previous{margin-top:4px}.o_toolbar .o_tool_next i,.o_toolbar .o_tool_previous i{font-size:18px}}@media (max-width: 767px){.o_toolbar .o_tool_next,.o_toolbar .o_tool_previous{margin-top:0}.o_toolbar .o_tool_next i,.o_toolbar .o_tool_previous i{font-size:20px}}.o_toolbar .o_tool_previous{margin-left:10px;border-bottom-left-radius:4px;border-top-left-radius:4px;border-right:0}.o_toolbar .o_tool_next{border-bottom-right-radius:4px;border-top-right-radius:4px}.o_toolbar .o_tool_dropdown{position:relative;margin:0 10px}.o_toolbar .o_tool_dropdown:first-child{margin-left:0}.o_toolbar .o_tool_dropdown:last-child{margin-right:0}.o_toolbar .o_tool_dropdown a.dropdown-toggle i{font-size:18px}.o_toolbar .o_tool_dropdown a.dropdown-toggle span{display:block;font-size:12px}.o_toolbar .o_tool_dropdown a.dropdown-toggle .o_icon_caret{position:absolute;right:50%;top:4px;margin-right:-20px;font-size:14px}@media (min-width: 767px) and (max-width: 991px){.o_toolbar .o_tool_dropdown a.dropdown-toggle i{font-size:16px}.o_toolbar .o_tool_dropdown a.dropdown-toggle span,.o_toolbar .o_tool_dropdown a.dropdown-toggle .o_icon_caret{font-size:11px}.o_toolbar .o_tool_dropdown a.dropdown-toggle .o_icon_caret{top:4px;margin-right:-18px;font-size:12px}}@media (max-width: 767px){.o_toolbar .o_tool_dropdown a.dropdown-toggle i{font-size:20px}.o_toolbar .o_tool_dropdown a.dropdown-toggle span,.o_toolbar .o_tool_dropdown a.dropdown-toggle .o_icon_caret{display:none}}.o_toolbar .o_tool_dropdown .dropdown-menu{text-align:left}.o_toolbar .o_tools_left{float:left}.o_toolbar .o_tools_right{float:right}.o_toolbar .o_tools_right_edge{float:right}@media (max-width: 991px){.o_toolbar .o_tools{margin-top:6px;margin-bottom:4px}.o_toolbar .o_tool span{max-width:10em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.o_toolbar .o_tool,.o_toolbar .o_text,.o_toolbar .o_tool_dropdown{margin:0 5px}}@media (max-width: 767px){.o_toolbar .o_tools{margin-top:6px;margin-bottom:4px}.o_toolbar .o_tools .o_chelp{top:0;vertical-align:top}.o_toolbar .o_tools_right,.o_toolbar .o_tools_right,.o_toolbar .o_tools_center{float:left}.o_toolbar .o_tool,.o_toolbar .o_text,.o_toolbar .o_tool_dropdown{margin:0 0}}
diff --git a/src/main/webapp/static/themes/light/theme_ie_completions.css b/src/main/webapp/static/themes/light/theme_ie_completions.css
index ec656ed117d..62bbde0338c 100644
--- a/src/main/webapp/static/themes/light/theme_ie_completions.css
+++ b/src/main/webapp/static/themes/light/theme_ie_completions.css
@@ -1,3 +1,3 @@
-.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_lifecycle.o_active:hover{color:#2b542c}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_desc{margin-top:0.5em}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_bookmark{position:absolute;top:-1px;right:15px}@media (min-width: 768px) and (max-width: 991px){.o_coursetable.o_rendertype_custom .o_table_row .o_meta{height:80px;margin:0 120px}}@media (max-width: 767px){.o_coursetable.o_rendertype_custom .o_table_row .o_meta{height:50px;margin:0 0 0 75px;padding:0 0 0 1em}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_title{line-height:50px}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_title a{border-right:37px solid transparent;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_author,.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_bookmark,.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_lifecycle,.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_desc{display:none}}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_go_xs{position:absolute;top:0;right:0;padding:0 1em;height:50px;width:37px;line-height:50px;color:#fff;background-color:#428bca}.o_coursetable.o_rendertype_classic .o_rating_explanation{display:none}.o_coursetable.o_rendertype_classic .o_start,.o_coursetable.o_rendertype_classic .o_book{white-space:nowrap}.o_coursetable.o_rendertype_classic .o_repoentry_type{color:#555}.o_coursetable.o_rendertype_classic .o_repoentry_ac{color:#555}.o_catalog .o_level{position:relative;margin-bottom:10px;padding:0;border-top:1px solid #428bca;border-bottom:1px solid #428bca}.o_catalog .o_level .o_visual{height:180px}.o_catalog .o_level .o_meta{position:relative;min-height:180px;height:180px;overflow:hidden;margin:0 0 0 180px;padding:1em 0.5em 0.5em 2em}.o_catalog .o_level .o_meta .o_title{margin:0}.o_catalog .o_level .o_meta .o_title a{display:block;color:#428bca}.o_catalog .o_level .o_meta .o_title a:hover{color:#3071a9}.o_catalog .o_level .o_meta .o_desc{padding:1em 0 0.5em 0}@media (min-width: 768px) and (max-width: 991px){.o_catalog .o_level .o_visual{height:120px}.o_catalog .o_level .o_meta{min-height:120px;height:120px;margin:0 0 0 120px}}@media (max-width: 767px){.o_catalog .o_level .o_visual{height:75px}.o_catalog .o_level .o_meta{min-height:75px;height:75px;margin:0 0 0 75px;padding:0 0 0 1em}.o_catalog .o_level .o_meta .o_title{line-height:75px}.o_catalog .o_level .o_meta .o_desc{display:none}}.o_catalog .o_sublevels{position:relative;margin-bottom:20px}.o_catalog .o_sublevels:before,.o_catalog .o_sublevels:after{content:" ";display:table}.o_catalog .o_sublevels:after{clear:both}.o_catalog .o_sublevels .o_sublevel{position:relative;float:left;margin:0 20px 20px 0;width:180px}.o_catalog .o_sublevels .o_sublevel:last-child{margin-right:0}.o_catalog .o_sublevels .o_sublevel .o_visual{border:1px solid #428bca;position:relative;height:180px}.o_catalog .o_sublevels .o_sublevel .o_meta{position:absolute;left:0;bottom:0;width:100%;border:1px solid #428bca;border-top:0;background-color:rgba(255,255,255,0.8)}.o_catalog .o_sublevels .o_sublevel .o_meta .o_title{margin:0;text-align:center;line-height:2em;height:2em;width:100%;overflow:hidden}.o_catalog .o_sublevels .o_sublevel .o_meta .o_title a{display:block;color:#428bca}.o_catalog .o_sublevels .o_sublevel .o_meta .o_title a:hover{color:#3071a9}@media (min-width: 768px) and (max-width: 991px){.o_catalog .o_sublevels .o_sublevel{width:120px;margin:0 10px 10px 0}.o_catalog .o_sublevels .o_sublevel .o_visual{height:120px}.o_catalog .o_sublevels .o_sublevel .o_title{font-size:90%}}@media (max-width: 767px){.o_catalog .o_sublevels .o_sublevel{width:120px;margin:0 1px 1px 0}.o_catalog .o_sublevels .o_sublevel .o_visual{height:120px;width:120px}.o_catalog .o_sublevels .o_sublevel .o_title{font-size:90%}}
+.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_lifecycle.o_active{color:#3c763d}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_lifecycle.o_active:hover{color:#2b542c}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_desc{margin-top:0.5em}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_bookmark{position:absolute;top:-1px;right:15px}@media (min-width: 768px) and (max-width: 991px){.o_coursetable.o_rendertype_custom .o_table_row .o_meta{height:80px;margin:0 120px}}@media (max-width: 767px){.o_coursetable.o_rendertype_custom .o_table_row .o_meta{height:50px;margin:0 0 0 75px;padding:0 0 0 1em}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_title{line-height:50px}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_title a{border-right:37px solid transparent;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_author,.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_bookmark,.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_lifecycle,.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_desc{display:none}}.o_coursetable.o_rendertype_custom .o_table_row .o_meta .o_go_xs{position:absolute;top:0;right:0;padding:0 1em;height:50px;width:37px;line-height:50px;color:#fff;background-color:#428bca}.o_coursetable.o_rendertype_classic .o_rating_explanation{display:none}.o_coursetable.o_rendertype_classic .o_start,.o_coursetable.o_rendertype_classic .o_book{white-space:nowrap}.o_coursetable.o_rendertype_classic .o_repoentry_type{color:#555}.o_coursetable.o_rendertype_classic .o_repoentry_ac{color:#555}.o_catalog .o_level{position:relative;margin-bottom:10px;padding:0;border-top:1px solid #428bca;border-bottom:1px solid #428bca}.o_catalog .o_level .o_visual{height:180px}.o_catalog .o_level .o_meta{position:relative;min-height:180px;height:180px;overflow:hidden;margin:0 0 0 180px;padding:1em 0.5em 0.5em 2em}.o_catalog .o_level .o_meta .o_title{margin:0}.o_catalog .o_level .o_meta .o_title a{display:block;color:#428bca}.o_catalog .o_level .o_meta .o_title a:hover{color:#3071a9}.o_catalog .o_level .o_meta .o_desc{padding:1em 0 0.5em 0}@media (min-width: 768px) and (max-width: 991px){.o_catalog .o_level .o_visual{height:120px}.o_catalog .o_level .o_meta{min-height:120px;height:120px;margin:0 0 0 120px}}@media (max-width: 767px){.o_catalog .o_level .o_visual{height:75px}.o_catalog .o_level .o_meta{min-height:75px;height:75px;margin:0 0 0 75px;padding:0 0 0 1em}.o_catalog .o_level .o_meta .o_title{line-height:75px}.o_catalog .o_level .o_meta .o_desc{display:none}}.o_catalog .o_sublevels{position:relative;margin-bottom:20px}.o_catalog .o_sublevels:before,.o_catalog .o_sublevels:after{content:" ";display:table}.o_catalog .o_sublevels:after{clear:both}.o_catalog .o_sublevels .o_sublevel{position:relative;float:left;margin:0 20px 20px 0;width:180px}.o_catalog .o_sublevels .o_sublevel:last-child{margin-right:0}.o_catalog .o_sublevels .o_sublevel .o_visual{border:1px solid #428bca;position:relative;height:180px}.o_catalog .o_sublevels .o_sublevel .o_meta{position:absolute;left:0;bottom:0;width:100%;border:1px solid #428bca;border-top:0;background-color:rgba(255,255,255,0.8)}.o_catalog .o_sublevels .o_sublevel .o_meta .o_title{margin:0;text-align:center;line-height:2em;height:2em;width:100%;overflow:hidden}.o_catalog .o_sublevels .o_sublevel .o_meta .o_title a{display:block;color:#428bca}.o_catalog .o_sublevels .o_sublevel .o_meta .o_title a:hover{color:#3071a9}@media (min-width: 768px) and (max-width: 991px){.o_catalog .o_sublevels .o_sublevel{width:120px;margin:0 10px 10px 0}.o_catalog .o_sublevels .o_sublevel .o_visual{height:120px}.o_catalog .o_sublevels .o_sublevel .o_title{font-size:90%}}@media (max-width: 767px){.o_catalog .o_sublevels .o_sublevel{width:120px;margin:0 1px 1px 0}.o_catalog .o_sublevels .o_sublevel .o_visual{height:120px;width:120px}.o_catalog .o_sublevels .o_sublevel .o_title{font-size:90%}}
 .o_repo_details{position:relative}.o_repo_details .o_lead .o_media{float:right;margin-left:2em;margin-bottom:2em}.o_repo_details .o_lead h1 i{display:none}.o_repo_details .o_overview i{margin-right:0.5em}.o_repo_details .o_overview div{margin-bottom:0.25em}.o_repo_details .o_start,.o_repo_details .o_book{margin:2em 0}.o_repo_details .o_social:before,.o_repo_details .o_social:after{content:" ";display:table}.o_repo_details .o_social:after{clear:both}.o_repo_details .o_social .o_rating_wrapper{float:left}.o_repo_details .o_social .o_comments{margin-left:1em}@media (max-width: 767px){.o_repo_details .o_lead p{font-size:16px}.o_repo_details .o_lead .o_media{margin-top:0}}@media (max-width: 613px){.o_repo_details .o_subcolumn{width:100%}}
 .badge.o_midpub{background-color:#3c763d}.badge.o_midwarn{background-color:#8a6d3b}.badge.o_midlock{background-color:#31708f}.badge.o_miderr{background-color:#a94442}.badge.o_middel{background-color:#777}.o_course_editor_legend .badge{font-size:80%}.o_course_editor_legend .badge:before{content:none}.o_passed{color:#3c763d;font-weight:bold}.o_passed a:hover{color:#2b542c}.o_passed th{color:#333}.o_failed{color:#a94442;font-weight:bold}.o_failed a:hover{color:#66512c}.o_failed th{color:#333}.o_unknown{color:#8a6d3b;font-weight:bold}.o_unknown a:hover{color:#66512c}.o_unknown th{color:#333}.o_noinfo{color:#777}.o_course_run .o_toc .o_entry .o_shorttitle{border-bottom:1px solid #777}.o_course_run .o_toc .o_entry .o_displaytitle{margin-top:5px;color:#777}.o_course_run .o_toc .o_entry .o_objectives{margin-top:10px;font-style:italic}.o_course_run.o_titled_wrapper>h2 i{display:none}.o_st_peekview ul li{margin-bottom:0.5em}.o_cl_line{margin-bottom:10px;padding-bottom:5px}.o_cl_line.o_even{background-color:#f9f9f9}.o_cmembers .o_cmember{margin:12px 0}.o_cmembers .o_cmember .o_portrait{margin-right:10px}.o_cmembers .o_cmember .o_portrait img{width:50px;height:50px}.o_cmembers .o_cmember .o_cmember_info_wrapper{line-height:50px}.o_cmembers .o_cmember .o_cmember_info_wrapper .o_mail{margin-left:6px}table.table.o_qti_item_kprim>thead>tr>th,table.table.o_qti_item_kprim>tbody>tr>td{border:none}td.o_qti_item_kprim_input,th.o_qti_item_kprim_input{text-align:center}td.o_qti_item_kprim_input .radio,th.o_qti_item_kprim_input .radio{display:inline}div.o_qti_menu_section{margin-top:10px}div.o_qti_menu_item a,div.o_qti_menu_section a{text-decoration:none}div.o_qti_menu_item{padding:.1em}div.o_qti_menu_item_active{padding:.1em;font-weight:bold}div.o_qti_item_itemfeedback{background-color:#ffffff;border-color:#000000}div.o_qti_item_choice_option_flow{display:inline-block;padding:.5em;border:1px solid transparent}.d3chart .bar_green{fill:#5cb85c}.d3chart .bar_red{fill:#d9534f}.d3chart .bar_grey{fill:lightgrey}div.o_qti_statistics ul{list-style-type:none;padding:0;margin:0;font-size:90%}div.o_qti_statistics ul strong{font-weight:normal}div.o_qti_statistics ul li{padding-left:48px;margin-left:0;margin-bottom:10px}div.o_qti_statistics ul li.o_qti_statistics-ncorrect:before{font-size:125%;content:'\2A2F\00A0\00A0'}div.o_qti_statistics ul li.o_qti_statistics-correct:before{font-size:125%;content:'\2713\00A0\00A0'}div.o_qti_statistics ul li.o_qti_statistics-kplus:before{font-size:125%;content:'\2713\00A0\2A2F\00A0\00A0'}div.o_qti_statistics ul li.o_qti_statistics-kminus:before{font-size:125%;content:'\2A2F\00A0\2713\00A0\00A0'}div.o_qti_statistics ul li img{vertical-align:top}div.o_qti_statistics table.o_qti_statistics_figures tr{float:left}div.o_qti_statistics table.o_qti_statistics_figures tr:nth-child(2n+1){clear:left;padding-right:20px}div.o_qti_statistics table.o_qti_statistics_figures td{width:200px;padding-left:0}div.o_qti_statistics table.o_qti_statistics_figures td+td{width:100px}div.o_qti_statistics .o_qti_statistics_answer{background:#F5F5F5;padding:1px 2px;width:90%}div.o_qti_statistics div.o_qti_statistics_legend{padding-top:10px;width:470px;border:1px solid #ddd;border-radius:4px}div.o_qti_statistics div.o_qti_statistics_legend ul li .bar_green{background-color:#9dd53a}div.o_qti_statistics div.o_qti_statistics_legend ul li .bar_red{background-color:#f85032}div.o_qti_statistics div.o_qti_statistics_legend ul li .bar_grey{background-color:lightgrey}div.o_qti_metadatas .panel-body{border-top:none}.o_qti_menu_item_attempts:after,.o_qti_menu_item_attempts_marked:after{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.o_qti_menu_item_attempts:after{content:"\f11d"}.o_qti_menu_item_attempts_marked:after{content:"\f024";color:#428bca}.onyx_iframe{width:100%;height:100%;border:none;min-height:60em}.o_qti_print div.o_qti_statistics{width:680px}@media print{div.o_qti_statistics{width:680px}}#o_dev_tool #o_dev_tool_mode{width:1em;height:1em;float:left;border:1px solid #000;margin-right:5px}a.o_dev{position:absolute;left:0;top:0;z-index:4000;background:#f0ad4e;border:1px solid #d59645;border-top:none;border-left:none;border-radius:0 0 4px 0;color:#fff}a.o_dev:hover{color:#d9534f}.o_dev_w{margin:1px}.o_dev_w .o_dev_h{color:#000;font-size:8px;line-height:10px;margin:0}.o_dev_w .o_dev_h span{background:#f4c37d;border:1px solid #f0ad4e;border-bottom:0}.o_dev_w .o_dev_c{position:relative;border:1px dotted #eee}.o_dev_w .o_dev_c .o_dev_i{position:absolute;top:0px;left:24px;height:auto;width:auto;padding:5px;border:1px solid black;display:none;margin:0px;z-index:999;font-size:11px;background-color:#BBF}.o_dev_w.o_dev_m>.o_dev_c{border:1px solid #f0ad4e;margin:0px;background-color:#f8e9d4}.o_wikimod_nav .o_noti{margin:0}.o_wikimod_editform_wrapper{margin-top:30px}.o_wiki-file-deleted{text-decoration:line-through}.o_ep_icon_map:before{content:"\f0b1"}.o_ep_icon_collection:before{content:"\f0b1"}.o_ep_icon_page:before{content:"\f016"}.o_ep_icon_struct:before{content:"\f1b3"}.o_ep_icon_liveblog:before{content:"\f0a1"}.o_artefact_closed:before{content:"\f023"}.o_portfolio_toc .o_ep_link{float:right;margin-right:0px}.o_portfolio_toc .o_ep_commentlink{float:right;margin-right:10%}.o_portfolio_toc li.level1{font-size:1.2em;margin:1.2em 0 0.2em 0;border-bottom:1px solid #ddd}.o_portfolio_toc li.level2{padding-left:20px;font-size:1.1em;border-bottom:1px dotted #ddd}.o_portfolio_toc li.level3{padding-left:40px}.o_eportfolio_page .o_eportfolio_structure>h5{border-bottom:1px solid #ddd;margin-top:1.2em}.o_eportfolio_maps .panel{font-family:'Century Gothic', 'Apple Gothic', sans-serif;box-shadow:3px 3px 4px rgba(20,20,20,0.4)}.o_eportfolio_maps .panel-heading{padding:5px 10px}.o_eportfolio_maps h4,.o_eportfolio_maps .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps h2{padding:11px 15px;background:rgba(255,255,230,0.7) none;border-radius:6px}.o_eportfolio_maps .table>tbody>tr>td{border-top:none}.o_eportfolio_maps .panel-body{border-top:none}.o_eportfolio_maps .panel>.panel-body+.table{border-top:none}.panel-footer .o_ep_options{display:inline-block}.o_eportfolio_map{padding:0 20px 2px 3px;border-radius:6px 10px 6px 0;font-family:'Century Gothic', 'Apple Gothic', sans-serif}.o_map_header{padding-left:5px}.o_eportfolio_map ul.nav-tabs li:not(.active) a{background-color:rgba(240,240,240,0.7);border-radius:4px 4px 0 0}.o_eportfolio_edit{border-radius:4px 4px 0 0}.o_ep_actualpage,.o_eportfolio_edit{padding:15px;background-color:#fff}.o_ep_content{margin-top:15px}.o_ep_filter .o_date.form-inline .form-group,.o_ep_filter .o_date.navbar-form .form-group,.o_ep_filter .o_date.o_navbar-form .form-group{margin-left:8px}.o_eportfolio_share_policy_wrapper{border:1px solid #ddd;border-radius:4px}.o_eportfolio_share_header{padding:10px 15px;border-bottom:1px solid #ddd;background-color:#f5f5f5}.o_eportfolio_share_policy{padding:10px 15px}.o_map-default{background:#fafafa;background:#fafafa -webkit-gradient(linear, 37% 20%, 53% 100%, from(#fafafa), to(#efefef));background:#fafafa -moz-linear-gradient(43% 71% 101deg, #efefef, #fafafa);background:#fafafa -o-linear-gradient(#fafafa, #efefef);filter:progid:DXImageTransform.Microsoft.gradient(startColorStr='#fafafa', EndColorStr='#efefef');border:1px solid #efefef;border-left:3px solid rgba(188,188,188,0.8)}.o_eportfolio_maps .o_map-default h4,.o_eportfolio_maps .o_map-default .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-default h2{color:#444;background:none}.o_eportfolio_maps .o_map-default .panel-body,.o_eportfolio_maps .o_map-default td,.o_eportfolio_maps .o_map-default a{color:#000}.o_map-comic{background:#a2c3e8 none;font-family:'Comic Sans MS', 'Comic Sans', fantasy;border:1px solid #888;border-left:3px solid rgba(85,85,85,0.8)}.o_map-leather{background-color:#957352;background-image:-webkit-gradient(linear, left top, left bottom, color-stop(0%, rgba(248,248,248,0.7)), color-stop(100%, rgba(193,193,193,0.5))),url("../light/images/portfolio/white-leather-tile.jpg");background-image:-webkit-linear-gradient(top, rgba(248,248,248,0.7), rgba(193,193,193,0.5)),url("../light/images/portfolio/white-leather-tile.jpg");background-image:-moz-linear-gradient(top, rgba(248,248,248,0.7), rgba(193,193,193,0.5)),url("../light/images/portfolio/white-leather-tile.jpg");background-image:-ms-linear-gradient(top, rgba(248,248,248,0.7), rgba(193,193,193,0.5)),url("../light/images/portfolio/white-leather-tile.jpg");background-image:-o-linear-gradient(top, rgba(248,248,248,0.7), rgba(193,193,193,0.5)),url("../light/images/portfolio/white-leather-tile.jpg");background-image:linear-gradient(top, rgba(248,248,248,0.7), rgba(193,193,193,0.5)),url("../light/images/portfolio/white-leather-tile.jpg");font-family:Palatino, Georgia, serif;border:1px solid #888;border-left:3px solid rgba(85,85,85,0.8)}.o_eportfolio_maps .o_map-leather h4,.o_eportfolio_maps .o_map-leather .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-leather h2{background:rgba(243,230,225,0.3) none}.o_eportfolio_maps .o_map-leather .panel-body,.o_eportfolio_maps .o_map-leather td{color:#333}.o_eportfolio_maps .o_map-leather a{color:#fad9a4}.o_eportfolio_map.o_map-leather .o_map_header h4,.o_eportfolio_map.o_map-leather .o_map_header .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_map.o_map-leather .o_map_header h2,.o_eportfolio_map.o_map-leather .o_map_header p,.o_eportfolio_map.o_map-leather .o_map_header a,.o_eportfolio_map.o_map-leather .o_map_header span,.o_eportfolio_map.o_map-leather .o_map_header label{color:#333}.o_map-epmst-green{background-color:#ecf69a;border:1px solid #888;border-left:3px solid rgba(85,85,85,0.8)}.o_eportfolio_maps .o_map-epmst-green h4,.o_eportfolio_maps .o_map-epmst-green .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-epmst-green h2{color:#444}.o_eportfolio_maps .o_map-epmst-green .panel-body,.o_eportfolio_maps .o_map-epmst-green td,.o_eportfolio_maps .o_map-epmst-green a{color:#000}.o_map-epmst-green2{background:#99e44d;background:#99e44d -webkit-gradient(linear, 37% 20%, 53% 100%, from(#99e44d), to(#cbf1a5));background:#99e44d -moz-linear-gradient(43% 71% 101deg, #cbf1a5, #99e44d);background:#99e44d -o-linear-gradient(#99e44d, #cbf1a5);filter:progid:DXImageTransform.Microsoft.gradient(startColorStr='#99e44d', EndColorStr='#cbf1a5');border:1px solid #bbb;border-left:3px solid rgba(136,136,136,0.8)}.o_eportfolio_maps .o_map-epmst-green2 h4,.o_eportfolio_maps .o_map-epmst-green2 .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-epmst-green2 h2{color:#555}.o_eportfolio_maps .o_map-epmst-green2 .panel-body,.o_eportfolio_maps .o_map-epmst-green2 td,.o_eportfolio_maps .o_map-epmst-green2 a{color:#000}.o_map-epmst-green3{background:#dff0c1;background:#dff0c1 -webkit-gradient(linear, 37% 20%, 53% 100%, from(#dff0c1), to(#a0d346));background:#dff0c1 -moz-linear-gradient(43% 71% 101deg, #a0d346, #dff0c1);background:#dff0c1 -o-linear-gradient(#dff0c1, #a0d346);filter:progid:DXImageTransform.Microsoft.gradient(startColorStr='#dff0c1', EndColorStr='#a0d346');border:1px solid #bbb;border-left:3px solid rgba(136,136,136,0.8)}.o_eportfolio_maps .o_map-epmst-green3 h4,.o_eportfolio_maps .o_map-epmst-green3 .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-epmst-green3 h2{color:#555}.o_eportfolio_maps .o_map-epmst-green3 .panel-body,.o_eportfolio_maps .o_map-epmst-green3 td,.o_eportfolio_maps .o_map-epmst-green3 a{color:#000}.o_map-epmst-green4{background-color:#d7dbb5;border:1px solid #bbb;border-left:3px solid rgba(136,136,136,0.8)}.o_eportfolio_maps .o_map-epmst-green4 h4,.o_eportfolio_maps .o_map-epmst-green4 .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-epmst-green4 h2{color:#555}.o_eportfolio_maps .o_map-epmst-green4 .panel-body,.o_eportfolio_maps .o_map-epmst-green4 td,.o_eportfolio_maps .o_map-epmst-green4 a{color:#000}.o_map-epmst-red{background:#ffba71;background:#ffba71 -webkit-gradient(linear, 37% 20%, 53% 100%, from(#ffba71), to(#ffba99));background:#ffba71 -moz-linear-gradient(43% 71% 101deg, #ffba99, #ffba71);background:#ffba71 -o-linear-gradient(#ffba71, #ffba99);filter:progid:DXImageTransform.Microsoft.gradient(startColorStr='#ffba71', EndColorStr='#ffba99');border:1px solid #888;border-left:3px solid rgba(85,85,85,0.8)}.o_eportfolio_maps .o_map-epmst-red h4,.o_eportfolio_maps .o_map-epmst-red .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-epmst-red h2{color:#444}.o_eportfolio_maps .o_map-epmst-red .panel-body,.o_eportfolio_maps .o_map-epmst-red td,.o_eportfolio_maps .o_map-epmst-red a{color:#000}.o_map-epmst-red2{background:#ff9772;background:#ff9772 -webkit-gradient(linear, 37% 20%, 53% 100%, from(#ff9772), to(#ff9780));background:#ff9772 -moz-linear-gradient(43% 71% 101deg, #ff9780, #ff9772);background:#ff9772 -o-linear-gradient(#ff9772, #ff9780);filter:progid:DXImageTransform.Microsoft.gradient(startColorStr='#ff9772', EndColorStr='#ff9780');border:1px solid #888;border-left:3px solid rgba(85,85,85,0.8)}.o_eportfolio_maps .o_map-epmst-red2 h4,.o_eportfolio_maps .o_map-epmst-red2 .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-epmst-red2 h2{color:#444}.o_eportfolio_maps .o_map-epmst-red2 .panel-body,.o_eportfolio_maps .o_map-epmst-red2 td,.o_eportfolio_maps .o_map-epmst-red2 a{color:#000}.o_map-epmst-red3{background:#e8afbb;background:#e8afbb -webkit-gradient(linear, 37% 20%, 53% 100%, from(#e8afbb), to(#e8afa0));background:#e8afbb -moz-linear-gradient(43% 71% 101deg, #e8afa0, #e8afbb);background:#e8afbb -o-linear-gradient(#e8afbb, #e8afa0);filter:progid:DXImageTransform.Microsoft.gradient(startColorStr='#e8afbb', EndColorStr='#e8afa0');border:1px solid #888;border-left:3px solid rgba(85,85,85,0.8)}.o_eportfolio_maps .o_map-epmst-red3 h4,.o_eportfolio_maps .o_map-epmst-red3 .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-epmst-red3 h2{color:#444}.o_eportfolio_maps .o_map-epmst-red3 .panel-body,.o_eportfolio_maps .o_map-epmst-red3 td,.o_eportfolio_maps .o_map-epmst-red3 a{color:#000}.o_map-epmst-red4{background:#ffa800;background:#ffa800 -webkit-gradient(linear, 37% 20%, 53% 100%, from(#ffa800), to(#ffaf00));background:#ffa800 -moz-linear-gradient(43% 71% 101deg, #ffaf00, #ffa800);background:#ffa800 -o-linear-gradient(#ffa800, #ffaf00);filter:progid:DXImageTransform.Microsoft.gradient(startColorStr='#ffa800', EndColorStr='#ffaf00');border:1px solid #888;border-left:3px solid rgba(85,85,85,0.8)}.o_eportfolio_maps .o_map-epmst-red4 h4,.o_eportfolio_maps .o_map-epmst-red4 .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-epmst-red4 h2{color:#444}.o_eportfolio_maps .o_map-epmst-red4 .panel-body,.o_eportfolio_maps .o_map-epmst-red4 td,.o_eportfolio_maps .o_map-epmst-red4 a{color:#000}.o_map-epmst-blue{background:#00d2f8;background:#00d2f8 -webkit-gradient(linear, 37% 20%, 53% 100%, from(#00d2f8), to(#4a9ead));background:#00d2f8 -moz-linear-gradient(43% 71% 101deg, #4a9ead, #00d2f8);background:#00d2f8 -o-linear-gradient(#00d2f8, #4a9ead);filter:progid:DXImageTransform.Microsoft.gradient(startColorStr='#00d2f8', EndColorStr='#4a9ead');border:1px solid #888;border-left:3px solid rgba(85,85,85,0.8)}.o_eportfolio_maps .o_map-epmst-blue h4,.o_eportfolio_maps .o_map-epmst-blue .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-epmst-blue h2{color:#444}.o_eportfolio_maps .o_map-epmst-blue .panel-body,.o_eportfolio_maps .o_map-epmst-blue td,.o_eportfolio_maps .o_map-epmst-blue a{color:#000}.o_map-epmst-blue2{background-color:#c4f6ff;border:1px solid #888;border-left:3px solid rgba(85,85,85,0.8)}.o_eportfolio_maps .o_map-epmst-blue2 h4,.o_eportfolio_maps .o_map-epmst-blue2 .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-epmst-blue2 h2{color:#444}.o_eportfolio_maps .o_map-epmst-blue2 .panel-body,.o_eportfolio_maps .o_map-epmst-blue2 td,.o_eportfolio_maps .o_map-epmst-blue2 a{color:#000}.o_map-epmst-blue3{background-color:#b3e2f7;border:1px solid #888;border-left:3px solid rgba(85,85,85,0.8)}.o_eportfolio_maps .o_map-epmst-blue3{box-shadow:3px 3px 4px rgba(20,20,20,0.4)}.o_eportfolio_maps .o_map-epmst-blue3 h4,.o_eportfolio_maps .o_map-epmst-blue3 .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-epmst-blue3 h2{color:#444}.o_eportfolio_maps .o_map-epmst-blue3 .panel-body,.o_eportfolio_maps .o_map-epmst-blue3 td,.o_eportfolio_maps .o_map-epmst-blue3 a{color:#000}.o_map-epmst-blue4{background:#dee7f7;background:#dee7f7 -webkit-gradient(linear, 37% 20%, 53% 100%, from(#dee7f7), to(#c1e9fd));background:#dee7f7 -moz-linear-gradient(43% 71% 101deg, #c1e9fd, #dee7f7);background:#dee7f7 -o-linear-gradient(#dee7f7, #c1e9fd);filter:progid:DXImageTransform.Microsoft.gradient(startColorStr='#dee7f7', EndColorStr='#c1e9fd');border:1px solid #888;border-left:3px solid rgba(85,85,85,0.8)}.o_eportfolio_maps .o_map-epmst-blue4 h4,.o_eportfolio_maps .o_map-epmst-blue4 .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_eportfolio_maps .o_map-epmst-blue4 h2{color:#444}.o_eportfolio_maps .o_map-epmst-blue4 .panel-body,.o_eportfolio_maps .o_map-epmst-blue4 td,.o_eportfolio_maps .o_map-epmst-blue4 a{color:#000}.o_userbulk_changedcell{font-style:italic;font-weight:bold}body.o_dmz{background:transparent}body.o_dmz #o_bg{position:absolute;top:0;left:0;width:100%;height:100%;background:url("../light/images/learn-bg.jpg") 0px 50px/cover;background:linear-gradient(to right, rgba(255,255,255,0.1) 0.2%, rgba(255,255,255,0.6) 60%, rgba(255,255,255,0.8) 100%),url("../light/images/learn-bg.jpg");background-size:cover, cover;background-position:0px 50px,0px 50px}body.o_dmz #o_main_wrapper,body.o_dmz #o_main_wrapper #o_main_container{background:transparent}.o_login{padding-bottom:20px;padding-left:10%;padding-right:10%;text-align:right}.o_login .o_login_intro{padding-left:10%}.o_login .o_login_intro h1{margin-bottom:40px;color:#428bca}.o_login .o_login_intro .lead{color:#333}.o_login .o_login_intro .lead h1,.o_login .o_login_intro .lead h2,.o_login .o_login_intro .lead h3,.o_login .o_login_intro .lead h4,.o_login .o_login_intro .lead .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_login .o_login_intro .lead h2,.o_login .o_login_intro .lead h5{margin-bottom:20px;color:#428bca}.o_login .o_login_messages,.o_login .o_login_box{display:inline-block;width:400px;text-align:left}.o_login .o_login_messages .o_infomessage_wrapper{background:rgba(255,255,255,0.5);border:1px solid transparent;border-radius:4px;padding:6px 12px}.o_login .o_login_messages .o_infomessage_wrapper .o_info,.o_login .o_login_messages .o_infomessage_wrapper .o_warning,.o_login .o_login_messages .o_infomessage_wrapper .o_note{margin:0}.o_login .o_login_box{padding-top:10px}.o_login .o_login_providers{margin-bottom:6px;border-radius:4px;-webkit-box-shadow:0px 1px 10px -1px rgba(0,0,0,0.3);box-shadow:0px 1px 10px -1px rgba(0,0,0,0.3)}.o_login .o_login_providers a span{display:block;font-size:9px;padding-top:6px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.o_login .o_login_provider{background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:0px 1px 10px -1px rgba(0,0,0,0.3);box-shadow:0px 1px 10px -1px rgba(0,0,0,0.3)}.o_login .o_login_form{position:relative;padding:10px 12px}.o_login .o_login_form .o_login_pwd{position:absolute;bottom:2em;right:12px}.o_login .o_login_form .o_form .o_desc{margin:0 0 30px 0;padding:0;border-left:0;background-color:transparent}.o_login .o_login_register{display:block;line-height:2em;font-size:18px;text-align:center;color:#fff;background-color:#5bc0de;border-color:#46b8da;border-radius:4px;margin-top:16px;padding:10px 12px}.o_login .o_login_register:hover,.o_login .o_login_register:focus,.o_login .o_login_register:active,.o_login .o_login_register.active,.open>.o_login .o_login_register.dropdown-toggle{color:#fff;background-color:#31b0d5;border-color:#269abc}.o_login .o_login_register:active,.o_login .o_login_register.active,.open>.o_login .o_login_register.dropdown-toggle{background-image:none}.o_login .o_login_register.disabled,.o_login .o_login_register.disabled:hover,.o_login .o_login_register.disabled:focus,.o_login .o_login_register.disabled:active,.o_login .o_login_register.disabled.active,.o_login .o_login_register[disabled],.o_login .o_login_register[disabled]:hover,.o_login .o_login_register[disabled]:focus,.o_login .o_login_register[disabled]:active,.o_login .o_login_register[disabled].active,fieldset[disabled] .o_login .o_login_register,fieldset[disabled] .o_login .o_login_register:hover,fieldset[disabled] .o_login .o_login_register:focus,fieldset[disabled] .o_login .o_login_register:active,fieldset[disabled] .o_login .o_login_register.active{background-color:#5bc0de;border-color:#46b8da}.o_login .o_login_register .badge{color:#5bc0de;background-color:#fff}.o_login .o_login_register small{font-size:14px}.o_login .o_login_social{position:relative;padding:10px 12px}.o_login .o_login_social li{padding:10px 12px}.o_login .o_login_social li>a{display:block;line-height:2em;text-align:center;font-size:18px;border-radius:4px;padding:10px 12px}.o_login .o_login_social a.o_sel_auth_facebook{color:white;background-color:#4568b2}.o_login .o_login_social a.o_sel_auth_twitter{color:white;background-color:#2cc5ff}.o_login .o_login_social a.o_sel_auth_google{color:white;background-color:#e15f4f}.o_login .o_login_social a.o_sel_auth_linkedin{color:white;background-color:#0181bd}.o_login .o_login_social a.o_sel_auth_adfs{color:#19a6e1;background-color:#1a1a1a}@media (max-width: 767px){body.o_dmz #o_bg{background:none;display:none}.o_login{padding:0}.o_login .o_login_intro{padding:0;text-align:left}.o_login .o_login_box_wrapper{text-align:center;padding:0}.o_login .o_login_box{padding-left:0;padding-right:0}.o_login .o_login_box .o_login_providers,.o_login .o_login_box .o_login_provider{-webkit-box-shadow:none;box-shadow:none}.o_login .o_login_messages,.o_login .o_login_box{width:100%;display:block}}.o_home_main h1{text-align:center}.o_home_main .o_icon_rss{line-height:20px;vertical-align:middle}.o_showall{font-size:12px;text-align:right;margin-bottom:5px;margin-top:10px}.o_portlet{position:relative;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.1);box-shadow:0 1px 1px rgba(0,0,0,0.1)}.o_portlet .o_header{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;padding:6px 12px;border-bottom:1px solid #ddd;background-color:#f5f5f5;border-top-right-radius:4px;border-top-left-radius:4px}.o_portlet .o_content{padding:6px 12px}.o_portlet .o_portlet_table{margin:-12px;margin-bottom:-6px;margin-top:0}.o_portlet .o_table_empty.o_info{padding:6px}.o_portlet .o_toolbox{position:absolute;top:-1px;right:-1px;z-index:2;background-color:#fff;border:1px solid #faebcc;border-top-right-radius:4px;border-top-left-radius:4px;border-bottom-right-radius:4px;border-bottom-left-radius:4px;padding:6px 12px}.o_portlet .o_toolbox div{display:inline}.o_portlet .o_edit_shim{position:absolute;height:100%;width:100%;z-index:1;background:#fcf8e3;opacity:0.8}.o_inactive .o_header a{float:right;margin-left:12px;margin-top:10px}.o_portlet_dyk_q{margin-top:5px;font-style:italic}.o_portlet_dyk_a{margin:5px 0}.o_portlet_dyk_next{margin:5px 0;text-align:right}.o_library_icon:before{content:"\f19c"}.o_library ul{list-style:none;margin:0 0 15px 0;padding:0}.o_library ul ul{margin:0}.o_library_overview .o_library_newest_files ul li{float:left;margin-right:15px}.o_library_item{margin-bottom:10px;position:relative}.o_library_item .o_library_visual,.o_library_item .o_library_extra,.o_library_item .o_library_meta{margin-top:15px}.o_library_item .o_library_visual{float:left;background-color:#fff;border-radius:4px;border:1px solid #ddd}.o_library_item .o_library_visual .o_thumbnail_available,.o_library_item .o_library_visual .o_thumbnail_unavailable{background-size:146px auto;width:150px !important;height:150px !important;background-repeat:no-repeat;background-position:50% 50%}.o_library_item .o_library_visual .o_thumbnail_available:before,.o_library_item .o_library_visual .o_thumbnail_unavailable:before{content:none}.o_library_item .o_library_visual .o_thumbnail_available{background-size:146px auto}.o_library_item .o_library_visual .o_thumbnail_unavailable{display:none}.o_library_item .o_library_extra{float:right;width:200px}.o_library_item .o_library_meta{clear:both}.o_library_item .o_library_meta .o_library_desc{padding-bottom:10px}.o_library_item .o_library_meta small{display:block;word-wrap:break-word}.o_library_item h4,.o_library_item .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_library_item h2{margin:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;line-height:normal}.o_library_item .btn{display:block;margin-bottom:0.5em}.o_library_item .o_comments{display:inline-block}.o_library_item .table{table-layout:fixed;word-wrap:break-word;margin-bottom:0}.o_library_item p.o_library_show_more{text-align:right;margin:0;padding-top:20px}.o_library_item .o_library_more{padding-top:20px;display:none}.o_library_folder{margin-top:-20px}.o_ratings_and_comments .o_rating_title,.o_ratings_and_comments .o_rating_explanation{display:none}@media (min-width: 768px){.o_library_item .o_library_meta{clear:none;margin-left:150px;margin-right:200px;padding:0 10px}.o_library_item .o_library_more{display:none}.o_library_item .o_library_more table tbody{vertical-align:top}.o_library_item .o_library_more table tr,.o_library_item .o_library_more table th,.o_library_item .o_library_more table td{display:inline-block}.o_library_item .o_library_more table tr{width:49%}.o_library_item .o_library_more table th{width:30%}.o_library_item .o_library_more table td{width:70%}}.o_library_item_compact .o_library_extra{width:auto}.o_library_item_compact .o_library_meta{padding:0 10px 0 0;margin:0;overflow:hidden}.o_library_item_compact .btn{display:inline-block}.o_library_item_compact h4,.o_library_item_compact .o_cal .fc-header-title h2,.o_cal .fc-header-title .o_library_item_compact h2{overflow:hidden;margin-right:70px}.o_library_item_compact h4 a,.o_library_item_compact .o_cal .fc-header-title h2 a,.o_cal .fc-header-title .o_library_item_compact h2 a{text-overflow:ellipsis;white-space:nowrap}.o_library_item_compact p.o_library_show_more{padding:20px;position:absolute;top:0;right:0}span.o_translation_i18nitem{position:relative !important}span.o_translation_i18nitem a.o_translation_i18nitem_launcher{position:absolute !important;z-index:100 !important;width:18px !important;height:20px !important;top:0 !important;left:5px !important;background:#fff;border:1px solid #428bca !important;border-radius:3px;text-align:center;padding:0 !important}.o_user_infos{position:relative}.o_user_infos .o_user_portrait{position:absolute;top:0;left:15px;width:100px;height:100px}.o_user_infos .o_user_infos_inner{margin:0 30px 0 100px}.o_user_infos .o_user_infos_inner table{margin:0 30px 15px 30px}.o_members_pagination{text-align:center}.o_visitingcard .o_portrait_avatar,.o_visitingcard .o_portrait_dummy,.o_visitingcard .o_portrait_dummy_female_big,.o_visitingcard .o_portrait_dummy_male_big,.o_visitingcard .o_portrait_anonymous{width:66px;height:66px;margin-right:10px}@media (max-width: 767px){.o_visitingcard .o_portrait_avatar,.o_visitingcard .o_portrait_dummy,.o_visitingcard .o_portrait_dummy_female_big,.o_visitingcard .o_portrait_dummy_male_big,.o_visitingcard .o_portrait_anonymous{width:50px;height:50px;margin:5px 5px 0 0}}.ui-widget{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:100%}.ui-widget-header{border-top:none;border-left:none;border-right:none;border-bottom:1px solid #eee;background:#fff;font-weight:bold}.ui-icon,.ui-widget-content .ui-icon,.ui-widget-header .ui-icon,.ui-state-default .ui-icon,.ui-state-hover .ui-icon,.ui-state-focus .ui-icon,.ui-state-active .ui-icon,.ui-state-highlight .ui-icon,.ui-state-error .ui-icon,.ui-state-error-text .ui-icon{background:none;background-image:none}.ui-dialog{-webkit-box-shadow:0px 1px 8px -1px rgba(0,0,0,0.35);box-shadow:0px 1px 8px -1px rgba(0,0,0,0.35);background-color:#fefefe}.ui-dialog .ui-widget-header .ui-dialog-title{color:#428bca;font-weight:500;font-family:inherit;line-height:1.1}.ui-dialog .ui-widget-header .ui-dialog-titlebar-close:before{content:"\f00d" !important}.ui-dialog .ui-widget-header .ui-dialog-titlebar-close{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;font-size:120%;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.ui-dialog .ui-widget-header .ui-button.ui-corner-all{border:none !important;background:#fff !important}.ui-dialog .ui-widget-content{border-color:#fff;padding:5px}.ui-dialog .ui-dialog-titlebar{padding:4px 30px 4px 7px;margin:-2px -2px 0 -2px;background-color:#eee}.ui-dialog.ui-corner-all{border-radius:4px}.ui-dialog.ui-widget-content{border:1px solid transparent}.ui-dialog.o_modal-ui div.ui-dialog-buttonpane{display:none}.ui-datepicker{z-index:2000 !important;-webkit-box-shadow:0px 1px 5px -1px rgba(0,0,0,0.15);box-shadow:0px 1px 5px -1px rgba(0,0,0,0.15)}.ui-datepicker .ui-widget-header .ui-corner-all,.ui-datepicker .ui-widget-header .ui-datepicker-next.ui-corner-all{border:none !important;background:#fff !important}.ui-datepicker .ui-widget-header .ui-icon.ui-icon-circle-triangle-e:before{content:"\f061";font-weight:normal;color:black}.ui-datepicker .ui-widget-header .ui-icon.ui-icon-circle-triangle-w:before{content:"\f060";font-weight:normal;color:black}.ui-datepicker .ui-widget-header .ui-icon.ui-icon-circle-triangle-e,.ui-datepicker .ui-widget-header .ui-icon.ui-icon-circle-triangle-w{font-family:'FontAwesome';display:inline-block;background-image:none;background-position:0 0;font-weight:normal;text-indent:0;color:white}.ui-datepicker .ui-widget-header .ui-datepicker .ui-datepicker-prev-hover,.ui-datepicker .ui-widget-header .ui-datepicker .ui-datepicker-next-hover{top:2px}.ui-datepicker .ui-state-default{background:#eee}.ui-datepicker .ui-state-highlight,.ui-datepicker .ui-widget-content .ui-state-highlight{border:1px solid #357ebd;background:#428bca;color:#fff}.ui-datepicker.ui-corner-all{border-radius:4px}.ui-datepicker.ui-widget-content{border:1px solid transparent}label.mce-label{display:inline;max-width:150px;margin-bottom:0;font-weight:normal}@media print{a[href]:after{content:""}#o_header_wrapper,#o_offcanvas_right,#o_navbar_wrapper,#o_footer_wrapper,#o_toplink,#o_main_left,#o_main_right,#o_main_toolbar,#jsMath_PrintWarning,.o_noti,.o_opener,.o_hide,.o_noprint{display:none !important}.o_print_break_avoid{page-break-inside:avoid}.o_print_break_before{page-break-before:always}body.o_dmz{background:white !important}}
\ No newline at end of file
diff --git a/src/test/java/org/olat/course/certificate/manager/CertificatesManagerTest.java b/src/test/java/org/olat/course/certificate/manager/CertificatesManagerTest.java
index 8ab92e3d068..1d244037145 100644
--- a/src/test/java/org/olat/course/certificate/manager/CertificatesManagerTest.java
+++ b/src/test/java/org/olat/course/certificate/manager/CertificatesManagerTest.java
@@ -23,6 +23,7 @@ import java.io.File;
 import java.net.URISyntaxException;
 import java.net.URL;
 import java.util.Calendar;
+import java.util.Date;
 import java.util.List;
 import java.util.UUID;
 
@@ -33,6 +34,7 @@ import org.olat.core.commons.persistence.DB;
 import org.olat.core.id.Identity;
 import org.olat.core.util.vfs.VFSLeaf;
 import org.olat.course.certificate.Certificate;
+import org.olat.course.certificate.CertificateLight;
 import org.olat.course.certificate.CertificateTemplate;
 import org.olat.course.certificate.CertificatesManager;
 import org.olat.course.certificate.model.CertificateInfos;
@@ -93,15 +95,86 @@ public class CertificatesManagerTest extends OlatTestCase {
 		Assert.assertNotNull(certificate);
 		Assert.assertNotNull(certificate.getKey());
 		Assert.assertNotNull(certificate.getUuid());
-		Assert.assertNotNull(certificate.getName());
 		Assert.assertEquals(entry.getOlatResource().getKey(), certificate.getArchivedResourceKey());
 		
-		//check if the pdf exists
-		VFSLeaf certificateFile = certificatesManager.getCertificateLeaf(certificate);
+		//need to sleep
+		sleep(2000);
+		
+		//check if the pdf exists / flush cache, reload the entry with the updated path
+		dbInstance.commitAndCloseSession();
+		Certificate reloadCertificate = certificatesManager.getCertificateById(certificate.getKey());
+		VFSLeaf certificateFile = certificatesManager.getCertificateLeaf(reloadCertificate);
 		Assert.assertNotNull(certificateFile);
 		Assert.assertTrue(certificateFile.exists());
 	}
 	
+	@Test
+	public void loadCertificate() {
+		Identity identity = JunitTestHelper.createAndPersistIdentityAsRndUser("cer-1");
+		RepositoryEntry entry = JunitTestHelper.deployDemoCourse(identity);
+		dbInstance.commitAndCloseSession();
+		
+		CertificateInfos certificateInfos = new CertificateInfos(identity, 5.0f, Boolean.TRUE);
+		Certificate certificate = certificatesManager.generateCertificate(certificateInfos, entry, null, null);
+		Assert.assertNotNull(certificate);
+		dbInstance.commitAndCloseSession();
+		
+		//full
+		Certificate reloadedCertificate = certificatesManager.getCertificateById(certificate.getKey());
+		Assert.assertNotNull(reloadedCertificate);
+		Assert.assertEquals(certificate, reloadedCertificate);
+		Assert.assertNotNull(reloadedCertificate.getUuid());
+		Assert.assertEquals(certificate.getUuid(), reloadedCertificate.getUuid());
+		Assert.assertEquals(entry.getDisplayname(), reloadedCertificate.getCourseTitle());
+		Assert.assertEquals(identity, reloadedCertificate.getIdentity());
+		
+		//light
+		CertificateLight reloadedLight = certificatesManager.getCertificateLightById(certificate.getKey());
+		Assert.assertNotNull(reloadedLight);
+		Assert.assertEquals(certificate.getKey(), reloadedLight.getKey());
+		Assert.assertEquals(entry.getDisplayname(), reloadedLight.getCourseTitle());
+		Assert.assertEquals(identity.getKey(), reloadedLight.getIdentityKey());
+		Assert.assertEquals(entry.getOlatResource().getKey(), reloadedLight.getOlatResourceKey());
+		
+		//uuid
+		Certificate reloadedUuid = certificatesManager.getCertificateByUuid(certificate.getUuid());
+		Assert.assertNotNull(reloadedUuid);
+		Assert.assertEquals(certificate, reloadedUuid);
+		Assert.assertEquals(entry.getDisplayname(), reloadedUuid.getCourseTitle());
+		Assert.assertEquals(identity, reloadedUuid.getIdentity());
+		
+		//boolean
+		boolean has = certificatesManager.hasCertificate(identity, entry.getOlatResource().getKey());
+		Assert.assertTrue(has);
+	}
+	
+	@Test
+	public void loadLastCertificate() {
+		Identity identity = JunitTestHelper.createAndPersistIdentityAsRndUser("cer-1");
+		RepositoryEntry entry = JunitTestHelper.deployDemoCourse(identity);
+		dbInstance.commitAndCloseSession();
+		
+		CertificateInfos certificateInfos = new CertificateInfos(identity, 5.0f, Boolean.TRUE);
+		Certificate certificate = certificatesManager.generateCertificate(certificateInfos, entry, null, null);
+		Assert.assertNotNull(certificate);
+		dbInstance.commitAndCloseSession();
+		
+		//per resource
+		Certificate reloadedCertificate = certificatesManager.getLastCertificate(identity, entry.getOlatResource().getKey());
+		Assert.assertNotNull(reloadedCertificate);
+		Assert.assertEquals(certificate, reloadedCertificate);
+		
+		//all
+		List<CertificateLight> allCertificates = certificatesManager.getLastCertificates(identity);
+		Assert.assertNotNull(allCertificates);
+		Assert.assertEquals(1, allCertificates.size());
+		CertificateLight allCertificate = allCertificates.get(0);
+		Assert.assertEquals(certificate.getKey(), allCertificate.getKey());
+		Assert.assertEquals(entry.getDisplayname(), allCertificate.getCourseTitle());
+		Assert.assertEquals(identity.getKey(), allCertificate.getIdentityKey());
+		Assert.assertEquals(entry.getOlatResource().getKey(), allCertificate.getOlatResourceKey());
+	}
+	
 	@Test
 	public void certificateNotifications_courseCoach() throws URISyntaxException {
 		Identity owner = JunitTestHelper.createAndPersistIdentityAsRndUser("cer-2");
@@ -179,4 +252,92 @@ public class CertificatesManagerTest extends OlatTestCase {
 		Assert.assertEquals(1, participantNotifications.size());
 		Assert.assertTrue(participantNotifications.contains(certificate1));
 	}
+	
+	@Test
+	public void uploadCertificate() throws URISyntaxException {
+		Identity identity = JunitTestHelper.createAndPersistIdentityAsRndUser("cer-1");
+		RepositoryEntry entry = JunitTestHelper.deployDemoCourse(identity);
+		dbInstance.commitAndCloseSession();
+		
+		Calendar cal = Calendar.getInstance();
+		cal.set(Calendar.MINUTE, 0);
+		cal.set(Calendar.SECOND, 0);
+		cal.set(Calendar.MILLISECOND, 0);
+		cal.set(Calendar.YEAR, 2012);
+		Date creationDate = cal.getTime();
+		URL certificateUrl = CertificatesManagerTest.class.getResource("template.pdf");
+		Assert.assertNotNull(certificateUrl);
+		File certificateFile = new File(certificateUrl.toURI());
+		
+		Certificate certificate = certificatesManager.uploadCertificate(identity, creationDate, entry.getOlatResource(), certificateFile);
+		Assert.assertNotNull(certificate);
+		Assert.assertNotNull(certificate.getKey());
+		Assert.assertNotNull(certificate.getUuid());
+		Assert.assertEquals(entry.getDisplayname(), certificate.getCourseTitle());
+		Assert.assertEquals(identity, certificate.getIdentity());
+		
+		dbInstance.commitAndCloseSession();
+		
+		//double check
+		Certificate reloadedCertificate = certificatesManager.getCertificateById(certificate.getKey());
+		Assert.assertNotNull(reloadedCertificate);
+		Assert.assertNotNull(reloadedCertificate.getUuid());
+		Assert.assertEquals(entry.getDisplayname(), reloadedCertificate.getCourseTitle());
+		Assert.assertEquals(identity, reloadedCertificate.getIdentity());
+		Assert.assertEquals(entry.getOlatResource().getKey(), reloadedCertificate.getArchivedResourceKey());
+		Assert.assertEquals(creationDate, reloadedCertificate.getCreationDate());
+		
+		//the file
+		VFSLeaf savedCertificateFile = certificatesManager.getCertificateLeaf(reloadedCertificate);
+		Assert.assertNotNull(savedCertificateFile);
+		Assert.assertTrue(savedCertificateFile.exists());
+		
+		//load last
+		Certificate lastCertificate = certificatesManager.getLastCertificate(identity, entry.getOlatResource().getKey());
+		Assert.assertNotNull(lastCertificate);
+		Assert.assertEquals(certificate, lastCertificate);
+	}
+	
+	@Test
+	public void uploadStandalone() throws URISyntaxException {
+		Identity identity = JunitTestHelper.createAndPersistIdentityAsRndUser("cer-1");
+		dbInstance.commitAndCloseSession();
+		
+		String courseTitle = "Unkown course";
+		Long resourceKey = 4l;
+		Calendar cal = Calendar.getInstance();
+		cal.set(Calendar.MINUTE, 0);
+		cal.set(Calendar.SECOND, 0);
+		cal.set(Calendar.MILLISECOND, 0);
+		cal.set(Calendar.YEAR, 2012);
+		Date creationDate = cal.getTime();
+		URL certificateUrl = CertificatesManagerTest.class.getResource("template.pdf");
+		Assert.assertNotNull(certificateUrl);
+		File certificateFile = new File(certificateUrl.toURI());
+		
+		Certificate certificate = certificatesManager
+				.uploadStandaloneCertificate(identity, creationDate, courseTitle, resourceKey, certificateFile);
+		Assert.assertNotNull(certificate);
+		Assert.assertNotNull(certificate.getKey());
+		Assert.assertNotNull(certificate.getUuid());
+		Assert.assertEquals(courseTitle, certificate.getCourseTitle());
+		Assert.assertEquals(identity, certificate.getIdentity());
+		
+		dbInstance.commitAndCloseSession();
+		
+		//load by id
+		Certificate reloadedCertificate = certificatesManager.getCertificateById(certificate.getKey());
+		Assert.assertNotNull(reloadedCertificate);
+		Assert.assertNotNull(reloadedCertificate.getUuid());
+		Assert.assertEquals(courseTitle, reloadedCertificate.getCourseTitle());
+		Assert.assertEquals(identity, reloadedCertificate.getIdentity());
+		Assert.assertEquals(resourceKey, reloadedCertificate.getArchivedResourceKey());
+		Assert.assertEquals(creationDate, reloadedCertificate.getCreationDate());
+		
+		//load last
+		Certificate lastCertificate = certificatesManager.getLastCertificate(identity, resourceKey);
+		Assert.assertNotNull(lastCertificate);
+		Assert.assertEquals(certificate.getKey(), lastCertificate.getKey());
+		Assert.assertEquals(reloadedCertificate, lastCertificate);
+	}
 }
diff --git a/src/test/java/org/olat/restapi/CertificationTest.java b/src/test/java/org/olat/restapi/CertificationTest.java
index af41aef45a2..b3a5abc97ab 100644
--- a/src/test/java/org/olat/restapi/CertificationTest.java
+++ b/src/test/java/org/olat/restapi/CertificationTest.java
@@ -118,6 +118,9 @@ public class CertificationTest extends OlatJerseyTestCase {
 		Assert.assertEquals(200, response.getStatusLine().getStatusCode());
 		EntityUtils.consume(response.getEntity());
 		
+		//async process mean sleep a little
+		sleep(2000);
+		
 		//check certificate
 		Certificate certificate = certificatesManager.getLastCertificate(assessedIdentity, entry.getOlatResource().getKey());
 		Assert.assertNotNull(certificate);
-- 
GitLab