diff --git a/src/main/java/org/olat/core/commons/persistence/_spring/core_persistence.xml b/src/main/java/org/olat/core/commons/persistence/_spring/core_persistence.xml
index 1c43c1649e23ddf8c30d82eb7cf272d80e785cc2..3e2e826da072353f7faea085128acc4bd53759b5 100644
--- a/src/main/java/org/olat/core/commons/persistence/_spring/core_persistence.xml
+++ b/src/main/java/org/olat/core/commons/persistence/_spring/core_persistence.xml
@@ -75,7 +75,9 @@
 		<mapping-file>org/olat/portfolio/model/notification/Notifications.hbm.xml</mapping-file>
 		<mapping-file>org/olat/portfolio/model/restriction/CollectRestriction.hbm.xml</mapping-file>
 		<mapping-file>org/olat/core/commons/services/commentAndRating/impl/UserCommentImpl.hbm.xml</mapping-file>
+		<!-- 
 		<mapping-file>org/olat/core/commons/services/commentAndRating/impl/UserRatingImpl.hbm.xml</mapping-file>
+		-->
 		<mapping-file>org/olat/core/commons/services/mark/impl/MarkImpl.hbm.xml</mapping-file>
 		<mapping-file>org/olat/core/commons/services/tagging/model/TagImpl.hbm.xml</mapping-file>
 		<mapping-file>org/olat/core/util/mail/model/DBMail.hbm.xml</mapping-file>
@@ -91,6 +93,7 @@
 		<class>org.olat.core.dispatcher.mapper.model.PersistedMapper</class>
 		<class>org.olat.core.commons.services.taskexecutor.model.PersistentTask</class>
 		<class>org.olat.core.commons.services.taskexecutor.model.PersistentTaskModifier</class>
+		<class>org.olat.core.commons.services.commentAndRating.impl.UserRatingImpl</class>
 		<class>org.olat.course.assessment.model.UserCourseInfosImpl</class>
 		<class>org.olat.group.model.ContactParticipantView</class>
 		<class>org.olat.group.model.ContactOwnerView</class>
diff --git a/src/main/java/org/olat/core/commons/services/_spring/servicesCorecontext.xml b/src/main/java/org/olat/core/commons/services/_spring/servicesCorecontext.xml
index 4c853341d0a2d51d745dfaaaac347f135f6b1d5f..90a6bf264edbb403d05b764626ca24c2449938e0 100644
--- a/src/main/java/org/olat/core/commons/services/_spring/servicesCorecontext.xml
+++ b/src/main/java/org/olat/core/commons/services/_spring/servicesCorecontext.xml
@@ -22,8 +22,8 @@
 	<!-- Define the manager implementation used in comment and rating service -->
 	<bean id="userCommentsManager" 
 		class="org.olat.core.commons.services.commentAndRating.impl.UserCommentsManagerImpl" scope="prototype" />
-	<bean id="userRatingsManager" 
-		class="org.olat.core.commons.services.commentAndRating.impl.UserRatingsManagerImpl" scope="prototype" />
-	
-
+			
+	<bean id="userRatingsManager" class="org.olat.core.commons.services.commentAndRating.impl.UserRatingsManagerImpl" scope="prototype">
+		<property name="userRatingsDAO" ref="userRatingsDAO"/>
+	</bean>
 </beans>
\ No newline at end of file
diff --git a/src/main/java/org/olat/core/commons/services/commentAndRating/impl/UserRatingImpl.hbm.xml b/src/main/java/org/olat/core/commons/services/commentAndRating/impl/UserRatingImpl.hbm.xml
deleted file mode 100644
index 43ff0bd48893c461f0c0c6cabf86f85332771e95..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/core/commons/services/commentAndRating/impl/UserRatingImpl.hbm.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0"?>
-<!DOCTYPE hibernate-mapping PUBLIC
-	"-//Hibernate/Hibernate Mapping DTD//EN"
-	"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
-<hibernate-mapping default-lazy="false">
-  <class name="org.olat.core.commons.services.commentAndRating.impl.UserRatingImpl" table="o_userrating">
-  		
-	<cache usage="transactional" />
-
-	<id name="key" type="long" column="rating_id"	unsaved-value="null">
-		<generator class="hilo"/>
-	</id>
-
-	<version name="version" access="field" column="version" type="int"/>
-	<property  name="creationDate" column="creationdate" type="timestamp" />   
-	
-	<property  name="lastModified" column="lastmodified" type="timestamp" />
-	 	
-	<property name="resName" type="string" >
-		<column name="resname" not-null="true" length="50" index="resname_idx2"/>
-	</property>    	
-
-	<property name="resId" type="long"> 
-		<column name="resid" not-null="true" index="id_idx4" />    	
-	</property>    
-
-	<property name="resSubPath" type="string" >
-		<column name="ressubpath" length="2048" sql-type="varchar(2048)" index="subpath_idx3"  not-null="false"/>
-	</property>    	
-	
-	<many-to-one name="creator" class="org.olat.basesecurity.IdentityImpl" 
-		column="creator_id" outer-join="true" cascade="none" not-null="true"/>     	
-	
-	<property name="rating" unique="false" type="int" not-null="false">
-		<column name="rating" />
-	</property> 
-
-  </class>
-</hibernate-mapping>
\ No newline at end of file
diff --git a/src/main/java/org/olat/core/commons/services/commentAndRating/impl/UserRatingImpl.java b/src/main/java/org/olat/core/commons/services/commentAndRating/impl/UserRatingImpl.java
index a0a2f666467cee7ad13d298b485db2cd21048519..27c0dda6e4d4773376deab9272be333b7d8e3991 100644
--- a/src/main/java/org/olat/core/commons/services/commentAndRating/impl/UserRatingImpl.java
+++ b/src/main/java/org/olat/core/commons/services/commentAndRating/impl/UserRatingImpl.java
@@ -21,10 +21,24 @@ package org.olat.core.commons.services.commentAndRating.impl;
 
 import java.util.Date;
 
-import org.olat.core.commons.persistence.PersistentObject;
+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.commons.services.commentAndRating.model.UserRating;
+import org.olat.core.id.CreateInfo;
 import org.olat.core.id.Identity;
 import org.olat.core.id.OLATResourceable;
+import org.olat.core.id.Persistable;
 
 /**
  * Description:<br>
@@ -35,20 +49,44 @@ import org.olat.core.id.OLATResourceable;
  * 
  * @author gnaegi
  */
