Description:
translates test_request input/output file paths for remote grading test_request
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r117:cc3e1102f8c6 - - 5 files changed: 36 inserted, 3 deleted

@@ -1,20 +1,23
1 #
1 #
2 # See documentation in lib/configuration.rb
2 # See documentation in lib/configuration.rb
3 #
3 #
4 Grader::Initializer.run do |config|
4 Grader::Initializer.run do |config|
5
5
6 config.problems_dir = GRADER_ROOT + "/../ev-exam"
6 config.problems_dir = GRADER_ROOT + "/../ev-exam"
7 config.user_result_dir = GRADER_ROOT + "/../result"
7 config.user_result_dir = GRADER_ROOT + "/../result"
8
8
9 config.talkative = true
9 config.talkative = true
10 config.logging = true
10 config.logging = true
11 config.log_dir = GRADER_ROOT + "/../log"
11 config.log_dir = GRADER_ROOT + "/../log"
12
12
13 config.report_grader = true
13 config.report_grader = true
14
14
15 config.test_request_input_base_dir = RAILS_ROOT + "/data/test_request/input"
15 config.test_request_input_base_dir = RAILS_ROOT + "/data/test_request/input"
16 config.test_request_output_base_dir = RAILS_ROOT + "/data/test_request/output"
16 config.test_request_output_base_dir = RAILS_ROOT + "/data/test_request/output"
17 config.test_request_problem_templates_dir = config.problems_dir + "/test_request"
17 config.test_request_problem_templates_dir = config.problems_dir + "/test_request"
18
18
19 + # change this if you want the path on the output to be translated
20 + config.test_request_org_output_base_dir = config.test_request_output_base_dir
21 +
19 config.comment_report_style = :short
22 config.comment_report_style = :short
20 end
23 end
@@ -1,19 +1,22
1 #
1 #
2 # See documentation in lib/configuration.rb
2 # See documentation in lib/configuration.rb
3 #
3 #
4 Grader::Initializer.run do |config|
4 Grader::Initializer.run do |config|
5 config.problems_dir = GRADER_ROOT + "/../ev"
5 config.problems_dir = GRADER_ROOT + "/../ev"
6 config.user_result_dir = GRADER_ROOT + "/../result"
6 config.user_result_dir = GRADER_ROOT + "/../result"
7
7
8 config.talkative = true
8 config.talkative = true
9 config.logging = true
9 config.logging = true
10 config.log_dir = GRADER_ROOT + "/../log"
10 config.log_dir = GRADER_ROOT + "/../log"
11
11
12 config.report_grader = true
12 config.report_grader = true
13
13
14 config.test_request_input_base_dir = RAILS_ROOT + "/data/test_request/input"
14 config.test_request_input_base_dir = RAILS_ROOT + "/data/test_request/input"
15 config.test_request_output_base_dir = RAILS_ROOT + "/data/test_request/output"
15 config.test_request_output_base_dir = RAILS_ROOT + "/data/test_request/output"
16 config.test_request_problem_templates_dir = config.problems_dir + "/test_request"
16 config.test_request_problem_templates_dir = config.problems_dir + "/test_request"
17 +
18 + # change this if you want the path on the output to be translated
19 + config.test_request_org_output_base_dir = config.test_request_output_base_dir
17
20
18 config.comment_report_style = :full
21 config.comment_report_style = :full
19 end
22 end
@@ -1,29 +1,32
1 #
1 #
2 # See documentation in lib/configuration.rb
2 # See documentation in lib/configuration.rb
3 #
3 #
4 Grader::Initializer.run do |config|
4 Grader::Initializer.run do |config|
5 config.problems_dir = GRADER_ROOT + "/test/sandbox/ev"
5 config.problems_dir = GRADER_ROOT + "/test/sandbox/ev"
6 config.user_result_dir = GRADER_ROOT + "/test/sandbox/result"
6 config.user_result_dir = GRADER_ROOT + "/test/sandbox/result"
7
7
8 config.talkative = false
8 config.talkative = false
9
9
10 config.report_grader = false
10 config.report_grader = false
11
11
12 config.rails_env = 'test'
12 config.rails_env = 'test'
13
13
14 config.comment_report_style = :full
14 config.comment_report_style = :full
15
15
16 config.test_request_input_base_dir = GRADER_ROOT + "/test/data/test_request/input"
16 config.test_request_input_base_dir = GRADER_ROOT + "/test/data/test_request/input"
17 config.test_request_output_base_dir = GRADER_ROOT + "/test/sandbox/test_request/output"
17 config.test_request_output_base_dir = GRADER_ROOT + "/test/sandbox/test_request/output"
18 config.test_request_problem_templates_dir = GRADER_ROOT + "/test/data/test_request/problems"
18 config.test_request_problem_templates_dir = GRADER_ROOT + "/test/data/test_request/problems"
19
19
20 + # change this if you want the path on the output to be translated
21 + config.test_request_org_output_base_dir = config.test_request_output_base_dir
22 +
20 #
23 #
21 # These options are for testing
24 # These options are for testing
22 #
25 #
23 class << config
26 class << config
24 attr_accessor :test_data_dir, :test_sandbox_dir
27 attr_accessor :test_data_dir, :test_sandbox_dir
25 end
28 end
26
29
27 config.test_data_dir = GRADER_ROOT + "/test/data"
30 config.test_data_dir = GRADER_ROOT + "/test/data"
28 config.test_sandbox_dir = GRADER_ROOT + "/test/sandbox"
31 config.test_sandbox_dir = GRADER_ROOT + "/test/sandbox"
29 end
32 end
@@ -1,83 +1,87
1 module Grader
1 module Grader
2
2
3 # This singleton class holds basic configurations for grader. When
3 # This singleton class holds basic configurations for grader. When
4 # running in each mode, grader uses resources from different
4 # running in each mode, grader uses resources from different
5 # directories and outputs differently. Usually the attributes name
5 # directories and outputs differently. Usually the attributes name
6 # are descriptive; below we explain more on each attributes.
6 # are descriptive; below we explain more on each attributes.
7 class Configuration
7 class Configuration
8 # Rails' environment: "development", "production"
8 # Rails' environment: "development", "production"
9 attr_accessor :rails_env
9 attr_accessor :rails_env
10
10
11 # Grader looks for problem [prob] in problem_dir/[prob], and store
11 # Grader looks for problem [prob] in problem_dir/[prob], and store
12 # execution results for submission [x] of user [u] in directory
12 # execution results for submission [x] of user [u] in directory
13 # user_result_dir/[u]/[x]
13 # user_result_dir/[u]/[x]
14 attr_accessor :problems_dir
14 attr_accessor :problems_dir
15 attr_accessor :user_result_dir
15 attr_accessor :user_result_dir
16
16
17 # If report_grader=true, the grader would add a row in model
17 # If report_grader=true, the grader would add a row in model
18 # GraderProcess. It would report itself with grader_hostname and
18 # GraderProcess. It would report itself with grader_hostname and
19 # process id.
19 # process id.
20 attr_accessor :report_grader
20 attr_accessor :report_grader
21 attr_accessor :grader_hostname
21 attr_accessor :grader_hostname
22
22
23 # If talkative=true, grader would report status to console. If
23 # If talkative=true, grader would report status to console. If
24 # logging=true, grader would report status to a log file located
24 # logging=true, grader would report status to a log file located
25 # in log_dir, in a file name mode.options.pid. TODO: defined
25 # in log_dir, in a file name mode.options.pid. TODO: defined
26 # log file naming.
26 # log file naming.
27 attr_accessor :talkative
27 attr_accessor :talkative
28 attr_accessor :logging
28 attr_accessor :logging
29 attr_accessor :log_dir
29 attr_accessor :log_dir
30
30
31 # These are directories related to the test interface.
31 # These are directories related to the test interface.
32 attr_accessor :test_request_input_base_dir
32 attr_accessor :test_request_input_base_dir
33 attr_accessor :test_request_output_base_dir
33 attr_accessor :test_request_output_base_dir
34 attr_accessor :test_request_problem_templates_dir
34 attr_accessor :test_request_problem_templates_dir
35
35
36 + # this is for linking output from test request
37 + # TODO: find a cleaner way to do this.
38 + attr_accessor :test_request_org_output_base_dir
39 +
36 # Comment received from the grading script will be filtered
40 # Comment received from the grading script will be filtered
37 # through Configuration#report_comment. How this method behave
41 # through Configuration#report_comment. How this method behave
38 # depends on this option; right now only two formats, :short and
42 # depends on this option; right now only two formats, :short and
39 # :long
43 # :long
40 attr_accessor :comment_report_style
44 attr_accessor :comment_report_style
41
45
42 def report_comment(comment)
46 def report_comment(comment)
43 case comment_report_style
47 case comment_report_style
44 when :short
48 when :short
45 if comment.chomp =~ /^[\[\]P]+$/ # all P's
49 if comment.chomp =~ /^[\[\]P]+$/ # all P's
46 'passed'
50 'passed'
47 elsif comment.chomp =~ /[Cc]ompil.*[Ee]rror/
51 elsif comment.chomp =~ /[Cc]ompil.*[Ee]rror/
48 'compilation error'
52 'compilation error'
49 else
53 else
50 'failed'
54 'failed'
51 end
55 end
52
56
53 when :full
57 when :full
54 comment.chomp
58 comment.chomp
55 end
59 end
56 end
60 end
57
61
58 # Codes for singleton
62 # Codes for singleton
59 private_class_method :new
63 private_class_method :new
60
64
61 @@instance = nil
65 @@instance = nil
62
66
63 def self.get_instance
67 def self.get_instance
64 if @@instance==nil
68 if @@instance==nil
65 @@instance = new
69 @@instance = new
66 end
70 end
67 @@instance
71 @@instance
68 end
72 end
69
73
70 private
74 private
71 def initialize
75 def initialize
72 @talkative = false
76 @talkative = false
73 @log_file = nil
77 @log_file = nil
74 @report_grader = false
78 @report_grader = false
75 @grader_hostname = `hostname`.chomp
79 @grader_hostname = `hostname`.chomp
76
80
77 @rails_env = 'development'
81 @rails_env = 'development'
78
82
79 @comment_report_style = :full
83 @comment_report_style = :full
80 end
84 end
81
85
82 end
86 end
83
87
@@ -1,55 +1,61
1 #
1 #
2 # This part contains various test_request helpers for interfacing
2 # This part contains various test_request helpers for interfacing
3 # with Grader::Engine. There are TestRequestRoomMaker and
3 # with Grader::Engine. There are TestRequestRoomMaker and
4 # TestRequestReporter.
4 # TestRequestReporter.
5
5
6 module Grader
6 module Grader
7
7
8 + def self.translate_filepath(filename, marker, new_base_path)
9 + p = filename.index(marker)
10 + end_path = filename[(p+marker.length)..-1]
11 + return new_base_path + end_path
12 + end
13 +
8 def self.link_or_copy(src, des)
14 def self.link_or_copy(src, des)
9 begin
15 begin
10 FileUtils.ln_s(src, des)
16 FileUtils.ln_s(src, des)
11 rescue NotImplementedError
17 rescue NotImplementedError
12 FileUtils.cp(src,des)
18 FileUtils.cp(src,des)
13 end
19 end
14 end
20 end
15
21
16 def self.call_and_log(error_message)
22 def self.call_and_log(error_message)
17 begin
23 begin
18 yield
24 yield
19 rescue
25 rescue
20 msg = "ERROR: #{error_message}"
26 msg = "ERROR: #{error_message}"
21 raise msg
27 raise msg
22 end
28 end
23 end
29 end
24
30
25 #
31 #
26 # A TestRequestRoomMaker is a helper object for Engine
32 # A TestRequestRoomMaker is a helper object for Engine
27 # - finds grading room: in user_result_dir/(user)/test_request/ ...
33 # - finds grading room: in user_result_dir/(user)/test_request/ ...
28 # - prepare problem configuration for grading --- basically it copy
34 # - prepare problem configuration for grading --- basically it copy
29 # all config files, and copy user's input into the testcase
35 # all config files, and copy user's input into the testcase
30 # directory. First, it finds the template from problem template
36 # directory. First, it finds the template from problem template
31 # directory; if it can't find a template, it'll use the template
37 # directory; if it can't find a template, it'll use the template
32 # from default template.
38 # from default template.
33 class TestRequestRoomMaker
39 class TestRequestRoomMaker
34 def initialize
40 def initialize
35 @config = Grader::Configuration.get_instance
41 @config = Grader::Configuration.get_instance
36 end
42 end
37
43
38 def produce_grading_room(test_request)
44 def produce_grading_room(test_request)
39 grading_room = grading_room_dir(test_request)
45 grading_room = grading_room_dir(test_request)
40 FileUtils.mkdir_p(grading_room)
46 FileUtils.mkdir_p(grading_room)
41
47
42 #
48 #
43 # Also copy additional submitted file to this directory as well.
49 # Also copy additional submitted file to this directory as well.
44 # The program would see this file only if it is copied
50 # The program would see this file only if it is copied
45 # to the sandbox directory later. The run script should do it.
51 # to the sandbox directory later. The run script should do it.
46 #
52 #
47 if FileTest.exists?("#{test_request.input_file_name}.files")
53 if FileTest.exists?("#{test_request.input_file_name}.files")
48 FileUtils.cp_r("#{test_request.input_file_name}.files/.",
54 FileUtils.cp_r("#{test_request.input_file_name}.files/.",
49 "#{grading_room}")
55 "#{grading_room}")
50 end
56 end
51
57
52 grading_room
58 grading_room
53 end
59 end
54
60
55 def find_problem_home(test_request)
61 def find_problem_home(test_request)
@@ -59,98 +65,105
59
65
60 raise "Test Request: error template not found" if !File.exists?(template_dir)
66 raise "Test Request: error template not found" if !File.exists?(template_dir)
61
67
62 problem_home = problem_home_dir(test_request)
68 problem_home = problem_home_dir(test_request)
63 FileUtils.mkdir_p(problem_home)
69 FileUtils.mkdir_p(problem_home)
64
70
65 copy_problem_template(template_dir,problem_home)
71 copy_problem_template(template_dir,problem_home)
66 link_input_file(test_request,problem_home)
72 link_input_file(test_request,problem_home)
67
73
68 problem_home
74 problem_home
69 end
75 end
70
76
71 def save_source(test_request,source_name)
77 def save_source(test_request,source_name)
72 dir = self.produce_grading_room(test_request)
78 dir = self.produce_grading_room(test_request)
73 submission = test_request.submission
79 submission = test_request.submission
74 f = File.open("#{dir}/#{source_name}","w")
80 f = File.open("#{dir}/#{source_name}","w")
75 f.write(submission.source)
81 f.write(submission.source)
76 f.close
82 f.close
77 end
83 end
78
84
79 def clean_up(test_request)
85 def clean_up(test_request)
80 problem_home = problem_home_dir(test_request)
86 problem_home = problem_home_dir(test_request)
81 remove_data_files(problem_home)
87 remove_data_files(problem_home)
82 end
88 end
83
89
84 protected
90 protected
85 def grading_room_dir(test_request)
91 def grading_room_dir(test_request)
86 problem_name = test_request.problem_name
92 problem_name = test_request.problem_name
87 user = test_request.user
93 user = test_request.user
88 grading_room = "#{@config.user_result_dir}" +
94 grading_room = "#{@config.user_result_dir}" +
89 "/#{user.login}/test_request" +
95 "/#{user.login}/test_request" +
90 "/#{problem_name}/#{test_request.id}"
96 "/#{problem_name}/#{test_request.id}"
91 grading_room
97 grading_room
92 end
98 end
93
99
94 def problem_home_dir(test_request)
100 def problem_home_dir(test_request)
95 problem_name = test_request.problem_name
101 problem_name = test_request.problem_name
96 user = test_request.user
102 user = test_request.user
97 "#{@config.user_result_dir}" +
103 "#{@config.user_result_dir}" +
98 "/#{user.login}/test_request/#{problem_name}"
104 "/#{user.login}/test_request/#{problem_name}"
99 end
105 end
100
106
101 def copy_problem_template(template_dir,problem_home)
107 def copy_problem_template(template_dir,problem_home)
102 Grader::call_and_log("Test Request: cannot copy problem template") {
108 Grader::call_and_log("Test Request: cannot copy problem template") {
103 FileUtils.cp_r("#{template_dir}/.","#{problem_home}")
109 FileUtils.cp_r("#{template_dir}/.","#{problem_home}")
104 }
110 }
105 end
111 end
106
112
113 + def translate_input_filename(filename)
114 + return Grader::translate_filepath(filename,
115 + 'input',
116 + @config.test_request_input_base_dir)
117 + end
118 +
107 def link_input_file(test_request, problem_home)
119 def link_input_file(test_request, problem_home)
108 - input_fname = "#{test_request.input_file_name}"
120 + input_fname = translate_input_filename(test_request.input_file_name)
121 +
109 if !File.exists?(input_fname)
122 if !File.exists?(input_fname)
110 raise "Test Request: input file not found."
123 raise "Test Request: input file not found."
111 end
124 end
112
125
113 input_fname_problem_home = "#{problem_home}/test_cases/1/input-1.txt"
126 input_fname_problem_home = "#{problem_home}/test_cases/1/input-1.txt"
114 if File.exists?(input_fname_problem_home)
127 if File.exists?(input_fname_problem_home)
115 FileUtils.rm([input_fname_problem_home], :force => true)
128 FileUtils.rm([input_fname_problem_home], :force => true)
116 end
129 end
117
130
118 Grader::link_or_copy("#{input_fname}", "#{input_fname_problem_home}")
131 Grader::link_or_copy("#{input_fname}", "#{input_fname_problem_home}")
119 end
132 end
120
133
121 def remove_data_files(problem_home)
134 def remove_data_files(problem_home)
122 if File.exists?("#{problem_home}/test_cases/1/input-1.txt")
135 if File.exists?("#{problem_home}/test_cases/1/input-1.txt")
123 Grader::call_and_log("Test Request: cannot remove data files") {
136 Grader::call_and_log("Test Request: cannot remove data files") {
124 FileUtils.rm Dir.glob("#{problem_home}/test_cases/1/*")
137 FileUtils.rm Dir.glob("#{problem_home}/test_cases/1/*")
125 }
138 }
126 end
139 end
127 end
140 end
128
141
129 end
142 end
130
143
131 class TestRequestReporter
144 class TestRequestReporter
132 def initialize
145 def initialize
133 @config = Grader::Configuration.get_instance
146 @config = Grader::Configuration.get_instance
134 end
147 end
135
148
136 def report(test_request,test_result_dir)
149 def report(test_request,test_result_dir)
137 save_result(test_request,read_result(test_result_dir))
150 save_result(test_request,read_result(test_result_dir))
138 end
151 end
139
152
140 def report_error(test_request, msg)
153 def report_error(test_request, msg)
141 save_result(test_request, {:running_stat => {
154 save_result(test_request, {:running_stat => {
142 :msg => "#{msg}",
155 :msg => "#{msg}",
143 :running_time => nil,
156 :running_time => nil,
144 :exit_status => "Some error occured. Program did not run",
157 :exit_status => "Some error occured. Program did not run",
145 :memory_usage => nil
158 :memory_usage => nil
146 }})
159 }})
147 end
160 end
148
161
149 protected
162 protected
150 def read_result(test_result_dir)
163 def read_result(test_result_dir)
151 # TODO:
164 # TODO:
152 cmp_msg_fname = "#{test_result_dir}/compiler_message"
165 cmp_msg_fname = "#{test_result_dir}/compiler_message"
153 cmp_file = File.open(cmp_msg_fname)
166 cmp_file = File.open(cmp_msg_fname)
154 cmp_msg = cmp_file.read
167 cmp_msg = cmp_file.read
155 cmp_file.close
168 cmp_file.close
156
169
@@ -169,86 +182,93
169 :running_stat => stat,
182 :running_stat => stat,
170 :comment => "",
183 :comment => "",
171 :cmp_msg => cmp_msg}
184 :cmp_msg => cmp_msg}
172 else
185 else
173 return {
186 return {
174 :running_stat => nil,
187 :running_stat => nil,
175 :comment => "Compilation error",
188 :comment => "Compilation error",
176 :cmp_msg => cmp_msg}
189 :cmp_msg => cmp_msg}
177 end
190 end
178 end
191 end
179
192
180 def extract_running_stat(results)
193 def extract_running_stat(results)
181 running_stat_line = results[-1]
194 running_stat_line = results[-1]
182
195
183 # extract exit status line
196 # extract exit status line
184 run_stat = ""
197 run_stat = ""
185 if !(/[Cc]orrect/.match(results[0]))
198 if !(/[Cc]orrect/.match(results[0]))
186 run_stat = results[0].chomp
199 run_stat = results[0].chomp
187 else
200 else
188 run_stat = 'Program exited normally'
201 run_stat = 'Program exited normally'
189 end
202 end
190
203
191 # extract running time
204 # extract running time
192 if res = /r(.*)u(.*)s/.match(running_stat_line)
205 if res = /r(.*)u(.*)s/.match(running_stat_line)
193 seconds = (res[1].to_f + res[2].to_f)
206 seconds = (res[1].to_f + res[2].to_f)
194 time_stat = "Time used: #{seconds} sec."
207 time_stat = "Time used: #{seconds} sec."
195 else
208 else
196 seconds = nil
209 seconds = nil
197 time_stat = "Time used: n/a sec."
210 time_stat = "Time used: n/a sec."
198 end
211 end
199
212
200 # extract memory usage
213 # extract memory usage
201 if res = /s(.*)m/.match(running_stat_line)
214 if res = /s(.*)m/.match(running_stat_line)
202 memory_used = res[1].to_i
215 memory_used = res[1].to_i
203 else
216 else
204 memory_used = -1
217 memory_used = -1
205 end
218 end
206
219
207 return {
220 return {
208 :msg => "#{run_stat}\n#{time_stat}",
221 :msg => "#{run_stat}\n#{time_stat}",
209 :running_time => seconds,
222 :running_time => seconds,
210 :exit_status => run_stat,
223 :exit_status => run_stat,
211 :memory_usage => memory_used
224 :memory_usage => memory_used
212 }
225 }
213 end
226 end
214
227
215 def save_result(test_request,result)
228 def save_result(test_request,result)
216 if result[:output_file_name]!=nil
229 if result[:output_file_name]!=nil
217 - test_request.output_file_name = link_output_file(test_request,
230 + org_filename = link_output_file(test_request,
218 - result[:output_file_name])
231 + result[:output_file_name])
232 + test_request.output_file_name = translate_output_filename(org_filename)
219 end
233 end
220 test_request.graded_at = Time.now
234 test_request.graded_at = Time.now
221 test_request.compiler_message = (result[:cmp_msg] or '')
235 test_request.compiler_message = (result[:cmp_msg] or '')
222 test_request.grader_comment = (result[:comment] or '')
236 test_request.grader_comment = (result[:comment] or '')
223 if result[:running_stat]!=nil
237 if result[:running_stat]!=nil
224 test_request.running_stat = (result[:running_stat][:msg] or '')
238 test_request.running_stat = (result[:running_stat][:msg] or '')
225 test_request.running_time = (result[:running_stat][:running_time] or nil)
239 test_request.running_time = (result[:running_stat][:running_time] or nil)
226 test_request.exit_status = result[:running_stat][:exit_status]
240 test_request.exit_status = result[:running_stat][:exit_status]
227 test_request.memory_usage = result[:running_stat][:memory_usage]
241 test_request.memory_usage = result[:running_stat][:memory_usage]
228 else
242 else
229 test_request.running_stat = ''
243 test_request.running_stat = ''
230 end
244 end
231 test_request.save
245 test_request.save
232 end
246 end
233
247
234 protected
248 protected
249 + def translate_output_filename(filename)
250 + return Grader::translate_filepath(filename,
251 + 'output',
252 + @config.test_request_org_output_base_dir)
253 + end
254 +
235 def link_output_file(test_request, fname)
255 def link_output_file(test_request, fname)
236 target_file_name = random_output_file_name(test_request.user,
256 target_file_name = random_output_file_name(test_request.user,
237 test_request.problem)
257 test_request.problem)
238 FileUtils.mkdir_p(File.dirname(target_file_name))
258 FileUtils.mkdir_p(File.dirname(target_file_name))
239 Grader::link_or_copy("#{fname}", "#{target_file_name}")
259 Grader::link_or_copy("#{fname}", "#{target_file_name}")
240 return target_file_name
260 return target_file_name
241 end
261 end
242
262
243 def random_output_file_name(user,problem)
263 def random_output_file_name(user,problem)
244 problem_name = TestRequest.name_of(problem)
264 problem_name = TestRequest.name_of(problem)
245 begin
265 begin
246 tmpname = "#{@config.test_request_output_base_dir}" +
266 tmpname = "#{@config.test_request_output_base_dir}" +
247 "/#{user.login}/#{problem_name}/#{rand(10000)}"
267 "/#{user.login}/#{problem_name}/#{rand(10000)}"
248 end while File.exists?(tmpname)
268 end while File.exists?(tmpname)
249 tmpname
269 tmpname
250 end
270 end
251
271
252 end
272 end
253
273
254 end
274 end
You need to be logged in to leave comments. Login now