Description:
add table sorter and combine user_stat and user_stat_max action into one view
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r430:6e39492e3fa5 - - 11 files changed: 286 inserted, 60 deleted

@@ -0,0 +1,197
1 + /*************
2 + Metro Dark Theme
3 + *************/
4 + /* overall */
5 + .tablesorter-cafe {
6 + // font: 12px/18px 'Segoe UI Semilight', 'Open Sans', Verdana, Arial, Helvetica, sans-serif;
7 + color: #000;
8 + background-color: #777;
9 + margin: 10px 0 15px;
10 + text-align: left;
11 + border-collapse: collapse;
12 + border: #555 1px solid;
13 + }
14 +
15 + .tablesorter-cafe tr.dark-row th, .tablesorter-cafe tr.dark-row td {
16 + background-color: #222;
17 + color: #fff;
18 + text-align: left;
19 + font-size: 14px;
20 + }
21 +
22 + /* header/footer */
23 + .tablesorter-cafe caption,
24 + .tablesorter-cafe th,
25 + .tablesorter-cafe thead td,
26 + .tablesorter-cafe tfoot th,
27 + .tablesorter-cafe tfoot td {
28 + //font-weight: 300;
29 + //font-size: 15px;
30 + color: #fff;
31 + background-color: #777;
32 + padding: 2px;
33 + border: #555 1px solid;
34 + }
35 +
36 + .tablesorter-cafe .header,
37 + .tablesorter-cafe .tablesorter-header {
38 + background-image: url(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAQBAMAAADQT4M0AAAAGFBMVEUAAADu7u7u7u7u7u7u7u7u7u7u7u7u7u5jNePWAAAACHRSTlMAMxIHKwEgMWD59H4AAABSSURBVAjXY2BgYFJgAAHzYhDJ6igSAKTYBAUTgJSioKAQAwNzoaCguAFDiCAQuDIkgigxBgiA8cJAVCpQt6AgSL+JoKAzA0gjUBsQqBcBCYhFAAE/CV4zeSzxAAAAAElFTkSuQmCC);
39 + background-position: center right;
40 + background-repeat: no-repeat;
41 + cursor: pointer;
42 + white-space: normal;
43 + }
44 + .tablesorter-cafe .tablesorter-header-inner {
45 + padding: 0 18px 0 4px;
46 + }
47 + .tablesorter-cafe thead .headerSortUp,
48 + .tablesorter-cafe thead .tablesorter-headerSortUp,
49 + .tablesorter-cafe thead .tablesorter-headerAsc {
50 + background-image: url(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAQBAMAAADQT4M0AAAAIVBMVEUAAADu7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u5meJAOAAAACnRSTlMAMwsqXt+gIBUGxGoDMAAAAFlJREFUCNctzC0SQAAUReEzGNQ3AlHRiSRZFCVZYgeswRL8hLdK7834wj3tAlGP6y7fYHpKS6w6WwbVG0I1NZVnZPG8/DYxOYlnhUYkA06R1s9ESsxR4NIdPhkPFDFYuEnMAAAAAElFTkSuQmCC);
51 + }
52 + .tablesorter-cafe thead .headerSortDown,
53 + .tablesorter-cafe thead .tablesorter-headerSortDown,
54 + .tablesorter-cafe thead .tablesorter-headerDesc {
55 + background-image: url(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAQBAMAAADQT4M0AAAALVBMVEUAAADu7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7i0NViAAAADnRSTlMAMiweCQITTvDctZZqaTlM310AAABcSURBVAjXY2BgYEtgAAFHERDJqigUAKSYBQUNgFSioKAYAwOLIBA4MASBKFUGQxAlzAAF+94BwWuGKBC1lIFl3rt3Lx0YGCzevWsGSjK9e6cAUlT3HKyW9wADAwDRrBiDy6bKzwAAAABJRU5ErkJggg==);
56 + }
57 + .tablesorter-cafe thead .sorter-false {
58 + background-image: none;
59 + cursor: default;
60 + padding: 4px;
61 + }
62 +
63 + /* tbody */
64 + .tablesorter-cafe td {
65 + background-color: #fff;
66 + padding: 1px 4px;
67 + vertical-align: top;
68 + border-style: solid;
69 + border-color: #666;
70 + border-collapse: collapse;
71 + border-width: 0px 1px;
72 +
73 + }
74 +
75 + /* hovered row colors */
76 + .tablesorter-cafe tbody > tr:hover > td,
77 + .tablesorter-cafe tbody > tr.even:hover > td,
78 + .tablesorter-cafe tbody > tr.odd:hover > td {
79 + background: #bbb;
80 + color: #000;
81 + }
82 +
83 + /* table processing indicator */
84 + .tablesorter-cafe .tablesorter-processing {
85 + background-position: center center !important;
86 + background-repeat: no-repeat !important;
87 + /* background-image: url(../addons/pager/icons/loading.gif) !important; */
88 + background-image: url(data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=) !important;
89 + }
90 +
91 + /* pager */
92 + .tablesorter-cafe .tablesorter-pager button {
93 + background-color: #444;
94 + color: #eee;
95 + border: #555 1px solid;
96 + cursor: pointer;
97 + }
98 + .tablesorter-cafe .tablesorter-pager button:hover {
99 + background-color: #555;
100 + }
101 +
102 + /* Zebra Widget - row alternating colors */
103 + .tablesorter-cafe tr.odd td {
104 + background-color: #eee;
105 + }
106 + .tablesorter-cafe tr.even td {
107 + background-color: #fff;
108 + }
109 +
110 + /* Column Widget - column sort colors */
111 + .tablesorter-cafe tr.odd td.primary {
112 + background-color: #bfbfbf;
113 + }
114 + .tablesorter-cafe td.primary,
115 + .tablesorter-cafe tr.even td.primary {
116 + background-color: #d9d9d9;
117 + }
118 + .tablesorter-cafe tr.odd td.secondary {
119 + background-color: #d9d9d9;
120 + }
121 + .tablesorter-cafe td.secondary,
122 + .tablesorter-cafe tr.even td.secondary {
123 + background-color: #e6e6e6;
124 + }
125 + .tablesorter-cafe tr.odd td.tertiary {
126 + background-color: #e6e6e6;
127 + }
128 + .tablesorter-cafe td.tertiary,
129 + .tablesorter-cafe tr.even td.tertiary {
130 + background-color: #f2f2f2;
131 + }
132 +
133 + /* filter widget */
134 + .tablesorter-cafe .tablesorter-filter-row td {
135 + background: #eee;
136 + line-height: normal;
137 + text-align: center; /* center the input */
138 + -webkit-transition: line-height 0.1s ease;
139 + -moz-transition: line-height 0.1s ease;
140 + -o-transition: line-height 0.1s ease;
141 + transition: line-height 0.1s ease;
142 + }
143 + /* optional disabled input styling */
144 + .tablesorter-cafe .tablesorter-filter-row .disabled {
145 + opacity: 0.5;
146 + filter: alpha(opacity=50);
147 + cursor: not-allowed;
148 + }
149 + /* hidden filter row */
150 + .tablesorter-cafe .tablesorter-filter-row.hideme td {
151 + /*** *********************************************** ***/
152 + /*** change this padding to modify the thickness ***/
153 + /*** of the closed filter row (height = padding x 2) ***/
154 + padding: 2px;
155 + /*** *********************************************** ***/
156 + margin: 0;
157 + line-height: 0;
158 + cursor: pointer;
159 + }
160 + .tablesorter-cafe .tablesorter-filter-row.hideme .tablesorter-filter {
161 + height: 1px;
162 + min-height: 0;
163 + border: 0;
164 + padding: 0;
165 + margin: 0;
166 + /* don't use visibility: hidden because it disables tabbing */
167 + opacity: 0;
168 + filter: alpha(opacity=0);
169 + }
170 + /* filters */
171 + .tablesorter-cafe .tablesorter-filter {
172 + width: 95%;
173 + height: auto;
174 + margin: 4px;
175 + padding: 4px;
176 + background-color: #fff;
177 + border: 1px solid #bbb;
178 + color: #333;
179 + -webkit-box-sizing: border-box;
180 + -moz-box-sizing: border-box;
181 + box-sizing: border-box;
182 + -webkit-transition: height 0.1s ease;
183 + -moz-transition: height 0.1s ease;
184 + -o-transition: height 0.1s ease;
185 + transition: height 0.1s ease;
186 + }
187 + /* rows hidden by filtering (needed for child rows) */
188 + .tablesorter .filtered {
189 + display: none;
190 + }
191 +
192 + /* ajax error row */
193 + .tablesorter .tablesorter-errorRow td {
194 + text-align: center;
195 + cursor: pointer;
196 + background-color: #e6bf99;
197 + }
@@ -0,0 +1,54
1 + - content_for :header do
2 + = javascript_include_tag 'new'
3 + = stylesheet_link_tag 'tablesorter-theme.cafe'
4 +
5 + %script{:type=>"text/javascript"}
6 + $(function () {
7 + $('#since_datetime').datetimepicker({ showButtonPanel: true, dateFormat: "yy-mm-dd", controlType: "slider"} );
8 + $('#until_datetime').datetimepicker({ showButtonPanel: true, dateFormat: "yy-mm-dd", controlType: "slider"} );
9 + $('#my_table').tablesorter({widgets: ['zebra']});
10 + });
11 +
12 + %h1 User grading results
13 + %h2= params[:action] == 'user_stat' ? "Show scores from latest submission" : "Show max scores in submission range"
14 +
15 +
16 + - if @problem and @problem.errors
17 + =error_messages_for 'problem'
18 +
19 + = render partial: 'submission_range'
20 +
21 + - if params[:action] == 'user_stat'
22 + = "latest score"
23 + - else
24 + = link_to '[Show only latest submissions]', controller: :user_admin, action: :user_stat
25 +
26 + %table.tablesorter-cafe#my_table
27 + %thead
28 + %tr
29 + %th User
30 + %th Name
31 + %th Activated?
32 + %th Logged in
33 + %th Contest(s)
34 + - @problems.each do |p|
35 + %th= p.name
36 + %th Total
37 + %th Passed
38 + %tbody
39 + - @scorearray.each do |sc|
40 + %tr{class: cycle('info-even','info-odd')}
41 + - total,num_passed = 0,0
42 + - sc.each_index do |i|
43 + - if i == 0
44 + %td= sc[i].login
45 + %td= sc[i].full_name
46 + %td= sc[i].activated
47 + %td= sc[i].try(:contest_stat).try(:started_at)!=nil ? 'yes' : 'no'
48 + %td= sc[i].contests.collect {|c| c.name}.join(', ')
49 + - else
50 + %td= sc[i][0]
51 + - total += sc[i][0]
52 + - num_passed += 1 if sc[i][1]
53 + %td= total
54 + %td= num_passed
@@ -1,19 +1,26
1 # See http://help.github.com/ignore-files/ for more about ignoring files.
1 # See http://help.github.com/ignore-files/ for more about ignoring files.
2 #
2 #
3 # If you find yourself ignoring temporary files generated by your text editor
3 # If you find yourself ignoring temporary files generated by your text editor
4 # or operating system, you probably want to add a global ignore instead:
4 # or operating system, you probably want to add a global ignore instead:
5 # git config --global core.excludesfile ~/.gitignore_global
5 # git config --global core.excludesfile ~/.gitignore_global
6
6
7 # Ignore bundler config
7 # Ignore bundler config
8 /.bundle
8 /.bundle
9
9
10 # Ignore the default SQLite database.
10 # Ignore the default SQLite database.
11 /db/*.sqlite3
11 /db/*.sqlite3
12
12
13 # Ignore all logfiles and tempfiles.
13 # Ignore all logfiles and tempfiles.
14 /log/*.log
14 /log/*.log
15 /tmp
15 /tmp
16
16
17 *~
17 *~
18
18
19 /vendor/plugins/rails_upgrade
19 /vendor/plugins/rails_upgrade
20 +
21 + #ignore public assets???
22 + /public/assets
23 +
24 + #ignore .orig and .swp
25 + *.orig
26 + *.swp
@@ -1,58 +1,60
1 source 'https://rubygems.org'
1 source 'https://rubygems.org'
2
2
3 gem 'rails', '3.2.19'
3 gem 'rails', '3.2.19'
4
4
5 # Bundle edge Rails instead:
5 # Bundle edge Rails instead:
6 # gem 'rails', :git => 'git://github.com/rails/rails.git'
6 # gem 'rails', :git => 'git://github.com/rails/rails.git'
7
7
8 gem 'mysql2'
8 gem 'mysql2'
9
9
10 # Gems used only for assets and not required
10 # Gems used only for assets and not required
11 # in production environments by default.
11 # in production environments by default.
12 group :assets do
12 group :assets do
13 gem 'sass-rails', '~> 3.2.3'
13 gem 'sass-rails', '~> 3.2.3'
14 gem 'coffee-rails', '~> 3.2.1'
14 gem 'coffee-rails', '~> 3.2.1'
15
15
16 # See https://github.com/sstephenson/execjs#readme for more supported runtimes
16 # See https://github.com/sstephenson/execjs#readme for more supported runtimes
17 # gem 'therubyracer', :platforms => :ruby
17 # gem 'therubyracer', :platforms => :ruby
18
18
19 gem 'uglifier', '>= 1.0.3'
19 gem 'uglifier', '>= 1.0.3'
20 end
20 end
21
21
22 gem 'prototype-rails'
22 gem 'prototype-rails'
23
23
24 # To use ActiveModel has_secure_password
24 # To use ActiveModel has_secure_password
25 # gem 'bcrypt-ruby', '~> 3.0.0'
25 # gem 'bcrypt-ruby', '~> 3.0.0'
26
26
27 # To use Jbuilder templates for JSON
27 # To use Jbuilder templates for JSON
28 # gem 'jbuilder'
28 # gem 'jbuilder'
29
29
30 # Use unicorn as the app server
30 # Use unicorn as the app server
31 # gem 'unicorn'
31 # gem 'unicorn'
32
32
33 # Deploy with Capistrano
33 # Deploy with Capistrano
34 # gem 'capistrano'
34 # gem 'capistrano'
35
35
36 # To use debugger
36 # To use debugger
37 # gem 'debugger'
37 # gem 'debugger'
38 #
38 #
39
39
40 + # jquery addition
40 gem 'jquery-rails'
41 gem 'jquery-rails'
41 gem 'jquery-ui-sass-rails'
42 gem 'jquery-ui-sass-rails'
42 gem 'jquery-timepicker-addon-rails'
43 gem 'jquery-timepicker-addon-rails'
44 + gem 'jquery-tablesorter'
43
45
44 #syntax highlighter
46 #syntax highlighter
45 gem 'rouge'
47 gem 'rouge'
46
48
47 gem "haml"
49 gem "haml"
48 gem "mail"
50 gem "mail"
49 gem "rdiscount"
51 gem "rdiscount"
50 gem "test-unit"
52 gem "test-unit"
51 gem 'will_paginate', '~> 3.0.0'
53 gem 'will_paginate', '~> 3.0.0'
52 gem 'dynamic_form'
54 gem 'dynamic_form'
53 gem 'in_place_editing'
55 gem 'in_place_editing'
54 gem 'verification', :git => 'git://github.com/sikachu/verification.git'
56 gem 'verification', :git => 'git://github.com/sikachu/verification.git'
55
57
56 group :test, :development do
58 group :test, :development do
57 gem "rspec-rails", "~> 2.0"
59 gem "rspec-rails", "~> 2.0"
58 end
60 end
@@ -1,168 +1,171
1 GIT
1 GIT
2 remote: git://github.com/sikachu/verification.git
2 remote: git://github.com/sikachu/verification.git
3 revision: 76eaf51b13276ecae54bd9cd115832595d2ff56d
3 revision: 76eaf51b13276ecae54bd9cd115832595d2ff56d
4 specs:
4 specs:
5 verification (1.0.3)
5 verification (1.0.3)
6 actionpack (>= 3.0.0, < 5.0)
6 actionpack (>= 3.0.0, < 5.0)
7 activesupport (>= 3.0.0, < 5.0)
7 activesupport (>= 3.0.0, < 5.0)
8
8
9 GEM
9 GEM
10 remote: https://rubygems.org/
10 remote: https://rubygems.org/
11 specs:
11 specs:
12 actionmailer (3.2.19)
12 actionmailer (3.2.19)
13 actionpack (= 3.2.19)
13 actionpack (= 3.2.19)
14 mail (~> 2.5.4)
14 mail (~> 2.5.4)
15 actionpack (3.2.19)
15 actionpack (3.2.19)
16 activemodel (= 3.2.19)
16 activemodel (= 3.2.19)
17 activesupport (= 3.2.19)
17 activesupport (= 3.2.19)
18 builder (~> 3.0.0)
18 builder (~> 3.0.0)
19 erubis (~> 2.7.0)
19 erubis (~> 2.7.0)
20 journey (~> 1.0.4)
20 journey (~> 1.0.4)
21 rack (~> 1.4.5)
21 rack (~> 1.4.5)
22 rack-cache (~> 1.2)
22 rack-cache (~> 1.2)
23 rack-test (~> 0.6.1)
23 rack-test (~> 0.6.1)
24 sprockets (~> 2.2.1)
24 sprockets (~> 2.2.1)
25 activemodel (3.2.19)
25 activemodel (3.2.19)
26 activesupport (= 3.2.19)
26 activesupport (= 3.2.19)
27 builder (~> 3.0.0)
27 builder (~> 3.0.0)
28 activerecord (3.2.19)
28 activerecord (3.2.19)
29 activemodel (= 3.2.19)
29 activemodel (= 3.2.19)
30 activesupport (= 3.2.19)
30 activesupport (= 3.2.19)
31 arel (~> 3.0.2)
31 arel (~> 3.0.2)
32 tzinfo (~> 0.3.29)
32 tzinfo (~> 0.3.29)
33 activeresource (3.2.19)
33 activeresource (3.2.19)
34 activemodel (= 3.2.19)
34 activemodel (= 3.2.19)
35 activesupport (= 3.2.19)
35 activesupport (= 3.2.19)
36 activesupport (3.2.19)
36 activesupport (3.2.19)
37 i18n (~> 0.6, >= 0.6.4)
37 i18n (~> 0.6, >= 0.6.4)
38 multi_json (~> 1.0)
38 multi_json (~> 1.0)
39 arel (3.0.3)
39 arel (3.0.3)
40 builder (3.0.4)
40 builder (3.0.4)
41 coffee-rails (3.2.2)
41 coffee-rails (3.2.2)
42 coffee-script (>= 2.2.0)
42 coffee-script (>= 2.2.0)
43 railties (~> 3.2.0)
43 railties (~> 3.2.0)
44 coffee-script (2.3.0)
44 coffee-script (2.3.0)
45 coffee-script-source
45 coffee-script-source
46 execjs
46 execjs
47 coffee-script-source (1.7.1)
47 coffee-script-source (1.7.1)
48 diff-lcs (1.2.5)
48 diff-lcs (1.2.5)
49 dynamic_form (1.1.4)
49 dynamic_form (1.1.4)
50 erubis (2.7.0)
50 erubis (2.7.0)
51 execjs (2.2.1)
51 execjs (2.2.1)
52 haml (4.0.5)
52 haml (4.0.5)
53 tilt
53 tilt
54 hike (1.2.3)
54 hike (1.2.3)
55 i18n (0.6.11)
55 i18n (0.6.11)
56 in_place_editing (1.2.0)
56 in_place_editing (1.2.0)
57 journey (1.0.4)
57 journey (1.0.4)
58 jquery-rails (3.1.1)
58 jquery-rails (3.1.1)
59 railties (>= 3.0, < 5.0)
59 railties (>= 3.0, < 5.0)
60 thor (>= 0.14, < 2.0)
60 thor (>= 0.14, < 2.0)
61 + jquery-tablesorter (1.12.7)
62 + railties (>= 3.1, < 5)
61 jquery-timepicker-addon-rails (1.4.1)
63 jquery-timepicker-addon-rails (1.4.1)
62 railties (>= 3.1)
64 railties (>= 3.1)
63 jquery-ui-rails (4.0.3)
65 jquery-ui-rails (4.0.3)
64 jquery-rails
66 jquery-rails
65 railties (>= 3.1.0)
67 railties (>= 3.1.0)
66 jquery-ui-sass-rails (4.0.3.0)
68 jquery-ui-sass-rails (4.0.3.0)
67 jquery-rails
69 jquery-rails
68 jquery-ui-rails (= 4.0.3)
70 jquery-ui-rails (= 4.0.3)
69 railties (>= 3.1.0)
71 railties (>= 3.1.0)
70 json (1.8.1)
72 json (1.8.1)
71 mail (2.5.4)
73 mail (2.5.4)
72 mime-types (~> 1.16)
74 mime-types (~> 1.16)
73 treetop (~> 1.4.8)
75 treetop (~> 1.4.8)
74 mime-types (1.25.1)
76 mime-types (1.25.1)
75 multi_json (1.10.1)
77 multi_json (1.10.1)
76 mysql2 (0.3.16)
78 mysql2 (0.3.16)
77 polyglot (0.3.5)
79 polyglot (0.3.5)
78 power_assert (0.1.3)
80 power_assert (0.1.3)
79 prototype-rails (3.2.1)
81 prototype-rails (3.2.1)
80 rails (~> 3.2)
82 rails (~> 3.2)
81 rack (1.4.5)
83 rack (1.4.5)
82 rack-cache (1.2)
84 rack-cache (1.2)
83 rack (>= 0.4)
85 rack (>= 0.4)
84 rack-ssl (1.3.4)
86 rack-ssl (1.3.4)
85 rack
87 rack
86 rack-test (0.6.2)
88 rack-test (0.6.2)
87 rack (>= 1.0)
89 rack (>= 1.0)
88 rails (3.2.19)
90 rails (3.2.19)
89 actionmailer (= 3.2.19)
91 actionmailer (= 3.2.19)
90 actionpack (= 3.2.19)
92 actionpack (= 3.2.19)
91 activerecord (= 3.2.19)
93 activerecord (= 3.2.19)
92 activeresource (= 3.2.19)
94 activeresource (= 3.2.19)
93 activesupport (= 3.2.19)
95 activesupport (= 3.2.19)
94 bundler (~> 1.0)
96 bundler (~> 1.0)
95 railties (= 3.2.19)
97 railties (= 3.2.19)
96 railties (3.2.19)
98 railties (3.2.19)
97 actionpack (= 3.2.19)
99 actionpack (= 3.2.19)
98 activesupport (= 3.2.19)
100 activesupport (= 3.2.19)
99 rack-ssl (~> 1.3.2)
101 rack-ssl (~> 1.3.2)
100 rake (>= 0.8.7)
102 rake (>= 0.8.7)
101 rdoc (~> 3.4)
103 rdoc (~> 3.4)
102 thor (>= 0.14.6, < 2.0)
104 thor (>= 0.14.6, < 2.0)
103 rake (10.3.2)
105 rake (10.3.2)
104 rdiscount (2.1.7.1)
106 rdiscount (2.1.7.1)
105 rdoc (3.12.2)
107 rdoc (3.12.2)
106 json (~> 1.4)
108 json (~> 1.4)
107 rouge (1.6.2)
109 rouge (1.6.2)
108 rspec-collection_matchers (1.0.0)
110 rspec-collection_matchers (1.0.0)
109 rspec-expectations (>= 2.99.0.beta1)
111 rspec-expectations (>= 2.99.0.beta1)
110 rspec-core (2.99.2)
112 rspec-core (2.99.2)
111 rspec-expectations (2.99.2)
113 rspec-expectations (2.99.2)
112 diff-lcs (>= 1.1.3, < 2.0)
114 diff-lcs (>= 1.1.3, < 2.0)
113 rspec-mocks (2.99.2)
115 rspec-mocks (2.99.2)
114 rspec-rails (2.99.0)
116 rspec-rails (2.99.0)
115 actionpack (>= 3.0)
117 actionpack (>= 3.0)
116 activemodel (>= 3.0)
118 activemodel (>= 3.0)
117 activesupport (>= 3.0)
119 activesupport (>= 3.0)
118 railties (>= 3.0)
120 railties (>= 3.0)
119 rspec-collection_matchers
121 rspec-collection_matchers
120 rspec-core (~> 2.99.0)
122 rspec-core (~> 2.99.0)
121 rspec-expectations (~> 2.99.0)
123 rspec-expectations (~> 2.99.0)
122 rspec-mocks (~> 2.99.0)
124 rspec-mocks (~> 2.99.0)
123 sass (3.4.1)
125 sass (3.4.1)
124 sass-rails (3.2.6)
126 sass-rails (3.2.6)
125 railties (~> 3.2.0)
127 railties (~> 3.2.0)
126 sass (>= 3.1.10)
128 sass (>= 3.1.10)
127 tilt (~> 1.3)
129 tilt (~> 1.3)
128 sprockets (2.2.2)
130 sprockets (2.2.2)
129 hike (~> 1.2)
131 hike (~> 1.2)
130 multi_json (~> 1.0)
132 multi_json (~> 1.0)
131 rack (~> 1.0)
133 rack (~> 1.0)
132 tilt (~> 1.1, != 1.3.0)
134 tilt (~> 1.1, != 1.3.0)
133 test-unit (3.0.1)
135 test-unit (3.0.1)
134 power_assert
136 power_assert
135 thor (0.19.1)
137 thor (0.19.1)
136 tilt (1.4.1)
138 tilt (1.4.1)
137 treetop (1.4.15)
139 treetop (1.4.15)
138 polyglot
140 polyglot
139 polyglot (>= 0.3.1)
141 polyglot (>= 0.3.1)
140 tzinfo (0.3.41)
142 tzinfo (0.3.41)
141 uglifier (2.5.3)
143 uglifier (2.5.3)
142 execjs (>= 0.3.0)
144 execjs (>= 0.3.0)
143 json (>= 1.8.0)
145 json (>= 1.8.0)
144 will_paginate (3.0.7)
146 will_paginate (3.0.7)
145
147
146 PLATFORMS
148 PLATFORMS
147 ruby
149 ruby
148
150
149 DEPENDENCIES
151 DEPENDENCIES
150 coffee-rails (~> 3.2.1)
152 coffee-rails (~> 3.2.1)
151 dynamic_form
153 dynamic_form
152 haml
154 haml
153 in_place_editing
155 in_place_editing
154 jquery-rails
156 jquery-rails
157 + jquery-tablesorter
155 jquery-timepicker-addon-rails
158 jquery-timepicker-addon-rails
156 jquery-ui-sass-rails
159 jquery-ui-sass-rails
157 mail
160 mail
158 mysql2
161 mysql2
159 prototype-rails
162 prototype-rails
160 rails (= 3.2.19)
163 rails (= 3.2.19)
161 rdiscount
164 rdiscount
162 rouge
165 rouge
163 rspec-rails (~> 2.0)
166 rspec-rails (~> 2.0)
164 sass-rails (~> 3.2.3)
167 sass-rails (~> 3.2.3)
165 test-unit
168 test-unit
166 uglifier (>= 1.0.3)
169 uglifier (>= 1.0.3)
167 verification!
170 verification!
168 will_paginate (~> 3.0.0)
171 will_paginate (~> 3.0.0)
@@ -1,6 +1,7
1 //= require jquery
1 //= require jquery
2 //= require jquery_ujs
2 //= require jquery_ujs
3 //= require jquery.ui.all
3 //= require jquery.ui.all
4 //= require jquery.ui.datepicker
4 //= require jquery.ui.datepicker
5 //= require jquery.ui.slider
5 //= require jquery.ui.slider
6 //= require jquery-ui-timepicker-addon
6 //= require jquery-ui-timepicker-addon
7 + //= require jquery-tablesorter
@@ -1,103 +1,104
1
1
2 @import jquery.ui.core
2 @import jquery.ui.core
3 @import jquery.ui.theme
3 @import jquery.ui.theme
4 @import jquery.ui.datepicker
4 @import jquery.ui.datepicker
5 @import jquery.ui.slider
5 @import jquery.ui.slider
6 @import jquery-ui-timepicker-addon
6 @import jquery-ui-timepicker-addon
7 -
7 + @import jquery-tablesorter/theme.metro-dark
8 + @import tablesorter-theme.cafe
8
9
9 body
10 body
10 background: white image-url("topbg.jpg") repeat-x top center
11 background: white image-url("topbg.jpg") repeat-x top center
11 font-size: 13px
12 font-size: 13px
12 font-family: Tahoma, "sans-serif"
13 font-family: Tahoma, "sans-serif"
13 margin: 10px
14 margin: 10px
14 padding: 10px
15 padding: 10px
15
16
16
17
17 input
18 input
18 font-family: Tahoma, "sans-serif"
19 font-family: Tahoma, "sans-serif"
19
20
20
21
21 h1
22 h1
22 font-size: 24px
23 font-size: 24px
23 color: #334488
24 color: #334488
24 line-height: 2em
25 line-height: 2em
25
26
26
27
27 h2
28 h2
28 font-size: 18px
29 font-size: 18px
29 color: #5566bb
30 color: #5566bb
30 line-height: 1.5em
31 line-height: 1.5em
31
32
32
33
33 hr
34 hr
34 border-top: 1px solid #dddddd
35 border-top: 1px solid #dddddd
35 border-bottom: 1px solid #eeeeee
36 border-bottom: 1px solid #eeeeee
36
37
37
38
38 a
39 a
39 color: #6666cc
40 color: #6666cc
40 text-decoration: none
41 text-decoration: none
41
42
42 &:link, &:visited
43 &:link, &:visited
43 color: #6666cc
44 color: #6666cc
44 text-decoration: none
45 text-decoration: none
45
46
46 &:hover, &:focus
47 &:hover, &:focus
47 color: #111166
48 color: #111166
48 text-decoration: none
49 text-decoration: none
49
50
50
51
51 div
52 div
52 &.userbar
53 &.userbar
53 line-height: 1.5em
54 line-height: 1.5em
54 text-align: right
55 text-align: right
55 font-size: 12px
56 font-size: 12px
56
57
57 &.title
58 &.title
58 padding: 10px 0px
59 padding: 10px 0px
59 line-height: 1.5em
60 line-height: 1.5em
60 font-size: 13px
61 font-size: 13px
61
62
62 span.contest-over-msg
63 span.contest-over-msg
63 font-size: 15px
64 font-size: 15px
64 color: red
65 color: red
65
66
66 table
67 table
67 width: 100%
68 width: 100%
68 font-weight: bold
69 font-weight: bold
69
70
70 td
71 td
71 &.left-col
72 &.left-col
72 text-align: left
73 text-align: left
73 vertical-align: top
74 vertical-align: top
74 color: #444444
75 color: #444444
75
76
76 &.right-col
77 &.right-col
77 text-align: right
78 text-align: right
78 vertical-align: top
79 vertical-align: top
79 font-size: 18px
80 font-size: 18px
80 color: #116699
81 color: #116699
81
82
82
83
83 table.info
84 table.info
84 margin: 10px 0
85 margin: 10px 0
85 border: 1px solid #666666
86 border: 1px solid #666666
86 border-collapse: collapse
87 border-collapse: collapse
87 font-size: 12px
88 font-size: 12px
88
89
89 th
90 th
90 border: 1px solid #666666
91 border: 1px solid #666666
91 line-height: 1.5em
92 line-height: 1.5em
92 padding: 0 0.5em
93 padding: 0 0.5em
93
94
94 td
95 td
95 border-left: 1px solid #666666
96 border-left: 1px solid #666666
96 border-right: 1px solid #666666
97 border-right: 1px solid #666666
97 line-height: 1.5em
98 line-height: 1.5em
98 padding: 0 0.5em
99 padding: 0 0.5em
99
100
100
101
101 tr
102 tr
102 &.info-head
103 &.info-head
103 background: #777777
104 background: #777777
@@ -66,192 +66,194
66 note = []
66 note = []
67
67
68 lines.split("\n").each do |line|
68 lines.split("\n").each do |line|
69 items = line.chomp.split(',')
69 items = line.chomp.split(',')
70 if items.length>=2
70 if items.length>=2
71 login = items[0]
71 login = items[0]
72 full_name = items[1]
72 full_name = items[1]
73
73
74 added_random_password = false
74 added_random_password = false
75 if items.length>=3
75 if items.length>=3
76 password = items[2].chomp(" ")
76 password = items[2].chomp(" ")
77 user_alias = (items.length>=4) ? items[3] : login
77 user_alias = (items.length>=4) ? items[3] : login
78 else
78 else
79 password = random_password
79 password = random_password
80 user_alias = (items.length>=4) ? items[3] : login
80 user_alias = (items.length>=4) ? items[3] : login
81 added_random_password = true
81 added_random_password = true
82 end
82 end
83
83
84 user = User.new({:login => login,
84 user = User.new({:login => login,
85 :full_name => full_name,
85 :full_name => full_name,
86 :password => password,
86 :password => password,
87 :password_confirmation => password,
87 :password_confirmation => password,
88 :alias => user_alias})
88 :alias => user_alias})
89 user.activated = true
89 user.activated = true
90 user.save
90 user.save
91
91
92 if added_random_password
92 if added_random_password
93 note << "'#{login}' (+)"
93 note << "'#{login}' (+)"
94 else
94 else
95 note << login
95 note << login
96 end
96 end
97 end
97 end
98 end
98 end
99 flash[:notice] = 'User(s) ' + note.join(', ') +
99 flash[:notice] = 'User(s) ' + note.join(', ') +
100 ' were successfully created. ' +
100 ' were successfully created. ' +
101 '( (+) - created with random passwords.)'
101 '( (+) - created with random passwords.)'
102 redirect_to :action => 'list'
102 redirect_to :action => 'list'
103 end
103 end
104
104
105 def edit
105 def edit
106 @user = User.find(params[:id])
106 @user = User.find(params[:id])
107 end
107 end
108
108
109 def update
109 def update
110 @user = User.find(params[:id])
110 @user = User.find(params[:id])
111 if @user.update_attributes(params[:user])
111 if @user.update_attributes(params[:user])
112 flash[:notice] = 'User was successfully updated.'
112 flash[:notice] = 'User was successfully updated.'
113 redirect_to :action => 'show', :id => @user
113 redirect_to :action => 'show', :id => @user
114 else
114 else
115 render :action => 'edit'
115 render :action => 'edit'
116 end
116 end
117 end
117 end
118
118
119 def destroy
119 def destroy
120 User.find(params[:id]).destroy
120 User.find(params[:id]).destroy
121 redirect_to :action => 'list'
121 redirect_to :action => 'list'
122 end
122 end
123
123
124 def user_stat
124 def user_stat
125 @problems = Problem.find_available_problems
125 @problems = Problem.find_available_problems
126 @users = User.find(:all, :include => [:contests, :contest_stat])
126 @users = User.find(:all, :include => [:contests, :contest_stat])
127 @scorearray = Array.new
127 @scorearray = Array.new
128 @users.each do |u|
128 @users.each do |u|
129 ustat = Array.new
129 ustat = Array.new
130 ustat[0] = u
130 ustat[0] = u
131 @problems.each do |p|
131 @problems.each do |p|
132 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
132 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
133 if (sub!=nil) and (sub.points!=nil)
133 if (sub!=nil) and (sub.points!=nil)
134 ustat << [(sub.points.to_f*100/p.full_score).round, (sub.points>=p.full_score)]
134 ustat << [(sub.points.to_f*100/p.full_score).round, (sub.points>=p.full_score)]
135 else
135 else
136 ustat << [0,false]
136 ustat << [0,false]
137 end
137 end
138 end
138 end
139 @scorearray << ustat
139 @scorearray << ustat
140 end
140 end
141 end
141 end
142
142
143 def user_stat_max
143 def user_stat_max
144 @problems = Problem.find_available_problems
144 @problems = Problem.find_available_problems
145 @users = User.find(:all, :include => [:contests, :contest_stat])
145 @users = User.find(:all, :include => [:contests, :contest_stat])
146 @scorearray = Array.new
146 @scorearray = Array.new
147 #set up range from param
147 #set up range from param
148 since_id = params.fetch(:since_id, 0).to_i
148 since_id = params.fetch(:since_id, 0).to_i
149 until_id = params.fetch(:until_id, 0).to_i
149 until_id = params.fetch(:until_id, 0).to_i
150 @users.each do |u|
150 @users.each do |u|
151 ustat = Array.new
151 ustat = Array.new
152 ustat[0] = u
152 ustat[0] = u
153 @problems.each do |p|
153 @problems.each do |p|
154 max_points = 0
154 max_points = 0
155 Submission.find_in_range_by_user_and_problem(u.id,p.id,since_id,until_id).each do |sub|
155 Submission.find_in_range_by_user_and_problem(u.id,p.id,since_id,until_id).each do |sub|
156 max_points = sub.points if sub and sub.points and (sub.points > max_points)
156 max_points = sub.points if sub and sub.points and (sub.points > max_points)
157 end
157 end
158 ustat << [(max_points.to_f*100/p.full_score).round, (max_points>=p.full_score)]
158 ustat << [(max_points.to_f*100/p.full_score).round, (max_points>=p.full_score)]
159 end
159 end
160 @scorearray << ustat
160 @scorearray << ustat
161 end
161 end
162 +
163 + render template: 'user_admin/user_stat'
162 end
164 end
163
165
164 def import
166 def import
165 if params[:file]==''
167 if params[:file]==''
166 flash[:notice] = 'Error importing no file'
168 flash[:notice] = 'Error importing no file'
167 redirect_to :action => 'list' and return
169 redirect_to :action => 'list' and return
168 end
170 end
169 import_from_file(params[:file])
171 import_from_file(params[:file])
170 end
172 end
171
173
172 def random_all_passwords
174 def random_all_passwords
173 users = User.find(:all)
175 users = User.find(:all)
174 @prefix = params[:prefix] || ''
176 @prefix = params[:prefix] || ''
175 @non_admin_users = User.find_non_admin_with_prefix(@prefix)
177 @non_admin_users = User.find_non_admin_with_prefix(@prefix)
176 @changed = false
178 @changed = false
177 if request.request_method == 'POST'
179 if request.request_method == 'POST'
178 @non_admin_users.each do |user|
180 @non_admin_users.each do |user|
179 password = random_password
181 password = random_password
180 user.password = password
182 user.password = password
181 user.password_confirmation = password
183 user.password_confirmation = password
182 user.save
184 user.save
183 end
185 end
184 @changed = true
186 @changed = true
185 end
187 end
186 end
188 end
187
189
188 # contest management
190 # contest management
189
191
190 def contests
192 def contests
191 @contest, @users = find_contest_and_user_from_contest_id(params[:id])
193 @contest, @users = find_contest_and_user_from_contest_id(params[:id])
192 @contests = Contest.enabled
194 @contests = Contest.enabled
193 end
195 end
194
196
195 def assign_from_list
197 def assign_from_list
196 contest_id = params[:users_contest_id]
198 contest_id = params[:users_contest_id]
197 org_contest, users = find_contest_and_user_from_contest_id(contest_id)
199 org_contest, users = find_contest_and_user_from_contest_id(contest_id)
198 contest = Contest.find(params[:new_contest][:id])
200 contest = Contest.find(params[:new_contest][:id])
199 if !contest
201 if !contest
200 flash[:notice] = 'Error: no contest'
202 flash[:notice] = 'Error: no contest'
201 redirect_to :action => 'contests', :id =>contest_id
203 redirect_to :action => 'contests', :id =>contest_id
202 end
204 end
203
205
204 note = []
206 note = []
205 users.each do |u|
207 users.each do |u|
206 u.contests = [contest]
208 u.contests = [contest]
207 note << u.login
209 note << u.login
208 end
210 end
209 flash[:notice] = 'User(s) ' + note.join(', ') +
211 flash[:notice] = 'User(s) ' + note.join(', ') +
210 " were successfully reassigned to #{contest.title}."
212 " were successfully reassigned to #{contest.title}."
211 redirect_to :action => 'contests', :id =>contest.id
213 redirect_to :action => 'contests', :id =>contest.id
212 end
214 end
213
215
214 def add_to_contest
216 def add_to_contest
215 user = User.find(params[:id])
217 user = User.find(params[:id])
216 contest = Contest.find(params[:contest_id])
218 contest = Contest.find(params[:contest_id])
217 if user and contest
219 if user and contest
218 user.contests << contest
220 user.contests << contest
219 end
221 end
220 redirect_to :action => 'list'
222 redirect_to :action => 'list'
221 end
223 end
222
224
223 def remove_from_contest
225 def remove_from_contest
224 user = User.find(params[:id])
226 user = User.find(params[:id])
225 contest = Contest.find(params[:contest_id])
227 contest = Contest.find(params[:contest_id])
226 if user and contest
228 if user and contest
227 user.contests.delete(contest)
229 user.contests.delete(contest)
228 end
230 end
229 redirect_to :action => 'list'
231 redirect_to :action => 'list'
230 end
232 end
231
233
232 def contest_management
234 def contest_management
233 end
235 end
234
236
235 def manage_contest
237 def manage_contest
236 contest = Contest.find(params[:contest][:id])
238 contest = Contest.find(params[:contest][:id])
237 if !contest
239 if !contest
238 flash[:notice] = 'You did not choose the contest.'
240 flash[:notice] = 'You did not choose the contest.'
239 redirect_to :action => 'contest_management' and return
241 redirect_to :action => 'contest_management' and return
240 end
242 end
241
243
242 operation = params[:operation]
244 operation = params[:operation]
243
245
244 if not ['add','remove','assign'].include? operation
246 if not ['add','remove','assign'].include? operation
245 flash[:notice] = 'You did not choose the operation to perform.'
247 flash[:notice] = 'You did not choose the operation to perform.'
246 redirect_to :action => 'contest_management' and return
248 redirect_to :action => 'contest_management' and return
247 end
249 end
248
250
249 lines = params[:login_list]
251 lines = params[:login_list]
250 if !lines or lines.blank?
252 if !lines or lines.blank?
251 flash[:notice] = 'You entered an empty list.'
253 flash[:notice] = 'You entered an empty list.'
252 redirect_to :action => 'contest_management' and return
254 redirect_to :action => 'contest_management' and return
253 end
255 end
254
256
255 note = []
257 note = []
256 users = []
258 users = []
257 lines.split("\n").each do |line|
259 lines.split("\n").each do |line|
@@ -1,31 +1,32
1 - content_for :header do
1 - content_for :header do
2 + = stylesheet_link_tag 'tablesorter-theme.cafe'
2 = javascript_include_tag 'new'
3 = javascript_include_tag 'new'
3
4
4 %script{:type=>"text/javascript"}
5 %script{:type=>"text/javascript"}
5 $(function () {
6 $(function () {
6 $('#since_datetime').datetimepicker({ showButtonPanel: true, dateFormat: "yy-mm-dd", controlType: "slider"} );
7 $('#since_datetime').datetimepicker({ showButtonPanel: true, dateFormat: "yy-mm-dd", controlType: "slider"} );
7 $('#until_datetime').datetimepicker({ showButtonPanel: true, dateFormat: "yy-mm-dd", controlType: "slider"} );
8 $('#until_datetime').datetimepicker({ showButtonPanel: true, dateFormat: "yy-mm-dd", controlType: "slider"} );
9 + $('#my_table').tablesorter({widthFixed: true, widgets: ['zebra']});
8 });
10 });
9
11
10 %h1 Login status
12 %h1 Login status
11
13
12 =render partial: 'report_menu'
14 =render partial: 'report_menu'
13 =render partial: 'date_range', locals: {param_text: 'Login date range:', title: 'Query login stat in the range' }
15 =render partial: 'date_range', locals: {param_text: 'Login date range:', title: 'Query login stat in the range' }
14
16
15 - %table.info
17 + %table.tablesorter-cafe#my_table
16 %thead
18 %thead
17 - %tr.info-head
19 + %tr
18 %th login
20 %th login
19 %th full name
21 %th full name
20 %th login count
22 %th login count
21 %th earliest
23 %th earliest
22 %th latest
24 %th latest
23 %tbody
25 %tbody
24 - @logins.each do |l|
26 - @logins.each do |l|
25 %tr{class: cycle('info-even','info-odd')}
27 %tr{class: cycle('info-even','info-odd')}
26 %td= l[:login]
28 %td= l[:login]
27 %td= l[:full_name]
29 %td= l[:full_name]
28 %td= l[:count]
30 %td= l[:count]
29 %td= l[:min] ? l[:min].in_time_zone.strftime('%Y-%m-%d %H:%M') : ''
31 %td= l[:min] ? l[:min].in_time_zone.strftime('%Y-%m-%d %H:%M') : ''
30 - %td= l[:max] ? l[:max].in_time_zone.strftime('%Y-%m-%d %H:%M') : ''
32 + %td= l[:max] ? time_ago_in_words(l[:max].in_time_zone) + ' ago' : ''
31 -
@@ -1,44 +1,50
1 + - content_for :header do
2 + = javascript_include_tag 'new'
3 + = stylesheet_link_tag 'tablesorter-theme.cafe'
4 +
5 + %script{:type=>"text/javascript"}
6 + $(function () {
7 + $('#since_datetime').datetimepicker({ showButtonPanel: true, dateFormat: "yy-mm-dd", controlType: "slider"} );
8 + $('#until_datetime').datetimepicker({ showButtonPanel: true, dateFormat: "yy-mm-dd", controlType: "slider"} );
9 + $('#my_table').tablesorter({widgets: ['zebra']});
10 + });
11 +
1 %h1 User grading results
12 %h1 User grading results
2 %h2 Show max scores in submission range
13 %h2 Show max scores in submission range
3
14
4 - if @problem and @problem.errors
15 - if @problem and @problem.errors
5 =error_messages_for 'problem'
16 =error_messages_for 'problem'
6
17
7 = render partial: 'submission_range'
18 = render partial: 'submission_range'
8
19
9 - - if @log
10 - %h3 Import log
11 - %pre.import-log
12 - = @log
13 -
14 %p= link_to '[Show only latest submissions]', controller: :user_admin, action: :user_stat
20 %p= link_to '[Show only latest submissions]', controller: :user_admin, action: :user_stat
15
21
16 - %table.info
22 + %table.tablesorter-cafe#my_table{style: 'width:auto;'}
17 %thead
23 %thead
18 - %tr.info-head
24 + %tr
19 %th User
25 %th User
20 %th Name
26 %th Name
21 %th Activated?
27 %th Activated?
22 %th Logged in
28 %th Logged in
23 %th Contest(s)
29 %th Contest(s)
24 - @problems.each do |p|
30 - @problems.each do |p|
25 %th= p.name
31 %th= p.name
26 %th Total
32 %th Total
27 %th Passed
33 %th Passed
28 %tbody
34 %tbody
29 - @scorearray.each do |sc|
35 - @scorearray.each do |sc|
30 %tr{class: cycle('info-even','info-odd')}
36 %tr{class: cycle('info-even','info-odd')}
31 - total,num_passed = 0,0
37 - total,num_passed = 0,0
32 - sc.each_index do |i|
38 - sc.each_index do |i|
33 - if i == 0
39 - if i == 0
34 %td= sc[i].login
40 %td= sc[i].login
35 %td= sc[i].full_name
41 %td= sc[i].full_name
36 %td= sc[i].activated
42 %td= sc[i].activated
37 %td= sc[i].try(:contest_stat).try(:started_at)!=nil ? 'yes' : 'no'
43 %td= sc[i].try(:contest_stat).try(:started_at)!=nil ? 'yes' : 'no'
38 %td= sc[i].contests.collect {|c| c.name}.join(', ')
44 %td= sc[i].contests.collect {|c| c.name}.join(', ')
39 - else
45 - else
40 %td= sc[i][0]
46 %td= sc[i][0]
41 - total += sc[i][0]
47 - total += sc[i][0]
42 - num_passed += 1 if sc[i][1]
48 - num_passed += 1 if sc[i][1]
43 %td= total
49 %td= total
44 %td= num_passed
50 %td= num_passed
deleted file
You need to be logged in to leave comments. Login now