Description:
- bootstrapize problem/edit - bootstrapize announcement/edit
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r650:72b80e42fb9b - - 5 files changed: 5 inserted, 116 deleted

@@ -1,376 +1,376
1 class MainController < ApplicationController
1 class MainController < ApplicationController
2
2
3 before_filter :authenticate, :except => [:index, :login]
3 before_filter :authenticate, :except => [:index, :login]
4 before_filter :check_viewability, :except => [:index, :login]
4 before_filter :check_viewability, :except => [:index, :login]
5
5
6 append_before_filter :confirm_and_update_start_time,
6 append_before_filter :confirm_and_update_start_time,
7 :except => [:index,
7 :except => [:index,
8 :login,
8 :login,
9 :confirm_contest_start]
9 :confirm_contest_start]
10
10
11 # to prevent log in box to be shown when user logged out of the
11 # to prevent log in box to be shown when user logged out of the
12 # system only in some tab
12 # system only in some tab
13 prepend_before_filter :reject_announcement_refresh_when_logged_out,
13 prepend_before_filter :reject_announcement_refresh_when_logged_out,
14 :only => [:announcements]
14 :only => [:announcements]
15
15
16 before_filter :authenticate_by_ip_address, :only => [:list]
16 before_filter :authenticate_by_ip_address, :only => [:list]
17
17
18 # COMMENTED OUT: filter in each action instead
18 # COMMENTED OUT: filter in each action instead
19 # before_filter :verify_time_limit, :only => [:submit]
19 # before_filter :verify_time_limit, :only => [:submit]
20
20
21 verify :method => :post, :only => [:submit],
21 verify :method => :post, :only => [:submit],
22 :redirect_to => { :action => :index }
22 :redirect_to => { :action => :index }
23
23
24 # COMMENT OUT: only need when having high load
24 # COMMENT OUT: only need when having high load
25 # caches_action :index, :login
25 # caches_action :index, :login
26
26
27 # NOTE: This method is not actually needed, 'config/routes.rb' has
27 # NOTE: This method is not actually needed, 'config/routes.rb' has
28 # assigned action login as a default action.
28 # assigned action login as a default action.
29 def index
29 def index
30 redirect_to :action => 'login'
30 redirect_to :action => 'login'
31 end
31 end
32
32
33 def login
33 def login
34 saved_notice = flash[:notice]
34 saved_notice = flash[:notice]
35 reset_session
35 reset_session
36 flash.now[:notice] = saved_notice
36 flash.now[:notice] = saved_notice
37
37
38 # EXPERIMENT:
38 # EXPERIMENT:
39 # Hide login if in single user mode and the url does not
39 # Hide login if in single user mode and the url does not
40 # explicitly specify /login
40 # explicitly specify /login
41 #
41 #
42 # logger.info "PATH: #{request.path}"
42 # logger.info "PATH: #{request.path}"
43 # if GraderConfiguration['system.single_user_mode'] and
43 # if GraderConfiguration['system.single_user_mode'] and
44 # request.path!='/main/login'
44 # request.path!='/main/login'
45 # @hidelogin = true
45 # @hidelogin = true
46 # end
46 # end
47
47
48 @announcements = Announcement.frontpage
48 @announcements = Announcement.frontpage
49 render :action => 'login', :layout => 'empty'
49 render :action => 'login', :layout => 'empty'
50 end
50 end
51
51
52 def list
52 def list
53 prepare_list_information
53 prepare_list_information
54 end
54 end
55
55
56 def help
56 def help
57 @user = User.find(session[:user_id])
57 @user = User.find(session[:user_id])
58 end
58 end
59
59
60 def submit
60 def submit
61 user = User.find(session[:user_id])
61 user = User.find(session[:user_id])
62
62
63 @submission = Submission.new
63 @submission = Submission.new
64 @submission.problem_id = params[:submission][:problem_id]
64 @submission.problem_id = params[:submission][:problem_id]
65 @submission.user = user
65 @submission.user = user
66 @submission.language_id = 0
66 @submission.language_id = 0
67 if (params['file']) and (params['file']!='')
67 if (params['file']) and (params['file']!='')
68 @submission.source = File.open(params['file'].path,'r:UTF-8',&:read)
68 @submission.source = File.open(params['file'].path,'r:UTF-8',&:read)
69 @submission.source.encode!('UTF-8','UTF-8',invalid: :replace, replace: '')
69 @submission.source.encode!('UTF-8','UTF-8',invalid: :replace, replace: '')
70 @submission.source_filename = params['file'].original_filename
70 @submission.source_filename = params['file'].original_filename
71 end
71 end
72
72
73 if (params[:editor_text])
73 if (params[:editor_text])
74 language = Language.find_by_id(params[:language_id])
74 language = Language.find_by_id(params[:language_id])
75 @submission.source = params[:editor_text]
75 @submission.source = params[:editor_text]
76 @submission.source_filename = "live_edit.#{language.ext}"
76 @submission.source_filename = "live_edit.#{language.ext}"
77 @submission.language = language
77 @submission.language = language
78 end
78 end
79
79
80 @submission.submitted_at = Time.new.gmtime
80 @submission.submitted_at = Time.new.gmtime
81 @submission.ip_address = request.remote_ip
81 @submission.ip_address = request.remote_ip
82
82
83 if GraderConfiguration.time_limit_mode? and user.contest_finished?
83 if GraderConfiguration.time_limit_mode? and user.contest_finished?
84 @submission.errors.add(:base,"The contest is over.")
84 @submission.errors.add(:base,"The contest is over.")
85 prepare_list_information
85 prepare_list_information
86 render :action => 'list' and return
86 render :action => 'list' and return
87 end
87 end
88
88
89 if @submission.valid?
89 if @submission.valid?
90 if @submission.save == false
90 if @submission.save == false
91 - flash[:notice] = 'Error saving your submission'
91 + flash[:notice] = 'Error saving your submission'
92 elsif Task.create(:submission_id => @submission.id,
92 elsif Task.create(:submission_id => @submission.id,
93 :status => Task::STATUS_INQUEUE) == false
93 :status => Task::STATUS_INQUEUE) == false
94 - flash[:notice] = 'Error adding your submission to task queue'
94 + flash[:notice] = 'Error adding your submission to task queue'
95 end
95 end
96 else
96 else
97 prepare_list_information
97 prepare_list_information
98 render :action => 'list' and return
98 render :action => 'list' and return
99 end
99 end
100 redirect_to :action => 'list'
100 redirect_to :action => 'list'
101 end
101 end
102
102
103 def source
103 def source
104 submission = Submission.find(params[:id])
104 submission = Submission.find(params[:id])
105 if ((submission.user_id == session[:user_id]) and
105 if ((submission.user_id == session[:user_id]) and
106 (submission.problem != nil) and
106 (submission.problem != nil) and
107 (submission.problem.available))
107 (submission.problem.available))
108 send_data(submission.source,
108 send_data(submission.source,
109 - {:filename => submission.download_filename,
109 + {:filename => submission.download_filename,
110 :type => 'text/plain'})
110 :type => 'text/plain'})
111 else
111 else
112 flash[:notice] = 'Error viewing source'
112 flash[:notice] = 'Error viewing source'
113 redirect_to :action => 'list'
113 redirect_to :action => 'list'
114 end
114 end
115 end
115 end
116
116
117 def compiler_msg
117 def compiler_msg
118 @submission = Submission.find(params[:id])
118 @submission = Submission.find(params[:id])
119 if @submission.user_id == session[:user_id]
119 if @submission.user_id == session[:user_id]
120 render :action => 'compiler_msg', :layout => 'empty'
120 render :action => 'compiler_msg', :layout => 'empty'
121 else
121 else
122 flash[:notice] = 'Error viewing source'
122 flash[:notice] = 'Error viewing source'
123 redirect_to :action => 'list'
123 redirect_to :action => 'list'
124 end
124 end
125 end
125 end
126
126
127 def result
127 def result
128 if !GraderConfiguration.show_grading_result
128 if !GraderConfiguration.show_grading_result
129 redirect_to :action => 'list' and return
129 redirect_to :action => 'list' and return
130 end
130 end
131 @user = User.find(session[:user_id])
131 @user = User.find(session[:user_id])
132 @submission = Submission.find(params[:id])
132 @submission = Submission.find(params[:id])
133 if @submission.user!=@user
133 if @submission.user!=@user
134 flash[:notice] = 'You are not allowed to view result of other users.'
134 flash[:notice] = 'You are not allowed to view result of other users.'
135 redirect_to :action => 'list' and return
135 redirect_to :action => 'list' and return
136 end
136 end
137 prepare_grading_result(@submission)
137 prepare_grading_result(@submission)
138 end
138 end
139
139
140 def load_output
140 def load_output
141 if !GraderConfiguration.show_grading_result or params[:num]==nil
141 if !GraderConfiguration.show_grading_result or params[:num]==nil
142 redirect_to :action => 'list' and return
142 redirect_to :action => 'list' and return
143 end
143 end
144 @user = User.find(session[:user_id])
144 @user = User.find(session[:user_id])
145 @submission = Submission.find(params[:id])
145 @submission = Submission.find(params[:id])
146 if @submission.user!=@user
146 if @submission.user!=@user
147 flash[:notice] = 'You are not allowed to view result of other users.'
147 flash[:notice] = 'You are not allowed to view result of other users.'
148 redirect_to :action => 'list' and return
148 redirect_to :action => 'list' and return
149 end
149 end
150 case_num = params[:num].to_i
150 case_num = params[:num].to_i
151 out_filename = output_filename(@user.login,
151 out_filename = output_filename(@user.login,
152 @submission.problem.name,
152 @submission.problem.name,
153 @submission.id,
153 @submission.id,
154 case_num)
154 case_num)
155 if !FileTest.exists?(out_filename)
155 if !FileTest.exists?(out_filename)
156 flash[:notice] = 'Output not found.'
156 flash[:notice] = 'Output not found.'
157 redirect_to :action => 'list' and return
157 redirect_to :action => 'list' and return
158 end
158 end
159
159
160 if defined?(USE_APACHE_XSENDFILE) and USE_APACHE_XSENDFILE
160 if defined?(USE_APACHE_XSENDFILE) and USE_APACHE_XSENDFILE
161 response.headers['Content-Type'] = "application/force-download"
161 response.headers['Content-Type'] = "application/force-download"
162 response.headers['Content-Disposition'] = "attachment; filename=\"output-#{case_num}.txt\""
162 response.headers['Content-Disposition'] = "attachment; filename=\"output-#{case_num}.txt\""
163 response.headers["X-Sendfile"] = out_filename
163 response.headers["X-Sendfile"] = out_filename
164 response.headers['Content-length'] = File.size(out_filename)
164 response.headers['Content-length'] = File.size(out_filename)
165 render :nothing => true
165 render :nothing => true
166 else
166 else
167 send_file out_filename, :stream => false, :filename => "output-#{case_num}.txt", :type => "text/plain"
167 send_file out_filename, :stream => false, :filename => "output-#{case_num}.txt", :type => "text/plain"
168 end
168 end
169 end
169 end
170
170
171 def error
171 def error
172 @user = User.find(session[:user_id])
172 @user = User.find(session[:user_id])
173 end
173 end
174
174
175 # announcement refreshing and hiding methods
175 # announcement refreshing and hiding methods
176
176
177 def announcements
177 def announcements
178 if params.has_key? 'recent'
178 if params.has_key? 'recent'
179 prepare_announcements(params[:recent])
179 prepare_announcements(params[:recent])
180 else
180 else
181 prepare_announcements
181 prepare_announcements
182 end
182 end
183 render(:partial => 'announcement',
183 render(:partial => 'announcement',
184 :collection => @announcements,
184 :collection => @announcements,
185 :locals => {:announcement_effect => true})
185 :locals => {:announcement_effect => true})
186 end
186 end
187
187
188 def confirm_contest_start
188 def confirm_contest_start
189 user = User.find(session[:user_id])
189 user = User.find(session[:user_id])
190 if request.method == 'POST'
190 if request.method == 'POST'
191 user.update_start_time
191 user.update_start_time
192 redirect_to :action => 'list'
192 redirect_to :action => 'list'
193 else
193 else
194 @contests = user.contests
194 @contests = user.contests
195 @user = user
195 @user = user
196 end
196 end
197 end
197 end
198
198
199 protected
199 protected
200
200
201 def prepare_announcements(recent=nil)
201 def prepare_announcements(recent=nil)
202 if GraderConfiguration.show_tasks_to?(@user)
202 if GraderConfiguration.show_tasks_to?(@user)
203 @announcements = Announcement.published(true)
203 @announcements = Announcement.published(true)
204 else
204 else
205 @announcements = Announcement.published
205 @announcements = Announcement.published
206 end
206 end
207 if recent!=nil
207 if recent!=nil
208 recent_id = recent.to_i
208 recent_id = recent.to_i
209 @announcements = @announcements.find_all { |a| a.id > recent_id }
209 @announcements = @announcements.find_all { |a| a.id > recent_id }
210 end
210 end
211 end
211 end
212
212
213 def prepare_list_information
213 def prepare_list_information
214 @user = User.find(session[:user_id])
214 @user = User.find(session[:user_id])
215 if not GraderConfiguration.multicontests?
215 if not GraderConfiguration.multicontests?
216 @problems = @user.available_problems
216 @problems = @user.available_problems
217 else
217 else
218 @contest_problems = @user.available_problems_group_by_contests
218 @contest_problems = @user.available_problems_group_by_contests
219 @problems = @user.available_problems
219 @problems = @user.available_problems
220 end
220 end
221 @prob_submissions = {}
221 @prob_submissions = {}
222 @problems.each do |p|
222 @problems.each do |p|
223 sub = Submission.find_last_by_user_and_problem(@user.id,p.id)
223 sub = Submission.find_last_by_user_and_problem(@user.id,p.id)
224 if sub!=nil
224 if sub!=nil
225 @prob_submissions[p.id] = { :count => sub.number, :submission => sub }
225 @prob_submissions[p.id] = { :count => sub.number, :submission => sub }
226 else
226 else
227 @prob_submissions[p.id] = { :count => 0, :submission => nil }
227 @prob_submissions[p.id] = { :count => 0, :submission => nil }
228 end
228 end
229 end
229 end
230 prepare_announcements
230 prepare_announcements
231 end
231 end
232
232
233 def check_viewability
233 def check_viewability
234 @user = User.find(session[:user_id])
234 @user = User.find(session[:user_id])
235 if (!GraderConfiguration.show_tasks_to?(@user)) and
235 if (!GraderConfiguration.show_tasks_to?(@user)) and
236 ((action_name=='submission') or (action_name=='submit'))
236 ((action_name=='submission') or (action_name=='submit'))
237 redirect_to :action => 'list' and return
237 redirect_to :action => 'list' and return
238 end
238 end
239 end
239 end
240
240
241 def prepare_grading_result(submission)
241 def prepare_grading_result(submission)
242 if GraderConfiguration.task_grading_info.has_key? submission.problem.name
242 if GraderConfiguration.task_grading_info.has_key? submission.problem.name
243 grading_info = GraderConfiguration.task_grading_info[submission.problem.name]
243 grading_info = GraderConfiguration.task_grading_info[submission.problem.name]
244 else
244 else
245 # guess task info from problem.full_score
245 # guess task info from problem.full_score
246 cases = submission.problem.full_score / 10
246 cases = submission.problem.full_score / 10
247 grading_info = {
247 grading_info = {
248 'testruns' => cases,
248 'testruns' => cases,
249 'testcases' => cases
249 'testcases' => cases
250 }
250 }
251 end
251 end
252 @test_runs = []
252 @test_runs = []
253 if grading_info['testruns'].is_a? Integer
253 if grading_info['testruns'].is_a? Integer
254 trun_count = grading_info['testruns']
254 trun_count = grading_info['testruns']
255 trun_count.times do |i|
255 trun_count.times do |i|
256 @test_runs << [ read_grading_result(@user.login,
256 @test_runs << [ read_grading_result(@user.login,
257 submission.problem.name,
257 submission.problem.name,
258 submission.id,
258 submission.id,
259 i+1) ]
259 i+1) ]
260 end
260 end
261 else
261 else
262 grading_info['testruns'].keys.sort.each do |num|
262 grading_info['testruns'].keys.sort.each do |num|
263 run = []
263 run = []
264 testrun = grading_info['testruns'][num]
264 testrun = grading_info['testruns'][num]
265 testrun.each do |c|
265 testrun.each do |c|
266 run << read_grading_result(@user.login,
266 run << read_grading_result(@user.login,
267 submission.problem.name,
267 submission.problem.name,
268 submission.id,
268 submission.id,
269 c)
269 c)
270 end
270 end
271 @test_runs << run
271 @test_runs << run
272 end
272 end
273 end
273 end
274 end
274 end
275
275
276 def grading_result_dir(user_name, problem_name, submission_id, case_num)
276 def grading_result_dir(user_name, problem_name, submission_id, case_num)
277 return "#{GRADING_RESULT_DIR}/#{user_name}/#{problem_name}/#{submission_id}/test-result/#{case_num}"
277 return "#{GRADING_RESULT_DIR}/#{user_name}/#{problem_name}/#{submission_id}/test-result/#{case_num}"
278 end
278 end
279
279
280 def output_filename(user_name, problem_name, submission_id, case_num)
280 def output_filename(user_name, problem_name, submission_id, case_num)
281 dir = grading_result_dir(user_name,problem_name, submission_id, case_num)
281 dir = grading_result_dir(user_name,problem_name, submission_id, case_num)
282 return "#{dir}/output.txt"
282 return "#{dir}/output.txt"
283 end
283 end
284
284
285 def read_grading_result(user_name, problem_name, submission_id, case_num)
285 def read_grading_result(user_name, problem_name, submission_id, case_num)
286 dir = grading_result_dir(user_name,problem_name, submission_id, case_num)
286 dir = grading_result_dir(user_name,problem_name, submission_id, case_num)
287 result_file_name = "#{dir}/result"
287 result_file_name = "#{dir}/result"
288 if !FileTest.exists?(result_file_name)
288 if !FileTest.exists?(result_file_name)
289 return {:num => case_num, :msg => 'program did not run'}
289 return {:num => case_num, :msg => 'program did not run'}
290 else
290 else
291 results = File.open(result_file_name).readlines
291 results = File.open(result_file_name).readlines
292 run_stat = extract_running_stat(results)
292 run_stat = extract_running_stat(results)
293 output_filename = "#{dir}/output.txt"
293 output_filename = "#{dir}/output.txt"
294 if FileTest.exists?(output_filename)
294 if FileTest.exists?(output_filename)
295 output_file = true
295 output_file = true
296 output_size = File.size(output_filename)
296 output_size = File.size(output_filename)
297 else
297 else
298 output_file = false
298 output_file = false
299 output_size = 0
299 output_size = 0
300 end
300 end
301
301
302 return {
302 return {
303 :num => case_num,
303 :num => case_num,
304 :msg => results[0],
304 :msg => results[0],
305 :run_stat => run_stat,
305 :run_stat => run_stat,
306 :output => output_file,
306 :output => output_file,
307 :output_size => output_size
307 :output_size => output_size
308 }
308 }
309 end
309 end
310 end
310 end
311
311
312 # copied from grader/script/lib/test_request_helper.rb
312 # copied from grader/script/lib/test_request_helper.rb
313 def extract_running_stat(results)
313 def extract_running_stat(results)
314 running_stat_line = results[-1]
314 running_stat_line = results[-1]
315
315
316 # extract exit status line
316 # extract exit status line
317 run_stat = ""
317 run_stat = ""
318 if !(/[Cc]orrect/.match(results[0]))
318 if !(/[Cc]orrect/.match(results[0]))
319 run_stat = results[0].chomp
319 run_stat = results[0].chomp
320 else
320 else
321 run_stat = 'Program exited normally'
321 run_stat = 'Program exited normally'
322 end
322 end
323
323
324 logger.info "Stat line: #{running_stat_line}"
324 logger.info "Stat line: #{running_stat_line}"
325
325
326 # extract running time
326 # extract running time
327 if res = /r(.*)u(.*)s/.match(running_stat_line)
327 if res = /r(.*)u(.*)s/.match(running_stat_line)
328 seconds = (res[1].to_f + res[2].to_f)
328 seconds = (res[1].to_f + res[2].to_f)
329 time_stat = "Time used: #{seconds} sec."
329 time_stat = "Time used: #{seconds} sec."
330 else
330 else
331 seconds = nil
331 seconds = nil
332 time_stat = "Time used: n/a sec."
332 time_stat = "Time used: n/a sec."
333 end
333 end
334
334
335 # extract memory usage
335 # extract memory usage
336 if res = /s(.*)m/.match(running_stat_line)
336 if res = /s(.*)m/.match(running_stat_line)
337 memory_used = res[1].to_i
337 memory_used = res[1].to_i
338 else
338 else
339 memory_used = -1
339 memory_used = -1
340 end
340 end
341
341
342 return {
342 return {
343 :msg => "#{run_stat}\n#{time_stat}",
343 :msg => "#{run_stat}\n#{time_stat}",
344 :running_time => seconds,
344 :running_time => seconds,
345 :exit_status => run_stat,
345 :exit_status => run_stat,
346 :memory_usage => memory_used
346 :memory_usage => memory_used
347 }
347 }
348 end
348 end
349
349
350 def confirm_and_update_start_time
350 def confirm_and_update_start_time
351 user = User.find(session[:user_id])
351 user = User.find(session[:user_id])
352 if (GraderConfiguration.indv_contest_mode? and
352 if (GraderConfiguration.indv_contest_mode? and
353 GraderConfiguration['contest.confirm_indv_contest_start'] and
353 GraderConfiguration['contest.confirm_indv_contest_start'] and
354 !user.contest_started?)
354 !user.contest_started?)
355 redirect_to :action => 'confirm_contest_start' and return
355 redirect_to :action => 'confirm_contest_start' and return
356 end
356 end
357 if not GraderConfiguration.analysis_mode?
357 if not GraderConfiguration.analysis_mode?
358 user.update_start_time
358 user.update_start_time
359 end
359 end
360 end
360 end
361
361
362 def reject_announcement_refresh_when_logged_out
362 def reject_announcement_refresh_when_logged_out
363 if not session[:user_id]
363 if not session[:user_id]
364 render :text => 'Access forbidden', :status => 403
364 render :text => 'Access forbidden', :status => 403
365 end
365 end
366
366
367 if GraderConfiguration.multicontests?
367 if GraderConfiguration.multicontests?
368 user = User.find(session[:user_id])
368 user = User.find(session[:user_id])
369 if user.contest_stat.forced_logout
369 if user.contest_stat.forced_logout
370 render :text => 'Access forbidden', :status => 403
370 render :text => 'Access forbidden', :status => 403
371 end
371 end
372 end
372 end
373 end
373 end
374
374
375 end
375 end
376
376
@@ -1,269 +1,269
1 %h2 Live submit
1 %h2 Live submit
2 %br
2 %br
3
3
4 - %textarea#text_haha{style: "display:none"}~ @source
4 + %textarea#text_sourcecode{style: "display:none"}~ @source
5 .container
5 .container
6 .row
6 .row
7 .col-md-12
7 .col-md-12
8 .alert.alert-info
8 .alert.alert-info
9 Write your code in the following box, choose language, and click submit button when finished
9 Write your code in the following box, choose language, and click submit button when finished
10 .row
10 .row
11 .col-md-8
11 .col-md-8
12 %div#editor{style: 'height: 500px; border-radius: 7px; font-size: 14px;'}
12 %div#editor{style: 'height: 500px; border-radius: 7px; font-size: 14px;'}
13 .col-md-4
13 .col-md-4
14 = form_tag({controller: :main, :action => 'submit'}, :multipart => true, class: 'form') do
14 = form_tag({controller: :main, :action => 'submit'}, :multipart => true, class: 'form') do
15
15
16 = hidden_field_tag 'editor_text', @source
16 = hidden_field_tag 'editor_text', @source
17 = hidden_field_tag 'submission[problem_id]', @problem.id
17 = hidden_field_tag 'submission[problem_id]', @problem.id
18 .form-group
18 .form-group
19 = label_tag "Task:"
19 = label_tag "Task:"
20 = text_field_tag 'asdf', "#{@problem.long_name}", class: 'form-control', disabled: true
20 = text_field_tag 'asdf', "#{@problem.long_name}", class: 'form-control', disabled: true
21
21
22 .form-group
22 .form-group
23 = label_tag 'Language'
23 = label_tag 'Language'
24 = select_tag 'language_id', options_from_collection_for_select(Language.all, 'id', 'pretty_name', @lang_id || Language.find_by_pretty_name("Python").id || Language.first.id), class: 'form-control select', style: "width: 100px"
24 = select_tag 'language_id', options_from_collection_for_select(Language.all, 'id', 'pretty_name', @lang_id || Language.find_by_pretty_name("Python").id || Language.first.id), class: 'form-control select', style: "width: 100px"
25 .form-group
25 .form-group
26 = submit_tag 'Submit', class: 'btn btn-success', id: 'live_submit',
26 = submit_tag 'Submit', class: 'btn btn-success', id: 'live_submit',
27 data: {confirm: "Submitting this source code for task #{@problem.long_name}?"}
27 data: {confirm: "Submitting this source code for task #{@problem.long_name}?"}
28 .panel.panel-info
28 .panel.panel-info
29 .panel-heading
29 .panel-heading
30 Latest Submission Status
30 Latest Submission Status
31 = link_to "Refresh",get_latest_submission_status_submissions_path(@submission.user,@problem), class: "btn btn-default btn-sm", remote: true if @submission
31 = link_to "Refresh",get_latest_submission_status_submissions_path(@submission.user,@problem), class: "btn btn-default btn-sm", remote: true if @submission
32 .panel-body
32 .panel-body
33 - if @submission
33 - if @submission
34 = render :partial => 'submission_short',
34 = render :partial => 'submission_short',
35 :locals => {submission: @submission, problem_name: @problem.name, problem_id: @problem.id }
35 :locals => {submission: @submission, problem_name: @problem.name, problem_id: @problem.id }
36 .row
36 .row
37 .col-md-12
37 .col-md-12
38 %h2 Console
38 %h2 Console
39 %textarea#console{style: 'height: 100%; width: 100%;background-color:#000;color:#fff;font-family: consolas, monaco, "Droid Sans Mono";',rows: 20}
39 %textarea#console{style: 'height: 100%; width: 100%;background-color:#000;color:#fff;font-family: consolas, monaco, "Droid Sans Mono";',rows: 20}
40
40
41 :javascript
41 :javascript
42 $(document).ready(function() {
42 $(document).ready(function() {
43 e = ace.edit("editor")
43 e = ace.edit("editor")
44 - e.setValue($("#text_haha").val());
44 + e.setValue($("#text_sourcecode").val());
45 e.gotoLine(1);
45 e.gotoLine(1);
46 $("#language_id").trigger('change');
46 $("#language_id").trigger('change');
47 brython();
47 brython();
48 });
48 });
49
49
50
50
51 %script#__main__{type:'text/python3'}
51 %script#__main__{type:'text/python3'}
52 :plain
52 :plain
53 import sys
53 import sys
54 import traceback
54 import traceback
55
55
56 from browser import document as doc
56 from browser import document as doc
57 from browser import window, alert, console
57 from browser import window, alert, console
58
58
59 _credits = """ Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands
59 _credits = """ Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands
60 for supporting Python development. See www.python.org for more information."""
60 for supporting Python development. See www.python.org for more information."""
61
61
62 _copyright = """Copyright (c) 2012, Pierre Quentel pierre.quentel@gmail.com
62 _copyright = """Copyright (c) 2012, Pierre Quentel pierre.quentel@gmail.com
63 All Rights Reserved.
63 All Rights Reserved.
64
64
65 Copyright (c) 2001-2013 Python Software Foundation.
65 Copyright (c) 2001-2013 Python Software Foundation.
66 All Rights Reserved.
66 All Rights Reserved.
67
67
68 Copyright (c) 2000 BeOpen.com.
68 Copyright (c) 2000 BeOpen.com.
69 All Rights Reserved.
69 All Rights Reserved.
70
70
71 Copyright (c) 1995-2001 Corporation for National Research Initiatives.
71 Copyright (c) 1995-2001 Corporation for National Research Initiatives.
72 All Rights Reserved.
72 All Rights Reserved.
73
73
74 Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam.
74 Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam.
75 All Rights Reserved."""
75 All Rights Reserved."""
76
76
77 _license = """Copyright (c) 2012, Pierre Quentel pierre.quentel@gmail.com
77 _license = """Copyright (c) 2012, Pierre Quentel pierre.quentel@gmail.com
78 All rights reserved.
78 All rights reserved.
79
79
80 Redistribution and use in source and binary forms, with or without
80 Redistribution and use in source and binary forms, with or without
81 modification, are permitted provided that the following conditions are met:
81 modification, are permitted provided that the following conditions are met:
82
82
83 Redistributions of source code must retain the above copyright notice, this
83 Redistributions of source code must retain the above copyright notice, this
84 list of conditions and the following disclaimer. Redistributions in binary
84 list of conditions and the following disclaimer. Redistributions in binary
85 form must reproduce the above copyright notice, this list of conditions and
85 form must reproduce the above copyright notice, this list of conditions and
86 the following disclaimer in the documentation and/or other materials provided
86 the following disclaimer in the documentation and/or other materials provided
87 with the distribution.
87 with the distribution.
88 Neither the name of the <ORGANIZATION> nor the names of its contributors may
88 Neither the name of the <ORGANIZATION> nor the names of its contributors may
89 be used to endorse or promote products derived from this software without
89 be used to endorse or promote products derived from this software without
90 specific prior written permission.
90 specific prior written permission.
91
91
92 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
92 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
93 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
93 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
94 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
94 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
95 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
95 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
96 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
96 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
97 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
97 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
98 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
98 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
99 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
99 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
100 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
100 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
101 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
101 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
102 POSSIBILITY OF SUCH DAMAGE.
102 POSSIBILITY OF SUCH DAMAGE.
103 """
103 """
104
104
105 def credits():
105 def credits():
106 print(_credits)
106 print(_credits)
107 credits.__repr__ = lambda:_credits
107 credits.__repr__ = lambda:_credits
108
108
109 def copyright():
109 def copyright():
110 print(_copyright)
110 print(_copyright)
111 copyright.__repr__ = lambda:_copyright
111 copyright.__repr__ = lambda:_copyright
112
112
113 def license():
113 def license():
114 print(_license)
114 print(_license)
115 license.__repr__ = lambda:_license
115 license.__repr__ = lambda:_license
116
116
117 def write(data):
117 def write(data):
118 doc['console'].value += str(data)
118 doc['console'].value += str(data)
119
119
120
120
121 sys.stdout.write = sys.stderr.write = write
121 sys.stdout.write = sys.stderr.write = write
122 history = []
122 history = []
123 current = 0
123 current = 0
124 _status = "main" # or "block" if typing inside a block
124 _status = "main" # or "block" if typing inside a block
125
125
126 # execution namespace
126 # execution namespace
127 editor_ns = {'credits':credits,
127 editor_ns = {'credits':credits,
128 'copyright':copyright,
128 'copyright':copyright,
129 'license':license,
129 'license':license,
130 '__name__':'__main__'}
130 '__name__':'__main__'}
131
131
132 def cursorToEnd(*args):
132 def cursorToEnd(*args):
133 pos = len(doc['console'].value)
133 pos = len(doc['console'].value)
134 doc['console'].setSelectionRange(pos, pos)
134 doc['console'].setSelectionRange(pos, pos)
135 doc['console'].scrollTop = doc['console'].scrollHeight
135 doc['console'].scrollTop = doc['console'].scrollHeight
136
136
137 def get_col(area):
137 def get_col(area):
138 # returns the column num of cursor
138 # returns the column num of cursor
139 sel = doc['console'].selectionStart
139 sel = doc['console'].selectionStart
140 lines = doc['console'].value.split('\n')
140 lines = doc['console'].value.split('\n')
141 for line in lines[:-1]:
141 for line in lines[:-1]:
142 sel -= len(line) + 1
142 sel -= len(line) + 1
143 return sel
143 return sel
144
144
145
145
146 def myKeyPress(event):
146 def myKeyPress(event):
147 global _status, current
147 global _status, current
148 if event.keyCode == 9: # tab key
148 if event.keyCode == 9: # tab key
149 event.preventDefault()
149 event.preventDefault()
150 doc['console'].value += " "
150 doc['console'].value += " "
151 elif event.keyCode == 13: # return
151 elif event.keyCode == 13: # return
152 src = doc['console'].value
152 src = doc['console'].value
153 if _status == "main":
153 if _status == "main":
154 currentLine = src[src.rfind('>>>') + 4:]
154 currentLine = src[src.rfind('>>>') + 4:]
155 elif _status == "3string":
155 elif _status == "3string":
156 currentLine = src[src.rfind('>>>') + 4:]
156 currentLine = src[src.rfind('>>>') + 4:]
157 currentLine = currentLine.replace('\n... ', '\n')
157 currentLine = currentLine.replace('\n... ', '\n')
158 else:
158 else:
159 currentLine = src[src.rfind('...') + 4:]
159 currentLine = src[src.rfind('...') + 4:]
160 if _status == 'main' and not currentLine.strip():
160 if _status == 'main' and not currentLine.strip():
161 doc['console'].value += '\n>>> '
161 doc['console'].value += '\n>>> '
162 event.preventDefault()
162 event.preventDefault()
163 return
163 return
164 doc['console'].value += '\n'
164 doc['console'].value += '\n'
165 history.append(currentLine)
165 history.append(currentLine)
166 current = len(history)
166 current = len(history)
167 if _status == "main" or _status == "3string":
167 if _status == "main" or _status == "3string":
168 try:
168 try:
169 _ = editor_ns['_'] = eval(currentLine, editor_ns)
169 _ = editor_ns['_'] = eval(currentLine, editor_ns)
170 if _ is not None:
170 if _ is not None:
171 write(repr(_)+'\n')
171 write(repr(_)+'\n')
172 doc['console'].value += '>>> '
172 doc['console'].value += '>>> '
173 _status = "main"
173 _status = "main"
174 except IndentationError:
174 except IndentationError:
175 doc['console'].value += '... '
175 doc['console'].value += '... '
176 _status = "block"
176 _status = "block"
177 except SyntaxError as msg:
177 except SyntaxError as msg:
178 if str(msg) == 'invalid syntax : triple string end not found' or \
178 if str(msg) == 'invalid syntax : triple string end not found' or \
179 str(msg).startswith('Unbalanced bracket'):
179 str(msg).startswith('Unbalanced bracket'):
180 doc['console'].value += '... '
180 doc['console'].value += '... '
181 _status = "3string"
181 _status = "3string"
182 elif str(msg) == 'eval() argument must be an expression':
182 elif str(msg) == 'eval() argument must be an expression':
183 try:
183 try:
184 exec(currentLine, editor_ns)
184 exec(currentLine, editor_ns)
185 except:
185 except:
186 traceback.print_exc()
186 traceback.print_exc()
187 doc['console'].value += '>>> '
187 doc['console'].value += '>>> '
188 _status = "main"
188 _status = "main"
189 elif str(msg) == 'decorator expects function':
189 elif str(msg) == 'decorator expects function':
190 doc['console'].value += '... '
190 doc['console'].value += '... '
191 _status = "block"
191 _status = "block"
192 else:
192 else:
193 traceback.print_exc()
193 traceback.print_exc()
194 doc['console'].value += '>>> '
194 doc['console'].value += '>>> '
195 _status = "main"
195 _status = "main"
196 except:
196 except:
197 traceback.print_exc()
197 traceback.print_exc()
198 doc['console'].value += '>>> '
198 doc['console'].value += '>>> '
199 _status = "main"
199 _status = "main"
200 elif currentLine == "": # end of block
200 elif currentLine == "": # end of block
201 block = src[src.rfind('>>>') + 4:].splitlines()
201 block = src[src.rfind('>>>') + 4:].splitlines()
202 block = [block[0]] + [b[4:] for b in block[1:]]
202 block = [block[0]] + [b[4:] for b in block[1:]]
203 block_src = '\n'.join(block)
203 block_src = '\n'.join(block)
204 # status must be set before executing code in globals()
204 # status must be set before executing code in globals()
205 _status = "main"
205 _status = "main"
206 try:
206 try:
207 _ = exec(block_src, editor_ns)
207 _ = exec(block_src, editor_ns)
208 if _ is not None:
208 if _ is not None:
209 print(repr(_))
209 print(repr(_))
210 except:
210 except:
211 traceback.print_exc()
211 traceback.print_exc()
212 doc['console'].value += '>>> '
212 doc['console'].value += '>>> '
213 else:
213 else:
214 doc['console'].value += '... '
214 doc['console'].value += '... '
215
215
216 cursorToEnd()
216 cursorToEnd()
217 event.preventDefault()
217 event.preventDefault()
218
218
219 def myKeyDown(event):
219 def myKeyDown(event):
220 global _status, current
220 global _status, current
221 if event.keyCode == 37: # left arrow
221 if event.keyCode == 37: # left arrow
222 sel = get_col(doc['console'])
222 sel = get_col(doc['console'])
223 if sel < 5:
223 if sel < 5:
224 event.preventDefault()
224 event.preventDefault()
225 event.stopPropagation()
225 event.stopPropagation()
226 elif event.keyCode == 36: # line start
226 elif event.keyCode == 36: # line start
227 pos = doc['console'].selectionStart
227 pos = doc['console'].selectionStart
228 col = get_col(doc['console'])
228 col = get_col(doc['console'])
229 doc['console'].setSelectionRange(pos - col + 4, pos - col + 4)
229 doc['console'].setSelectionRange(pos - col + 4, pos - col + 4)
230 event.preventDefault()
230 event.preventDefault()
231 elif event.keyCode == 38: # up
231 elif event.keyCode == 38: # up
232 if current > 0:
232 if current > 0:
233 pos = doc['console'].selectionStart
233 pos = doc['console'].selectionStart
234 col = get_col(doc['console'])
234 col = get_col(doc['console'])
235 # remove current line
235 # remove current line
236 doc['console'].value = doc['console'].value[:pos - col + 4]
236 doc['console'].value = doc['console'].value[:pos - col + 4]
237 current -= 1
237 current -= 1
238 doc['console'].value += history[current]
238 doc['console'].value += history[current]
239 event.preventDefault()
239 event.preventDefault()
240 elif event.keyCode == 40: # down
240 elif event.keyCode == 40: # down
241 if current < len(history) - 1:
241 if current < len(history) - 1:
242 pos = doc['console'].selectionStart
242 pos = doc['console'].selectionStart
243 col = get_col(doc['console'])
243 col = get_col(doc['console'])
244 # remove current line
244 # remove current line
245 doc['console'].value = doc['console'].value[:pos - col + 4]
245 doc['console'].value = doc['console'].value[:pos - col + 4]
246 current += 1
246 current += 1
247 doc['console'].value += history[current]
247 doc['console'].value += history[current]
248 event.preventDefault()
248 event.preventDefault()
249 elif event.keyCode == 8: # backspace
249 elif event.keyCode == 8: # backspace
250 src = doc['console'].value
250 src = doc['console'].value
251 lstart = src.rfind('\n')
251 lstart = src.rfind('\n')
252 if (lstart == -1 and len(src) < 5) or (len(src) - lstart < 6):
252 if (lstart == -1 and len(src) < 5) or (len(src) - lstart < 6):
253 event.preventDefault()
253 event.preventDefault()
254 event.stopPropagation()
254 event.stopPropagation()
255
255
256
256
257 doc['console'].bind('keypress', myKeyPress)
257 doc['console'].bind('keypress', myKeyPress)
258 doc['console'].bind('keydown', myKeyDown)
258 doc['console'].bind('keydown', myKeyDown)
259 doc['console'].bind('click', cursorToEnd)
259 doc['console'].bind('click', cursorToEnd)
260 v = sys.implementation.version
260 v = sys.implementation.version
261 doc['console'].value = "Brython %s.%s.%s on %s %s\n>>> " % (
261 doc['console'].value = "Brython %s.%s.%s on %s %s\n>>> " % (
262 v[0], v[1], v[2], window.navigator.appName, window.navigator.appVersion)
262 v[0], v[1], v[2], window.navigator.appName, window.navigator.appVersion)
263 #doc['console'].value += 'Type "copyright", "credits" or "license" for more information.'
263 #doc['console'].value += 'Type "copyright", "credits" or "license" for more information.'
264 doc['console'].focus()
264 doc['console'].focus()
265 cursorToEnd()
265 cursorToEnd()
266
266
267
267
268
268
269
269
deleted file
deleted file
deleted file
You need to be logged in to leave comments. Login now