diff --git a/html/relnotes.html b/html/relnotes.html
index 46e2a61ee2f756e7c757d665eebd30f7b0833830..03a706ee0735ac875a93b834ce36b1d3c5ff9745 100644
--- a/html/relnotes.html
+++ b/html/relnotes.html
@@ -74,6 +74,7 @@ The development of 4 versions continue.
 <li>Added <tt>InstanceBasedMatrixMeasure</tt> for instance based alignments (impl)</li>
 <li>Added a <tt>getResult()</tt> method to <tt>Evaluator</tt> (api)</li>
 <li>Added a <tt>DiffAlign( al1, al2 )</tt> evaluator (impl)</li>
+<li>Added an <tt>aggr.ConsensusAggregator</tt> for merging several alignments (impl)</li>
 <li>Implemented online evaluation and diff (server)</li>
 <li>Added the possibility to drop a number of correspondences in <tt>ONetworkWeakener</tt> (util)</li>
 <li>Added a google chart API display of plots <tt>GenPlot -t html</tt> (util)</li>
@@ -81,7 +82,7 @@ The development of 4 versions continue.
   can be empty (edoal)</li>
 <li>Upgraded to <span style="color: green">Pellet 2.1</span> (but
   Pellet is not anymore distributed <a href="lib.html">due to license restrictions</a>)</li>
-<li>Upgraded to <span style="color: green">OntoSim 2.0</span> (lib)</li>
+<li>Upgraded to <span style="color: green">OntoSim 2.1</span> (lib)</li>
 <li>Added <a href="tutorial/tutorial4/index.html">tutorial 4</a> Pellet action (tutorial)</li>
 <li>Added <a href="tutorial/tutorial5/index.html">tutorial 5</a> about exposing matchers as web services (tutorial)</li>
 <li>Fixed path errors in tutorials (tutorial)</li>
diff --git a/src/fr/inrialpes/exmo/align/impl/aggr/ConsensusAggregator.java b/src/fr/inrialpes/exmo/align/impl/aggr/ConsensusAggregator.java
new file mode 100644
index 0000000000000000000000000000000000000000..bd6dc837f4431bf62032e1a83a1ec13c6cf802f8
--- /dev/null
+++ b/src/fr/inrialpes/exmo/align/impl/aggr/ConsensusAggregator.java
@@ -0,0 +1,155 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) INRIA, 2010
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+package fr.inrialpes.exmo.align.impl.aggr; 
+
+import java.util.Hashtable;
+import java.util.Set;
+import java.util.HashSet;
+
+import org.semanticweb.owl.align.Alignment;
+import org.semanticweb.owl.align.AlignmentException;
+import org.semanticweb.owl.align.Cell;
+import org.semanticweb.owl.align.Relation;
+
+import fr.inrialpes.exmo.align.impl.BasicAlignment;
+
+/**
+ *
+ * @author Jérôme Euzenat
+ * @version $Id$ 
+ *
+ * This class is a generalisation of a consensus aggregation.
+ * It is fed by "ingesting" various alignments, i.e., collecting and counting their correspondences
+ * Then the extraction of an alignement is made by extracting an alignment
+ * So the aggregator works with the following interface:
+ * aggr = new ConsensusAggregator();
+ * aggr.ingest( Alignment );
+ * aggr.ingest( Alignment );
+ * ...
+ * aggr.extract( double, boolean )
+ * or
+ * aggr.extract( int, boolean )
+ * for the interpretation of these two primitives, see the definition of extract.
+ *
+ * There could be also a possibility to introduce a hook depending on the entities to be compared. 
+ * For instance, in multilingual matching, if the labels are one word, then n=5, if they are more than one word, n=2
+ */
+
+public class ConsensusAggregator extends BasicAlignment {
+
+    int nbAlignments = 0;
+    Hashtable<Cell, CountCell> count;
+
+    /** Creation **/
+    public ConsensusAggregator() {
+	// Initialising the hash table
+	count = new Hashtable<Cell, CountCell>();
+    }
+
+
+    /**
+     * Extract the alignment from consensus
+     */
+    public void ingest( Alignment al ) throws AlignmentException {
+	nbAlignments++;
+	for ( Cell c : al ) {
+	    Cell newc = isAlreadyThere( c );
+	    if ( newc == null ) {
+		newc = addAlignCell( c.getObject1(), c.getObject2(), c.getRelation().toString(), 1. );
+		count.put( newc, new CountCell() );
+	    }
+	    count.get( newc ).incr( c.getStrength() );
+	}
+    }
+
+    /**
+     * Extract the alignment from consensus
+     * If absolute, then retain correspondences found in more than n alignments
+     * Otherwise, retain those found in more than n% of alignments
+     */
+    public void extract( int minVal, boolean absolute ) throws AlignmentException {
+	// Check that this is between 0. and 1.
+	double threshold = (double)minVal;
+	if ( !absolute ) threshold = minVal*(double)nbAlignments;
+	Set<Cell> todelete = new HashSet<Cell>();
+	for ( Cell c : this ) {
+	    // if it is not more than X time, then return 0
+	    if ( count.get( c ).getOccurences() >= threshold ) {
+		c.setStrength( (double)count.get( c ).getOccurences() / (double)nbAlignments );
+	    } else {
+		todelete.add( c );
+	    }
+	}
+	for ( Cell c : todelete ) {
+	    try { remCell( c ); } catch (Exception ex ) {};
+	}
+
+    }
+
+    /**
+     * Extract the alignment from consensus
+     * If absolute, then retain correspondences scoring more than n
+     * Otherwise, retain those scoring more than n in average, i.e., n*nbAlignments
+     */
+    public void extract( double minVal, boolean absolute ) throws AlignmentException {
+	double threshold = minVal;
+	if ( !absolute ) threshold = minVal*(double)nbAlignments; // Check that this is between 0. and 1.
+	Set<Cell> todelete = new HashSet<Cell>();
+	for ( Cell c : this ) {
+	    if ( count.get( c ).getValue() >= minVal ) {
+		c.setStrength( count.get( c ).getValue() / (double)nbAlignments );
+	    } else {
+		todelete.add( c );
+	    }
+	}
+	for ( Cell c : todelete ) {
+	    try { remCell( c ); } catch (Exception ex ) {};
+	}
+
+    }
+
+    public Cell isAlreadyThere( Cell c ){
+	try {
+	    Set<Cell> possible = getAlignCells1( c.getObject1() );
+	    Object ob2 = c.getObject2();
+	    Relation r = c.getRelation();
+	    if ( possible!= null ) {
+		for ( Cell c2 : possible ) {
+		    if ( ob2.equals( c2.getObject2() ) && r.equals( c2.getRelation() ) ) return c2;
+		}
+	    }
+	} catch (Exception ex) {
+	    ex.printStackTrace();
+	}
+	return null;
+    }
+
+    private class CountCell {
+	private int occ;
+	private double number;
+	public CountCell() { number = 0.; occ = 0; }
+	public CountCell( double i, int j ) { number = i; occ = j; }
+	public void incr( double d ) { number += d; occ++; }
+	public double getValue() { return number; }
+	public int getOccurences() { return occ; }
+    }
+
+}