-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathwhatif.rb
executable file
·179 lines (153 loc) · 5.62 KB
/
whatif.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# STV Explorer using Historical data from ASF Board Votes
#####
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#####
#
# Prereqs:
#
# * svn checkout of foundation:voter and foundation:Meetings
# * Web server with the ability to run cgi (Apache httpd recommended)
# * Python 2.6.x
# * Ruby 1.9.x
# * wunderbar gem ([sudo] gem install wunderbar)
# * (optional) jQuery http://code.jquery.com/jquery-min.js
#
# Installation instructions:
#
# ruby whatif.rb --install=/var/www
#
# 1) Specify a path that supports cgi, like public-html or Sites.
# 2) (optional, but highly recommended) download jquery-min.js into
# your installation directory.
#
# Execution instructions:
#
# Point your web browser at your cgi script. For best results, use
# Firefox 4 or a WebKit based browser, like Google Chrome.
MEETINGS = File.expand_path('../Meetings') unless defined? MEETINGS
WHATIF = './whatif.py' unless defined? WHATIF
require 'wunderbar'
require 'tempfile'
def raw_votes(date)
all_votes = Dir["#{MEETINGS}/*/raw_board_votes.txt"]
if date
result = "#{MEETINGS}/#{date}/raw_board_votes.txt"
else
result = all_votes.sort.last
end
result
end
def ini(vote)
vote.sub('/raw_','/').sub('votes.','nominations.').sub('.txt','.ini')
end
def filtered_election(votes, seats, candidates)
list = candidates.join(' ')
output = `#{WHATIF} #{votes} #{seats} #{list}`
output.scan(/.*elected$/).inject(Hash.new('none')) do |results, line|
name, status = line.scan(/^(.*?)\s+(n?o?t?\s?elected)$/).flatten
results.merge({name.gsub(/[^[[:alnum:]]]/,'') => status.gsub(/\s/, '-')})
end
end
# XMLHttpRequest (AJAX)
_json do
nominees = File.read(ini(raw_votes(@date))).scan(/^\w:\s*(.*)/).flatten
candidates = params.keys & nominees.map {|name| name.gsub(/[^[[:alnum:]]]/,'')}
_! filtered_election(raw_votes(@date), @seats, candidates)
end
# main output
_html do
_head_ do
_title 'STV Explorer'
_style! %{
h1 {font-family: sans-serif; font-weight: normal}
select {display: block; margin: 0 0 1em 1em; font-size: 140%}
label div {display: inline-block; min-width: 12em; font-size: x-large}
label div {-webkit-transition: background-color 1s}
label div {-moz-transition: background-color 1s}
label {float: left; clear: both}
label[for=seats] {display: inline; line-height: 500%}
p, input[type=checkbox] {margin-left: 1em}
p, input[type=submit] {display: block; clear: both}
.elected {background: #0F0}
.not-elected {background: #F00}
.none {background: yellow}
}
_script src: 'assets/jquery-min.js'
end
_body? do
_h1_ 'STV Explorer'
nominees = Hash[File.read(ini(raw_votes(@date))).scan(/^\w:\s*(.*)/).
flatten.map {|name| [name.gsub(/[^[[:alnum:]]]/,''), name]}]
candidates = params.keys & nominees.keys
candidates = nominees.keys if candidates.empty? or @reset
@seats ||= '9'
results = filtered_election(raw_votes(@date), @seats, candidates)
# form of nominees and seats
_form method: 'post', id: 'vote' do
_select name: 'date' do
Dir["#{MEETINGS}/*/raw_board_votes.txt"].sort.reverse.each do |votes|
next unless File.exist? ini(votes)
date = votes[/(\d+)\/raw_board_votes.txt$/,1]
display = date.sub(/(\d{4})(\d\d)(\d\d)/,'\1-\2-\3')
_option display, value: date, selected: (votes == raw_votes(@date))
end
end
nominees.sort.each do |id, name|
_label_ id: id do
_input type: 'checkbox', name: id, checked: candidates.include?(id)
_div name, class: results[id]
end
end
_label_ for: 'seats' do
_span 'seats:'
_input name: 'seats', id: 'seats', value: @seats, size: 2,
type: 'number', min: 1, max: nominees.length-1
end
_input type: 'submit', value: 'submit', name: 'submit'
end
_p_ do
_a "Member's Meeting Information",
href: 'https://whimsy.apache.org/members/meeting'
end
_script %{
// submit form using XHR; update class for labels based on results
function refresh() {
$.post('', $('#vote').serialize(), function(results) {
for (var name in results) {
$('#'+name+' div').attr('class', results[name]);
}
}, 'json');
return false;
}
// On checkbox click, remove class from associated label & refresh
$(':checkbox').click(function() {
$('div', $(this).parent()).attr('class', 'none');
refresh();
});
// reset whenever the date changes
$('select').change(function() {
$('input[value=submit]').attr('name', 'reset');
$('input[value=submit]').click();
});
// If JS is enabled, we don't need a submit button
$('input[type=submit]').hide();
// Refresh on change in number of seats
$('#seats').on('input', function() {return refresh()});
}
end
end
__END__
MEETINGS = '../Meetings'