|  line  | 
 stmt  | 
 bran  | 
 cond  | 
 sub  | 
 pod  | 
 time  | 
 code  | 
| 
1
 | 
  
2
  
 | 
 
 | 
 
 | 
  
2
  
 | 
 
 | 
522780
 | 
 use strict;  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
19
 | 
    | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
59
 | 
    | 
| 
2
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
 
 | 
12
 | 
 use warnings;  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
    | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
46
 | 
    | 
| 
3
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
 
 | 
47
 | 
 use 5.024;  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
    | 
| 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 package Vote::Count::Method::WIGM;  | 
| 
6
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
 
 | 
1072
 | 
 use namespace::autoclean;  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
37941
 | 
    | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8
 | 
    | 
| 
7
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
 
 | 
1409
 | 
 use Moose;  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
979509
 | 
    | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
16
 | 
    | 
| 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 extends 'Vote::Count::Charge';  | 
| 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
10
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
 
 | 
15731
 | 
 no warnings 'experimental';  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
    | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
119
 | 
    | 
| 
11
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
 
 | 
16
 | 
 use feature qw /postderef signatures/;  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
    | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
307
 | 
    | 
| 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
13
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
 
 | 
2068
 | 
 use Storable 3.15 'dclone';  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8396
 | 
    | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
139
 | 
    | 
| 
14
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
 
 | 
1144
 | 
 use Mojo::Template;  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
428697
 | 
    | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
22
 | 
    | 
| 
15
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
 
 | 
1169
 | 
 use Sort::Hash;  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1857
 | 
    | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
107
 | 
    | 
| 
16
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
 
 | 
15
 | 
 use Data::Dumper;  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
    | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3353
 | 
    | 
| 
17
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
18
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 our $VERSION='2.00';  | 
| 
19
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
20
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 NAME  | 
| 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
22
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Vote::Count::Method::WIGM  | 
| 
23
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
24
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 VERSION 2.00  | 
| 
25
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
26
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut  | 
| 
27
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
28
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # ABSTRACT: An implementation of WIGM STV using Vote::Charge.  | 
| 
29
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
30
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =pod  | 
| 
31
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
32
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 SYNOPSIS  | 
| 
33
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
34
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   use Vote::Count::Method::WIGM;  | 
| 
35
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   use Vote::Count::ReadBallots 'read_ballots';  | 
| 
36
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
37
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   my $ballotset = read_ballots('t/data/Scotland2012/Cumbernauld_South.txt');  | 
| 
38
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   my $Cumbernauld   = Vote::Count::Method::WIGM->new(  | 
| 
39
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     Seats     => 4,  | 
| 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     BallotSet => $ballotset,  | 
| 
41
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     VoteValue => 100000, # default  | 
| 
42
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     LogTo => '/tmp/cumbernauld_south_2012',  | 
| 
43
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   );  | 
| 
44
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
45
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # Run the Election  | 
| 
46
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   $D->WIGRun();  | 
| 
47
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # Write the Human Readable Logs  | 
| 
48
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   $D->WriteLog();  | 
| 
49
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # Write the Events in JSON and YAML  | 
| 
50
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   $D->WriteSTVEvent();  | 
| 
51
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
52
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 Description  | 
| 
53
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
54
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Implements Weighted Improved Gregory Single Transferable Vote based on Scotland's rules.  | 
| 
55
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
56
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 WIGRun  | 
| 
57
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
58
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Run and log the Election.  | 
| 
59
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
60
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head2 Implementation Notes  | 
| 
61
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
62
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 The Scottish Rules specify 5 decimal places, a weight of 100,000 is used which is equivalent.  | 
| 
63
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
64
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 When more than one choice is Pending the rules call for a full Stage to elect each of them. Pending Choices cannot recieve additional votes, this implementation elects, charges, and rebates the Pending Choices, then starts a new Round. The final result will be the same, but Vote::Count::Method::WIGM rounds will not always match the stages of the Hand Count rules.  | 
| 
65
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
66
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 Experimental  | 
| 
67
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
68
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Small discrepencies with the stages data available for testing have been seen, which are likely to be rounding issues. Until further review can be taken, this code should be considered a preview.  | 
| 
69
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
70
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 The Rules  | 
| 
71
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
72
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 L<The Official Rules|http://www.opsi.gov.uk/legislation/scotland/ssi2007/ssi_20070042_en.pdf>  | 
| 
73
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
74
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut  | 
| 
75
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
76
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 has 'VoteValue' => (  | 
| 
77
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   is      => 'ro',  | 
| 
78
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   isa     => 'Int',  | 
| 
79
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   default => 100000,  | 
| 
80
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 );  | 
| 
81
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
82
 | 