-public class UserRatingImpl extends PersistentObject implements UserRating {
+@Entity(name="userrating")
+@Table(name="o_userrating")
+public class UserRatingImpl implements Persistable, CreateInfo,  UserRating {
+
+	private static final long serialVersionUID = -5830951461259559219L;
+
+	@Id
+	@GeneratedValue(generator = "system-uuid")
+	@GenericGenerator(name = "system-uuid", strategy = "hilo")
+	@Column(name="rating_id", nullable=false, unique=true, insertable=true, updatable=false)
+	private Long key;
+
+	@Column(name="version", nullable=false, insertable=true, updatable=false)
+	private int version = 0;
+	
+	@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 modifiedDate;
+
+	@Column(name="resname", nullable=false, insertable=true, updatable=false)
 	private String resName;
+	@Column(name="resid", nullable=false, insertable=true, updatable=false)
 	private Long resId;
+	@Column(name="ressubpath", nullable=true, insertable=true, updatable=false)
 	private String resSubPath;
-	
+
+	@ManyToOne(targetEntity=IdentityImpl.class,fetch=FetchType.LAZY,optional=false)
+	@JoinColumn(name="creator_id", nullable=false, updatable=false)
 	private Identity creator;
+	@Column(name="rating", nullable=false, insertable=true, updatable=true)
 	private Integer rating;
 	
-	private Date modifiedDate;
 
-	/**
-	 * Default constructor for hibernate, don't use this!
-	 */
-	private UserRatingImpl() {
+	public UserRatingImpl() {
 		// 
 	}
 
@@ -59,14 +97,30 @@ public class UserRatingImpl extends PersistentObject implements UserRating {
 	 * @param creator
 	 * @param ratingValue
 	 */
-	UserRatingImpl(OLATResourceable ores, String subpath, Identity creator, Integer ratingValue) {
+	public UserRatingImpl(OLATResourceable ores, String subpath, Identity creator, Integer ratingValue) {
 		this.creator = creator;
 		this.resName = ores.getResourceableTypeName();
 		this.resId = ores.getResourceableId();
 		this.resSubPath = subpath;
 		this.rating = ratingValue;
+		this.creationDate = new Date();
+		this.modifiedDate = new Date();
 	}
 	
+	@Override
+	public Long getKey() {
+		return key;
+	}
+	
+	@Override
+	public Date getCreationDate() {
+		return creationDate;
+	}
+	
+	public void setCreationDate(Date creationDate) {
+		this.creationDate = creationDate;
+	}
+
 	/**
 	 * @see org.olat.core.commons.services.commentAndRating.model.UserComment#getCreator()
 	 */
@@ -153,5 +207,26 @@ public class UserRatingImpl extends PersistentObject implements UserRating {
 	public void setLastModified(Date date) {
 		modifiedDate = date;
 	}
+	
+	@Override
+	public int hashCode() {
+		return key == null ? 13256 : key.hashCode();
+	}
 
-}
+	@Override
+	public boolean equals(Object obj) {
+		if(this == obj) {
+			return true;
+		}
+		if(obj instanceof UserRatingImpl) {
+			UserRatingImpl q = (UserRatingImpl)obj;
+			return key != null && key.equals(q.key);
+		}
+		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/core/commons/services/commentAndRating/impl/UserRatingsDAO.java b/src/main/java/org/olat/core/commons/services/commentAndRating/impl/UserRatingsDAO.java
new file mode 100644
index 0000000000000000000000000000000000000000..d49d142ed0d700de1bea50a72233fe30312cb739
--- /dev/null
+++ b/src/main/java/org/olat/core/commons/services/commentAndRating/impl/UserRatingsDAO.java
@@ -0,0 +1,162 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.core.commons.services.commentAndRating.impl;
+
+import java.util.Date;
+import java.util.List;
+
+import javax.persistence.TypedQuery;
+
+import org.olat.core.commons.persistence.DB;
+import org.olat.core.commons.services.commentAndRating.model.UserRating;
+import org.olat.core.id.Identity;
+import org.olat.core.id.OLATResourceable;
+import org.olat.core.logging.OLog;
+import org.olat.core.logging.Tracing;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * 
+ * Initial date: 31.01.2014<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+@Service("userRatingsDAO")
+public class UserRatingsDAO {
+	
+	private static final OLog log = Tracing.createLoggerFor(UserRatingsDAO.class);
+	
+	@Autowired
+	private DB dbInstance;
+	
+	public UserRating createRating(Identity creator, OLATResourceable ores, String resSubPath, int ratingValue) {
+		UserRatingImpl rating = new UserRatingImpl();
+		rating.setCreator(creator);
+		rating.setResName(ores.getResourceableTypeName());
+		rating.setResId(ores.getResourceableId());
+		rating.setResSubPath(resSubPath);
+		rating.setCreationDate(new Date());
+		rating.setLastModified(new Date());
+		rating.setRating(ratingValue);
+		dbInstance.getCurrentEntityManager().persist(rating);
+		return rating;
+	}
+	
+	public float getRatingAverage(OLATResourceable ores, String resSubPath) {
+		TypedQuery<Number> query;
+		if (resSubPath == null) {
+			// special query when sub path is null
+			query = dbInstance.getCurrentEntityManager()
+					.createQuery("select avg(rating) from userrating where resName=:resname AND resId=:resId AND resSubPath is NULL", Number.class);
+		} else {
+			query = dbInstance.getCurrentEntityManager()
+					.createQuery("select avg(rating) from userrating where resName=:resname AND resId=:resId AND resSubPath=:resSubPath", Number.class)
+					.setParameter("resSubPath", resSubPath);
+		}
+		Number average = query
+		     .setParameter("resname", ores.getResourceableTypeName())
+		     .setParameter("resId", ores.getResourceableId())
+		     .getSingleResult();
+		// When no ratings are found, a null value is returned!
+		if (average== null) {
+			return 0.0f;
+		}
+		return average.floatValue();	
+	}
+	
+	public int countRatings(OLATResourceable ores, String resSubPath) {
+		TypedQuery<Number> query;
+		if (resSubPath == null) {
+			// special query when sub path is null
+			query = dbInstance.getCurrentEntityManager()
+					.createQuery("select count(*) from userrating where resName=:resname AND resId=:resId AND resSubPath is NULL", Number.class);
+		} else {
+			query = dbInstance.getCurrentEntityManager()
+					.createQuery("select count(*) from userrating where resName=:resname AND resId=:resId AND resSubPath=:resSubPath", Number.class)
+					.setParameter("resSubPath", resSubPath);
+		}
+		Number count = query.setParameter("resname", ores.getResourceableTypeName())
+		     .setParameter("resId", ores.getResourceableId())
+		     .setHint("org.hibernate.cacheable", Boolean.TRUE)
+		     .getSingleResult();
+		return count.intValue();
+	}
+	
+	public UserRatingImpl getRating(Identity identity, OLATResourceable ores, String resSubPath) {
+		StringBuilder sb = new StringBuilder();
+		sb.append("select r from userrating as r where r.creator.key=:creatorKey and r.resName=:resname and r.resId=:resId");
+		TypedQuery<UserRatingImpl> query;
+		if (resSubPath == null) {
+			sb.append(" and r.resSubPath is NULL");
+			query = dbInstance.getCurrentEntityManager().createQuery(sb.toString(), UserRatingImpl.class);
+		} else {
+			sb.append(" and resSubPath=:resSubPath");
+			query = dbInstance.getCurrentEntityManager()
+					.createQuery(sb.toString(), UserRatingImpl.class)
+					.setParameter("resSubPath", resSubPath);
+		}
+		List<UserRatingImpl> results = query
+			 .setParameter("resname", ores.getResourceableTypeName())
+		     .setParameter("resId", ores.getResourceableId())
+		     .setParameter("creatorKey", identity.getKey())
+		     .setHint("org.hibernate.cacheable", Boolean.TRUE)
+		     .getResultList();
+		if (results.size() == 0) return null;		
+		return results.get(0);
+	}
+	
+	public UserRating updateRating(Identity identity, OLATResourceable ores, String resSubPath, int newRatingValue) {
+		UserRatingImpl rating = getRating(identity, ores, resSubPath);
+		if (rating == null) {
+			return createRating(identity, ores, resSubPath, newRatingValue);
+		}
+		// Update DB entry
+		rating.setRating(newRatingValue);
+		rating.setLastModified(new Date());
+		rating = dbInstance.getCurrentEntityManager().merge(rating);
+		return rating;
+	}
+
+	public UserRating updateRating(UserRating rating, int newRatingValue) {
+		// First reload parent from cache to prevent stale object or cache issues
+		rating = reloadRating(rating);
+		if (rating == null) {
+			// Original rating has been deleted in the meantime. Don't update it
+			return null;
+		}
+		// Update DB entry
+		rating.setRating(newRatingValue);
+		rating.setLastModified(new Date());
+		rating = dbInstance.getCurrentEntityManager().merge(rating);
+		return rating;
+	}
+
+	public UserRating reloadRating(UserRating rating) {
+		try {
+			return (UserRating)dbInstance.loadObject(rating);		
+		} catch (Exception e) {
+			// Huh, most likely the given object does not exist anymore on the
+			// db, probably deleted by someone else
+			log.warn("Tried to reload a user rating but got an exception. Probably deleted in the meantime", e);
+			return null;
+		}
+	}
+}
diff --git a/src/main/java/org/olat/core/commons/services/commentAndRating/impl/UserRatingsManagerImpl.java b/src/main/java/org/olat/core/commons/services/commentAndRating/impl/UserRatingsManagerImpl.java
index 29f6490a20440b56df5063e171391b9826e08ac3..685553a67c4bd5ade3167aa3ce9b7ee96c2a0428 100644
--- a/src/main/java/org/olat/core/commons/services/commentAndRating/impl/UserRatingsManagerImpl.java
+++ b/src/main/java/org/olat/core/commons/services/commentAndRating/impl/UserRatingsManagerImpl.java
@@ -24,7 +24,6 @@
 */
 package org.olat.core.commons.services.commentAndRating.impl;
 
-import java.util.Date;
 import java.util.List;
 
 import org.olat.core.commons.persistence.DB;
@@ -51,6 +50,8 @@ import org.olat.core.logging.activity.ThreadLocalUserActivityLogger;
  */
 public class UserRatingsManagerImpl extends UserRatingsManager {
 
+	private UserRatingsDAO userRatingsDAO;
+	
 	/**
 	 * Spring constructor. Use the getInstance method instead of calling this
 	 * constructor directly.
@@ -58,13 +59,23 @@ public class UserRatingsManagerImpl extends UserRatingsManager {
 	public UserRatingsManagerImpl() {
 		// nothing to do
 	}
+	
+	/**
+	 * [used by Spring]
+	 * @param userRatingsDAO
+	 */
+
+	public void setUserRatingsDAO(UserRatingsDAO userRatingsDAO) {
+		this.userRatingsDAO = userRatingsDAO;
+	}
 
 	/**
 	 * @see org.olat.core.commons.services.commentAndRating.UserRatingsManager#createRatingsManager(org.olat.core.id.OLATResourceable, java.lang.String)
 	 */
 	@Override
 	protected UserRatingsManager createRatingsManager(OLATResourceable ores, String subpath) {
-		UserRatingsManager manager = new UserRatingsManagerImpl();
+		UserRatingsManagerImpl manager = new UserRatingsManagerImpl();
+		manager.userRatingsDAO = userRatingsDAO;
 		manager.init(ores, subpath);
 		return manager;
 	}
@@ -74,29 +85,7 @@ public class UserRatingsManagerImpl extends UserRatingsManager {
 	 */
 	@Override
 	public Float calculateRatingAverage() {
-		DBQuery query;
-		if (getOLATResourceableSubPath() == null) {
-			// special query when sub path is null
-			query = DBFactory
-					.getInstance()
-					.createQuery(
-							"select avg(rating) from UserRatingImpl where resName=:resname AND resId=:resId AND resSubPath is NULL");
-		} else {
-			query = DBFactory
-					.getInstance()
-					.createQuery(
-							"select avg(rating) from UserRatingImpl where resName=:resname AND resId=:resId AND resSubPath=:resSubPath");
-			query.setString("resSubPath", getOLATResourceableSubPath());
-		}
-		query.setString("resname", getOLATResourceable()
-				.getResourceableTypeName());
-		query.setLong("resId", getOLATResourceable().getResourceableId());
-		query.setCacheable(true);
-		//
-		Double average = (Double)query.list().get(0);
-		// When no ratings are found, a null value is returned!
-		if (average == null) return Float.valueOf(0);
-		else return average.floatValue();			
+		return userRatingsDAO.getRatingAverage(getOLATResourceable(), getOLATResourceableSubPath());		
 	}
 
 	/**
@@ -104,27 +93,8 @@ public class UserRatingsManagerImpl extends UserRatingsManager {
 	 */
 	@Override
 	public Long countRatings() {
-		DBQuery query;
-		if (getOLATResourceableSubPath() == null) {
-			// special query when sub path is null
-			query = DBFactory
-					.getInstance()
-					.createQuery(
-							"select count(*) from UserRatingImpl where resName=:resname AND resId=:resId AND resSubPath is NULL");
-		} else {
-			query = DBFactory
-					.getInstance()
-					.createQuery(
-							"select count(*) from UserRatingImpl where resName=:resname AND resId=:resId AND resSubPath=:resSubPath");
-			query.setString("resSubPath", getOLATResourceableSubPath());
-		}
-		query.setString("resname", getOLATResourceable()
-				.getResourceableTypeName());
-		query.setLong("resId", getOLATResourceable().getResourceableId());
-		query.setCacheable(true);
-		//
-		Long count = (Long) query.list().get(0);
-		return count;
+		int count = userRatingsDAO.countRatings(getOLATResourceable(), getOLATResourceableSubPath());
+		return new Long(count);
 	}
 	
 	/**
@@ -138,12 +108,12 @@ public class UserRatingsManagerImpl extends UserRatingsManager {
 			query = DBFactory
 					.getInstance()
 					.createQuery(
-							"select rating from UserRatingImpl as rating where resName=:resname AND resId=:resId AND resSubPath is NULL");
+							"select rating from userrating as rating where resName=:resname AND resId=:resId AND resSubPath is NULL");
 		} else {
 			query = DBFactory
 					.getInstance()
 					.createQuery(
-							"select rating from UserRatingImpl as rating where resName=:resname AND resId=:resId AND resSubPath=:resSubPath");
+							"select rating from userrating as rating where resName=:resname AND resId=:resId AND resSubPath=:resSubPath");
 			query.setString("resSubPath", getOLATResourceableSubPath());
 		}
 		query.setString("resname", getOLATResourceable()
@@ -160,9 +130,7 @@ public class UserRatingsManagerImpl extends UserRatingsManager {
 	 */
 	@Override
 	public UserRating createRating(Identity creator, int ratingValue) {
-		UserRating rating = new UserRatingImpl(getOLATResourceable(),
-				getOLATResourceableSubPath(), creator, Integer.valueOf(ratingValue));
-		DBFactory.getInstance().saveObject(rating);
+		UserRating rating = userRatingsDAO.createRating(creator, getOLATResourceable(), getOLATResourceableSubPath(), ratingValue);
 		// do logging
 		ThreadLocalUserActivityLogger.log(CommentAndRatingLoggingAction.RATING_CREATED, getClass(),
 				CoreLoggingResourceable.wrap(getOLATResourceable(), OlatResourceableType.feedItem));
@@ -181,12 +149,12 @@ public class UserRatingsManagerImpl extends UserRatingsManager {
 			query = DBFactory
 					.getInstance()
 					.createQuery(
-							"select userRating from UserRatingImpl as userRating where creator=:creator AND resName=:resname AND resId=:resId AND resSubPath is NULL ");
+							"select userRating from userrating as userRating where creator=:creator AND resName=:resname AND resId=:resId AND resSubPath is NULL ");
 		} else {
 			query = DBFactory
 					.getInstance()
 					.createQuery(
-							"select userRating from UserRatingImpl as userRating where creator=:creator AND resName=:resname AND resId=:resId AND resSubPath=:resSubPath");
+							"select userRating from userrating as userRating where creator=:creator AND resName=:resname AND resId=:resId AND resSubPath=:resSubPath");
 			query.setString("resSubPath", getOLATResourceableSubPath());
 		}
 		query.setString("resname", getOLATResourceable()
@@ -231,14 +199,14 @@ public class UserRatingsManagerImpl extends UserRatingsManager {
 		// special query when sub path is null
 		if (getOLATResourceableSubPath() == null) {
 			StringBuilder sb = new StringBuilder();
-			sb.append("delete from ").append(UserRatingImpl.class.getName()).append(" where resName=:resName and resId=:resId and resSubPath is null");
+			sb.append("delete from userrating where resName=:resName and resId=:resId and resSubPath is null");
 			return db.getCurrentEntityManager().createQuery(sb.toString())
 					.setParameter("resName", getOLATResourceable().getResourceableTypeName())
 					.setParameter("resId", getOLATResourceable().getResourceableId())
 					.executeUpdate();
 		} else {
 			StringBuilder sb = new StringBuilder();
-			sb.append("delete from ").append(UserRatingImpl.class.getName()).append(" where resName=:resName and resId=:resId and resSubPath=:resSubPath");
+			sb.append("delete from userrating where resName=:resName and resId=:resId and resSubPath=:resSubPath");
 			return db.getCurrentEntityManager().createQuery(sb.toString())
 					.setParameter("resName", getOLATResourceable().getResourceableTypeName())
 					.setParameter("resId", getOLATResourceable().getResourceableId())
@@ -255,7 +223,7 @@ public class UserRatingsManagerImpl extends UserRatingsManager {
 	public int deleteAllRatingsIgnoringSubPath() {
 		DB db = DBFactory.getInstance();
 		StringBuilder sb = new StringBuilder();
-		sb.append("delete from ").append(UserRatingImpl.class.getName()).append(" where resName=:resName and resId=:resId");
+		sb.append("delete from userrating where resName=:resName and resId=:resId");
 		return db.getCurrentEntityManager().createQuery(sb.toString())
 				.setParameter("resName", getOLATResourceable().getResourceableTypeName())
 				.setParameter("resId", getOLATResourceable().getResourceableId())
@@ -267,15 +235,7 @@ public class UserRatingsManagerImpl extends UserRatingsManager {
 	 */
 	@Override
 	public UserRating reloadRating(UserRating rating) {
-		try {
-			DB db = DBFactory.getInstance();
-			return (UserRating) db.loadObject(rating);			
-		} catch (Exception e) {
-			// Huh, most likely the given object does not exist anymore on the
-			// db, probably deleted by someone else
-			logWarn("Tried to reload a user rating but got an exception. Probably deleted in the meantime", e);
-			return null;
-		}
+		return userRatingsDAO.reloadRating(rating);
 	}
 
 	/**
@@ -287,21 +247,7 @@ public class UserRatingsManagerImpl extends UserRatingsManager {
 			throw new AssertException(
 					"This user rating manager is initialized for another resource than the given comment.");
 		}
-		// First reload parent from cache to prevent stale object or cache issues
-		rating = reloadRating(rating);
-		if (rating == null) {
-			// Original rating has been deleted in the meantime. Don't update it
-			return null;
-		}
-		// Update DB entry
-		rating.setRating(newRatingValue);
-		rating.setLastModified(new Date());
-		DB db = DBFactory.getInstance();
-		db.updateObject(rating);
-		// do logging
-		ThreadLocalUserActivityLogger.log(CommentAndRatingLoggingAction.RATING_UPDATED, getClass(),
-				CoreLoggingResourceable.wrap(getOLATResourceable(), OlatResourceableType.feedItem));
-		return rating;
+		return userRatingsDAO.updateRating(rating, newRatingValue);
 	}
 
 	/**
@@ -328,12 +274,11 @@ public class UserRatingsManagerImpl extends UserRatingsManager {
 	}
 
 	@Override
-	//fxdiff
 	public List<OLATResourceableRating> getMostRatedResourceables(int maxResults) {
 		StringBuilder sb = new StringBuilder();
 		sb.append("select new ").append(OLATResourceableRating.class.getName()).append("(")
 			.append(" rating.resName, rating.resId, rating.resSubPath, avg(rating.rating))")
-			.append(" from ").append(UserRatingImpl.class.getName()).append(" as rating ")
+			.append(" from userrating as rating ")
 			.append(" where rating.resName=:resName and rating.resId=:resId")
 			.append(" group by rating.resName, rating.resId, rating.resSubPath")
 			.append(" order by avg(rating.rating) desc");
diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/elements/FlexiTableElement.java b/src/main/java/org/olat/core/gui/components/form/flexible/elements/FlexiTableElement.java
index 5f2ad6b6421f79bb4ee2e674077d81008fc0acbb..f9526fa08033c05d8d06f34d2141147b0a0d398f 100644
--- a/src/main/java/org/olat/core/gui/components/form/flexible/elements/FlexiTableElement.java
+++ b/src/main/java/org/olat/core/gui/components/form/flexible/elements/FlexiTableElement.java
@@ -30,6 +30,7 @@ import java.util.Set;
 import org.olat.core.gui.components.form.flexible.FormItem;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.ExtendedFlexiTableSearchController;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableRendererType;
+import org.olat.core.gui.components.velocity.VelocityContainer;
 
 /**
  * 
@@ -48,6 +49,10 @@ public interface FlexiTableElement extends FormItem {
 	 * @param rendererType
 	 */
 	public void setRendererType(FlexiTableRendererType rendererType);
+	
+	public void setRowRenderer(VelocityContainer renderer);
+	
+	public void addFormItem(FormItem item);
 
 	/**
 	 * @return True if muli selection is enabled
diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/AbstractFlexiTableRenderer.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/AbstractFlexiTableRenderer.java
index 6d6d4896350a4e7413972d81229b4636e96c35b0..b75de3ca03cd98ab7e8667bf6204005557c9ad2c 100644
--- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/AbstractFlexiTableRenderer.java
+++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/AbstractFlexiTableRenderer.java
@@ -20,13 +20,13 @@
 package org.olat.core.gui.components.form.flexible.impl.elements.table;
 
 import org.olat.core.gui.components.Component;
-import org.olat.core.gui.components.ComponentRenderer;
+import org.olat.core.gui.components.DefaultComponentRenderer;
 import org.olat.core.gui.components.form.flexible.FormItem;
+import org.olat.core.gui.components.form.flexible.impl.Form;
 import org.olat.core.gui.components.form.flexible.impl.FormJSHelper;
 import org.olat.core.gui.components.form.flexible.impl.NameValuePair;
 import org.olat.core.gui.render.RenderResult;
 import org.olat.core.gui.render.Renderer;
-import org.olat.core.gui.render.RenderingState;
 import org.olat.core.gui.render.StringOutput;
 import org.olat.core.gui.render.URLBuilder;
 import org.olat.core.gui.translator.Translator;
@@ -37,7 +37,7 @@ import org.olat.core.gui.translator.Translator;
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  *
  */
-public abstract class AbstractFlexiTableRenderer implements ComponentRenderer {
+public abstract class AbstractFlexiTableRenderer extends DefaultComponentRenderer {
 
 	@Override
 	public void render(Renderer renderer, StringOutput sb, Component source, URLBuilder ubu, Translator translator,
@@ -54,10 +54,11 @@ public abstract class AbstractFlexiTableRenderer implements ComponentRenderer {
 		//render headers
 		renderHeaders(sb, ftE, translator);
 		//render body
+		sb.append("<tbody>");
 		renderBody(renderer, sb, ftC, ubu, translator, renderResult);
-		sb.append("</table>");
+		sb.append("</tbody></table>");
 		
-		renderFooterButtons(renderer, sb, ftE, ubu, translator, renderResult, args);
+		renderFooterButtons(renderer, sb, ftC, ubu, translator, renderResult, args);
 		sb.append("</div>");
 		
 		//source
@@ -90,9 +91,10 @@ public abstract class AbstractFlexiTableRenderer implements ComponentRenderer {
 		}
 	}
 	
-	protected void renderFooterButtons(Renderer renderer, StringOutput sb, FlexiTableElementImpl ftE, URLBuilder ubu, Translator translator,
+	protected void renderFooterButtons(Renderer renderer, StringOutput sb, FlexiTableComponent ftC, URLBuilder ubu, Translator translator,
 			RenderResult renderResult, String[] args) {
-		
+
+		FlexiTableElementImpl ftE = ftC.getFlexiTableElement();
 		if(ftE.isSelectAllEnable()) {
 			String formName = ftE.getRootForm().getFormName();
 			String dispatchId = ftE.getFormDispatchId();
@@ -111,6 +113,10 @@ public abstract class AbstractFlexiTableRenderer implements ComponentRenderer {
 			
 			sb.append("</div>");
 		}
+		
+		if(ftE.getRendererType() != FlexiTableRendererType.dataTables && ftE.getPageSize() > 0) {
+			renderPagesLinks(sb, ftC);
+		}
 	}
 	
 	protected void renderHeaders(StringOutput target, FlexiTableElementImpl ftE, Translator translator) {
@@ -132,7 +138,7 @@ public abstract class AbstractFlexiTableRenderer implements ComponentRenderer {
 			if(ftE.isColumnModelVisible(fcm)) {
 				renderHeader(target, fcm, col++, cols, translator);
 			}
-  	}
+		}
 		
 		target.append("</tr></thead>");
 	}
@@ -152,9 +158,6 @@ public abstract class AbstractFlexiTableRenderer implements ComponentRenderer {
 		String id = ftC.getFormDispatchId();
 		FlexiTableElementImpl ftE = ftC.getFlexiTableElement();
 		FlexiTableDataModel<?> dataModel = ftE.getTableDataModel();
-
-		// build rows
-		target.append("<tbody>");
 		
 		// the really selected rowid (from the tabledatamodel)
 		int firstRow = ftE.getFirstRow();
@@ -169,7 +172,6 @@ public abstract class AbstractFlexiTableRenderer implements ComponentRenderer {
 			}
 		}				
 		// end of table table
-		target.append("</tbody>");
 	}
 	
 	protected void renderRow(Renderer renderer, StringOutput target, FlexiTableComponent ftC, String rowIdPrefix,
@@ -241,22 +243,103 @@ public abstract class AbstractFlexiTableRenderer implements ComponentRenderer {
 		}
 		target.append("</td>");
 	}
+	
 
+	private void renderPagesLinks(StringOutput sb, FlexiTableComponent ftC) {
+		FlexiTableElementImpl ftE = ftC.getFlexiTableElement();
+		int pageSize = ftE.getPageSize();
+		FlexiTableDataModel<?> dataModel = ftE.getTableDataModel();
+		int rows = dataModel.getRowCount();
+		
+		if(pageSize > 0 && rows > pageSize) {
+			sb.append("<div class='b_table_page'>");
 
-	@Override
-	public void renderHeaderIncludes(Renderer renderer, StringOutput sb, Component source, URLBuilder ubu,
-			Translator translator, RenderingState rstate) {
-		//
-	}
+			int page = ftE.getPage();
+			int maxPage = (int)Math.ceil(((double) rows / (double) pageSize));
+	
+			renderPageBackLink(sb, ftC, page);
+			renderPageNumberLinks(sb, ftC, page, maxPage);
+			renderPageNextLink(sb, ftC, page, maxPage);
 
-	@Override
-	public void renderBodyOnLoadJSFunctionCall(Renderer renderer, StringOutput sb, Component source,
-			RenderingState rstate) {
-		//
+			sb.append("</div>");
+		}
 	}
 	
-	
+	private void renderPageBackLink(StringOutput sb, FlexiTableComponent ftC, int page) {
+		if (page <= 0) return;
 
+		FlexiTableElementImpl ftE = ftC.getFlexiTableElement();
+		Form theForm = ftE.getRootForm();
+		sb.append("<a class='b_table_backward' href=\"javascript:")
+		  .append(FormJSHelper.getXHRFnCallFor(theForm, ftC.getFormDispatchId(), 1, new NameValuePair("page", Integer.toString(page - 1))))
+		  .append("\">").append("&nbsp;").append("</a>");
+	}
+	
+	private void renderPageNextLink(StringOutput sb, FlexiTableComponent ftC, int page, int maxPage) {
+		if (page == maxPage) return;
 
+		FlexiTableElementImpl ftE = ftC.getFlexiTableElement();
+		Form theForm = ftE.getRootForm();
+		sb.append("<a class='b_table_forward' href=\"javascript:")
+		  .append(FormJSHelper.getXHRFnCallFor(theForm, ftC.getFormDispatchId(), 1, new NameValuePair("page", Integer.toString(page + 1))))
+		  .append("\">").append("&nbsp;").append("</a>");
+	}
+	
+	private void renderPageNumberLinks(StringOutput sb, FlexiTableComponent ftC, int page, int maxPage) {
+		if (maxPage < 12) {
+			for (int i=0; i<maxPage; i++) {
+				appendPagenNumberLink(sb, ftC, page, i);
+			}
+		} else {
+			int powerOf10 = String.valueOf(maxPage).length() - 1;
+			int maxStepSize = (int) Math.pow(10, powerOf10);
+			int stepSize = (int) Math.pow(10, String.valueOf(page).length() - 1);
+			boolean isStep = false;
+			int useEveryStep = 3;
+			int stepCnt = 0;
+			boolean isNear = false;
+			int nearleft = 5;
+			int nearright = 5;
+			if (page < nearleft) {
+				nearleft = page;
+				nearright += (nearright - nearleft);
+			} else if (page > (maxPage - nearright)) {
+				nearright = maxPage - page;
+				nearleft += (nearleft - nearright);
+			}
+			for (int i = 1; i <= maxPage; i++) {
+				// adapt stepsize if needed
+				stepSize = adaptStepIfNeeded(page, maxStepSize, stepSize, i);
+	
+				isStep = ((i % stepSize) == 0);
+				if (isStep) {
+					stepCnt++;
+					isStep = isStep && (stepCnt % useEveryStep == 0);
+				}
+				isNear = (i > (page - nearleft) && i < (page + nearright));
+				if (i == 1 || i == maxPage || isStep || isNear) {
+					appendPagenNumberLink(sb, ftC, page, i);
+				}
+			}
+		}
+	}
+	
+	private void appendPagenNumberLink(StringOutput sb, FlexiTableComponent ftC, int page, int i) {
+		FlexiTableElementImpl ftE = ftC.getFlexiTableElement();
+		Form theForm = ftE.getRootForm();
+		String cssClass = (page == i) ? "b_table_page b_table_page_active" : "b_table_page";
+		sb.append("<a class='").append(cssClass).append("' href=\"javascript:")
+		  .append(FormJSHelper.getXHRFnCallFor(theForm, ftC.getFormDispatchId(), 1, new NameValuePair("page", Integer.toString(i))))
+		  .append("\">").append(i+1).append("</a>");
+	}
 
+	private int adaptStepIfNeeded(final int page, final int maxStepSize, final int stepSize, final int i) {
+		int newStepSize = stepSize;
+		if (i < page && stepSize > 1 && ((page - i) / stepSize == 0)) {
+			newStepSize = stepSize / 10;
+		} else if (i > page && stepSize < maxStepSize && ((i - page) / stepSize == 9)) {
+			newStepSize = stepSize * 10;
+		}
+		return newStepSize;
+	}
 }
diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiDataTablesRenderer.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiDataTablesRenderer.java
index 7f6b82ee3cbd5ddd64bdedb3b1f61621e4a2cef5..52c9cc841cb90cfc10159b075c6bbaafb44cc92e 100644
--- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiDataTablesRenderer.java
+++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiDataTablesRenderer.java
@@ -87,22 +87,22 @@ class FlexiDataTablesRenderer extends AbstractFlexiTableRenderer implements Comp
 		  .append("jQuery(function() {\n")
 		  .append(" var scrollHeight = ").append(scrollHeight).append(";\n")
 		  .append(" var selectedIndex =").append(selectPos).append(";\n")
-      .append("	jQuery('#").append(id).append("').dataTable( {\n")
-      .append("		'bScrollInfinite': true,\n")
-      .append("		'bScrollCollapse': true,\n")
-      .append("		'bFilter': false,\n")
-      .append("		'sScrollY': ").append(scrollHeight).append(",\n")
-      .append("		'bProcessing': true,\n")
-      .append("		'bServerSide': true,\n")
-      .append("		'iDisplayLength': ").append(ftE.getPageSize()).append(",\n")
-      .append("		'iDeferLoading': ").append(loadedRows).append(",\n")
-      .append("		'sAjaxSource': '").append(ftE.getMapperUrl()).append("',\n")
-      .append("		'oLanguage': {\n")
-      .append("		  'sInfo': '").append(translator.translate("table.sInfo")).append("',\n")
-      .append("		  'sEmptyTable': '").append(translator.translate("table.sEmptyTable")).append("'\n")
-      .append("    },\n")
-      .append("   'asStripeClasses': ['','b_table_odd'],\n")
-      .append("		'aoColumns': [\n");
+		  .append("	jQuery('#").append(id).append("').dataTable( {\n")
+		  .append("		'bScrollInfinite': true,\n")
+		  .append("		'bScrollCollapse': true,\n")
+		  .append("		'bFilter': false,\n")
+		  .append("		'sScrollY': ").append(scrollHeight).append(",\n")
+		  .append("		'bProcessing': true,\n")
+		  .append("		'bServerSide': true,\n")
+		  .append("		'iDisplayLength': ").append(ftE.getPageSize()).append(",\n")
+		  .append("		'iDeferLoading': ").append(loadedRows).append(",\n")
+		  .append("		'sAjaxSource': '").append(ftE.getMapperUrl()).append("',\n")
+		  .append("		'oLanguage': {\n")
+		  .append("		  'sInfo': '").append(translator.translate("table.sInfo")).append("',\n")
+		  .append("		  'sEmptyTable': '").append(translator.translate("table.sEmptyTable")).append("'\n")
+		  .append("    },\n")
+		  .append("   'asStripeClasses': ['','b_table_odd'],\n")
+		  .append("		'aoColumns': [\n");
 		int count = 0;
 		if(ftE.isMultiSelect()) {
 			target.append("			{'mData':'multiSelectCol', bSortable: false }\n");
diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiTableComponent.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiTableComponent.java
index 1d049a872962753c3b02432ab880250977d340a6..6446a8fb0b1b57f030516c4bbbebf92a746c3606 100644
--- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiTableComponent.java
+++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiTableComponent.java
@@ -42,8 +42,9 @@ import org.olat.core.gui.translator.Translator;
  */
 public class FlexiTableComponent extends FormBaseComponentImpl implements ComponentCollection {
 
-	private ComponentRenderer DATATABLES_RENDERER = new FlexiDataTablesRenderer();
-	private ComponentRenderer CLASSIC_RENDERER = new FlexiTableClassicRenderer();
+	private static final ComponentRenderer DATATABLES_RENDERER = new FlexiDataTablesRenderer();
+	private static final ComponentRenderer CLASSIC_RENDERER = new FlexiTableClassicRenderer();
+	private static final ComponentRenderer CUSTOM_RENDERER = new FlexiTableCustomRenderer();
 	
 	
 	private FlexiTableElementImpl element;
@@ -100,6 +101,7 @@ public class FlexiTableComponent extends FormBaseComponentImpl implements Compon
 		switch(element.getRendererType()) {
 			case classic: return CLASSIC_RENDERER;
 			case dataTables: return DATATABLES_RENDERER;
+			case custom: return CUSTOM_RENDERER;
 			default: return CLASSIC_RENDERER;
 		}
 	}
diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiTableCustomRenderer.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiTableCustomRenderer.java
new file mode 100644
index 0000000000000000000000000000000000000000..e2ba56e95baa648a8f1cdefc1a2b4789a053e57b
--- /dev/null
+++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiTableCustomRenderer.java
@@ -0,0 +1,110 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.core.gui.components.form.flexible.impl.elements.table;
+
+
+import org.olat.core.gui.components.Component;
+import org.olat.core.gui.components.ComponentRenderer;
+import org.olat.core.gui.components.form.flexible.FormItem;
+import org.olat.core.gui.components.form.flexible.impl.FormJSHelper;
+import org.olat.core.gui.components.velocity.VelocityContainer;
+import org.olat.core.gui.render.RenderResult;
+import org.olat.core.gui.render.Renderer;
+import org.olat.core.gui.render.StringOutput;
+import org.olat.core.gui.render.URLBuilder;
+import org.olat.core.gui.translator.Translator;
+
+/**
+ * 
+ * Initial date: 28.01.2014<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+class FlexiTableCustomRenderer extends AbstractFlexiTableRenderer implements ComponentRenderer {
+
+	@Override
+	public void render(Renderer renderer, StringOutput sb, Component source, URLBuilder ubu, Translator translator,
+			RenderResult renderResult, String[] args) {
+		
+		FlexiTableComponent ftC = (FlexiTableComponent)source;
+		FlexiTableElementImpl ftE = ftC.getFlexiTableElement();
+
+		String id = ftC.getFormDispatchId();
+		sb.append("<div class=\"b_table_wrapper b_floatscrollbox\">");
+		renderHeaderButtons(renderer, sb, ftE, ubu, translator, renderResult, args);
+
+		//render body
+
+		sb.append("<div class='b_table_row'>");
+		renderBody(renderer, sb, ftC, ubu, translator, renderResult);
+		sb.append("</div>");
+
+		renderFooterButtons(renderer, sb, ftC, ubu, translator, renderResult, args);
+		sb.append("</div>");
+		
+		//source
+		if (source.isEnabled()) {
+			sb.append(FormJSHelper.getJSStartWithVarDeclaration(id));
+			sb.append(FormJSHelper.getSetFlexiFormDirty(ftE.getRootForm(), id));
+			sb.append(FormJSHelper.getJSEnd());
+		}
+	}
+
+	@Override
+	protected void renderHeaders(StringOutput sb, FlexiTableElementImpl ftE, Translator translator) {
+		//do nothing
+	}
+
+	@Override
+	protected void renderRow(Renderer renderer, StringOutput sb, FlexiTableComponent ftC, String rowIdPrefix,
+			int row, int rows, URLBuilder ubu, Translator translator, RenderResult renderResult) {
+		sb.append("<div class='b_clearfix b_table_row'>");
+
+		FlexiTableElementImpl ftE = ftC.getFlexiTableElement();
+		FlexiTableDataModel<?> dataModel = ftE.getTableDataModel();
+		VelocityContainer container = ftE.getRowRenderer();
+		
+		Object rowObject = ftE.getTableDataModel().getObject(row);
+		container.contextPut("row", rowObject);
+		
+		FlexiTableColumnModel columnsModel = ftE.getTableDataModel().getTableColumnModel();
+		int numOfCols = columnsModel.getColumnCount();
+		//link to the table element the form elements in the data model	
+		for (int j = 0; j<numOfCols; j++) {
+			FlexiColumnModel fcm = columnsModel.getColumnModel(j);
+			int columnIndex = fcm.getColumnIndex();
+			Object cellValue = columnIndex >= 0 ? dataModel.getValueAt(row, columnIndex) : null;
+			if (cellValue instanceof FormItem) {
+				FormItem formItem = (FormItem)cellValue;
+				formItem.setTranslator(translator);
+				if(ftE.getRootForm() != formItem.getRootForm()) {
+					formItem.setRootForm(ftE.getRootForm());
+				}
+				ftE.addFormItem(formItem);
+				container.put(formItem.getComponent().getComponentName(), formItem.getComponent());
+			}
+		}
+
+		container.getHTMLRendererSingleton().render(renderer, sb, container, ubu, translator, renderResult, null);
+		container.contextRemove("row");
+
+		sb.append("</div>");
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiTableElementImpl.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiTableElementImpl.java
index e7a24a76bc2a40b122430dd8accaa1af4372b771..b31c0cb9f48d433ae8ca17c39949ba059cafe760 100644
--- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiTableElementImpl.java
+++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiTableElementImpl.java
@@ -47,11 +47,13 @@ import org.olat.core.gui.components.form.flexible.FormItemCollection;
 import org.olat.core.gui.components.form.flexible.elements.FlexiTableElement;
 import org.olat.core.gui.components.form.flexible.elements.FormLink;
 import org.olat.core.gui.components.form.flexible.elements.TextElement;
+import org.olat.core.gui.components.form.flexible.impl.Form;
 import org.olat.core.gui.components.form.flexible.impl.FormEvent;
 import org.olat.core.gui.components.form.flexible.impl.FormItemImpl;
 import org.olat.core.gui.components.form.flexible.impl.elements.FormLinkImpl;
 import org.olat.core.gui.components.form.flexible.impl.elements.TextElementImpl;
 import org.olat.core.gui.components.link.Link;
+import org.olat.core.gui.components.velocity.VelocityContainer;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.ControllerEventListener;
 import org.olat.core.gui.control.Event;
@@ -83,6 +85,8 @@ public class FlexiTableElementImpl extends FormItemImpl implements FlexiTableEle
 	private boolean selectAllEnabled;
 	
 	private int columnLabelForDragAndDrop;
+	
+	private VelocityContainer rowRenderer;
 
 	private FormLink customButton;
 	private FormLink searchButton, extendedSearchButton;
@@ -90,7 +94,7 @@ public class FlexiTableElementImpl extends FormItemImpl implements FlexiTableEle
 	private ExtendedFlexiTableSearchController extendedSearchCtrl;
 	
 	private final FlexiTableDataModel<?> dataModel;
-	private FlexiTableDataSource<?> dataSource;
+	private final FlexiTableDataSource<?> dataSource;
 	private final FlexiTableComponent component;
 	private CloseableCalloutWindowController callout;
 	private final WindowControl wControl;
@@ -168,6 +172,9 @@ public class FlexiTableElementImpl extends FormItemImpl implements FlexiTableEle
 	@Override
 	public void setRendererType(FlexiTableRendererType rendererType) {
 		this.rendererType = rendererType;
+		if(component != null) {
+			component.setDirty(true);
+		}
 	}
 	
 	@Override
@@ -179,8 +186,6 @@ public class FlexiTableElementImpl extends FormItemImpl implements FlexiTableEle
 	public void setMultiSelect(boolean multiSelect) {
 		this.multiSelect = multiSelect;
 	}
-	
-	
 
 	public boolean isCustomizeColumns() {
 		return customizeColumns;
@@ -198,6 +203,14 @@ public class FlexiTableElementImpl extends FormItemImpl implements FlexiTableEle
 		this.wrapperSelector = wrapperSelector;
 	}
 
+	public VelocityContainer getRowRenderer() {
+		return rowRenderer;
+	}
+
+	public void setRowRenderer(VelocityContainer rowRenderer) {
+		this.rowRenderer = rowRenderer;
+	}
+
 	@Override
 	public boolean isSearchEnabled() {
 		return searchEnabled;
@@ -301,8 +314,15 @@ public class FlexiTableElementImpl extends FormItemImpl implements FlexiTableEle
 	
 	@Override
 	public void setPage(int page) {
-		currentPage = page;//TODO
-		//tableModel.load(0, getPageSize());
+		if(currentPage == page) return;
+		
+		currentPage = page;
+		if(dataSource != null) {
+			int firstResult = currentPage * getPageSize();
+			int maxResults = getPageSize();
+			dataSource.load(getSearchText(), getConditionalQueries(), firstResult, maxResults, orderBy);
+		}
+		component.setDirty(true);
 	}
 
 	public int getCurrentFirstResult() {
@@ -327,7 +347,7 @@ public class FlexiTableElementImpl extends FormItemImpl implements FlexiTableEle
 		return components.get(name);
 	}
 	
-	protected void addFormItem(FormItem item) {
+	public void addFormItem(FormItem item) {
 		components.put(item.getName(), item);
 	}
 
@@ -351,11 +371,16 @@ public class FlexiTableElementImpl extends FormItemImpl implements FlexiTableEle
 			setMultiSelectIndex(selectedIndexArr);
 		}
 
-		String selectedIndex = getRootForm().getRequestParameter("rSelect");
-		String dispatchuri = getRootForm().getRequestParameter("dispatchuri");
-		String select = getRootForm().getRequestParameter("select");
+		Form form = getRootForm();
+		String selectedIndex = form.getRequestParameter("rSelect");
+		String dispatchuri = form.getRequestParameter("dispatchuri");
+		String select = form.getRequestParameter("select");
+		String page = form.getRequestParameter("page");
 		if("undefined".equals(dispatchuri)) {
 			evalSearchRequest(ureq);
+		} else if(StringHelper.containsNonWhitespace(page)) {
+			int p = Integer.parseInt(page);
+			setPage(p);
 		} else if(StringHelper.containsNonWhitespace(selectedIndex)) {
 			int index = selectedIndex.lastIndexOf('-');
 			if(index > 0 && index+1 < selectedIndex.length()) {
@@ -482,7 +507,7 @@ public class FlexiTableElementImpl extends FormItemImpl implements FlexiTableEle
 		if(StringHelper.containsNonWhitespace(search)) {
 			doSearch(search, null);
 		} else {
-			doResetSearch(ureq);
+			doResetSearch();
 		}
 	}
 	
@@ -543,7 +568,7 @@ public class FlexiTableElementImpl extends FormItemImpl implements FlexiTableEle
 		return Arrays.equals(orderBy , sortKeys);
 	}
 	
-	protected void doResetSearch(UserRequest ureq) {
+	protected void doResetSearch() {
 		if(dataSource != null) {
 			resetInternComponents();
 			dataSource.clear();
@@ -677,6 +702,9 @@ public class FlexiTableElementImpl extends FormItemImpl implements FlexiTableEle
 	}
 	
 	public int getFirstRow() {
+		if(getPageSize() > 0) {
+			return getPage() * getPageSize();
+		}
 		return 0;
 	}
 	
diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiTableModelMapper.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiTableModelMapper.java
index 3bd79c82058788df48dddc7f06dd69aa0ca48cac..1e995fc76764b85a3068631b14ae7d1060d96f72 100644
--- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiTableModelMapper.java
+++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiTableModelMapper.java
@@ -143,7 +143,7 @@ public class FlexiTableModelMapper implements Mapper {
 									item.setRootForm(ftE.getRootForm());
 								}
 								ftE.addFormItem(item);
-								val = renderFormItem(item, request, ftE.getTranslator());
+								val = renderFormItem(item, request);
 							} else {
 								val = renderColumnRenderer(col, value, i, ftC, ubu, ftE.getTranslator());
 							}
@@ -173,7 +173,7 @@ public class FlexiTableModelMapper implements Mapper {
 		return target.toString();
 	}
 	
-	private String renderFormItem(FormItem item, HttpServletRequest request, Translator translator) {
+	private String renderFormItem(FormItem item, HttpServletRequest request) {
 		UserSession usess = CoreSpringFactory.getImpl(UserSessionManager.class).getUserSession(request);
 		ChiefController cc = (ChiefController)Windows.getWindows(usess).getAttribute("AUTHCHIEFCONTROLLER");
 		return cc.getWindow().renderComponent(item.getComponent());
diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiTableRendererType.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiTableRendererType.java
index b73a06b054758e8a6a0a5644587585033b367ba9..f7710585544cd94f02c884cb49dd46dccfb111fe 100644
--- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiTableRendererType.java
+++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiTableRendererType.java
@@ -27,5 +27,6 @@ package org.olat.core.gui.components.form.flexible.impl.elements.table;
 public enum FlexiTableRendererType {
 	classic,
 	dataTables,
+	custom
 
 }
diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/SyntheticFormItem.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/SyntheticFormItem.java
deleted file mode 100644
index a9de2218046ea196fcad9d6ea367298676a67a93..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/SyntheticFormItem.java
+++ /dev/null
@@ -1,275 +0,0 @@
-/**
- * <a href="http://www.openolat.org">
- * OpenOLAT - Online Learning and Training</a><br>
- * <p>
- * Licensed under the Apache License, Version 2.0 (the "License"); <br>
- * you may not use this file except in compliance with the License.<br>
- * You may obtain a copy of the License at the
- * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
- * <p>
- * Unless required by applicable law or agreed to in writing,<br>
- * software distributed under the License is distributed on an "AS IS" BASIS, <br>
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
- * See the License for the specific language governing permissions and <br>
- * limitations under the License.
- * <p>
- * Initial code contributed and copyrighted by<br>
- * frentix GmbH, http://www.frentix.com
- * <p>
- */
-package org.olat.core.gui.components.form.flexible.impl.elements.table;
-
-import java.util.List;
-
-import org.olat.core.gui.UserRequest;
-import org.olat.core.gui.components.Component;
-import org.olat.core.gui.components.form.flexible.FormItem;
-import org.olat.core.gui.components.form.flexible.FormItemContainer;
-import org.olat.core.gui.components.form.flexible.FormLayouter;
-import org.olat.core.gui.components.form.flexible.impl.Form;
-import org.olat.core.gui.control.Controller;
-import org.olat.core.gui.translator.Translator;
-import org.olat.core.util.ValidationStatus;
-
-/**
- * 
- * Initial date: 06.02.2013<br>
- * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
- *
- */
-class SyntheticFormItem<T> implements FormItem {
-	
-	private final String name;
-	private final String itemId;
-	private final String dispatchId;
-	private final FlexiTableElementImpl table;
-	
-	public SyntheticFormItem(String name, String itemId, String dispatchId, FlexiTableElementImpl table) {
-		this.name = name;
-		this.itemId = itemId;
-		this.dispatchId = dispatchId;
-		this.table = table;
-	}
-	
-
-	@Override
-	public String getName() {
-		return name;
-	}
-
-	@Override
-	public String getFormItemId() {
-		return itemId;
-	}
-
-	@Override
-	public String getFormDispatchId() {
-		return dispatchId;
-	}
-	
-	@Override
-	public Form getRootForm() {
-		return table.getRootForm();
-	}
-
-	@Override
-	public void evalFormRequest(UserRequest ureq) {
-		//
-	}
-	
-	@Override
-	public void doDispatchFormRequest(UserRequest ureq) {
-		//
-	}
-
-	@Override
-	public void validate(List<ValidationStatus> validationResults) {
-		//
-	}
-
-	@Override
-	public void reset() {
-		//
-	}
-
-	@Override
-	public boolean hasFocus() {
-		return false;
-	}
-	
-	@Override
-	public void setFocus(boolean hasFocus) {
-		//
-	}
-
-
-	@Override
-	public String getElementCssClass() {
-		return null;
-	}
-
-	@Override
-	public void setElementCssClass(String cssClass) {
-		//
-	}
-
-	@Override
-	public Component getComponent() {
-		return null;
-	}
-
-	@Override
-	public Component getLabelC() {
-		return null;
-	}
-
-	@Override
-	public String getLabelText() {
-		return null;
-	}
-
-	@Override
-	public void setLabel(String labelkey, String[] params) {
-		//
-	}
-
-	@Override
-	public void setLabel(String labelkey, String[] params, boolean translate) {
-		//
-	}
-
-	@Override
-	public FormItem setLabelComponent(FormItem labelComponent, FormItemContainer formLayout) {
-		return null;
-	}
-
-	@Override
-	public boolean isMandatory() {
-		return false;
-	}
-
-	@Override
-	public void setMandatory(boolean isMandatory) {
-		//
-	}
-
-	@Override
-	public Component getErrorC() {
-		return null;
-	}
-	
-	@Override
-	public void setErrorKey(String errorKey, String[] params) {
-		//
-	}
-
-	@Override
-	public void setErrorComponent(FormItem errorFormItem, FormLayouter container) {
-		//
-	}
-
-	@Override
-	public Component getExampleC() {
-		return null;
-	}
-
-	@Override
-	public String getExampleText() {
-		return null;
-	}
-
-	@Override
-	public void setExampleKey(String exampleKey, String[] params) {
-		//
-	}
-
-	@Override
-	public Translator getTranslator() {
-		return null;
-	}
-	
-	@Override
-	public void setTranslator(Translator translator) {
-		//
-	}
-
-	@Override
-	public boolean isVisible() {
-		return false;
-	}
-	
-	@Override
-	public void setVisible(boolean isVisible) {
-		//
-	}
-
-	@Override
-	public boolean isEnabled() {
-		return true;
-	}
-	
-	@Override
-	public void setEnabled(boolean isEnabled) {
-		//
-	}
-
-	@Override
-	public boolean hasError() {
-		return false;
-	}
-
-	@Override
-	public boolean hasLabel() {
-		return false;
-	}
-
-	@Override
-	public boolean hasExample() {
-		return false;
-	}
-
-	@Override
-	public void setRootForm(Form rootForm) {
-		//
-	}
-
-	@Override
-	public void showLabel(boolean show) {
-		//
-	}
-
-	@Override
-	public void showError(boolean show) {
-		//
-	}
-
-	@Override
-	public void clearError() {
-		//
-	}
-
-	@Override
-	public void showExample(boolean show) {
-		//
-	}
-
-	@Override
-	public void addActionListener(Controller listener, int events) {
-		//
-	}
-
-	@Override
-	public int getAction() {
-		return 0;
-	}
-
-	@Override
-	public void setUserObject(Object userObject) {
-		//
-	}
-
-	@Override
-	public Object getUserObject() {
-		return null;
-	}
-}
\ No newline at end of file
diff --git a/src/main/java/org/olat/core/gui/components/panel/MainPanel.java b/src/main/java/org/olat/core/gui/components/panel/MainPanel.java
new file mode 100644
index 0000000000000000000000000000000000000000..1643e2521abd84cd854ac305eec4f8e09457efde
--- /dev/null
+++ b/src/main/java/org/olat/core/gui/components/panel/MainPanel.java
@@ -0,0 +1,47 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.core.gui.components.panel;
+
+import org.olat.core.gui.components.ComponentRenderer;
+
+/**
+ * 
+ * This component wrapped the content to mimic
+ * the 3 columsn main controller with only
+ * one column.
+ * 
+ * 
+ * Initial date: 28.01.2014<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class MainPanel extends Panel {
+	
+	private static final ComponentRenderer RENDERER = new MainPanelRenderer();
+	
+	public MainPanel(String name) {
+		super(name);
+	}
+
+	@Override
+	public ComponentRenderer getHTMLRendererSingleton() {
+		return RENDERER;
+	}
+}
diff --git a/src/main/java/org/olat/core/gui/components/panel/MainPanelRenderer.java b/src/main/java/org/olat/core/gui/components/panel/MainPanelRenderer.java
new file mode 100644
index 0000000000000000000000000000000000000000..0f3e6c8f37aad634ef7b3ec13d9bef997e618f59
--- /dev/null
+++ b/src/main/java/org/olat/core/gui/components/panel/MainPanelRenderer.java
@@ -0,0 +1,58 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.core.gui.components.panel;
+
+import org.olat.core.gui.components.Component;
+import org.olat.core.gui.render.RenderResult;
+import org.olat.core.gui.render.Renderer;
+import org.olat.core.gui.render.StringOutput;
+import org.olat.core.gui.render.URLBuilder;
+import org.olat.core.gui.translator.Translator;
+
+/**
+ * 
+ * Initial date: 28.01.2014<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class MainPanelRenderer extends PanelRenderer {
+
+	@Override
+	public void render(Renderer renderer, StringOutput sb, Component source, URLBuilder ubu,
+			Translator translator, RenderResult renderResult, String[] args) {
+
+		sb.append("<div id='b_main' class='b_hidecol1 b_hidecol2'>\n")
+		  .append("<div id='b_col3' class='split-pane'>\n")
+		  .append("<div id='b_col3_content' class='b_clearfix'>\n")
+		  .append("<a id='b_content' name='content'></a>\n")
+		  .append("<div id='b_col3_content_inner' class='b_floatscrollbox'>\n")
+		  .append("<a name='b_col3'></a>\n");
+		
+		super.render(renderer, sb, source, ubu, translator, renderResult, args);
+		
+		sb.append("</div>\n")
+		  .append("</div>\n")
+		  .append("<div id='b_ie_clearing'>&nbsp;</div>\n")
+		  .append("</div>\n")
+		  .append("</div>	\n");
+				
+	}
+
+}
diff --git a/src/main/java/org/olat/core/gui/components/rating/RatingComponent.java b/src/main/java/org/olat/core/gui/components/rating/RatingComponent.java
index 1c2814447d777bc492590e4f55da72b4b6e6f15a..736e388c22c8ff98eec6de3452c784efd84d14e1 100644
--- a/src/main/java/org/olat/core/gui/components/rating/RatingComponent.java
+++ b/src/main/java/org/olat/core/gui/components/rating/RatingComponent.java
@@ -25,6 +25,7 @@ import java.util.List;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
 import org.olat.core.gui.components.ComponentRenderer;
+import org.olat.core.gui.components.form.flexible.impl.Form;
 import org.olat.core.gui.components.velocity.VelocityContainer;
 import org.olat.core.gui.control.Event;
 import org.olat.core.logging.AssertException;
@@ -56,6 +57,7 @@ public class RatingComponent extends Component {
 	private boolean allowUserInput;
 	private String cssClass;
 	private float currentRating;
+	private Form form;
 
 	/**
 	 * Create a rating component with no title and a default explanation and hover
@@ -68,7 +70,11 @@ public class RatingComponent extends Component {
 	 * @param allowUserInput
 	 */
 	public RatingComponent(String name, float currentRating, int maxRating, boolean allowUserInput) {
-		super(name);
+		this(null, name, currentRating, maxRating, allowUserInput, null);
+	}
+		
+	public RatingComponent(String id, String name, float currentRating, int maxRating, boolean allowUserInput, Form form) {
+		super(id, name);
 		if (currentRating > maxRating) 
 			throw new AssertException("Current rating set to higher value::" + currentRating + " than the maxRating::" + maxRating);
 		this.allowUserInput = allowUserInput;
@@ -86,7 +92,7 @@ public class RatingComponent extends Component {
 		else this.explanation = null;
 		this.translateExplanation = true;
 		this.showRatingAsText = false;
-		
+		this.form = form;
 	}
 
 	/**
@@ -99,9 +105,9 @@ public class RatingComponent extends Component {
 			log.debug("***RATING_CLICKED*** dispatchID::" + ureq.getComponentID() + " rating::" + cmd);
 		}
 		try {
-			float rating = Float.parseFloat(cmd);			
+			float rating = Float.parseFloat(cmd);
 			// update GUI
-			this.setCurrentRating(rating);
+			setCurrentRating(rating);
 			// notify listeners
 			Event event = new RatingEvent(rating);
 			fireEvent(ureq, event);
@@ -118,10 +124,14 @@ public class RatingComponent extends Component {
 	}
 
 	
+	
 	//
 	// Various getter and setter methods
 	//
-	
+	Form getForm() {
+		return form;
+	}
+
 	// only package scope, used by renderer
 	List<String> getRatingLabel() {
 		return ratingLabels;
diff --git a/src/main/java/org/olat/core/gui/components/rating/RatingEvent.java b/src/main/java/org/olat/core/gui/components/rating/RatingEvent.java
index 418de5a222510d50ac843ee163eb5176bc93a31d..d2bc683ca3dbbedbdec8052a1f1d2a59b57dc0f9 100644
--- a/src/main/java/org/olat/core/gui/components/rating/RatingEvent.java
+++ b/src/main/java/org/olat/core/gui/components/rating/RatingEvent.java
@@ -29,6 +29,8 @@ import org.olat.core.gui.control.Event;
  * @author gnaegi
  */
 public class RatingEvent extends Event {
+
+	private static final long serialVersionUID = -7584762233026409541L;
 	private static final String RATING_EVENT = "ratingEvent";
 	private float rating;
 
diff --git a/src/main/java/org/olat/core/gui/components/rating/RatingFormEvent.java b/src/main/java/org/olat/core/gui/components/rating/RatingFormEvent.java
new file mode 100644
index 0000000000000000000000000000000000000000..b69463da2a05426777048c27f6bac13c7d933fbd
--- /dev/null
+++ b/src/main/java/org/olat/core/gui/components/rating/RatingFormEvent.java
@@ -0,0 +1,50 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.core.gui.components.rating;
+
+import org.olat.core.gui.components.form.flexible.FormItem;
+import org.olat.core.gui.components.form.flexible.impl.FormEvent;
+
+/**
+ * 
+ * Initial date: 31.01.2014<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class RatingFormEvent extends FormEvent {
+
+	private static final long serialVersionUID = -3560846420954074918L;
+	
+	private static final String RATING_EVENT = "ratingEvent";
+	private float rating;
+
+	public RatingFormEvent(FormItem source, float rating) {
+		super(RATING_EVENT, source, ONCLICK);
+		this.rating = rating;
+	}
+
+	public float getRating() {
+		return rating;
+	}
+
+	public void setRating(float rating) {
+		this.rating = rating;
+	}
+}
diff --git a/src/main/java/org/olat/core/gui/components/rating/RatingFormItem.java b/src/main/java/org/olat/core/gui/components/rating/RatingFormItem.java
new file mode 100644
index 0000000000000000000000000000000000000000..e735bcccdeb126d7b39c350f8cef5685fa135619
--- /dev/null
+++ b/src/main/java/org/olat/core/gui/components/rating/RatingFormItem.java
@@ -0,0 +1,81 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.core.gui.components.rating;
+
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.form.flexible.impl.FormItemImpl;
+
+/**
+ * 
+ * Initial date: 31.01.2014<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class RatingFormItem extends FormItemImpl {
+
+	private float currentRating;
+	private int maxRating;
+	private boolean allowUserInput;
+	
+	private RatingComponent component;
+	
+	public RatingFormItem(String name, float currentRating, int maxRating, boolean allowUserInput) {
+		super(name);
+		
+		this.currentRating = currentRating;
+		this.maxRating = maxRating;
+		this.allowUserInput = allowUserInput;
+	}
+
+	public float getCurrentRating() {
+		return currentRating;
+	}
+
+	@Override
+	protected RatingComponent getFormItemComponent() {
+		return component;
+	}
+
+	@Override
+	protected void rootFormAvailable() {
+		if(component == null) {
+			component = new RatingComponent(null, getName(), currentRating, maxRating, allowUserInput, getRootForm());
+		}
+	}
+
+	@Override
+	public void evalFormRequest(UserRequest ureq) {
+		//
+	}
+	
+	@Override
+	public void dispatchFormRequest(UserRequest ureq) {
+		component.doDispatchRequest(ureq);
+		currentRating = component.getCurrentRating();
+
+		
+		getRootForm().fireFormEvent(ureq, new RatingFormEvent(this, currentRating));
+	}
+
+	@Override
+	public void reset() {
+		//
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/core/gui/components/rating/RatingRenderer.java b/src/main/java/org/olat/core/gui/components/rating/RatingRenderer.java
index f69101048043e563f87f8a3ea5705911b2b11787..099a4ecce182a3ddb96324b4dfc2524816d51899 100644
--- a/src/main/java/org/olat/core/gui/components/rating/RatingRenderer.java
+++ b/src/main/java/org/olat/core/gui/components/rating/RatingRenderer.java
@@ -23,12 +23,15 @@ import java.util.List;
 
 import org.apache.commons.lang.StringEscapeUtils;
 import org.olat.core.gui.components.Component;
-import org.olat.core.gui.components.ComponentRenderer;
+import org.olat.core.gui.components.DefaultComponentRenderer;
+import org.olat.core.gui.components.form.flexible.FormBaseComponentIdProvider;
+import org.olat.core.gui.components.form.flexible.impl.Form;
+import org.olat.core.gui.components.form.flexible.impl.FormJSHelper;
+import org.olat.core.gui.components.form.flexible.impl.NameValuePair;
 import org.olat.core.gui.components.velocity.VelocityContainer;
 import org.olat.core.gui.control.winmgr.AJAXFlags;
 import org.olat.core.gui.render.RenderResult;
 import org.olat.core.gui.render.Renderer;
-import org.olat.core.gui.render.RenderingState;
 import org.olat.core.gui.render.StringOutput;
 import org.olat.core.gui.render.URLBuilder;
 import org.olat.core.gui.translator.Translator;
@@ -42,7 +45,7 @@ import org.olat.core.util.Formatter;
  * 
  * @author gnaegi
  */
-public class RatingRenderer implements ComponentRenderer {
+public class RatingRenderer extends DefaultComponentRenderer {
 
 	/**
 	 * @see org.olat.core.gui.components.ComponentRenderer#render(org.olat.core.gui.render.Renderer,
@@ -52,8 +55,9 @@ public class RatingRenderer implements ComponentRenderer {
 	 *      org.olat.core.gui.translator.Translator,
 	 *      org.olat.core.gui.render.RenderResult, java.lang.String[])
 	 */
+	@Override
 	public void render(Renderer renderer, StringOutput sb, Component source, URLBuilder ubu, Translator translator,
-			@SuppressWarnings("unused") RenderResult renderResult, @SuppressWarnings("unused") String[] args) {
+			RenderResult renderResult, String[] args) {
 		RatingComponent rating = (RatingComponent) source;
 		sb.append("<div class='b_rating ");
 		// Add custom css class
@@ -90,17 +94,26 @@ public class RatingRenderer implements ComponentRenderer {
 			sb.append("'");
 			// Add action
 			if (rating.isAllowUserInput()) {
-				// Add link
-				sb.append(" href=\"");
-				ubu.buildURI(sb, new String[] { VelocityContainer.COMMAND_ID }, new String[] { (i+1) +"" },
-						ajaxModeEnabled ? AJAXFlags.MODE_TOBGIFRAME : AJAXFlags.MODE_NORMAL);
-				sb.append("\"");
-				// add link target
-				if (ajaxModeEnabled) {
-					ubu.appendTarget(sb);
-				}				
-				// add check for olat busy
-				sb.append(" onclick=\"return o2cl()\"  onkeypress=\"return o2cl()\"");
+				if(rating.getForm() == null) {
+					// Add link
+					sb.append(" href=\"");
+					ubu.buildURI(sb, new String[] { VelocityContainer.COMMAND_ID }, new String[] { (i+1) +"" },
+							ajaxModeEnabled ? AJAXFlags.MODE_TOBGIFRAME : AJAXFlags.MODE_NORMAL);
+					sb.append("\"");
+					// add link target
+					if (ajaxModeEnabled) {
+						ubu.appendTarget(sb);
+					}				
+					// add check for olat busy
+					sb.append(" onclick=\"return o2cl()\"  onkeypress=\"return o2cl()\"");
+				} else {
+					Form theForm = rating.getForm();
+					String elementId = FormBaseComponentIdProvider.DISPPREFIX + rating.getDispatchID();
+					sb.append("href=\"javascript:")
+					  .append(FormJSHelper.getXHRFnCallFor(theForm, elementId, 1,
+							  new NameValuePair(VelocityContainer.COMMAND_ID, Integer.toString(i+1))))
+					  .append("\" ");
+				}
 
 			} else {
 				// Disabled link
@@ -137,28 +150,4 @@ public class RatingRenderer implements ComponentRenderer {
 		}
 		sb.append("</div>");//b_rating
 	}
-
-	/**
-	 * @see org.olat.core.gui.components.ComponentRenderer#renderBodyOnLoadJSFunctionCall(org.olat.core.gui.render.Renderer,
-	 *      org.olat.core.gui.render.StringOutput,
-	 *      org.olat.core.gui.components.Component,
-	 *      org.olat.core.gui.render.RenderingState)
-	 */
-	public void renderBodyOnLoadJSFunctionCall(Renderer renderer, StringOutput sb, Component source, RenderingState rstate) {
-		// no body onload to execute
-	}
-
-	/**
-	 * @see org.olat.core.gui.components.ComponentRenderer#renderHeaderIncludes(org.olat.core.gui.render.Renderer,
-	 *      org.olat.core.gui.render.StringOutput,
-	 *      org.olat.core.gui.components.Component,
-	 *      org.olat.core.gui.render.URLBuilder,
-	 *      org.olat.core.gui.translator.Translator,
-	 *      org.olat.core.gui.render.RenderingState)
-	 */
-	public void renderHeaderIncludes(Renderer renderer, StringOutput sb, Component source, URLBuilder ubu, Translator translator,
-			RenderingState rstate) {
-		// no headers to load
-	}
-
 }
diff --git a/src/main/java/org/olat/core/gui/components/rating/RatingWithAverageComponent.java b/src/main/java/org/olat/core/gui/components/rating/RatingWithAverageComponent.java
new file mode 100644
index 0000000000000000000000000000000000000000..9dc03b88acb9aa9342f4fc9c6e752912b3699c5c
--- /dev/null
+++ b/src/main/java/org/olat/core/gui/components/rating/RatingWithAverageComponent.java
@@ -0,0 +1,65 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.core.gui.components.rating;
+
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.Component;
+import org.olat.core.gui.components.ComponentEventListener;
+import org.olat.core.gui.components.ComponentRenderer;
+import org.olat.core.gui.control.Event;
+
+/**
+ * 
+ * Initial date: 31.01.2014<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class RatingWithAverageComponent extends Component implements ComponentEventListener {
+	
+	private static final RatingWithAverageRenderer RENDERER = new RatingWithAverageRenderer();
+	
+	private final RatingWithAverageFormItem formItem;
+	
+	public RatingWithAverageComponent(String name, RatingWithAverageFormItem formItem) {
+		super(name);
+		this.formItem = formItem;
+	}
+
+	public RatingWithAverageFormItem getFormItem() {
+		return formItem;
+	}
+
+	@Override
+	protected void doDispatchRequest(UserRequest ureq) {
+		//
+	}
+
+	@Override
+	public ComponentRenderer getHTMLRendererSingleton() {
+		return RENDERER;
+	}
+
+	@Override
+	public void dispatchEvent(UserRequest ureq, Component source, Event event) {
+		formItem.dispatchFormRequest(ureq);
+	}
+	
+	
+}
diff --git a/src/main/java/org/olat/core/gui/components/rating/RatingWithAverageFormItem.java b/src/main/java/org/olat/core/gui/components/rating/RatingWithAverageFormItem.java
new file mode 100644
index 0000000000000000000000000000000000000000..7f395b87dc29b5796b07a157ebc0919aa94fcaa3
--- /dev/null
+++ b/src/main/java/org/olat/core/gui/components/rating/RatingWithAverageFormItem.java
@@ -0,0 +1,130 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.core.gui.components.rating;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.Component;
+import org.olat.core.gui.components.form.flexible.FormItem;
+import org.olat.core.gui.components.form.flexible.FormItemCollection;
+import org.olat.core.gui.components.form.flexible.impl.FormItemImpl;
+
+/**
+ * 
+ * Initial date: 31.01.2014<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class RatingWithAverageFormItem extends FormItemImpl implements FormItemCollection {
+
+	private float userRating;
+	private int numOfRatings;
+	private float averageRating;
+	private int maxRating;
+	
+	private RatingFormItem userComponent;
+	private RatingFormItem averageComponent;
+	private RatingWithAverageComponent component;
+	
+	public RatingWithAverageFormItem(String name, float userRating, float averageRating, int maxRating, int numOfRatings) {
+		super(name);
+
+		this.maxRating = maxRating;
+		this.userRating = userRating;
+		this.numOfRatings = numOfRatings;
+		this.averageRating = averageRating;
+		component = new RatingWithAverageComponent(name, this);
+	}
+	
+	protected Component getUserComponent() {
+		return userComponent.getComponent();
+	}
+	
+	protected Component getAverageComponent() {
+		return averageComponent.getComponent();
+	}
+
+	@Override
+	protected Component getFormItemComponent() {
+		return component;
+	}
+
+	@Override
+	public Iterable<FormItem> getFormItems() {
+		List<FormItem> items = new ArrayList<FormItem>();
+		items.add(userComponent);
+		items.add(averageComponent);
+		return items;
+	}
+
+	@Override
+	public FormItem getFormComponent(String name) {
+		if(userComponent.getName().equals(name)) {
+			return userComponent;
+		} else if(averageComponent.getName().equals(name)) {
+			return averageComponent;
+		}
+		return null;
+	}
+
+	@Override
+	protected void rootFormAvailable() {
+		if(userComponent == null) {
+			userComponent = new RatingFormItem("rusr_" + getName(), userRating, maxRating, true);
+			userComponent.setRootForm(getRootForm());
+			userComponent.rootFormAvailable();
+			userComponent.getComponent().addListener(component);
+
+			userComponent.getFormItemComponent().setTranslateExplanation(true);
+			userComponent.getFormItemComponent().setTranslateRatingLabels(false);
+			
+			averageComponent = new RatingFormItem("ravg_" + getName(), averageRating, maxRating, false);
+			averageComponent.setRootForm(getRootForm());
+			averageComponent.rootFormAvailable();
+
+			String[] args = new String[]{ Integer.toString(numOfRatings)};
+			String explanation = translator.translate("rating.average.explanation", args);
+			averageComponent.getFormItemComponent().setExplanation(explanation);
+			averageComponent.getFormItemComponent().setTranslateExplanation(false);
+			averageComponent.getFormItemComponent().setTranslateRatingLabels(false);
+		}
+	}
+
+	@Override
+	public void evalFormRequest(UserRequest ureq) {
+		//
+	}
+	
+	@Override
+	public void dispatchFormRequest(UserRequest ureq) {
+		userRating = userComponent.getCurrentRating();
+		getRootForm().fireFormEvent(ureq, new RatingFormEvent(this, userRating));
+		component.setDirty(true);
+	}
+
+	@Override
+	public void reset() {
+		//
+	}
+	
+	
+}
diff --git a/src/main/java/org/olat/core/gui/components/rating/RatingWithAverageRenderer.java b/src/main/java/org/olat/core/gui/components/rating/RatingWithAverageRenderer.java
new file mode 100644
index 0000000000000000000000000000000000000000..4f5e3f4a19042fa37da74c3fdb3157391d2252a8
--- /dev/null
+++ b/src/main/java/org/olat/core/gui/components/rating/RatingWithAverageRenderer.java
@@ -0,0 +1,71 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.core.gui.components.rating;
+
+import org.olat.core.gui.components.Component;
+import org.olat.core.gui.components.DefaultComponentRenderer;
+import org.olat.core.gui.render.RenderResult;
+import org.olat.core.gui.render.Renderer;
+import org.olat.core.gui.render.StringOutput;
+import org.olat.core.gui.render.URLBuilder;
+import org.olat.core.gui.translator.Translator;
+
+/**
+ * 
+ * Initial date: 31.01.2014<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class RatingWithAverageRenderer extends DefaultComponentRenderer {
+
+	@Override
+	public void render(Renderer renderer, StringOutput sb, Component source, URLBuilder ubu, Translator translator,
+			RenderResult renderResult, String[] args) {
+		
+		RatingWithAverageComponent ratingCmp = (RatingWithAverageComponent)source;
+		RatingWithAverageFormItem item = ratingCmp.getFormItem();
+		
+		String viewIdent = item.getFormDispatchId();
+		sb.append("<div id=").append(viewIdent).append(" class='b_ratings_and_comments'>")
+		  .append("<div id='b_rating_wrapper_").append(viewIdent).append("' class='b_rating_wrapper'>")
+		  .append("<div id='b_rating_").append(viewIdent).append("' style='display:none;'>");
+		
+		Component userCmp = item.getUserComponent();
+		userCmp.getHTMLRendererSingleton().render(renderer, sb, userCmp, ubu, translator, renderResult, args);
+		sb.append("</div>")
+		  .append("<div id='b_rating_avg_").append(viewIdent).append("'>");
+		Component averageCmp = item.getAverageComponent();
+		averageCmp.getHTMLRendererSingleton().render(renderer, sb, averageCmp, ubu, translator, renderResult, args);
+		sb.append("</div>")
+		  .append("</div>")
+		  .append("</div>")
+		  .append("<script type='text/javascript'>\n")
+		  .append("/* <![CDATA[ */ \n")
+		  .append("jQuery(function(){\n")
+		  .append("  jQuery('#b_rating_wrapper_").append(viewIdent).append("')\n")
+		  .append("    .hover(\n")
+		  .append("      function(){ jQuery('#b_rating_").append(viewIdent).append("').show(); jQuery('#b_rating_avg_").append(viewIdent).append("').hide(); }, \n")
+		  .append("      function(){ jQuery('#b_rating_").append(viewIdent).append("').hide(); jQuery('#b_rating_avg_").append(viewIdent).append("').show(); }\n")  
+		  .append("	   );\n")
+		  .append("});\n")
+		  .append("/* ]]> */\n")
+		  .append("</script>\n");
+	}
+}
diff --git a/src/main/java/org/olat/gui/control/OlatTopNavController.java b/src/main/java/org/olat/gui/control/OlatTopNavController.java
index 0cb351239b2639b2c8cc63cc2d34468ea49bc193..8cd845917f338b815e4a60080890f8d2df1c8c2b 100644
--- a/src/main/java/org/olat/gui/control/OlatTopNavController.java
+++ b/src/main/java/org/olat/gui/control/OlatTopNavController.java
@@ -1,79 +1,90 @@
 /**
-* OLAT - Online Learning and Training<br>
-* http://www.olat.org
-* <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
-* <p>
-* http://www.apache.org/licenses/LICENSE-2.0
-* <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>
-* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br>
-* University of Zurich, Switzerland.
-* <hr>
-* <a href="http://www.openolat.org">
-* OpenOLAT - Online Learning and Training</a><br>
-* This file has been modified by the OpenOLAT community. Changes are licensed
-* under the Apache 2.0 license as the original file.
-*/
-
+ * <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.gui.control;
 
+import java.util.ArrayList;
+import java.util.List;
+
+import org.olat.NewControllerFactory;
 import org.olat.basesecurity.AuthHelper;
 import org.olat.core.CoreSpringFactory;
 import org.olat.core.commons.controllers.impressum.ImpressumMainController;
 import org.olat.core.commons.fullWebApp.popup.BaseFullWebappPopupLayoutFactory;
 import org.olat.core.dispatcher.DispatcherModule;
+import org.olat.core.extensions.ExtManager;
+import org.olat.core.extensions.Extension;
+import org.olat.core.extensions.ExtensionElement;
+import org.olat.core.extensions.action.GenericActionExtension;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.Windows;
 import org.olat.core.gui.components.Component;
+import org.olat.core.gui.components.image.ImageComponent;
 import org.olat.core.gui.components.link.Link;
 import org.olat.core.gui.components.link.LinkFactory;
+import org.olat.core.gui.components.tree.GenericTreeNode;
 import org.olat.core.gui.components.velocity.VelocityContainer;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.Event;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.core.gui.control.controller.BasicController;
 import org.olat.core.gui.control.creator.ControllerCreator;
+import org.olat.core.gui.control.generic.closablewrapper.CloseableCalloutWindowController;
 import org.olat.core.gui.control.generic.popup.PopupBrowserWindow;
+import org.olat.core.gui.media.MediaResource;
 import org.olat.core.id.OLATResourceable;
+import org.olat.core.util.StringHelper;
 import org.olat.core.util.event.EventBus;
 import org.olat.core.util.event.GenericEventListener;
 import org.olat.core.util.resource.OresHelper;
 import org.olat.course.CourseFactory;
 import org.olat.course.CourseModule;
 import org.olat.course.nodes.iq.AssessmentEvent;
+import org.olat.home.HomeMainController;
 import org.olat.ims.qti.process.AssessmentInstance;
 import org.olat.instantMessaging.InstantMessagingModule;
 import org.olat.instantMessaging.ui.InstantMessagingMainController;
 import org.olat.search.SearchServiceUIFactory;
 import org.olat.search.SearchServiceUIFactory.DisplayOption;
 import org.olat.search.ui.SearchInputController;
+import org.olat.user.DisplayPortraitManager;
+import org.olat.user.UserManager;
 
 /**
- * Description:<br>
- * TODO: patrickb Class Description for OlatTopNavController
- * <P>
- * Initial Date: 13.06.2006 <br>
  * 
- * @author patrickb
+ * Initial date: 21.01.2014<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
  */
 public class OlatTopNavController extends BasicController implements GenericEventListener {
 	
 	private static final String ACTION_LOGOUT = "logout";
-	private VelocityContainer topNavVC;
-	private InstantMessagingMainController imController;
 	private SearchInputController searchC;
-	private Link helpLink, loginLink, impressumLink;
+	private Link helpLink, loginLink, impressumLink, myMenuLink;
 
+	private VelocityContainer menuVC;
+	private VelocityContainer topNavVC;
+	private InstantMessagingMainController imController;
+	private CloseableCalloutWindowController calloutCtr;
 	
 	private EventBus singleUserEventCenter;
+	private final DisplayPortraitManager portraitManager;
 	private OLATResourceable ass;
 	
 	public OlatTopNavController(UserRequest ureq, WindowControl wControl) {
@@ -84,6 +95,7 @@ public class OlatTopNavController extends BasicController implements GenericEven
 		super(ureq, wControl);
 		
 		topNavVC = createVelocityContainer("topnav");
+		portraitManager = DisplayPortraitManager.getInstance();
 		
 		boolean isGuest = ureq.getUserSession().getRoles().isGuestOnly();
 		boolean isInvitee = ureq.getUserSession().getRoles().isInvitee();
@@ -127,46 +139,152 @@ public class OlatTopNavController extends BasicController implements GenericEven
 			ass = OresHelper.createOLATResourceableType(AssessmentEvent.class);
 			singleUserEventCenter = ureq.getUserSession().getSingleUserEventCenter();
 			singleUserEventCenter.registerFor(this, getIdentity(), ass);
+			
+			UserManager userManager = CoreSpringFactory.getImpl(UserManager.class);
+	
+			myMenuLink = LinkFactory.createButton("topnav.my.menu", topNavVC, this);
+			myMenuLink.setCustomDisplayText(userManager.getUserDisplayName(getIdentity()));
+			myMenuLink.setCustomEnabledLinkCSS("o_topnav_impressum");
+			myMenuLink.setElementCssClass("o_sel_my_menu_open");
+			
+			MediaResource image = portraitManager.getSmallPortraitResource(getIdentity().getName());
+
+			if (image != null) {
+				// display only within 600x300 - everything else looks ugly
+				ImageComponent ic = new ImageComponent("image");
+				ic.setSpanAsDomReplaceable(true);
+				ic.setMediaResource(image);
+				topNavVC.contextPut("hasPortrait", Boolean.TRUE);
+				topNavVC.put("portrait", ic);
+			} else {
+				topNavVC.contextPut("hasPortrait", Boolean.FALSE);
+			}
 		}
 		
 		putInitialPanel(topNavVC);
 	}
 	
-	/**
-	 * 
-	 * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest, org.olat.core.gui.components.Component, org.olat.core.gui.control.Event)
-	 */
 	@Override
 	public void event(UserRequest ureq, Component source, Event event) {
-		String command = event.getCommand();
-			if (source == helpLink) {
-				ControllerCreator ctrlCreator = new ControllerCreator() {
-					public Controller createController(UserRequest lureq, WindowControl lwControl) {
-						return CourseFactory.createHelpCourseLaunchController(lureq, lwControl);
-					}					
-				};
-				//wrap the content controller into a full header layout
-				ControllerCreator layoutCtrlr = BaseFullWebappPopupLayoutFactory.createAuthMinimalPopupLayout(ureq, ctrlCreator);
-				//open in new browser window
-				openInNewBrowserWindow(ureq, layoutCtrlr);
-				//
-			} else if (source == loginLink) {
-				DispatcherModule.redirectToDefaultDispatcher(ureq.getHttpResp());
-			} else if (source == topNavVC) {
+		if (source == helpLink) {
+			doOpenHelp(ureq) ;
+		} else if(source == myMenuLink) {
+			myMenuLink.setDirty(false);
+			doOpenMyMenu(ureq);
+		} else if(source instanceof Link && source.getComponentName().startsWith("personal.tool.")) {
+			doCloseMyMenu();
+			doOpenPersonalTool(ureq, (Link)source);
+		} else if (source == loginLink) {
+			DispatcherModule.redirectToDefaultDispatcher(ureq.getHttpResp());
+		} else if (source == menuVC) {
+			String command = event.getCommand();
 			if (command.equals(ACTION_LOGOUT)) {
 				AuthHelper.doLogout(ureq);
 			}
-		}	else if (source == impressumLink) {
-			ControllerCreator impressumControllerCreator = new ControllerCreator() {
-				public Controller createController(UserRequest lureq, WindowControl lwControl) {
-					return new ImpressumMainController(lureq, lwControl);
-				}
-			};
-			PopupBrowserWindow popupBrowserWindow = Windows.getWindows(ureq).getWindowManager().createNewPopupBrowserWindowFor(ureq, impressumControllerCreator);
-			popupBrowserWindow.open(ureq);
+		} else if (source == impressumLink) {
+			doOpenImpressum(ureq);
+		}
+	}
+	
+	@Override
+	protected void event(UserRequest ureq, Controller source, Event event) {
+		if (source == calloutCtr) {
+			closePersonalMenu();
 		}
 	}
+	
+	private void doOpenPersonalTool(UserRequest ureq, Link link) {
+		GenericActionExtension gAe = (GenericActionExtension)link.getUserObject();
+		String navKey = gAe.getNavigationKey();
+		String businessPath = "[HomeSite:" + getIdentity().getKey() + "][" + navKey + ":0]";
+		NewControllerFactory.getInstance().launch(businessPath, ureq, getWindowControl());
+	}
+	
+	private void doCloseMyMenu() {
+		calloutCtr.deactivate();
+		removeAsListenerAndDispose(calloutCtr);
+		calloutCtr = null;
+	}
 
+	private void doOpenMyMenu(UserRequest ureq) {
+		removeAsListenerAndDispose(calloutCtr);
+		Component menu =  getMenuCmp(ureq);
+		calloutCtr = new CloseableCalloutWindowController(ureq, getWindowControl(), menu, myMenuLink, "", true, null);
+		listenTo(calloutCtr);
+		calloutCtr.activate();
+	}
+	
+	private void closePersonalMenu() {
+		removeAsListenerAndDispose(calloutCtr);
+		calloutCtr = null;
+	}
+	
+	private Component getMenuCmp(UserRequest ureq) {
+		VelocityContainer container = createVelocityContainer("menu");
+		loadPersonalTools(ureq, container);
+		menuVC = container;
+		return menuVC;
+	}
+	
+	private void loadPersonalTools(UserRequest ureq, VelocityContainer container) {
+		List<String> linksName = new ArrayList<String>();
+		List<String> configLinksName = new ArrayList<String>();
+		
+		ExtManager extm = ExtManager.getInstance();
+		for (Extension anExt : extm.getExtensions()) {
+			// check for sites
+			ExtensionElement ae = anExt.getExtensionFor(HomeMainController.class.getName(), ureq);
+			if (ae != null && ae instanceof GenericActionExtension) {
+				if(anExt.isEnabled()){
+					GenericActionExtension gAe = (GenericActionExtension) ae;
+					if(!StringHelper.containsNonWhitespace(gAe.getParentTreeNodeIdentifier())) {
+						GenericTreeNode node = gAe.createMenuNode(ureq);
+						String linkName = "personal.tool." + node.getIdent();
+						Link link = LinkFactory.createLink(linkName, container, this);
+						link.setUserObject(gAe);
+						link.setCustomDisplayText(gAe.getActionText(getLocale()));
+						link.setCustomEnabledLinkCSS(node.getIconCssClass());
+						linksName.add(linkName);
+					} else if("config".equals(gAe.getParentTreeNodeIdentifier())) {
+						GenericTreeNode node = gAe.createMenuNode(ureq);
+						String linkName = "personal.tool." + node.getIdent();
+						Link link = LinkFactory.createLink(linkName, container, this);
+						link.setUserObject(gAe);
+						link.setCustomDisplayText(gAe.getActionText(getLocale()));
+						link.setCustomEnabledLinkCSS(node.getIconCssClass());
+						configLinksName.add(linkName);
+					}
+				}	
+			}
+		}
+		
+		container.contextPut("personalTools", linksName);
+		container.contextPut("configs", configLinksName);
+	}
+	
+	protected void doOpenHelp(UserRequest ureq) {
+		ControllerCreator ctrlCreator = new ControllerCreator() {
+			public Controller createController(UserRequest lureq, WindowControl lwControl) {
+				return CourseFactory.createHelpCourseLaunchController(lureq, lwControl);
+			}					
+		};
+		//wrap the content controller into a full header layout
+		ControllerCreator layoutCtrlr = BaseFullWebappPopupLayoutFactory.createAuthMinimalPopupLayout(ureq, ctrlCreator);
+		//open in new browser window
+		openInNewBrowserWindow(ureq, layoutCtrlr);
+	}
+	
+	protected void doOpenImpressum(UserRequest ureq) {
+		ControllerCreator impressumControllerCreator = new ControllerCreator() {
+			public Controller createController(UserRequest lureq, WindowControl lwControl) {
+				return new ImpressumMainController(lureq, lwControl);
+			}
+		};
+		PopupBrowserWindow popupBrowserWindow = Windows.getWindows(ureq).getWindowManager().createNewPopupBrowserWindowFor(ureq, impressumControllerCreator);
+		popupBrowserWindow.open(ureq);
+	}
+
+	@Override
 	protected void doDispose() {
 		//controllers are disposed by BasicController
 		// im header controller mus be disposed last - content or navigation control
@@ -199,4 +317,4 @@ public class OlatTopNavController extends BasicController implements GenericEven
 			} 
 		}
 	}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/gui/control/TopNavCreator.java b/src/main/java/org/olat/gui/control/TopNavCreator.java
index 973babde47178061433ec4cd3afcc46b26001751..ad140e0aa47b69f58bb3ce6ef92e45859e692610 100644
--- a/src/main/java/org/olat/gui/control/TopNavCreator.java
+++ b/src/main/java/org/olat/gui/control/TopNavCreator.java
@@ -28,7 +28,7 @@ import org.olat.core.gui.control.creator.AutoCreator;
  * 
  * <h3>Description:</h3>
  * AutoCreator for the FrentixTopNavController which allow to configure
- * an impressum or not, annd the search or not
+ * an impressum or not, and the search or not
  * 
  * <p>
  * Initial Date:  25 nov. 2010 <br>
@@ -39,7 +39,6 @@ public class TopNavCreator extends AutoCreator {
 	private boolean impressum;
 	private boolean search;
 	
-	
 	@Override
 	public Controller createController(UserRequest ureq, WindowControl wControl) {
 		return new OlatTopNavController(ureq, wControl, impressum, search);
@@ -60,4 +59,4 @@ public class TopNavCreator extends AutoCreator {
 	public void setSearch(boolean search) {
 		this.search = search;
 	}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/gui/control/_content/menu.html b/src/main/java/org/olat/gui/control/_content/menu.html
new file mode 100644
index 0000000000000000000000000000000000000000..41bb50eb530e2705988441a2c68d98256a34780d
--- /dev/null
+++ b/src/main/java/org/olat/gui/control/_content/menu.html
@@ -0,0 +1,24 @@
+<div class="o_topnav_my_menu">
+	<span class="o_topnav_my_submenu">$r.translate("topnav.my.menu.tools")</span>
+	<ul>
+	#foreach($personalTool in $personalTools)
+	 	<li>$r.render($personalTool)</li>
+	#end
+	</ul>
+	<hr/>
+	<span class="o_topnav_my_submenu">$r.translate("topnav.my.menu.configurations")</span>
+	<ul>
+	#foreach($config in $configs)
+	 	<li>$r.render($config)</li>
+	#end
+	</ul>
+	<hr/>
+	<ul>
+		<li id="o_topnav_logout">
+			## make logout link very basic without onClick handler in case javaScript is broken it is still possible to log out
+			## except for the onolatunload() method which must be executed to correctly finish SCORM modules (OLAT-6255)
+			## must be on one line to work with inline translation tool
+			<a id="b_logout" href="$r.commandURI("logout")" title="$r.translateInAttribute("topnav.logout.alt")" onclick="if (window.olatonunload) {olatonunload();}"><span class="b_logout_icon">$r.translate("topnav.logout")</span></a>
+		</li>
+	</ul>
+</div>
\ No newline at end of file
diff --git a/src/main/java/org/olat/gui/control/_content/topnav.html b/src/main/java/org/olat/gui/control/_content/topnav.html
index 893c75705c67896ed68080d98163159ce09779fd..d2bad79f28e814990c928fc500244b94cbe03540 100644
--- a/src/main/java/org/olat/gui/control/_content/topnav.html
+++ b/src/main/java/org/olat/gui/control/_content/topnav.html
@@ -4,6 +4,12 @@
 		$r.render("topnav.impressum")
 	</li>
 #end
+
+#if (!$inAssessment && $r.available("search_input"))
+	<li id="o_topnav_search">
+		$r.render("search_input")
+	</li>
+#end
 #if ($r.available("groupchatcontroller"))
 	<li id="o_topnav_imgroupclient">
 		$r.render("groupchatcontroller")
@@ -14,25 +20,14 @@
 		$r.render("imclient")
 	</li>
 #end
-#if (!$inAssessment && $r.available("search_input"))
-	<li id="o_topnav_search">
-		$r.render("search_input")
-	</li>
-#end
-	<li id="o_topnav_printview">
-		<a href="javascript:b_doPrint();" title="$r.translateInAttribute("topnav.printview.alt")" >$r.translate("topnav.printview")</a>
-	</li>
-#if ($r.available("topnav.help"))
-	<li id="o_topnav_help">
-		$r.render("topnav.help")
-	</li>
-#end
 #if (!$isGuest)
-	<li id="o_topnav_logout">
-		## make logout link very basic without onClick handler in case javaScript is broken it is still possible to log out
-		## except for the onolatunload() method which must be executed to correctly finish SCORM modules (OLAT-6255)
-		## must be on one line to work with inline translation tool
-		<a id="b_logout" href="$r.commandURI("logout")" title="$r.translateInAttribute("topnav.logout.alt")" onclick="if (window.olatonunload) {olatonunload();}"><span class="b_logout_icon">$r.translate("topnav.logout")</span></a>
+	<li id="o_topnav_my_menu_link">
+		<div class="o_topnav_portrait">
+		#if($hasPortrait)
+			$r.render("portrait")
+		#end
+		</div>
+		$r.render("topnav.my.menu")
 	</li>
 #else
 	<li id="o_topnav_login">
diff --git a/src/main/java/org/olat/gui/control/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/gui/control/_i18n/LocalStrings_de.properties
index 75a332de9acc668b845d7e3dacf9c6bb7272af37..4d64a906b0836e09127d429442af620a3df6da09 100644
--- a/src/main/java/org/olat/gui/control/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/gui/control/_i18n/LocalStrings_de.properties
@@ -22,3 +22,7 @@ topnav.printview.alt=Diese Seite drucken
 topnav.search=Suche
 topnav.search.alt=Suchen Sie innerhalb von OLAT
 username=Eingeloggt als <i>{0}</i>
+topnav.my.menu=My menu
+topnav.my.menu.tools=Persönliche Werkzeuge
+topnav.my.menu.configurations=Konfiguration
+
diff --git a/src/main/java/org/olat/repository/RepositoryManager.java b/src/main/java/org/olat/repository/RepositoryManager.java
index c62748197928a4dc6de0688a3f7ef99350cdcf77..034314ef4e421a504c2a73aeb271147813b0530f 100644
--- a/src/main/java/org/olat/repository/RepositoryManager.java
+++ b/src/main/java/org/olat/repository/RepositoryManager.java
@@ -1683,8 +1683,8 @@ public class RepositoryManager extends BasicManager {
 		return results;
 	}
 	
-	public int countGenericANDQueryWithRolesRestriction(SearchRepositoryEntryParameters params, boolean orderBy) {
-		DBQuery dbQuery = createGenericANDQueryWithRolesRestriction(params, orderBy, true);
+	public int countGenericANDQueryWithRolesRestriction(SearchRepositoryEntryParameters params) {
+		DBQuery dbQuery = createGenericANDQueryWithRolesRestriction(params, false, true);
 		Number count = (Number)dbQuery.uniqueResult();
 		return count.intValue();
 	}
diff --git a/src/main/java/org/olat/repository/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/repository/_i18n/LocalStrings_de.properties
index 56a12b0a6df5b1bc93c75de2482a3c910f89c975..85535e0889a3aef74f21ff9553f441a099fddfb6 100644
--- a/src/main/java/org/olat/repository/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/repository/_i18n/LocalStrings_de.properties
@@ -384,6 +384,7 @@ search.home=Lernressourcen
 search.id.format=Nur Ziffern erlaubt
 search.intro=Benutzen Sie den OpenOLAT-Katalog, um zu einem Lerninhalt zu gelangen. Alternativ k\u00F6nnen Sie eine allgemeine Suche \u00FCber den Men\u00FCpunkt 'Suchmaske' starten oder Sie w\u00E4hlen eine der vordefinierten Suchen im Menu auf der linken Seite.
 search.limit.type=Suche einschr\u00E4nken
+search.mark=Favoriten
 search.my=Meine Eintr\u00E4ge
 search.mycourses.student=Meine Kurse
 search.mycourses.teacher=Meine betreuten Kurse
@@ -398,6 +399,12 @@ security.disabled.title=Lernressource nicht verf
 security.disabled.info=Diese Lernressourcen ist aus Sicherheitsgründen gesperrt. Weitere Informationen erhalten Sie von Ihrem Systemadministrator. 
 sf.notconfigured=Kein Ressourcenordner ausgew\u00E4hlt
 sf.resourcetitle=Gew\u00E4hlter Ressourcenordner
+start=starten
+details=mehr...
+ratings=Bewertung
+rating.average.explanation=Basierend auf {0} Bewertungen
+rating.average.title=Bewertung der anderen
+rating.personal.title=Ihre Bewertung
 tab.accesscontrol=Access control
 tab.calendar=Kalender
 tab.chat=Kurs-Chat
@@ -428,10 +435,13 @@ table.header.externalid=Ext. ID
 table.header.externalref=Ext. Ref.
 table.header.lastusage=Letzter Zugriff
 table.header.typeimg=Typ
+table.header.mark=Favorit
+table.header.key=ID
 table.header.lifecycle.label=Semester
 table.header.lifecycle.softkey=Semesterbezeichnung
 table.header.lifecycle.start=$\:cif.date.start
 table.header.lifecycle.end=$\:cif.date.end
+table.header.start=Starten
 table.subject.addeddate=Wann hinzugef\u00FCgt 
 table.subject.birthDay=Geburtsdatum
 table.subject.city=Stadt
@@ -452,6 +462,8 @@ table.subject.telOffice=Telefon Gesch\u00E4ft
 table.subject.telPrivate=Telefon Privat
 table.subject.zipCode=Postleitzahl
 table.user.login=Benutzername
+table.switch.list=Liste
+table.switch.table=Table
 title.prefix.closed=beendet
 tools.add.blog=Blog
 tools.add.course=Kurs
diff --git a/src/main/java/org/olat/repository/site/MyCoursesSite.java b/src/main/java/org/olat/repository/site/MyCoursesSite.java
new file mode 100644
index 0000000000000000000000000000000000000000..7b23571b324564207b78bfe643b34b232528448c
--- /dev/null
+++ b/src/main/java/org/olat/repository/site/MyCoursesSite.java
@@ -0,0 +1,92 @@
+/**
+ * <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.repository.site;
+
+import java.util.Locale;
+
+import org.olat.core.commons.chiefcontrollers.BaseChiefController;
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.gui.control.generic.layout.MainLayoutController;
+import org.olat.core.gui.control.navigation.AbstractSiteInstance;
+import org.olat.core.gui.control.navigation.DefaultNavElement;
+import org.olat.core.gui.control.navigation.NavElement;
+import org.olat.core.gui.control.navigation.SiteConfiguration;
+import org.olat.core.gui.control.navigation.SiteDefinition;
+import org.olat.core.gui.translator.Translator;
+import org.olat.core.id.OLATResourceable;
+import org.olat.core.id.context.BusinessControlFactory;
+import org.olat.core.id.context.StateSite;
+import org.olat.core.logging.activity.ThreadLocalUserActivityLogger;
+import org.olat.core.util.Util;
+import org.olat.core.util.resource.OresHelper;
+import org.olat.repository.ui.list.MyCoursesMainController;
+import org.olat.util.logging.activity.LoggingResourceable;
+
+/**
+ * 
+ * Initial date: 28.01.2014<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class MyCoursesSite extends AbstractSiteInstance {
+
+	private NavElement origNavElem;
+	private NavElement curNavElem;
+
+	public MyCoursesSite(SiteDefinition siteDef, Locale loc) {
+		super(siteDef);
+		Translator trans = Util.createPackageTranslator(BaseChiefController.class, loc);
+		origNavElem = new DefaultNavElement(trans.translate("topnav.mycourses"), trans.translate("topnav.mycourses.alt"), "o_site_repository");		
+		origNavElem.setAccessKey("r".charAt(0));
+		curNavElem = new DefaultNavElement(origNavElem);
+	}
+
+	/**
+	 * @see org.olat.navigation.SiteInstance#getNavElement()
+	 */
+	public NavElement getNavElement() {
+		return curNavElem;
+	}
+
+	@Override
+	protected MainLayoutController createController(UserRequest ureq, WindowControl wControl, SiteConfiguration config) {
+		OLATResourceable ores = OresHelper.createOLATResourceableInstance(MyCoursesSite.class, 0l);
+		ThreadLocalUserActivityLogger.addLoggingResourceInfo(LoggingResourceable.wrapBusinessPath(ores));
+		WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(ureq, ores, new StateSite(this), wControl, true);
+		MainLayoutController c = new MyCoursesMainController(ureq, bwControl);
+
+		//MainLayoutController c2 = new LayoutMain3ColsController(ureq, bwControl, c);
+		return c;
+	}
+
+	/**
+	 * @see org.olat.navigation.SiteInstance#isKeepState()
+	 */
+	public boolean isKeepState() {
+		return true;
+	}
+	
+	public void reset() {
+		curNavElem = new DefaultNavElement(origNavElem);
+	}
+
+}
+
diff --git a/src/main/java/org/olat/repository/site/MyCoursesSiteDef.java b/src/main/java/org/olat/repository/site/MyCoursesSiteDef.java
new file mode 100644
index 0000000000000000000000000000000000000000..0790ffe3cd6ca025863a15a8119e25f6d38bde5f
--- /dev/null
+++ b/src/main/java/org/olat/repository/site/MyCoursesSiteDef.java
@@ -0,0 +1,56 @@
+/**
+ * <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.repository.site;
+
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.gui.control.navigation.AbstractSiteDefinition;
+import org.olat.core.gui.control.navigation.SiteConfiguration;
+import org.olat.core.gui.control.navigation.SiteDefinition;
+import org.olat.core.gui.control.navigation.SiteInstance;
+import org.olat.core.util.StringHelper;
+
+/**
+ * 
+ * Initial date: 28.01.2014<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class MyCoursesSiteDef extends AbstractSiteDefinition implements SiteDefinition {
+
+	public MyCoursesSiteDef() {
+		//
+	}
+
+	/**
+	 * site is open to both normal users and guest users
+	 */
+	@Override
+	public SiteInstance createSite(UserRequest ureq, WindowControl wControl, SiteConfiguration config) {
+		if(StringHelper.containsNonWhitespace(config.getSecurityCallbackBeanId())) {
+			return new MyCoursesSite(this, ureq.getLocale());
+		} else if(!ureq.getUserSession().getRoles().isInvitee()) {
+			//for all excepts invitees
+			return new MyCoursesSite(this, ureq.getLocale());
+		}
+		return null;
+	}
+}
+
diff --git a/src/main/java/org/olat/repository/ui/list/AbstractRepositoryEntryDataSource.java b/src/main/java/org/olat/repository/ui/list/AbstractRepositoryEntryDataSource.java
new file mode 100644
index 0000000000000000000000000000000000000000..f331956523b0423bc7ac8df3b79875223cf27679
--- /dev/null
+++ b/src/main/java/org/olat/repository/ui/list/AbstractRepositoryEntryDataSource.java
@@ -0,0 +1,230 @@
+/**
+ * <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.repository.ui.list;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.olat.basesecurity.BaseSecurity;
+import org.olat.basesecurity.SecurityGroup;
+import org.olat.core.CoreSpringFactory;
+import org.olat.core.commons.persistence.ResultInfos;
+import org.olat.core.commons.persistence.SortKey;
+import org.olat.core.commons.services.mark.MarkManager;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataSourceDelegate;
+import org.olat.core.id.Identity;
+import org.olat.core.util.StringHelper;
+import org.olat.core.util.resource.OresHelper;
+import org.olat.core.util.vfs.VFSLeaf;
+import org.olat.course.assessment.AssessmentHelper;
+import org.olat.course.assessment.UserCourseInformations;
+import org.olat.course.assessment.UserEfficiencyStatement;
+import org.olat.course.assessment.manager.UserCourseInformationsManager;
+import org.olat.modules.coach.manager.CoachingService;
+import org.olat.modules.coach.model.EfficiencyStatementEntry;
+import org.olat.repository.RepositoryEntry;
+import org.olat.repository.RepositoryManager;
+import org.olat.repository.model.RepositoryEntryLifecycle;
+import org.olat.repository.model.RepositoryEntryMembership;
+import org.olat.repository.ui.PriceMethod;
+import org.olat.resource.OLATResource;
+import org.olat.resource.accesscontrol.ACService;
+import org.olat.resource.accesscontrol.model.OLATResourceAccess;
+import org.olat.resource.accesscontrol.model.PriceMethodBundle;
+import org.olat.resource.accesscontrol.ui.PriceFormat;
+import org.olat.user.UserManager;
+
+/**
+ * 
+ * Initial date: 28.01.2014<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public abstract class AbstractRepositoryEntryDataSource implements FlexiTableDataSourceDelegate<RepositoryEntryRow> {
+	
+	private final Identity identity;
+	private RepositoryEntryDataSourceUIFactory uifactory;
+	
+	protected final ACService acService;
+	protected final MarkManager markManager;
+	protected final UserManager userManager;
+	protected final CoachingService coachService;
+	protected final BaseSecurity securityManager;
+	protected final RepositoryManager repositoryManager;
+	protected final UserCourseInformationsManager courseInfoManager;
+	
+	private Integer count;
+	
+	public AbstractRepositoryEntryDataSource(Identity identity, RepositoryEntryDataSourceUIFactory uifactory) {
+		this.identity = identity;
+		this.uifactory = uifactory;
+		
+		acService = CoreSpringFactory.getImpl(ACService.class);
+		markManager = CoreSpringFactory.getImpl(MarkManager.class);
+		userManager = CoreSpringFactory.getImpl(UserManager.class);
+		coachService = CoreSpringFactory.getImpl(CoachingService.class);
+		securityManager = CoreSpringFactory.getImpl(BaseSecurity.class);
+		repositoryManager = CoreSpringFactory.getImpl(RepositoryManager.class);
+		courseInfoManager = CoreSpringFactory.getImpl(UserCourseInformationsManager.class);
+	}
+	
+	public Identity getIdentity() {
+		return identity;
+	}
+
+	@Override
+	public int getRowCount() {
+		if(count == null) {
+			count = getNumOfRepositoryEntries();
+		}
+		return count.intValue();
+	}
+	
+	protected abstract int getNumOfRepositoryEntries();
+
+	@Override
+	public List<RepositoryEntryRow> reload(List<RepositoryEntryRow> rows) {
+		return Collections.emptyList();
+	}
+
+	@Override
+	public abstract ResultInfos<RepositoryEntryRow> getRows(String query, List<String> condQueries, int firstResult, int maxResults,
+			SortKey... orderBy);
+	
+	protected List<RepositoryEntryRow> processModel(List<RepositoryEntry> repoEntries) {
+		List<OLATResource> resources = new ArrayList<OLATResource>(repoEntries.size());
+		List<SecurityGroup> authorsSecGroup = new ArrayList<SecurityGroup>(repoEntries.size());
+		Set<Long> markedResources = new HashSet<Long>(repoEntries.size() * 2 + 1);
+		for(RepositoryEntry entry:repoEntries) {
+			resources.add(entry.getOlatResource());
+			authorsSecGroup.add(entry.getOwnerGroup());
+			markedResources.add(entry.getResourceableId());
+		}
+
+		List<UserCourseInformations> courseInfos = courseInfoManager.getUserCourseInformations(identity, resources);
+		List<RepositoryEntryMembership> authors = repositoryManager.getOwnersMembership(repoEntries);
+		
+		Set<Long> authorKeys = new HashSet<>();
+		for(RepositoryEntryMembership membership:authors) {
+			authorKeys.add(membership.getIdentityKey());
+		}
+		Map<Long,String> authorNames = userManager.getUserDisplayNamesByKey(authorKeys);
+		markManager.filterMarks(identity, "RepositoryEntry", markedResources);
+		List<OLATResourceAccess> resourcesWithOffer = acService.filterRepositoryEntriesWithAC(repoEntries);
+		List<EfficiencyStatementEntry> statements = coachService.getEfficencyStatements(identity, repoEntries);
+
+		List<RepositoryEntryRow> items = new ArrayList<RepositoryEntryRow>();
+		for(RepositoryEntry entry:repoEntries) {
+			RepositoryEntryRow details = new RepositoryEntryRow();
+			details.setKey(entry.getKey());
+			details.setDisplayName(entry.getDisplayname());
+			details.setDescription(entry.getDescription());
+			details.setMarked(markedResources.contains(entry.getResourceableId()));
+			details.setOLATResourceable(OresHelper.clone(entry.getOlatResource()));
+			
+			RepositoryEntryLifecycle lifecycle = entry.getLifecycle();
+			if(lifecycle != null) {
+				details.setLifecycleStart(lifecycle.getValidFrom());
+				details.setLifecycleEnd(lifecycle.getValidTo());
+				if(!lifecycle.isPrivateCycle()) {
+					details.setLifecycle(lifecycle.getLabel());
+					details.setLifecycleSoftKey(lifecycle.getSoftKey());
+				}
+			}
+			
+			uifactory.forgeMarkLink(details);
+			uifactory.forgeSelectLink(details);
+			uifactory.forgeStartLink(details);
+			uifactory.forgeDetailsLink(details);
+			uifactory.forgeRatings(details, entry);
+
+			VFSLeaf image = repositoryManager.getImage(entry);
+			if(image != null) {
+				details.setThumbnailRelPath(uifactory.getMapperThumbnailUrl() + "/" + image.getName());
+			}
+			
+			StringBuilder sb = new StringBuilder();
+			for(RepositoryEntryMembership membership:authors) {
+				if(entry.getKey().equals(membership.getOwnerRepoKey())) {
+					String authorName = authorNames.get(membership.getIdentityKey());
+					if(StringHelper.containsNonWhitespace(authorName)) {
+						if(sb.length() > 0) {
+							sb.append(" &amp; ");
+						}
+						sb.append(authorName);
+					}
+				}
+			}
+			if(sb.length() > 0) {
+				details.setAuthor(sb.toString());
+			}
+			
+			
+			
+			for(UserCourseInformations courseInfo:courseInfos) {
+				if(courseInfo.getResource().equals(entry.getOlatResource())) {
+					details.setInitialLaunch(courseInfo.getInitialLaunch());
+					details.setRecentLaunch(courseInfo.getRecentLaunch());
+					details.setVisit(courseInfo.getVisit());
+					details.setTimeSpend(courseInfo.getTimeSpend());
+				}
+			}
+			
+			for(EfficiencyStatementEntry statement:statements) {
+				if(statement.getUserEfficencyStatement() != null && statement.getCourse().equals(entry)) {
+					UserEfficiencyStatement userStatement = statement.getUserEfficencyStatement();
+
+					details.setPassed(userStatement.getPassed());
+					details.setScore(AssessmentHelper.getRoundedScore(userStatement.getScore()));
+				}
+			}
+			
+			List<PriceMethod> types = new ArrayList<PriceMethod>();
+			if (entry.isMembersOnly()) {
+				// members only always show lock icon
+				types.add(new PriceMethod("", "b_access_membersonly_icon"));
+			} else {
+				// collect access control method icons
+				OLATResource resource = entry.getOlatResource();
+				for(OLATResourceAccess resourceAccess:resourcesWithOffer) {
+					if(resource.getKey().equals(resourceAccess.getResource().getKey())) {
+						for(PriceMethodBundle bundle:resourceAccess.getMethods()) {
+							String type = (bundle.getMethod().getMethodCssClass() + "_icon").intern();
+							String price = bundle.getPrice() == null || bundle.getPrice().isEmpty() ? "" : PriceFormat.fullFormat(bundle.getPrice());
+							types.add(new PriceMethod(price, type));
+						}
+					}
+				}
+			}
+			
+			if(!types.isEmpty()) {
+				details.setAccessTypes(types);
+			}
+			
+			items.add(details);
+			
+		}
+		return items;
+	}
+}
diff --git a/src/main/java/org/olat/repository/ui/list/AbstractRepositoryEntryListController.java b/src/main/java/org/olat/repository/ui/list/AbstractRepositoryEntryListController.java
new file mode 100644
index 0000000000000000000000000000000000000000..4b436a58f0b9bae1ea992816bc8340ae589a81e2
--- /dev/null
+++ b/src/main/java/org/olat/repository/ui/list/AbstractRepositoryEntryListController.java
@@ -0,0 +1,234 @@
+/**
+ * <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.repository.ui.list;
+
+import org.olat.NewControllerFactory;
+import org.olat.core.CoreSpringFactory;
+import org.olat.core.commons.services.commentAndRating.CommentAndRatingService;
+import org.olat.core.commons.services.commentAndRating.impl.UserRatingsDAO;
+import org.olat.core.commons.services.commentAndRating.model.UserRating;
+import org.olat.core.commons.services.mark.MarkManager;
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.form.flexible.FormItem;
+import org.olat.core.gui.components.form.flexible.FormItemContainer;
+import org.olat.core.gui.components.form.flexible.elements.FlexiTableElement;
+import org.olat.core.gui.components.form.flexible.elements.FormLink;
+import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
+import org.olat.core.gui.components.form.flexible.impl.FormEvent;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiColumnModel;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataSourceDelegate;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableRendererType;
+import org.olat.core.gui.components.link.Link;
+import org.olat.core.gui.components.rating.RatingFormEvent;
+import org.olat.core.gui.components.rating.RatingWithAverageFormItem;
+import org.olat.core.gui.components.velocity.VelocityContainer;
+import org.olat.core.gui.control.Controller;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.id.OLATResourceable;
+import org.olat.core.util.Util;
+import org.olat.core.util.resource.OresHelper;
+import org.olat.repository.RepositoryEntry;
+import org.olat.repository.RepositoryManager;
+import org.olat.repository.ui.RepositoryEntryImageMapper;
+import org.olat.repository.ui.list.RepositoryEntryDataModel.Cols;
+
+/**
+ * 
+ * Initial date: 20.11.2012<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public abstract class AbstractRepositoryEntryListController extends FormBasicController implements RepositoryEntryDataSourceUIFactory {
+	
+	private FormLink listLink, tableLink;
+	private FlexiTableElement tableEl;
+	private RepositoryEntryDataModel model;
+	private FlexiTableDataSourceDelegate<RepositoryEntryRow> dataSource;
+	
+	private final String mapperThumbnailUrl;
+	private final MarkManager markManager;
+	private final UserRatingsDAO userRatingsDao;
+	
+	public AbstractRepositoryEntryListController(UserRequest ureq, WindowControl wControl) {
+		super(ureq, wControl, "repoentry_table");
+		setTranslator(Util.createPackageTranslator(RepositoryManager.class, getLocale(), getTranslator()));
+		markManager = CoreSpringFactory.getImpl(MarkManager.class);
+		userRatingsDao = CoreSpringFactory.getImpl(UserRatingsDAO.class);
+		mapperThumbnailUrl = registerCacheableMapper(ureq, "repositoryentryImage", new RepositoryEntryImageMapper());
+	}
+	
+	public FlexiTableDataSourceDelegate<RepositoryEntryRow> getDataSource() {
+		return dataSource;
+	}
+	
+	public void setDataSource(FlexiTableDataSourceDelegate<RepositoryEntryRow> dataSource) {
+		this.dataSource = dataSource;
+		if(tableEl != null) {
+			model.setSource(dataSource);
+			tableEl.reset();
+		}
+	}
+
+	@Override
+	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		listLink = uifactory.addFormLink("switchLayoutList", "list", "table.switch.list", null, formLayout, Link.BUTTON);
+		tableLink = uifactory.addFormLink("switchLayoutTable", "table", "table.switch.table", null, formLayout, Link.BUTTON);
+		
+		//add the table
+		FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel();
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, Cols.key.i18nKey(), Cols.key.ordinal(), false, null));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.mark.i18nKey(), Cols.mark.ordinal()));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.displayName.i18nKey(), Cols.displayName.ordinal()));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.lifecycleLabel.i18nKey(), Cols.lifecycleLabel.ordinal()));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.lifecycleSoftkey.i18nKey(), Cols.lifecycleSoftkey.ordinal()));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.lifecycleStart.i18nKey(), Cols.lifecycleStart.ordinal()));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.lifecycleEnd.i18nKey(), Cols.lifecycleEnd.ordinal()));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, Cols.select.i18nKey(), Cols.select.ordinal(), false, null));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.details.i18nKey(), Cols.details.ordinal()));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.start.i18nKey(), Cols.start.ordinal()));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.ratings.i18nKey(), Cols.ratings.ordinal()));
+
+		model = new RepositoryEntryDataModel(dataSource, columnsModel);
+		tableEl = uifactory.addTableElement(ureq, getWindowControl(), "table", model, 20, getTranslator(), formLayout);
+		tableEl.setRendererType(FlexiTableRendererType.custom);
+		
+		VelocityContainer row = createVelocityContainer("row_1");
+		tableEl.setRowRenderer(row);
+	}
+
+	@Override
+	public String getMapperThumbnailUrl() {
+		return mapperThumbnailUrl;
+	}
+
+	@Override
+	protected void doDispose() {
+		//
+	}
+
+	@Override
+	protected void formOK(UserRequest ureq) {
+		//
+	}
+
+	@Override
+	protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) {
+		if(source == listLink) {
+			tableEl.setRendererType(FlexiTableRendererType.custom);
+		} else if(source == tableLink) {
+			tableEl.setRendererType(FlexiTableRendererType.classic);
+		} else if(source instanceof RatingWithAverageFormItem && event instanceof RatingFormEvent) {
+			RatingFormEvent ratingEvent = (RatingFormEvent)event;
+			RatingWithAverageFormItem ratingItem = (RatingWithAverageFormItem)source;
+			RepositoryEntryRow row = (RepositoryEntryRow)ratingItem.getUserObject();
+			doRating(row, ratingEvent.getRating());
+		} else if(source instanceof FormLink) {
+			FormLink link = (FormLink)source;
+			String cmd = link.getCmd();
+			
+			if("mark".equals(cmd)) {
+				RepositoryEntryRow row = (RepositoryEntryRow)link.getUserObject();
+				if(doMark(row)) {
+					link.setCustomEnabledLinkCSS("b_mark_set");
+				} else {
+					link.setCustomEnabledLinkCSS("b_mark_not_set");
+				}
+				link.getComponent().setDirty(true);
+			} else if ("select".equals(cmd) || "start".equals(cmd)){
+				RepositoryEntryRow row = (RepositoryEntryRow)link.getUserObject();
+				doOpen(ureq, row);
+			} else if ("details".equals(cmd)){
+				RepositoryEntryRow row = (RepositoryEntryRow)link.getUserObject();
+				doOpenDetails(ureq, row);
+			}
+		}
+		
+		super.formInnerEvent(ureq, source, event);
+	}
+	
+	protected void doRating(RepositoryEntryRow row, float rating) {
+		OLATResourceable ores = row.getOLATResourceable();
+		userRatingsDao.updateRating(getIdentity(), ores, null, Math.round(rating));
+	}
+	
+	protected void doOpen(UserRequest ureq, RepositoryEntryRow row) {
+		String businessPath = "[RepositoryEntry:" + row.getKey() + "]";
+		NewControllerFactory.getInstance().launch(businessPath, ureq, getWindowControl());
+	}
+	
+	protected void doOpenDetails(UserRequest ureq, RepositoryEntryRow row) {
+		String businessPath = "[RepositoryEntry:" + row.getKey() + "][details:0]";
+		NewControllerFactory.getInstance().launch(businessPath, ureq, getWindowControl());
+	}
+	
+	protected boolean doMark(RepositoryEntryRow row) {
+		OLATResourceable item = OresHelper.createOLATResourceableInstance("RepositoryEntry", row.getKey());
+		if(markManager.isMarked(item, getIdentity(), null)) {
+			markManager.removeMark(item, getIdentity(), null);
+			return false;
+		} else {
+			String businessPath = "[QuestionItem:" + item.getResourceableId() + "]";
+			markManager.setMark(item, getIdentity(), null, businessPath);
+			return true;
+		}
+	}
+
+	@Override
+	public void forgeMarkLink(RepositoryEntryRow row) {
+		FormLink markLink = uifactory.addFormLink("mark_" + row.getKey(), "mark", "&nbsp;&nbsp;&nbsp;&nbsp;", null, null, Link.NONTRANSLATED);
+		markLink.setCustomEnabledLinkCSS(row.isMarked() ? "b_mark_set" : "b_mark_not_set");
+		markLink.setUserObject(row);
+		row.setMarkLink(markLink);
+	}
+	
+	@Override
+	public void forgeSelectLink(RepositoryEntryRow row) {
+		String name = row.getDisplayName();
+		FormLink selectLink = uifactory.addFormLink("select_" + row.getKey(), "select", name, null, null, Link.NONTRANSLATED);
+		selectLink.setUserObject(row);
+		row.setSelectLink(selectLink);
+	}
+
+	@Override
+	public void forgeStartLink(RepositoryEntryRow row) {
+		FormLink startLink = uifactory.addFormLink("start_" + row.getKey(), "start", "start", null, null, Link.LINK);
+		startLink.setUserObject(row);
+		row.setStartLink(startLink);
+	}
+	
+	@Override
+	public void forgeDetailsLink(RepositoryEntryRow row) {
+		FormLink detailsLink = uifactory.addFormLink("details_" + row.getKey(), "details", "details", null, null, Link.LINK);
+		detailsLink.setUserObject(row);
+		row.setDetailsLink(detailsLink);
+	}
+
+	@Override
+	public void forgeRatings(RepositoryEntryRow row, RepositoryEntry entry) {
+		CommentAndRatingService commentAndRatingService = (CommentAndRatingService) CoreSpringFactory.getBean(CommentAndRatingService.class);
+		commentAndRatingService.init(getIdentity(), entry.getOlatResource(), null, false, false);
+		UserRating rating = userRatingsDao.getRating(getIdentity(), row.getOLATResourceable(), null);
+		float ratingValue = rating != null ? rating.getRating() : 0.0f;
+		RatingWithAverageFormItem ratingCmp = new RatingWithAverageFormItem("rat_" + row.getKey(), ratingValue, 4, 5, 32);
+		row.setRatingFormItem(ratingCmp);
+		ratingCmp.setUserObject(row);
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/repository/ui/list/CatalogEntryListController.java b/src/main/java/org/olat/repository/ui/list/CatalogEntryListController.java
new file mode 100644
index 0000000000000000000000000000000000000000..047eb1a82d26af9a952ef148fc3e0084640f5a80
--- /dev/null
+++ b/src/main/java/org/olat/repository/ui/list/CatalogEntryListController.java
@@ -0,0 +1,46 @@
+/**
+ * <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.repository.ui.list;
+
+import java.util.List;
+
+import org.olat.catalog.CatalogEntry;
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.control.WindowControl;
+
+/**
+ * 
+ * Initial date: 21.11.2012<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class CatalogEntryListController extends AbstractRepositoryEntryListController {
+	
+	public CatalogEntryListController(UserRequest ureq, WindowControl wControl) {
+		super(ureq, wControl);
+		
+		setDataSource(new CategoriesDataSource(null, getIdentity(), this));
+		initForm(ureq);
+	}
+	
+	public void setCatalogEntries(List<CatalogEntry> entries) {
+		setDataSource(new CategoriesDataSource(entries, getIdentity(), this));
+	}
+}
diff --git a/src/main/java/org/olat/repository/ui/list/CatalogNodeController.java b/src/main/java/org/olat/repository/ui/list/CatalogNodeController.java
new file mode 100644
index 0000000000000000000000000000000000000000..1560678bf43ac70e2ae425a1726f705f7fd83585
--- /dev/null
+++ b/src/main/java/org/olat/repository/ui/list/CatalogNodeController.java
@@ -0,0 +1,313 @@
+/**
+ * <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.repository.ui.list;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import org.olat.basesecurity.BaseSecurityManager;
+import org.olat.catalog.CatalogEntry;
+import org.olat.catalog.CatalogManager;
+import org.olat.catalog.ui.CatalogEntryComparator;
+import org.olat.core.CoreSpringFactory;
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.Component;
+import org.olat.core.gui.components.link.Link;
+import org.olat.core.gui.components.link.LinkFactory;
+import org.olat.core.gui.components.panel.MainPanel;
+import org.olat.core.gui.components.stack.StackedController;
+import org.olat.core.gui.components.stack.StackedControllerAware;
+import org.olat.core.gui.components.velocity.VelocityContainer;
+import org.olat.core.gui.control.Controller;
+import org.olat.core.gui.control.Event;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.gui.control.controller.BasicController;
+import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController;
+import org.olat.core.gui.control.generic.dtabs.Activateable2;
+import org.olat.core.helpers.Settings;
+import org.olat.core.id.Identity;
+import org.olat.core.id.OLATResourceable;
+import org.olat.core.id.context.ContextEntry;
+import org.olat.core.id.context.StateEntry;
+import org.olat.core.util.StringHelper;
+import org.olat.core.util.Util;
+import org.olat.core.util.mail.ContactList;
+import org.olat.core.util.mail.ContactMessage;
+import org.olat.core.util.resource.OresHelper;
+import org.olat.modules.co.ContactFormController;
+import org.olat.repository.RepositoryEntry;
+import org.olat.repository.RepositoryManager;
+import org.olat.repository.RepositoryTableModel;
+import org.olat.repository.SearchRepositoryEntryParameters;
+import org.olat.repository.controllers.RepositorySearchController;
+
+/**
+ * 
+ * Initial date: 28.01.2014<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class CatalogNodeController extends BasicController implements Activateable2, StackedControllerAware {
+
+	private StackedController stackPanel;
+	private CatalogEntryListController entryListController;
+	
+	private final VelocityContainer mainVC;
+	private Link contactLink;
+	
+	private CloseableModalController cmc;
+	private ContactFormController contactCtrl;
+	private CatalogNodeController childNodeController;
+	private RepositorySearchController searchResourceCtrl;
+
+	private CatalogEntry catalogEntry;
+
+	private final CatalogManager cm;
+	private final RepositoryManager repositoryManager;
+	
+	public CatalogNodeController(UserRequest ureq, WindowControl wControl, CatalogEntry catalogEntry) {
+		// fallback translator to repository package to reduce redundant translations
+		super(ureq, wControl, Util.createPackageTranslator(RepositoryManager.class, ureq.getLocale()));
+
+		cm = CatalogManager.getInstance();
+		repositoryManager = CoreSpringFactory.getImpl(RepositoryManager.class);
+
+		this.catalogEntry = catalogEntry;
+		
+		mainVC = createVelocityContainer("node");
+
+		//catalog resources
+		entryListController = new CatalogEntryListController(ureq, wControl);
+		mainVC.put("entries", entryListController.getInitialComponent());
+		listenTo(entryListController);
+
+
+		MainPanel mainPanel = new MainPanel("myCoursesMainPanel");
+		mainPanel.setContent(mainVC);
+		putInitialPanel(mainPanel);
+		updateContent(ureq);
+	}
+
+	@Override
+	public void setStackedController(StackedController stackPanel) {
+		this.stackPanel = stackPanel;
+	}
+
+	@Override
+	public void event(UserRequest ureq, Component source, Event event) {
+		if(source == contactLink) {
+			doContactOwners(ureq);
+		} else if(source instanceof Link) {
+			Link link = (Link)source;
+			if("select_node".equals(link.getCommand())) {
+				Long categoryNodeKey = (Long)link.getUserObject();
+				CatalogEntry entry = cm.getCatalogEntryByKey(categoryNodeKey);
+				if(entry != null && entry.getType() == CatalogEntry.TYPE_NODE) {
+					removeAsListenerAndDispose(childNodeController);
+					childNodeController = new CatalogNodeController(ureq, getWindowControl(), entry);
+					listenTo(childNodeController);
+					childNodeController.setStackedController(stackPanel);
+					stackPanel.pushController(entry.getName(), childNodeController);	
+				}
+			}
+		}
+	}
+
+	/**
+	 * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest,
+	 *      org.olat.core.gui.control.Controller, org.olat.core.gui.control.Event)
+	 */
+	@Override
+	public void event(UserRequest ureq, Controller source, Event event) {
+		if(source == searchResourceCtrl) {
+			if (event.getCommand().equals(RepositoryTableModel.TABLE_ACTION_SELECT_LINK)) {
+				addResource(searchResourceCtrl.getSelectedEntry());
+				updateGUI(ureq);
+			}
+			cmc.deactivate();
+			cleanUp();
+		//add/remove owners
+		} else if(source == contactCtrl) {
+			cmc.deactivate();
+			cleanUp();
+		} else if(source == childNodeController) {
+			if(event == Event.DONE_EVENT) {
+				stackPanel.popController(childNodeController);
+				removeAsListenerAndDispose(childNodeController);
+				childNodeController = null;
+				updateGUI(ureq);
+			} else if(event == Event.CHANGED_EVENT) {
+				updateGUI(ureq);
+			}
+		} else if(source == entryListController) {
+			if(event == Event.CHANGED_EVENT) {
+				updateGUI(ureq);
+			}
+		} else if(source == cmc) {
+			cleanUp();
+		} else {
+			super.event(ureq, source, event);
+		}
+	}
+	
+	private void cleanUp() {
+		removeAsListenerAndDispose(cmc);
+		removeAsListenerAndDispose(contactCtrl);
+		removeAsListenerAndDispose(searchResourceCtrl);
+		
+		cmc = null;
+		contactCtrl = null;
+		searchResourceCtrl = null;
+	}
+
+	/**
+	 * @see org.olat.core.gui.control.DefaultController#doDispose(boolean)
+	 */
+	protected void doDispose() {
+		//
+	}
+	
+	private void doContactOwners(UserRequest ureq) {
+		ContactList caretaker = new ContactList(translate("contact.to.groupname.caretaker"));
+		List<Identity> owners = cm.getOwnersOfParentLine(catalogEntry);
+		caretaker.addAllIdentites(owners);
+		ContactMessage cmsg = new ContactMessage(getIdentity());
+		cmsg.addEmailTo(caretaker);
+		contactCtrl = new ContactFormController(ureq, getWindowControl(), false, true, false, false, cmsg);
+		listenTo(contactCtrl);
+		
+		cmc = new CloseableModalController(getWindowControl(), "close", contactCtrl.getInitialComponent(), true, translate("contact.caretaker"));
+		listenTo(cmc);
+		cmc.activate();
+	}
+	
+	private void addResource(RepositoryEntry re) {
+		CatalogEntry newCatalogEntry = cm.createCatalogEntry();
+		newCatalogEntry.setName(re.getDisplayname());
+		newCatalogEntry.setDescription(re.getDescription());
+		newCatalogEntry.setRepositoryEntry(re);
+		newCatalogEntry.setType(CatalogEntry.TYPE_LEAF);
+		newCatalogEntry.setOwnerGroup(BaseSecurityManager.getInstance().createAndPersistSecurityGroup());
+		cm.addCatalogEntry(catalogEntry, newCatalogEntry);
+		cm.saveCatalogEntry(newCatalogEntry);
+	}
+
+	/**
+	 * refresh content of current category for displaying
+	 * 
+	 * @param ce
+	 * @param ceLevel
+	 */
+	private void updateGUI(UserRequest ureq) {
+		updateContent(ureq);
+		updateHistory(ureq);
+	}
+
+	private void updateContent(UserRequest ureq) {
+		mainVC.contextPut("catalogEntryName", catalogEntry.getName());
+		if(StringHelper.containsNonWhitespace(catalogEntry.getDescription())) {
+			mainVC.contextPut("catalogEntryDesc", catalogEntry.getDescription());
+		}
+		
+		List<CatalogEntry> childCe = cm.getChildrenOf(catalogEntry);
+		// Sort to fix ordering by repo entry display name. For leafs the displayed
+		// name is not the catalog entry name but the repo entry display name. The
+		// SQL query orders by catalog entry name, thus the visual ordering is
+		// wrong.
+		Collections.sort(childCe, new CatalogEntryComparator(getLocale()));
+	
+		List<Long> repositoryEntryKeys = new ArrayList<Long>();
+		List<Link> subCategories = new ArrayList<Link>();
+		for (CatalogEntry entry : childCe) {
+			if(entry.getType() == CatalogEntry.TYPE_NODE) {
+				String cmpId = "cat_" + entry.getKey();
+				Link link = LinkFactory.createCustomLink(cmpId, "select_node", cmpId, Link.LINK + Link.NONTRANSLATED, mainVC, this);
+				link.setCustomDisplayText(entry.getName());
+				link.setCustomEnabledLinkCSS("b_with_small_icon_left o_catalog_sub_icon");
+				link.setUserObject(entry.getKey());
+				subCategories.add(link);
+			} else if(entry.getRepositoryEntry() != null && entry.getRepositoryEntry().getOlatResource() != null) {
+				repositoryEntryKeys.add(entry.getRepositoryEntry().getKey());
+			}
+		}
+		boolean hasEntries = subCategories.size() != childCe.size();
+		mainVC.getComponent("entries").setVisible(hasEntries);
+		mainVC.contextPut("subCategories", subCategories);
+		
+		if(!repositoryEntryKeys.isEmpty()) {
+			SearchRepositoryEntryParameters params = new SearchRepositoryEntryParameters();
+			params.setIdentity(getIdentity());
+			params.setRoles(ureq.getUserSession().getRoles());
+			params.setRepositoryEntryKeys(repositoryEntryKeys);
+			List<RepositoryEntry> allowedEntries = repositoryManager.genericANDQueryWithRolesRestriction(params, 0, -1, false);
+
+			List<CatalogEntry> catalogEntriesOfRepo = new ArrayList<CatalogEntry>(childCe);
+			for(Iterator<CatalogEntry> it=catalogEntriesOfRepo.iterator(); it.hasNext(); ) {
+				RepositoryEntry catRepoEntry = it.next().getRepositoryEntry();
+				if(catRepoEntry == null || !allowedEntries.contains(catRepoEntry)) {
+					it.remove();
+				}
+			}
+	
+			entryListController.setCatalogEntries(catalogEntriesOfRepo);
+		}
+
+		String url = Settings.getServerContextPathURI() + "/url/CatalogEntry/" + catalogEntry.getKey();
+		mainVC.contextPut("guestExtLink", url + "?guest=true&amp;lang=" + getLocale().getLanguage());
+		if (!ureq.getUserSession().getRoles().isGuestOnly()) {
+			mainVC.contextPut("extLink", url);
+		}
+	}
+
+	public void updateHistory(UserRequest ureq) {
+		if(catalogEntry != null) {
+			OLATResourceable ores = OresHelper.createOLATResourceableInstance(CatalogEntry.class, catalogEntry.getKey());
+			addToHistory(ureq, ores, null);
+		} else {
+			addToHistory(ureq);
+		}
+	}
+
+	@Override
+	public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) {
+		if(entries == null || entries.isEmpty()) return;
+		
+	}
+	
+	public class PriceMethod {
+		private String price;
+		private String type;
+		
+		public PriceMethod(String price, String type) {
+			this.price = price;
+			this.type = type;
+		}
+		
+		public String getPrice() {
+			return price;
+		}
+		
+		public String getType() {
+			return type;
+		}
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/repository/ui/list/CategoriesDataSource.java b/src/main/java/org/olat/repository/ui/list/CategoriesDataSource.java
new file mode 100644
index 0000000000000000000000000000000000000000..3e0af1cb51107994bab2cd1a349d912dae2737f3
--- /dev/null
+++ b/src/main/java/org/olat/repository/ui/list/CategoriesDataSource.java
@@ -0,0 +1,71 @@
+/**
+ * <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.repository.ui.list;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.olat.catalog.CatalogEntry;
+import org.olat.core.commons.persistence.DefaultResultInfos;
+import org.olat.core.commons.persistence.ResultInfos;
+import org.olat.core.commons.persistence.SortKey;
+import org.olat.core.id.Identity;
+import org.olat.repository.RepositoryEntry;
+
+/**
+ * 
+ * Initial date: 29.01.2014<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class CategoriesDataSource extends AbstractRepositoryEntryDataSource {
+	
+	private final List<CatalogEntry> entries;
+	
+	public CategoriesDataSource(List<CatalogEntry> entries, Identity identity,
+			RepositoryEntryDataSourceUIFactory uifactory) {
+		super(identity, uifactory);
+		this.entries = entries;
+	}
+
+	@Override
+	protected int getNumOfRepositoryEntries() {
+		return entries == null ? 0 : entries.size();
+	}
+
+	@Override
+	public List<RepositoryEntryRow> reload(List<RepositoryEntryRow> rows) {
+		return Collections.emptyList();
+	}
+
+	@Override
+	public ResultInfos<RepositoryEntryRow> getRows(String query, List<String> condQueries, int firstResult, int maxResults,
+			SortKey... orderBy) {
+		
+		List<RepositoryEntry> repoEntries = new ArrayList<>(maxResults);
+		for(int i=firstResult; i<maxResults && i<getNumOfRepositoryEntries(); i++) {
+			CatalogEntry entry = entries.get(i);
+			repoEntries.add(entry.getRepositoryEntry());
+		}
+		List<RepositoryEntryRow> rows = processModel(repoEntries);
+		return new DefaultResultInfos<RepositoryEntryRow>(firstResult + rows.size(), -1, rows);
+	}
+}
diff --git a/src/main/java/org/olat/repository/ui/list/FavoritRepositoryEntryDataSource.java b/src/main/java/org/olat/repository/ui/list/FavoritRepositoryEntryDataSource.java
new file mode 100644
index 0000000000000000000000000000000000000000..418f86e5d822c0eafff36fba1f2f8563583cbf0c
--- /dev/null
+++ b/src/main/java/org/olat/repository/ui/list/FavoritRepositoryEntryDataSource.java
@@ -0,0 +1,70 @@
+/**
+ * <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.repository.ui.list;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.olat.core.commons.persistence.DefaultResultInfos;
+import org.olat.core.commons.persistence.ResultInfos;
+import org.olat.core.commons.persistence.SortKey;
+import org.olat.core.id.Identity;
+import org.olat.core.id.Roles;
+import org.olat.repository.RepositoryEntry;
+import org.olat.repository.SearchRepositoryEntryParameters;
+
+/**
+ * 
+ * Initial date: 29.01.2014<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class FavoritRepositoryEntryDataSource extends AbstractRepositoryEntryDataSource {
+	
+	private final Roles roles;
+	
+	public FavoritRepositoryEntryDataSource(Identity identity, Roles roles, RepositoryEntryDataSourceUIFactory uifactory) {
+		super(identity, uifactory);
+		this.roles = roles;
+	}
+
+	@Override
+	protected int getNumOfRepositoryEntries() {
+		SearchRepositoryEntryParameters params = new SearchRepositoryEntryParameters(getIdentity(), roles, "CourseModule");
+		params.setMarked(Boolean.TRUE);
+		return repositoryManager.countGenericANDQueryWithRolesRestriction(params);
+	}
+
+	@Override
+	public List<RepositoryEntryRow> reload(List<RepositoryEntryRow> rows) {
+		return Collections.emptyList();
+	}
+
+	@Override
+	public ResultInfos<RepositoryEntryRow> getRows(String query, List<String> condQueries, int firstResult, int maxResults,
+			SortKey... orderBy) {
+		
+		SearchRepositoryEntryParameters params = new SearchRepositoryEntryParameters(getIdentity(), roles, "CourseModule");
+		params.setMarked(Boolean.TRUE);
+		List<RepositoryEntry> repoEntries = repositoryManager.genericANDQueryWithRolesRestriction(params, firstResult, maxResults, true);
+		List<RepositoryEntryRow> rows = processModel(repoEntries);
+		return new DefaultResultInfos<RepositoryEntryRow>(firstResult + rows.size(), -1, rows);
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/repository/ui/list/FavoritRepositoryEntryListController.java b/src/main/java/org/olat/repository/ui/list/FavoritRepositoryEntryListController.java
new file mode 100644
index 0000000000000000000000000000000000000000..8678ef0f1def6a83ac1b5361685d22beeb0ad771
--- /dev/null
+++ b/src/main/java/org/olat/repository/ui/list/FavoritRepositoryEntryListController.java
@@ -0,0 +1,49 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.repository.ui.list;
+
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.id.Roles;
+
+/**
+ * 
+ * Initial date: 28.01.2014<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class FavoritRepositoryEntryListController extends AbstractRepositoryEntryListController {
+	
+	private final Roles roles;
+	
+	public FavoritRepositoryEntryListController(UserRequest ureq, WindowControl wControl) {
+		super(ureq, wControl);
+		roles = ureq.getUserSession().getRoles();
+		
+		FavoritRepositoryEntryDataSource dataSource = new FavoritRepositoryEntryDataSource(getIdentity(), roles, this);
+		setDataSource(dataSource);
+		
+		initForm(ureq);
+	}
+
+	protected boolean updateMarkedEntries() {
+		return getDataSource().getRowCount() > 0;
+	}
+}
diff --git a/src/main/java/org/olat/repository/ui/list/MyCoursesMainController.java b/src/main/java/org/olat/repository/ui/list/MyCoursesMainController.java
new file mode 100644
index 0000000000000000000000000000000000000000..279990d937bc29e414811e67a6630fb42634ceb2
--- /dev/null
+++ b/src/main/java/org/olat/repository/ui/list/MyCoursesMainController.java
@@ -0,0 +1,77 @@
+/**
+ * <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.repository.ui.list;
+
+import java.util.List;
+
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.Component;
+import org.olat.core.gui.components.panel.MainPanel;
+import org.olat.core.gui.components.stack.StackedController;
+import org.olat.core.gui.components.stack.StackedControllerImpl;
+import org.olat.core.gui.control.Event;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.gui.control.controller.MainLayoutBasicController;
+import org.olat.core.gui.control.generic.dtabs.Activateable2;
+import org.olat.core.id.context.ContextEntry;
+import org.olat.core.id.context.StateEntry;
+
+/**
+ * 
+ * Initial date: 28.01.2014<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class MyCoursesMainController extends MainLayoutBasicController implements Activateable2 {
+
+	private final MainPanel mainPanel;
+	private final StackedController stackPanel;
+	private final OverviewRepositoryListController overviewCtrl;
+	
+	public MyCoursesMainController(UserRequest ureq, WindowControl wControl) {
+		super(ureq, wControl);
+		
+		mainPanel = new MainPanel("myCoursesMainPanel");
+
+		overviewCtrl = new OverviewRepositoryListController(ureq, wControl);
+		listenTo(overviewCtrl);
+		stackPanel = new StackedControllerImpl(getWindowControl(), getTranslator(), "o_courses_breadcrumbs");
+		listenTo(stackPanel);
+		stackPanel.pushController("Kurse", overviewCtrl);
+		overviewCtrl.setStackedController(stackPanel);
+		mainPanel.setContent(stackPanel.getInitialComponent());
+		putInitialPanel(stackPanel.getInitialComponent());
+	}
+	
+	@Override
+	protected void doDispose() {
+		//
+	}
+	
+	@Override
+	protected void event(UserRequest ureq, Component source, Event event) {
+		//
+	}
+
+	@Override
+	public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) {
+		overviewCtrl.activate(ureq, entries, state);
+	}
+}
diff --git a/src/main/java/org/olat/repository/ui/list/OverviewRepositoryListController.java b/src/main/java/org/olat/repository/ui/list/OverviewRepositoryListController.java
new file mode 100644
index 0000000000000000000000000000000000000000..dc550bf04e976e831b42b9372791023923c0b41d
--- /dev/null
+++ b/src/main/java/org/olat/repository/ui/list/OverviewRepositoryListController.java
@@ -0,0 +1,157 @@
+/**
+ * <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.repository.ui.list;
+
+import java.util.List;
+
+import org.olat.catalog.CatalogEntry;
+import org.olat.catalog.CatalogManager;
+import org.olat.core.CoreSpringFactory;
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.Component;
+import org.olat.core.gui.components.link.Link;
+import org.olat.core.gui.components.link.LinkFactory;
+import org.olat.core.gui.components.panel.MainPanel;
+import org.olat.core.gui.components.segmentedview.SegmentViewComponent;
+import org.olat.core.gui.components.segmentedview.SegmentViewEvent;
+import org.olat.core.gui.components.segmentedview.SegmentViewFactory;
+import org.olat.core.gui.components.stack.StackedController;
+import org.olat.core.gui.components.stack.StackedControllerAware;
+import org.olat.core.gui.components.velocity.VelocityContainer;
+import org.olat.core.gui.control.Event;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.gui.control.controller.BasicController;
+import org.olat.core.gui.control.generic.dtabs.Activateable2;
+import org.olat.core.id.context.ContextEntry;
+import org.olat.core.id.context.StateEntry;
+import org.olat.core.util.Util;
+import org.olat.repository.RepositoryManager;
+
+/**
+ * 
+ * Initial date: 28.01.2014<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class OverviewRepositoryListController extends BasicController implements StackedControllerAware, Activateable2 {
+
+	private MainPanel mainPanel;
+	private final VelocityContainer mainVC;
+	private final SegmentViewComponent segmentView;
+	private final Link favoriteLink, myCourseLink, catalogLink;
+	
+	private FavoritRepositoryEntryListController markedCtrl;
+	private RepositoryEntryListController myCoursesCtrl;
+	private CatalogNodeController catalogCtrl;
+	private StackedController stackPanel;
+	
+	private CatalogManager catalogManager;
+	
+	public OverviewRepositoryListController(UserRequest ureq, WindowControl wControl) {
+		super(ureq, wControl);
+		setTranslator(Util.createPackageTranslator(RepositoryManager.class, getLocale(), getTranslator()));
+		
+		catalogManager = CoreSpringFactory.getImpl(CatalogManager.class);
+
+		mainPanel = new MainPanel("myCoursesMainPanel");
+		mainVC = createVelocityContainer("overview");
+		mainPanel.setContent(mainVC);
+		
+		boolean hasMarkedEntries = doOpenMark(ureq);
+		if(!hasMarkedEntries) {
+			doOpenMyCourses(ureq);
+		}
+		segmentView = SegmentViewFactory.createSegmentView("segments", mainVC, this);
+		favoriteLink = LinkFactory.createLink("search.mark", mainVC, this);
+		segmentView.addSegment(favoriteLink, hasMarkedEntries);
+		myCourseLink = LinkFactory.createLink("search.mycourses.student", mainVC, this);
+		segmentView.addSegment(myCourseLink, !hasMarkedEntries);
+		catalogLink = LinkFactory.createLink("search.catalog", mainVC, this);
+		segmentView.addSegment(catalogLink, false);
+		
+		putInitialPanel(mainPanel);
+	}
+	
+	@Override
+	public void setStackedController(StackedController stackPanel) {
+		this.stackPanel = stackPanel;
+	}
+	
+	@Override
+	public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) {
+		//
+	}
+
+	@Override
+	protected void doDispose() {
+		//
+	}
+
+	@Override
+	protected void event(UserRequest ureq, Component source, Event event) {
+		if(source == segmentView) {
+			if(event instanceof SegmentViewEvent) {
+				SegmentViewEvent sve = (SegmentViewEvent)event;
+				String segmentCName = sve.getComponentName();
+				Component clickedLink = mainVC.getComponent(segmentCName);
+				if (clickedLink == favoriteLink) {
+					doOpenMark(ureq);
+				} else if (clickedLink == myCourseLink) {
+					doOpenMyCourses(ureq);
+				} else if (clickedLink == catalogLink) {
+					doOpenCatalog(ureq);
+				}
+			}
+		}
+	}
+	
+	private boolean doOpenMark(UserRequest ureq) {
+		boolean hasMarkedEntries = true;
+		if(markedCtrl == null) {
+			markedCtrl = new FavoritRepositoryEntryListController(ureq, getWindowControl());
+			hasMarkedEntries = markedCtrl.updateMarkedEntries();
+			listenTo(markedCtrl);
+		}
+		mainVC.put("segmentCmp", markedCtrl.getInitialComponent());
+		return hasMarkedEntries;
+	}
+	
+	private void doOpenMyCourses(UserRequest ureq) {
+		if(myCoursesCtrl == null) {
+			myCoursesCtrl = new RepositoryEntryListController(ureq, getWindowControl());
+			listenTo(myCoursesCtrl);
+		}
+		mainVC.put("segmentCmp", myCoursesCtrl.getInitialComponent());
+	}
+	
+	private void doOpenCatalog(UserRequest ureq) {
+		if(catalogCtrl == null) {
+			List<CatalogEntry> entries = catalogManager.getRootCatalogEntries();
+			CatalogEntry rootEntry = null;
+			if(entries.size() > 0) {
+				rootEntry = entries.get(0);
+			}
+			catalogCtrl = new CatalogNodeController(ureq, getWindowControl(), rootEntry);
+			catalogCtrl.setStackedController(stackPanel);
+			listenTo(catalogCtrl);
+		}
+		mainVC.put("segmentCmp", catalogCtrl.getInitialComponent());
+	}
+}
diff --git a/src/main/java/org/olat/repository/ui/list/RepositoryEntryAsParticipantDataSource.java b/src/main/java/org/olat/repository/ui/list/RepositoryEntryAsParticipantDataSource.java
new file mode 100644
index 0000000000000000000000000000000000000000..754ca1a6fb82d2f5a2d5c0f5b78713769d4dc5fb
--- /dev/null
+++ b/src/main/java/org/olat/repository/ui/list/RepositoryEntryAsParticipantDataSource.java
@@ -0,0 +1,66 @@
+/**
+ * <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.repository.ui.list;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.olat.core.commons.persistence.DefaultResultInfos;
+import org.olat.core.commons.persistence.ResultInfos;
+import org.olat.core.commons.persistence.SortKey;
+import org.olat.core.id.Identity;
+import org.olat.repository.RepositoryEntry;
+import org.olat.repository.RepositoryEntryOrder;
+
+/**
+ * 
+ * Initial date: 29.01.2014<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class RepositoryEntryAsParticipantDataSource extends AbstractRepositoryEntryDataSource {
+	
+	public RepositoryEntryAsParticipantDataSource(Identity identity, RepositoryEntryDataSourceUIFactory uifactory) {
+		super(identity, uifactory);
+	}
+
+	@Override
+	protected int getNumOfRepositoryEntries() {
+		long start = System.nanoTime();
+		int n = repositoryManager.countLearningResourcesAsStudent(getIdentity());
+		System.out.println("Count takes (ms): " + ((System.nanoTime() - start) / 1000000));
+		return n;
+	}
+
+	@Override
+	public List<RepositoryEntryRow> reload(List<RepositoryEntryRow> rows) {
+		return Collections.emptyList();
+	}
+
+	@Override
+	public ResultInfos<RepositoryEntryRow> getRows(String query, List<String> condQueries,
+			int firstResult, int maxResults, SortKey... orderBy) {
+
+		List<RepositoryEntry> repoEntries = repositoryManager
+				.getLearningResourcesAsStudent(getIdentity(), firstResult, maxResults, RepositoryEntryOrder.nameDesc);
+		List<RepositoryEntryRow> rows = processModel(repoEntries);
+		return new DefaultResultInfos<RepositoryEntryRow>(firstResult + rows.size(), -1, rows);
+	}
+}
diff --git a/src/main/java/org/olat/repository/ui/list/RepositoryEntryDataModel.java b/src/main/java/org/olat/repository/ui/list/RepositoryEntryDataModel.java
new file mode 100644
index 0000000000000000000000000000000000000000..81a482765f97a38d526a7901d449102bd477983e
--- /dev/null
+++ b/src/main/java/org/olat/repository/ui/list/RepositoryEntryDataModel.java
@@ -0,0 +1,89 @@
+/**
+ * <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.repository.ui.list;
+
+import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiTableDataSourceModel;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataSourceDelegate;
+
+/**
+ * 
+ * Initial date: 29.01.2014<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class RepositoryEntryDataModel extends DefaultFlexiTableDataSourceModel<RepositoryEntryRow> {
+	
+	public RepositoryEntryDataModel(FlexiTableDataSourceDelegate<RepositoryEntryRow> source, FlexiTableColumnModel columnModel) {
+		super(source, columnModel);
+	}
+
+	@Override
+	public DefaultFlexiTableDataSourceModel<RepositoryEntryRow> createCopyWithEmptyList() {
+		return new RepositoryEntryDataModel(getSourceDelegate(), getTableColumnModel());
+	}
+
+	@Override
+	public Object getValueAt(int row, int col) {
+		RepositoryEntryRow item = getObject(row);
+		if(item == null) {
+			return null;//don't break here
+		}
+		
+		switch(Cols.values()[col]) {
+			case key: return item.getKey();
+			case displayName: return item.getDisplayName();
+			case lifecycleLabel: return item.getLifecycle();
+			case lifecycleSoftkey: return item.getLifecycleSoftKey();
+			case lifecycleStart: return item.getLifecycleStart();
+			case lifecycleEnd: return item.getLifecycleEnd();
+			case mark: return item.getMarkLink();
+			case select: return item.getSelectLink();
+			case start: return item.getStartLink();
+			case details: return item.getDetailsLink();
+			case ratings: return item.getRatingFormItem();
+		}
+		return null;
+	}
+	
+	public enum Cols {
+		key("table.header.key"),
+		displayName("cif.displayname"),
+		lifecycleLabel("table.header.lifecycle.label"),
+		lifecycleSoftkey("table.header.lifecycle.softkey"),
+		lifecycleStart("table.header.lifecycle.start"),
+		lifecycleEnd("table.header.lifecycle.end"),
+		details("table.header.details"),
+		select("table.header.details"),
+		start("table.header.start"),
+		mark("table.header.mark"),
+		ratings("ratings");
+		
+		private final String i18nKey;
+		
+		private Cols(String i18nKey) {
+			this.i18nKey = i18nKey;
+		}
+		
+		public String i18nKey() {
+			return i18nKey;
+		}
+	}
+}
diff --git a/src/main/java/org/olat/repository/ui/list/RepositoryEntryDataSourceUIFactory.java b/src/main/java/org/olat/repository/ui/list/RepositoryEntryDataSourceUIFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..14b62a4a837dca89b2578df6b21da8de545a9d32
--- /dev/null
+++ b/src/main/java/org/olat/repository/ui/list/RepositoryEntryDataSourceUIFactory.java
@@ -0,0 +1,46 @@
+/**
+ * <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.repository.ui.list;
+
+import org.olat.repository.RepositoryEntry;
+
+/**
+ * 
+ * Delegate to the controller the job of forgeing the links and the mapperUrl.
+ * 
+ * Initial date: 29.01.2014<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public interface RepositoryEntryDataSourceUIFactory {
+	
+	public String getMapperThumbnailUrl();
+	
+	public void forgeMarkLink(RepositoryEntryRow row);
+	
+	public void forgeSelectLink(RepositoryEntryRow row);
+	
+	public void forgeStartLink(RepositoryEntryRow row);
+	
+	public void forgeDetailsLink(RepositoryEntryRow row);
+	
+	public void forgeRatings(RepositoryEntryRow row, RepositoryEntry entry);
+
+}
diff --git a/src/main/java/org/olat/repository/ui/list/RepositoryEntryListController.java b/src/main/java/org/olat/repository/ui/list/RepositoryEntryListController.java
new file mode 100644
index 0000000000000000000000000000000000000000..3e79c23b0df978024f8d5cddae39015e5a65e5a7
--- /dev/null
+++ b/src/main/java/org/olat/repository/ui/list/RepositoryEntryListController.java
@@ -0,0 +1,41 @@
+/**
+ * <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.repository.ui.list;
+
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.control.WindowControl;
+
+/**
+ * 
+ * Initial date: 28.01.2014<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class RepositoryEntryListController extends AbstractRepositoryEntryListController {
+	
+	public RepositoryEntryListController(UserRequest ureq, WindowControl wControl) {
+		super(ureq, wControl);
+		
+		RepositoryEntryAsParticipantDataSource dataSource = new RepositoryEntryAsParticipantDataSource(getIdentity(), this);
+		setDataSource(dataSource);
+		initForm(ureq);
+	}
+
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/repository/ui/list/RepositoryEntryRow.java b/src/main/java/org/olat/repository/ui/list/RepositoryEntryRow.java
new file mode 100644
index 0000000000000000000000000000000000000000..710ee0aeb7af62f8f5790f5d40d353488e254eed
--- /dev/null
+++ b/src/main/java/org/olat/repository/ui/list/RepositoryEntryRow.java
@@ -0,0 +1,304 @@
+/**
+ * <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.repository.ui.list;
+
+import java.util.Date;
+import java.util.List;
+
+import org.olat.core.gui.components.form.flexible.elements.FormLink;
+import org.olat.core.gui.components.rating.RatingWithAverageFormItem;
+import org.olat.core.id.OLATResourceable;
+import org.olat.core.util.StringHelper;
+import org.olat.repository.ui.PriceMethod;
+
+/**
+ * 
+ * Initial date: 29.01.2014<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class RepositoryEntryRow {
+	private boolean marked;
+	private boolean selected;
+	
+	private Long key;
+	private String name;
+	private String author;
+	private String description;
+	private String thumbnailRelPath;
+	
+	private String score;
+	private Boolean passed;
+	
+	public int visit;
+	public long timeSpend;
+	public Date initialLaunch;
+	public Date recentLaunch;
+	
+	private String lifecycle;
+	private String lifecycleSoftKey;
+	private Date lifecycleStart;
+	private Date lifecycleEnd;
+	
+	private List<PriceMethod> accessTypes;
+	
+	private FormLink markLink;
+	private FormLink selectLink;
+	private FormLink startLink;
+	private FormLink detailsLink;
+	
+	private OLATResourceable olatResource;
+	private RatingWithAverageFormItem ratingFormItem;
+	
+	public RepositoryEntryRow() {
+		//
+	}
+	
+	public String getCssClass() {
+		return "o_CourseModule_icon";
+	}
+	
+	public Long getKey() {
+		return key;
+	}
+	
+	public void setKey(Long key) {
+		this.key = key;
+	}
+	
+	public String getDisplayName() {
+		return name;
+	}
+	
+	public void setDisplayName(String name) {
+		this.name = name;
+	}
+	
+	public String getDescription() {
+		return description;
+	}
+	
+	public void setDescription(String description) {
+		this.description = description;
+	}
+	
+	public String getLifecycle() {
+		return lifecycle;
+	}
+
+	public void setLifecycle(String lifecycle) {
+		this.lifecycle = lifecycle;
+	}
+
+	public String getLifecycleSoftKey() {
+		return lifecycleSoftKey;
+	}
+
+	public void setLifecycleSoftKey(String lifecycleSoftKey) {
+		this.lifecycleSoftKey = lifecycleSoftKey;
+	}
+
+	public Date getLifecycleStart() {
+		return lifecycleStart;
+	}
+
+	public void setLifecycleStart(Date lifecycleStart) {
+		this.lifecycleStart = lifecycleStart;
+	}
+
+	public Date getLifecycleEnd() {
+		return lifecycleEnd;
+	}
+
+	public void setLifecycleEnd(Date lifecycleEnd) {
+		this.lifecycleEnd = lifecycleEnd;
+	}
+	
+	public List<PriceMethod> getAccessTypes() {
+		return accessTypes;
+	}
+
+	public void setAccessTypes(List<PriceMethod> accessTypes) {
+		this.accessTypes = accessTypes;
+	}
+
+	public String getSelectLinkName() {
+		return selectLink.getComponent().getComponentName();
+	}
+	
+	public FormLink getSelectLink() {
+		return selectLink;
+	}
+	
+	public void setSelectLink(FormLink selectLink) {
+		this.selectLink = selectLink;
+	}
+	
+	public String getStartLinkName() {
+		return startLink.getComponent().getComponentName();
+	}
+	
+	public FormLink getStartLink() {
+		return startLink;
+	}
+
+	public void setStartLink(FormLink startLink) {
+		this.startLink = startLink;
+	}
+	
+	public String getDetailsLinkName() {
+		return detailsLink.getComponent().getComponentName();
+	}
+
+	public FormLink getDetailsLink() {
+		return detailsLink;
+	}
+
+	public void setDetailsLink(FormLink detailsLink) {
+		this.detailsLink = detailsLink;
+	}
+
+	public FormLink getMarkLink() {
+		return markLink;
+	}
+	
+	public String getMarkLinkName() {
+		if(markLink != null) {
+			return markLink.getComponent().getComponentName();
+		}
+		return null;
+	}
+	
+	public void setMarkLink(FormLink markLink) {
+		this.markLink = markLink;
+	}
+	
+	public String getRatingFormItemName() {
+		return ratingFormItem.getComponent().getComponentName();
+	}
+
+	public RatingWithAverageFormItem getRatingFormItem() {
+		return ratingFormItem;
+	}
+
+	public void setRatingFormItem(RatingWithAverageFormItem ratingFormItem) {
+		this.ratingFormItem = ratingFormItem;
+	}
+	
+	/**
+	 * This is a clone of the repositoryEntry.getOLATResource();
+	 * @return
+	 */
+	public OLATResourceable getOLATResourceable() {
+		return olatResource;
+	}
+	
+	public void setOLATResourceable(OLATResourceable olatResource) {
+		this.olatResource = olatResource;
+	}
+
+	public String getAuthor() {
+		return author;
+	}
+	
+	public void setAuthor(String author) {
+		this.author = author;
+	}
+	
+	public String getThumbnailRelPath() {
+		return thumbnailRelPath;
+	}
+	
+	public void setThumbnailRelPath(String path) {
+		this.thumbnailRelPath = path;
+	}
+	
+	public boolean isThumbnailAvailable() {
+		return StringHelper.containsNonWhitespace(thumbnailRelPath);
+	}
+	
+	public boolean isMarked() {
+		return marked;
+	}
+	
+	public void setMarked(boolean marked) {
+		this.marked = marked;
+	}
+	
+	public boolean isSelected() {
+		return selected;
+	}
+	
+	public void setSelected(boolean selected) {
+		this.selected = selected;
+	}
+	
+	public String getScore() {
+		return score;
+	}
+	
+	public void setScore(String score) {
+		this.score = score;
+	}
+	
+	public boolean isPassed() {
+		return passed != null && passed.booleanValue();
+	}
+	
+	public void setPassed(Boolean passed) {
+		this.passed = passed;
+	}
+	
+	public boolean isFailed() {
+		return passed != null && !passed.booleanValue();
+	}
+	
+	public int getVisit() {
+		return visit;
+	}
+	
+	public void setVisit(int visit) {
+		this.visit = visit;
+	}
+	
+	public long getTimeSpend() {
+		return timeSpend;
+	}
+	
+	public void setTimeSpend(long timeSpend) {
+		this.timeSpend = timeSpend;
+	}
+	
+	public Date getInitialLaunch() {
+		return initialLaunch;
+	}
+	
+	public void setInitialLaunch(Date initialLaunch) {
+		this.initialLaunch = initialLaunch;
+	}
+	
+	public Date getRecentLaunch() {
+		return recentLaunch;
+	}
+	
+	public void setRecentLaunch(Date recentLaunch) {
+		this.recentLaunch = recentLaunch;
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/repository/ui/list/_content/node.html b/src/main/java/org/olat/repository/ui/list/_content/node.html
new file mode 100644
index 0000000000000000000000000000000000000000..3e17ae0afaad4c97b7ec44f89099ef6296ef0fc0
--- /dev/null
+++ b/src/main/java/org/olat/repository/ui/list/_content/node.html
@@ -0,0 +1,16 @@
+<div class="o_catalog">
+	<fieldset>
+		<legend>$catalogEntryName</legend>
+		#if($catalogEntryDesc)
+			<i>$catalogEntryDesc</i>
+		#end
+		#if($subCategories.size != 0)
+			<div class="o_catalog_itemlist">
+				#foreach($subCategory in $subCategories)
+					$r.render($subCategory.componentName),
+				#end
+			</div>
+		#end
+		</fieldset>
+</div>
+$r.render("entries")
diff --git a/src/main/java/org/olat/repository/ui/list/_content/overview.html b/src/main/java/org/olat/repository/ui/list/_content/overview.html
new file mode 100644
index 0000000000000000000000000000000000000000..94c1c0ab3da2ef1d638f32497494d46e16d22b38
--- /dev/null
+++ b/src/main/java/org/olat/repository/ui/list/_content/overview.html
@@ -0,0 +1,4 @@
+<div class="b_clearfix">
+	$r.render("segments")<br/>
+	$r.render("segmentCmp")
+</div>
\ No newline at end of file
diff --git a/src/main/java/org/olat/repository/ui/list/_content/repoentry_table.html b/src/main/java/org/olat/repository/ui/list/_content/repoentry_table.html
new file mode 100644
index 0000000000000000000000000000000000000000..01996d44603777f601e0888ed3e2e88c68865b7f
--- /dev/null
+++ b/src/main/java/org/olat/repository/ui/list/_content/repoentry_table.html
@@ -0,0 +1,5 @@
+<div class="o_buttons_box_right">
+	$r.render("switchLayoutList")
+	$r.render("switchLayoutTable")
+</div>
+$r.render("table")
\ No newline at end of file
diff --git a/src/main/java/org/olat/repository/ui/list/_content/row_1.html b/src/main/java/org/olat/repository/ui/list/_content/row_1.html
new file mode 100644
index 0000000000000000000000000000000000000000..fe28d778d62d31b5476dc06f31fa70e7cda65e0d
--- /dev/null
+++ b/src/main/java/org/olat/repository/ui/list/_content/row_1.html
@@ -0,0 +1,77 @@
+<div class="b_clearfix o_table_rowline">
+<div class="f_item  #if($row.selected) f_item_selected #end">
+	<div class="f_metadata b_clearfix">
+		<div class="f_thumbnail">
+			#if($row.isThumbnailAvailable())
+				<div class="f_thumbnail_inner f_thumbnail_available" style="width:280px; height:158px; float:left; background:transparent url('${row.getThumbnailRelPath()}') no-repeat 50% 50%;">&nbsp;</div>
+			#else
+				<div class="f_thumbnail_inner f_thumbnail_unavailable" style="">&nbsp;</div>
+			#end	
+		</div>
+		<div class="f_metadata_text">
+			<div class="f_metadata_text_inner">
+				<h4>$r.render($row.getSelectLinkName())</h4>
+				#if($row.author)
+					$row.author<br/>
+				#end
+				#if($row.lifecycle || $row.lifecycleSoftKey || $row.lifecycleStart || $row.lifecycleEnd)
+					<div class="f_metadata_lifecycle">
+						<p>
+							#if($row.lifecycle) $row.lifecycle #end
+							#if($row.lifecycleSoftKey) $row.lifecycleSoftKey #end
+							#if($row.lifecycleStart) $r.formatDateAndTime($row.lifecycleStart) #end
+							#if($row.lifecycleEnd) - $r.formatDateAndTime($row.lifecycleEnd) #end
+						</p>
+					</div>
+				#end
+				<p>$row.description</p>
+				
+				
+			</div>
+		</div>
+		<div class="f_metadata_additional_infos">
+			<div class="f_metadata_additional_infos_inner">
+				<div class="f_metadata_mark">$r.render($row.markLinkName)</div>
+				
+				#if($r.get("ac_$item.key"))
+					#foreach($ac_type in $r.get("ac_$item.key"))
+						#if($ac_type.price && $ac_type.price.length() > 0)
+							<span class='b_float_right b_with_small_icon_left $ac_type.type'>$ac_type.price</span>
+						#else
+							<span class='b_float_right b_small_icon $ac_type.type'></span>
+						#end
+					#end
+					$r.render($row.getSelectLinkName())
+				#end
+
+				#if($row.passed)
+					$r.translate("passed.true")
+				#elseif($item.failed)
+					$r.translate("passed.false")
+				#end
+				#if($row.score) <span>/ $row.score</span> #end
+
+				#if($row.recentLaunch)
+					$r.formatDateAndTime($row.recentLaunch)<br/>
+				#end
+				
+				#if($row.accessTypes)
+					$r.translate("details.orders"):
+					#foreach($type in $row.accessTypes)
+						<span class="$type.type b_access_method">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>
+					#end
+				#end
+				
+				$r.render($row.ratingFormItemName)
+				
+				<div class="f_metadata_details">
+					$r.render($row.getDetailsLinkName())
+				</div>
+				<div class="f_metadata_start">
+					$r.render($row.getStartLinkName())
+				</div>
+			</div>
+		</div>
+	</div>
+</div>
+</div>
\ No newline at end of file
diff --git a/src/main/java/org/olat/resource/accesscontrol/_spring/acContext.xml b/src/main/java/org/olat/resource/accesscontrol/_spring/acContext.xml
index 0db01a0526f7f674dbfe12ff40ca9235844b1c50..cfa2968de5c456b709aeb24d0d96865febee9a70 100644
--- a/src/main/java/org/olat/resource/accesscontrol/_spring/acContext.xml
+++ b/src/main/java/org/olat/resource/accesscontrol/_spring/acContext.xml
@@ -71,13 +71,15 @@
 				<property name="factoryMethod" value="createOrdersController"/>
 			</bean>
 		</property>
+		<property name="navigationKey" value="booking" />
+		<property name="iconCssClass" value="b_with_small_icon_left b_order_icon" />
 		<property name="securityCallbackClassName" value="org.olat.core.extensions.security.UserOnlyExtensionSecurityCallback" />
 		<property name="translationPackage" value="org.olat.home" />
 		<property name="i18nActionKey" value="menu.orders"/>
 		<property name="i18nDescriptionKey" value="menu.orders.alt"/>
 		<property name="extensionPoints">
 			<list>	
-				<value>org.olat.home.HomeMainController</value>		
+				<value>org.olat.home.HomeMainController</value>
 			</list>
 		</property>
 	</bean>
diff --git a/src/main/java/org/olat/restapi/repository/RepositoryEntriesResource.java b/src/main/java/org/olat/restapi/repository/RepositoryEntriesResource.java
index b57024b896d66189a30e2fcae488a3d618152240..bf656934770e8af0e58d6fada71df7147549549f 100644
--- a/src/main/java/org/olat/restapi/repository/RepositoryEntriesResource.java
+++ b/src/main/java/org/olat/restapi/repository/RepositoryEntriesResource.java
@@ -184,7 +184,7 @@ public class RepositoryEntriesResource {
 			}
 			
 			if(MediaTypeVariants.isPaged(httpRequest, request)) {
-				int totalCount = rm.countGenericANDQueryWithRolesRestriction(params, true);
+				int totalCount = rm.countGenericANDQueryWithRolesRestriction(params);
 				List<RepositoryEntry> res = rm.genericANDQueryWithRolesRestriction(params, start, limit, true);
 				RepositoryEntryVOes voes = new RepositoryEntryVOes();
 				voes.setRepositoryEntries(toArrayOfVOes(res));
diff --git a/src/main/java/org/olat/restapi/repository/course/CoursesInfosWebService.java b/src/main/java/org/olat/restapi/repository/course/CoursesInfosWebService.java
index 4693d9f1e7b1bed71970c385f066513bea608a3c..7b65f8a352ede68a5bf131910da091a96bb15f43 100644
--- a/src/main/java/org/olat/restapi/repository/course/CoursesInfosWebService.java
+++ b/src/main/java/org/olat/restapi/repository/course/CoursesInfosWebService.java
@@ -109,7 +109,7 @@ public class CoursesInfosWebService {
 		Identity identity = getIdentity(httpRequest);
 		SearchRepositoryEntryParameters params = new SearchRepositoryEntryParameters(identity, roles, CourseModule.getCourseTypeName());
 		if(MediaTypeVariants.isPaged(httpRequest, request)) {
-			int totalCount = rm.countGenericANDQueryWithRolesRestriction(params, true);
+			int totalCount = rm.countGenericANDQueryWithRolesRestriction(params);
 			List<RepositoryEntry> repoEntries = rm.genericANDQueryWithRolesRestriction(params, start, limit, true);
 			List<CourseInfoVO> infos = new ArrayList<CourseInfoVO>();
 
diff --git a/src/main/java/org/olat/restapi/repository/course/CoursesWebService.java b/src/main/java/org/olat/restapi/repository/course/CoursesWebService.java
index 8933f13999a1f23323580b64d264ce99ae03272a..d2fdb7c9daa753074948586143368a12cb6d9ff4 100644
--- a/src/main/java/org/olat/restapi/repository/course/CoursesWebService.java
+++ b/src/main/java/org/olat/restapi/repository/course/CoursesWebService.java
@@ -158,7 +158,7 @@ public class CoursesWebService {
 		}
 
 		if(MediaTypeVariants.isPaged(httpRequest, request)) {
-			int totalCount = rm.countGenericANDQueryWithRolesRestriction(params, true);
+			int totalCount = rm.countGenericANDQueryWithRolesRestriction(params);
 			List<RepositoryEntry> repoEntries = rm.genericANDQueryWithRolesRestriction(params, start, limit, true);
 			CourseVO[] vos = toCourseVo(repoEntries);
 			CourseVOes voes = new CourseVOes();
diff --git a/src/test/java/org/olat/core/commons/services/usercomments/UserRatingsDAOTest.java b/src/test/java/org/olat/core/commons/services/usercomments/UserRatingsDAOTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..4a3633c278ff39ced0c4be939dd3f4b8d5529963
--- /dev/null
+++ b/src/test/java/org/olat/core/commons/services/usercomments/UserRatingsDAOTest.java
@@ -0,0 +1,93 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.core.commons.services.usercomments;
+
+import java.util.UUID;
+
+import junit.framework.Assert;
+
+import org.junit.Test;
+import org.olat.core.commons.persistence.DB;
+import org.olat.core.commons.services.commentAndRating.impl.UserRatingsDAO;
+import org.olat.core.commons.services.commentAndRating.model.UserRating;
+import org.olat.core.id.Identity;
+import org.olat.core.id.OLATResourceable;
+import org.olat.test.JunitTestHelper;
+import org.olat.test.OlatTestCase;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * 
+ * Initial date: 31.01.2014<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class UserRatingsDAOTest extends OlatTestCase {
+	
+	@Autowired
+	private DB dbInstance;
+	@Autowired
+	private UserRatingsDAO userRatingsDao;
+	
+	@Test
+	public void createRating() {
+		OLATResourceable ores = JunitTestHelper.createRandomResource();
+		Identity id = JunitTestHelper.createAndPersistIdentityAsUser("ucar-crud-1-" + UUID.randomUUID().toString());
+		dbInstance.commitAndCloseSession();
+
+		//create
+		UserRating newRating = userRatingsDao.createRating(id, ores, "test-1", 5);
+		dbInstance.commit();
+		Assert.assertNotNull(newRating);
+		Assert.assertNotNull(newRating.getKey());
+		Assert.assertNotNull(newRating.getCreationDate());
+		Assert.assertNotNull(newRating.getLastModified());
+		Assert.assertEquals(ores.getResourceableTypeName(), newRating.getResName());
+		Assert.assertEquals(ores.getResourceableId(), newRating.getResId());
+		Assert.assertEquals("test-1", newRating.getResSubPath());
+		Assert.assertEquals(id, newRating.getCreator());
+		Assert.assertEquals(new Integer(5), newRating.getRating());
+	}
+	
+	@Test
+	public void createUpdateRating() {
+		OLATResourceable ores = JunitTestHelper.createRandomResource();
+		Identity id = JunitTestHelper.createAndPersistIdentityAsUser("ucar-crud-1-" + UUID.randomUUID().toString());
+		dbInstance.commitAndCloseSession();
+
+		//create
+		UserRating newRating = userRatingsDao.createRating(id, ores, "test-2", 5);
+		dbInstance.commitAndCloseSession();
+		
+		UserRating updatedRating = userRatingsDao.updateRating(newRating, 4);
+		dbInstance.commit();
+		
+		Assert.assertNotNull(updatedRating);
+		Assert.assertEquals(newRating, updatedRating);
+		Assert.assertNotNull(updatedRating.getCreationDate());
+		Assert.assertNotNull(updatedRating.getLastModified());
+		Assert.assertEquals(ores.getResourceableTypeName(), updatedRating.getResName());
+		Assert.assertEquals(ores.getResourceableId(), updatedRating.getResId());
+		Assert.assertEquals("test-2", updatedRating.getResSubPath());
+		Assert.assertEquals(id, updatedRating.getCreator());
+		Assert.assertEquals(new Integer(4), updatedRating.getRating());
+	}
+	
+}
diff --git a/src/test/java/org/olat/repository/RepositoryManagerQueryTest.java b/src/test/java/org/olat/repository/RepositoryManagerQueryTest.java
index aceacc5ac475e1952ba02a5542c8d7c5dd29003a..c3398361dfa63e88ca8c49831a0129ec0f73ca67 100644
--- a/src/test/java/org/olat/repository/RepositoryManagerQueryTest.java
+++ b/src/test/java/org/olat/repository/RepositoryManagerQueryTest.java
@@ -245,7 +245,7 @@ public class RepositoryManagerQueryTest extends OlatTestCase {
 		//test paging
 		SearchRepositoryEntryParameters params = new SearchRepositoryEntryParameters(null, "kan", null, types, null, role4, "Volks");
 		List<RepositoryEntry> resultOneShootInstitut6 = rm.genericANDQueryWithRolesRestriction(params, 0, 50, true);
-		int resultOneShootInstitutTotal6 = rm.countGenericANDQueryWithRolesRestriction(params, true);
+		int resultOneShootInstitutTotal6 = rm.countGenericANDQueryWithRolesRestriction(params);
 		assertNotNull(resultOneShootInstitut6);
 		assertEquals(50, resultOneShootInstitut6.size());
 		//check
diff --git a/src/test/java/org/olat/test/AllTestsJunit4.java b/src/test/java/org/olat/test/AllTestsJunit4.java
index d671a169be784879ddc598a56e23ff195b6d212e..f015bf8d4e0e1fa0cc579bbfbb9c76b7f745921f 100644
--- a/src/test/java/org/olat/test/AllTestsJunit4.java
+++ b/src/test/java/org/olat/test/AllTestsJunit4.java
@@ -150,6 +150,7 @@ import org.junit.runners.Suite;
 	org.olat.test.SpringInitDestroyVerficationTest.class,
 	//org.olat.course.statistic.weekly.TestWeeklyStatisticManager_fillGaps.class, don't know what it tests
 	org.olat.core.commons.services.usercomments.UserCommentsTest.class,
+	org.olat.core.commons.services.usercomments.UserRatingsDAOTest.class,
 	org.olat.core.commons.services.usercomments.UserRatingsTest.class,
 	org.olat.course.auditing.UserNodeAuditManagerTest.class,
 	org.olat.shibboleth.util.ShibbolethAttributeTest.class,