diff --git a/.gitignore b/.gitignore
index c4df824b65212877ccbb9386d297b7c8dc6b76a5..9e357c60be30e78d3e9ea0456ea862cedf6db4ca 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,4 +5,6 @@
 
 # generated
 /Selection
+/Selection.zip
 /students.csv
+/select-by-*.txt
diff --git a/html2csv.pl b/html2csv.pl
new file mode 100644
index 0000000000000000000000000000000000000000..c83fdd68f143f82b4dc9749995ebc77688a3162b
--- /dev/null
+++ b/html2csv.pl
@@ -0,0 +1,40 @@
+#!/usr/bin/perl -w
+
+# Copyright © 2019 Forschungszentrum Juelich GmbH (Andreas Beckmann <a.beckmann@fz-juelich.de>)
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+while (<>) {
+	last if /REGISTRANTS EVALUATIONS/;
+}
+
+while (<>) {
+	if (/<tr/) {
+		@cell = ();
+		while (<>) {
+			last if /<\/tr>/;
+			push @cell, $1 if /<td.*?>(.*?)(<\/td>|$)/;
+		}
+		if (@cell) {
+			$_ = $cell[1];
+			$id = $1 if /\(ID: (\d+)\)/;
+			$name = $1 if /<a.*?>(.*?)<\/a>/;
+			@prj = /project_(\d+)/g;
+			$score = $cell[-1];
+			#printf "%s: %s\n", $_, $cell[$_] foreach (0..$#cell-1);
+			printf "%3d, %.2f, %4d, %4d, %4d, %s\n", $id || 0, $score || 0.0, $prj[0] || 0, $prj[1] || 0, $prj[2] || 0, $name || "???";
+		}
+	}
+}
+
diff --git a/prepare-selection.sh b/prepare-selection.sh
index d4de3e84f41d1edae2327201172b8adff0ae9cea..1a423245a3f0f3683fbc630bf8c4cb43bd935a4b 100755
--- a/prepare-selection.sh
+++ b/prepare-selection.sh
@@ -5,10 +5,11 @@ cd Selection
 python3 ../create-evaluation-files.py ../registrations.csv ../submissions-638.csv
 cd ..
 perl html2csv.pl Selection/evaluation.html > students.csv
-perl sohpc-assign.pl students.csv 
+perl sohpc-assign.pl weights-pref.csv students.csv project-preferences.csv > select-by-pref.txt
+perl sohpc-assign.pl weights-score.csv students.csv project-preferences.csv > select-by-score.txt
 mkdir Selection/scripts
 cp sohpc-assign.pl html2csv.pl submissions-638.csv registrations.csv create-evaluation-files.py Selection/scripts
-cp prepare-selection.sh students.csv Selection/scripts
+cp prepare-selection.sh weights-*.csv students.csv project-preferences.csv select-by-*.txt Selection/scripts
 echo zip -r Selection Selection
 # submissions-638.csv: David Henty's #24 renamed to #34, Duplicate #15 on line 151 removed
 # registrations.csv: Keys 1,2,3 changed to Choice 1, Choice 2, Choice 3