4
 | 
 
 | 
 
 | 
  
4
  
 | 
 
 | 
19
 | 
 sub _SetWIGQuota ( $I, $ballots = 0 ) {  | 
| 
 
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
9
 | 
    | 
| 
 
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
9
 | 
    | 
| 
 
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
    | 
| 
83
 | 
4
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
26
 | 
   $ballots = $I->VotesCast() unless $ballots;  | 
| 
84
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
193
 | 
   my $denominator = $I->Seats() + 1;  | 
| 
85
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
19
 | 
   my $q           = 1 + int( $ballots / $denominator );  | 
| 
86
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
131
 | 
   return ( $q * $I->VoteValue );  | 
| 
87
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
88
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
89
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # If a floor is applied there may be abandoned ballots,  | 
| 
90
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # _WIGStart will remove these from the quota.  | 
| 
91
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
92
 | 
12
 | 
 
 | 
 
 | 
  
12
  
 | 
 
 | 
31
 | 
 sub _format_round_result ( $rslt, $topcount, $votevalue ) {  | 
| 
 
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
28
 | 
    | 
| 
 
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
27
 | 
    | 
| 
 
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
28
 | 
    | 
| 
 
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
24
 | 
    | 
| 
93
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2143
 | 
   my $top = dclone $topcount;  | 
| 
94
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
57
 | 
   my $rawcount = $top->{'rawcount'};  | 
| 
95
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
69
 | 
   for my $t ( keys $rawcount->%* ) {  | 
| 
96
 | 
54
 | 
 
 | 
 
 | 
 
 | 
 
 | 
139
 | 
     my $folded = $rawcount->{$t} / $votevalue;  | 
| 
97
 | 
54
 | 
 
 | 
 
 | 
 
 | 
 
 | 
381
 | 
     $rawcount->{$t} = "$folded ($rawcount->{$t})";  | 
| 
98
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
99
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # die Dumper $rawcount;  | 
| 
100
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
38
 | 
   my $tmpl = q|% use feature 'postderef';  | 
| 
101
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 % my @pending = $rslt->{'pending'}->@*;  | 
| 
102
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 ## Round: <%= $rslt->{'round'} %>  | 
| 
103
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
104
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 <%= $tc->RankTable() %>  | 
| 
105
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 % if ( @pending ) {  | 
| 
106
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 ### Winners:  | 
| 
107
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
108
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 % for my $p ( @pending ) {  | 
| 
109
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 *<%= $p %>*: <%= $rslt->{'winvotes'}{$p} / $votevalue %> (<%= $rslt->{'winvotes'}{$p} %>)  | 
| 
110
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
111
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 % }  | 
| 
112
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 % } else {  | 
| 
113
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 ### No Winners  | 
| 
114
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
115
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 % }|;  | 
| 
116
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
143
 | 
   my $mt = Mojo::Template->new;  | 
| 
117
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
197
 | 
   return $mt->vars(1)->render( $tmpl, {rslt => $rslt, tc => $top, votevalue => $votevalue });  | 
| 
118
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
119
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
120
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
 
 | 
110
 | 
 sub _WIGStart ( $I ) {  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
    | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
    | 
| 
121
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
42
 | 
   my $seats        = $I->Seats();  | 
| 
122
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8
 | 
   my $ballots_cast = $I->VotesCast();  | 
| 
123
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
38
 | 
   $I->TopCount();    # Set the topchoice values on the ballots.  | 
| 
124
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
20
 | 
   my $abandoned     = $I->CountAbandoned()->{'count_abandoned'};  | 
| 
125
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
   my $ballots_valid = $ballots_cast - $abandoned;  | 
| 
126
 | 
1
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
8
 | 
   my $abandonmsg =  | 
| 
127
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     $abandoned  | 
| 
128
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     ? "\nThere are $ballots_cast ballots. \n$abandoned ballots have no choices and will be disregarded"  | 
| 
129
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     : '';  | 
| 
130
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
9
 | 
   my $quota = $I->_SetWIGQuota($ballots_valid);  | 
| 
131
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
45
 | 
   $I->logt(  | 
| 
132
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     qq/Using Weighted Inclusive Gregory, Scottish Rules. $abandonmsg  | 
| 
133
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         Seats to Fill: $seats  | 
| 
134
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         Ballots Counted for Quota: $ballots_valid  | 
| 
135
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         Quota: $quota;  | 
| 
136
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     /  | 
| 
137
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   );  | 
| 
138
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
   my $event = { ballots => $ballots_valid, quota => $quota };  | 
| 
139
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
12
 | 
   $I->STVEvent($event);  | 
| 
140
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
   return $event;  | 
| 
141
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
142
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
143
 | 
12
 | 
 
 | 
 
 | 
  
12
  
 | 
 
 | 
1273
 | 
 sub _WIGRound ( $I, $quota ) {  | 
| 
 
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
29
 | 
    | 
| 
 
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
26
 | 
    | 
| 
 
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
24
 | 
    | 
| 
144
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
62
 | 
   my $round_num = $I->NextSTVRound();  | 
| 
145
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
117
 | 
   my $round     = $I->TopCount();  | 
| 
146
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
77
 | 
   my $roundcnt  = $round->RawCount();  | 
| 
147
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
93
 | 
   my @choices   = $I->GetActiveList();  | 
| 
148
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
42
 | 
   my %rndvotes  = ();  | 
| 
149
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
66
 | 
   my $leader = $round->Leader()->{'winner'};  | 
| 
150
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
58
 | 
   my $votes4leader = $round->RawCount->{$leader};  | 
| 
151
 | 
12
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
54
 | 
   my $pending = $votes4leader >= $quota ? $leader : '';  | 
| 
152
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
153
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
50
 | 
   for my $C (@choices ) {  | 
| 
154
 | 
54
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
125
 | 
     if( $roundcnt->{ $C} >= $quota ) {  | 
| 
155
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
26
 | 
       $rndvotes{ $C } = $roundcnt->{ $C } ;  | 
| 
156
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
157
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
158
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
88
 | 
   my @pending = sort_hash( \%rndvotes, 'numeric', 'desc' );  | 
| 
159
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
160
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   my $rslt = {  | 
| 
161
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     pending  => \@pending,  | 
| 
162
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     winvotes => \%rndvotes,  | 
| 
163
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     quota    => $quota,  | 
| 
164
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     round    => $round_num,  | 
| 
165
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     allvotes => $round->RawCount(),  | 
| 
166
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     lowest   => $round->ArrayBottom()->[0],  | 
| 
167
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2788
 | 
     noncontinuing => $I->CountAbandoned()->{'value_abandoned'},  | 
| 
168
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   };  | 
| 
169
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
189
 | 
   $I->STVEvent($rslt);  | 
| 
170
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
808
 | 
   $I->logv( _format_round_result( $rslt, $round, $I->VoteValue() ) );  | 
| 
171
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
372
 | 
   return ($rslt);  | 
| 
172
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
173
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
174
 | 
7
 | 
 
 | 
 
 | 
  
7
  
 | 
 
 | 
28
 | 
 sub _WIGElect ( $I, $chrg ) {  | 
| 
 
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
26
 | 
    | 
| 
 
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
13
 | 
    | 
| 
 
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
14
 | 
    | 
| 
175
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
20
 | 
   my $choice = $chrg->{'choice'};  | 
| 
176
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
36
 | 
   my $refund   = int( $chrg->{'surplus'} / $chrg->{'cntchrgd'} );  | 
| 
177
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
15
 | 
   my $refunded = 0;  | 
| 
178
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
26
 | 
   for my $b ( $chrg->{'ballotschrgd'}->@* ) {  | 
| 
179
 | 
1047
 | 
 
 | 
 
 | 
 
 | 
 
 | 
24101
 | 
     my $ballot = $I->BallotSet()->{'ballots'}{$b};  | 
| 
180
 | 
1047
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
2464
 | 
      if  ( $ballot->{'charged'}{$choice} < $refund )  | 
| 
181
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
      {  | 
| 
182
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       $ballot->{'votevalue'} += $ballot->{'charged'}{$choice};  | 
| 
183
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       $refunded += $ballot->{'charged'}{$choice} * $ballot->{'count'};  | 
| 
184
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       $ballot->{'charged'}{$choice} = 0;  | 
| 
185
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } else  | 
| 
186
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
      {  | 
| 
187
 | 
1047
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1596
 | 
     $ballot->{'votevalue'} += $refund;  | 
| 
188
 | 
1047
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1561
 | 
     $refunded += $ballot->{'count'} * $refund;  | 
| 
189
 | 
1047
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1801
 | 
     $ballot->{'charged'}{$choice} -= $refund;  | 
| 
190
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
      }  | 
| 
191
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
192
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   my $candvotes =  | 
| 
193
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
63
 | 
     $I->GetChoiceStatus( $choice )->{'votes'} - $refunded;  | 
| 
194
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
68
 | 
   $I->SetChoiceStatus( $choice, { votes => $candvotes } );  | 
| 
195
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
45
 | 
   $I->Elect( $choice );  | 
| 
196
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
197
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
198
 | 
10
 | 
 
 | 
 
 | 
  
10
  
 | 
 
 | 
24
 | 
 sub _wigcomplete ( $I, $_WIGRound ) {  | 
| 
 
 | 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
18
 | 
    | 
| 
 
 | 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
18
 | 
    | 
| 
 
 | 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
17
 | 
    | 
| 
199
 | 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
62
 | 
   my @choices = $I->GetActiveList();  | 
| 
200
 | 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
28
 | 
   my $choiceremain = scalar @choices;  | 
| 
201
 | 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
28
 | 
   my $numelected   = scalar( $I->{'elected'}->@* );  | 
| 
202
 | 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
294
 | 
   my $openseats = $I->Seats() - $numelected;  | 
| 
203
 | 
10
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
35
 | 
   if ( $choiceremain <= $openseats ) {  | 
| 
204
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
11
 | 
     $I->logv( "Electing all Remaining Choices: @choices.\n");  | 
| 
205
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
     for my $C (@choices) {  | 
| 
206
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
       my $cvotes = $_WIGRound->{'allvotes'}{$C};  | 
| 
207
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
         $I->Elect($C);  | 
| 
208
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
         $I->SetChoiceStatus( $C, { votes => $cvotes } );  | 
| 
209
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
210
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8
 | 
   return 1;  | 
| 
211
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
212
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
47
 | 
   return 0;  | 
| 
213
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
214
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
215
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
  
0
  
 | 
8
 | 
 sub WIGRun ( $I ) {  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
    | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
    | 
| 
216
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
   my $pre_rslt = $I->_WIGStart();  | 
| 
217
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
   my $quota    = $pre_rslt->{'quota'};  | 
| 
218
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
29
 | 
   my $seats    = $I->Seats();  | 
| 
219
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
220
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 WIGDOROUNDLOOP:  | 
| 
221
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8
 | 
   while ( $I->Elected() < $seats ) {  | 
| 
222
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
32
 | 
     my $rnd = $I->_WIGRound($quota);  | 
| 
223
 | 
6
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
35
 | 
     last WIGDOROUNDLOOP if _wigcomplete ( $I, $rnd );  | 
| 
224
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
30
 | 
     my @pending = $rnd->{'pending'}->@*;  | 
| 
225
 | 
6
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
22
 | 
     if ( scalar(@pending)){  | 
| 
226
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
       for my $pending (@pending) {  | 
| 
227
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
33
 | 
         my $chrg = $I->Charge( $pending, $quota );  | 
| 
228
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
21
 | 
         $I->_WIGElect($chrg);  | 
| 
229
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
230
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } else {  | 
| 
231
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
36
 | 
       $I->logv( "Eliminating low choice: $rnd->{'lowest'}\n");  | 
| 
232
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
43
 | 
       $I->Defeat($rnd->{'lowest'});  | 
| 
233
 | 
4
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
18
 | 
       last WIGDOROUNDLOOP if _wigcomplete ( $I, $rnd );  | 
| 
234
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
235
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
236
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8
 | 
   my @elected = $I->Elected();  | 
| 
237
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10
 | 
   $I->STVEvent( { winners => \@elected });  | 
| 
238
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
9
 | 
   $I->logt( "Winners: " . join( ', ', @elected ));  | 
| 
239
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
240
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
241
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 __PACKAGE__->meta->make_immutable;  | 
| 
242
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 1;  | 
| 
243
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
244
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 #FOOTER  | 
| 
245
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
246
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =pod  | 
| 
247
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
248
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 BUG TRACKER  | 
| 
249
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
250
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 L<https://github.com/brainbuz/Vote-Count/issues>  | 
| 
251
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
252
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 AUTHOR  | 
| 
253
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
254
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 John Karr (BRAINBUZ) brainbuz@cpan.org  | 
| 
255
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
256
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 CONTRIBUTORS  | 
| 
257
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
258
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Copyright 2019-2021 by John Karr (BRAINBUZ) brainbuz@cpan.org.  | 
| 
259
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
260
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 LICENSE  | 
| 
261
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
262
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 This module is released under the GNU Public License Version 3. See license file for details. For more information on this license visit L<http://fsf.org>.  | 
| 
263
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
264
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 SUPPORT  | 
| 
265
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
266
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 This software is provided as is, per the terms of the GNU Public License. Professional support and customisation services are available from the author.  | 
| 
267
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
268
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut  | 
| 
269
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    |