+
+ foreach my $s (@newsurpluses) {
+ # calculate the transfer value of each surplus
+ # we do this simultaneously, but based on the number of
+ # continuing candidates (excluding all the ones elected already)
+ # ERS rule 5.3.3
+
+ my $votes = $s->{Votes};
+ my $surplus = $s->{Surplus};
+ my $transferrable =
+ sum0
+ map { $_->{Weight} }
+ grep { !!voteliveprefs $_ }
+ @$votes;
+
+ my $derate = 1/1;
+ printf "%7s %10s %s\n", 'xfrable', $s->{Cand}, pr $transferrable;
+ if ($transferrable > $surplus) {
+ $derate = $transferrable / $surplus;
+ printf "%7s %10s %s\n", 'derate', $s->{Cand}, pr $derate;
+ foreach my $vote (@{ $s->{Votes} }) {
+ votelog $vote, "part of surplus, derated ". pr $derate;
+ $vote->{Weight} /= $derate;
+ }
+ }
+ $s->{Total} = $transferrable / $derate;
+
+ push @surpluses, $s;
+
+ $things_update->();
+ printf "%7s %10s %s\n", 'surplus', $s->{Cand}, pr $s->{Total};
+
+ $need_to_transfer_surplus = 0;
+ # before actually transferring a surplus, we will consider
+ # eliminating, and then reconsider with a lower quota
+ }
+
+ my $deferredsurplus = sum0 map { $_->{Total} } @surpluses;
+ printf "%18s %s\n", 'deferred surplus', pr $deferredsurplus;
+
+ # Look for people to eliminate
+ # We eliminate before trying to transfer surpluses
+ # ERS 5.2.5
+ my $elimvotebefore = 0/1;
+ for (;;) {
+ last unless @sorted;
+
+ if ($elimvotebefore) {
+ printf "%18s %s\n", 'elimination, sofar', pr $elimvotebefore;
+ } elsif (@surpluses) {
+ printf "%18s\n", 'elimination, maybe';
+ } else {
+ printf "%18s\n", 'elimination, starts';
+ }
+
+ my @elim = equalpiles 'elim?', reverse @sorted;
+ my $elimvotenow = sum0 map { $_->{Total} } @elim;
+
+ if (@surpluses || $elimvotebefore) {
+ # rule 5.2.2
+ if (@sorted == @elim) {
+ printf "%18s\n", 'no-elim (all-equal)';
+ last;
+ }
+ my $nextup = $sorted[ $#sorted - @elim ];
+ printf "%7s %10s %s\n", 'nextup', $nextup->{Cand},
+ pr $nextup->{Total};
+ my $aheadby = $nextup->{Total} - ($elimvotenow + $elimvotebefore);
+ unless ($deferredsurplus <= $aheadby) {
+ # rule 5.2.2 (b)
+ printf "%18s %s\n", 'no-elim (nextup)', pr $aheadby;
+ last;
+ }
+ }
+
+ my $elim_tie =
+ @elim > 1 &&
+ (scalar keys %continuing) - (scalar @elim) < $placesremain;
+ if ($elim_tie) {
+ # eliminate only one then, and try again
+ printf "elim-tie!\n";
+ @elim = historically_prefer -1, @elim;
+ }
+
+ foreach my $s (@elim) {
+ my $c = $s->{Cand};
+ printf "%7s %10s %s\n", 'ELIM', $c, '----------';
+ my $votes = $s->{Votes};
+ votelogfull $_, "failed to stop $c elimination" foreach @$votes;
+ $elimvotebefore += $s->{Total};
+ delete $continuing{$c};
+ delete $sorted{$c};
+ push @unsorted, @$votes;
+ }
+
+ $things_update->();
+ $need_to_transfer_surplus = 0;
+ last if $elim_tie; # no more, then!
+ }
+
+ next unless $need_to_transfer_surplus;
+
+ @surpluses = nsort_by { $_->{Total} } @surpluses;
+ my @surplusxfer = equalpiles 'xfer?', @surpluses;
+ die unless @surplusxfer;
+
+ if (@surplusxfer > 1) {
+ @surplusxfer = historically_prefer +1, @surplusxfer;
+ }
+
+ my $s = $surplusxfer[0];
+ my $c = $s->{Cand};
+ printf "%7s %10s\n", 'xfer', $c;
+ my $votes = $s->{Votes};
+ votelogfull $_, "surplus transferred" foreach @$votes;
+ @surpluses = grep { $_->{Cand} ne $c } @surpluses;
+ push @unsorted, @$votes;