diff --git a/project-preferences.csv b/project-preferences.csv
new file mode 100644
index 0000000000000000000000000000000000000000..536f30b20c2c0fdae871ef74d3777280b6e2e265
--- /dev/null
+++ b/project-preferences.csv
@@ -0,0 +1,5 @@
+# ProjectID, ApplicantID, Weight[, Comment]
+# Weight: > 1.0: preference (use same value for equal student, different values for ranking)
+#         = 1.0: indifference
+#         < 1.0: weighted rejection
+#         = 0.0: invalid preference/unsuitable
diff --git a/sohpc-assign.pl b/sohpc-assign.pl
new file mode 100755
index 0000000000000000000000000000000000000000..833e7978a0945c9194e91d80a1116617a5bf1b3b
--- /dev/null
+++ b/sohpc-assign.pl
@@ -0,0 +1,134 @@
+#!/usr/bin/perl -w
+
+# Copyright © 2019-2020 Forschungszentrum Juelich GmbH (Andreas Beckmann <a.beckmann@fz-juelich.de>)
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Usage: ./sohpc-assign.pl [weights.csv] students.csv [projectprefs.csv]
+
+$verbose = 1;
+
+$weight1 = 1.00;
+$weight2 = 0.90;
+$weight3 = 0.75;
+
+%project = ();
+%student = ();
+%project2student = ();
+%student2project = ();
+
+$cmt = "";
+
+while (<>) {
+	chomp;
+	s/^\s*//;
+	$first = (split(/, */, $_, 2))[0];
+	if (!$first || $first =~ /^#/) {
+		# empty or comment
+	} elsif ($first eq "weights") {
+		($first, $weight1, $weight2, $weight3) = split(/, */, $_, 4);
+		next;
+	} elsif ($first < 1000) {
+		($id, $score, $pref1, $pref2, $pref3, $name) = split(/[, ]+/, $_, 6);
+		#print "id=$id score=$score p1=$pref1 p2=$pref2 p3=$pref3\n";
+		$pref2 = 0 if $pref1 == $pref2;
+		$pref3 = 0 if $pref1 == $pref3 || $pref2 == $pref3;
+		$student{$id}{name} = $name;
+		$student{$id}{score} = $score;
+		$student{$id}{pref1} = $pref1;
+		$student{$id}{pref2} = $pref2;
+		$student{$id}{pref3} = $pref3;
+
+		push @{$project{$pref1}{cand}}, {value => $score * $weight1, student => $id, score => $score, spref => 1, pweight => 1.0, ppref => 0} if $pref1;
+		push @{$project{$pref2}{cand}}, {value => $score * $weight2, student => $id, score => $score, spref => 2, pweight => 1.0, ppref => 0} if $pref2;
+		push @{$project{$pref3}{cand}}, {value => $score * $weight3, student => $id, score => $score, spref => 3, pweight => 1.0, ppref => 0} if $pref3;
+	} else {
+		($proj, $stud, $pweight, $cmt) = split(/[, ]+/, $_, 4);
+		if (defined $project{$proj}) {
+			foreach (@{$project{$proj}{cand}}) {
+				if ($_->{student} == $stud) {
+					$_->{pweight} = $pweight;
+					$_->{value} *= $pweight;
+				}
+			}
+		}
+	}
+}
+
+foreach $p (sort keys %project) {
+	$pw = -1;
+	$pp = 0;
+	foreach (sort {$b->{pweight} <=> $a->{pweight}} @{$project{$p}{cand}}) {
+		if ($pw != $_->{pweight}) {
+			$pw = $_->{pweight};
+			++$pp;
+		}
+		$_->{ppref} = $pp;
+	}
+	@{$project{$p}{cand}} = sort {$b->{value} <=> $a->{value}} @{$project{$p}{cand}};
+	if ($verbose) {
+		print "$p: $_->{student}: $_->{spref}/$_->{ppref} $_->{score} ($_->{value})\n" foreach (@{$project{$p}{cand}});
+	}
+}
+
+sub max_score($$)
+{
+	my $p2s = shift;
+	my $s2p = shift;
+	my $s = 0.;
+	foreach my $p (keys %project) {
+		next if defined $p2s->{$p};
+		foreach my $c (@{$project{$p}{cand}}) {
+			if (!defined $s2p->{$c->{student}}) {
+				$s += $c->{score};
+				last;
+			}
+		}
+	}
+	return $s;
+}
+
+$total = 0.;
+@todo = keys %project;
+
+print "max_score=", max_score({}, {}), "\n" if $verbose;
+while (@todo) {
+	my @cand = ();
+	my ($p, $c, $s);
+	foreach $p (@todo) {
+		foreach $c (@{$project{$p}{cand}}) {
+			next if defined $student2project{$c->{student}};
+			push @cand, {project => $p, student => $c, value => $c->{value} +  max_score({%project2student, $p => $c->{student}}, {%student2project, $c->{student} => $p})};
+		}
+	}
+	last unless @cand;
+	$_ = (sort {$b->{value} <=> $a->{value}} @cand)[0];
+	$p = $_->{project};
+	$s = $_->{student};
+	$project2student{$p} = $s;
+	$student2project{$s->{student}} = $p;
+	$total += $s->{score};
+	printf "assigned %4d: %3d (%d/%d) %.2f\n", $p, $s->{student}, $s->{spref}, $s->{ppref}, $s->{score} if $verbose;
+
+	@todo = grep {$_ != $p} @todo;
+}
+
+foreach $p (sort keys %project) {
+	my $s = $project2student{$p}->{student} || "???";
+	my $spref = $project2student{$p}->{spref};
+	my $ppref = $project2student{$p}->{ppref};
+	printf "%4d: %3d (%d/%d) %.2f %s\n", $p, $s, $spref, $ppref, $student{$s}{score} || 0, $student{$s}{name};
+}
+print "total score: $total\n";
+print "weights: $weight1, $weight2, $weight3\n";
diff --git a/weights-pref.csv b/weights-pref.csv
new file mode 100644
index 0000000000000000000000000000000000000000..5359eb7cd5821cf0030dcc1f627b065917fd8232
--- /dev/null
+++ b/weights-pref.csv
@@ -0,0 +1 @@
+weights, 1.0, 0.8, 0.5
diff --git a/weights-score.csv b/weights-score.csv
new file mode 100644
index 0000000000000000000000000000000000000000..80c8ae6bac7bc5727b342ea9c271022ab9f4f636
--- /dev/null
+++ b/weights-score.csv
@@ -0,0 +1 @@
+weights, 1.0, 0.95, 0.90