gettc 1.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Rakefile +41 -0
- data/bin/gettc +63 -0
- data/core/lib/topcoder.rb +3 -0
- data/core/lib/topcoder/download.rb +89 -0
- data/core/lib/topcoder/generate.rb +131 -0
- data/core/lib/topcoder/parse.rb +231 -0
- data/core/lib/topcoder/print.rb +56 -0
- data/core/lib/topcoder/problem.rb +33 -0
- data/core/lib/topcoder/signature.rb +55 -0
- data/core/lib/topcoder/types.rb +62 -0
- data/core/test/topcoder/download_test.rb +29 -0
- data/core/test/topcoder/generate_test.rb +31 -0
- data/core/test/topcoder/parse_test.rb +104 -0
- data/core/test/topcoder/signature_test.rb +52 -0
- data/core/test/topcoder/types_test.rb +24 -0
- data/dist/config.yml +2 -0
- data/dist/include/cpp/engine.rb +90 -0
- data/dist/include/cpp/topcoder +212 -0
- data/dist/include/haskell/TopCoder.hs +82 -0
- data/dist/include/haskell/engine.rb +122 -0
- data/dist/include/java/TopCoder.jar +0 -0
- data/dist/include/java/engine.rb +207 -0
- data/dist/template/bin/runner.sh +113 -0
- data/dist/template/data/demo/{examples_d} +0 -0
- data/dist/template/data/sys/{systests_d} +0 -0
- data/dist/template/prob/images/{images_d} +0 -0
- data/dist/template/prob/{name}.html +8 -0
- data/dist/template/prob/{name}.md +1 -0
- data/dist/template/solve/cpp/Makefile +30 -0
- data/dist/template/solve/cpp/{name}.cpp +11 -0
- data/dist/template/solve/cpp/{name}Runner.cpp +26 -0
- data/dist/template/solve/cpp/{name}Test.cpp +8 -0
- data/dist/template/solve/haskell/Makefile +30 -0
- data/dist/template/solve/haskell/{name}.hs +7 -0
- data/dist/template/solve/haskell/{name}Runner.hs +27 -0
- data/dist/template/solve/haskell/{name}Test.hs +10 -0
- data/dist/template/solve/java/build.xml +78 -0
- data/dist/template/solve/java/{name}.java +9 -0
- data/dist/template/solve/java/{name}Runner.java +32 -0
- data/dist/template/solve/java/{name}Test.java +8 -0
- data/dist/template/util/check/Makefile +5 -0
- data/dist/template/util/check/check.cpp +26 -0
- metadata +121 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c80f45fecd9b96df8986e44dc295099b2d3dfa04
|
4
|
+
data.tar.gz: 78336c74d9779a92f2c6b7121b534f5e79fe5f3c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7962d7609c319a030aa2cfbb1cb30f05a8cfc5f0461948ed6738109dabd76473828b8c4182d7590588f2f49366c42909866edb5080903d4fb43689006d1406e0
|
7
|
+
data.tar.gz: e35c776a854fb551e71aa9bc87b872467b942b211fe6df7201ef17fcfee60540f6415b21be0ce79c5885439d00d8f2c2996baf6907604707d2bfec24adae8f38
|
data/Rakefile
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'rake/testtask'
|
2
|
+
require 'rubygems/package_task'
|
3
|
+
require 'rubygems/installer'
|
4
|
+
require 'fileutils'
|
5
|
+
|
6
|
+
Rake::TestTask.new do |t|
|
7
|
+
t.libs << 'core/lib'
|
8
|
+
t.pattern = 'core/test/**/*_test.rb'
|
9
|
+
end
|
10
|
+
|
11
|
+
spec = Gem::Specification.new do |s|
|
12
|
+
s.platform = Gem::Platform::RUBY
|
13
|
+
s.name = 'gettc'
|
14
|
+
s.summary = 'Download TopCoder problem and generate a skeleton solution'
|
15
|
+
s.description = 'Given a TopCoder problem ID, gettc downloads the problem specification, parses the whole thing into a Markdown file, generates inputs/outputs based on the Examples and System Tests given, and finally generates basic solution files for you to get started.'
|
16
|
+
s.version = '1.2.2'
|
17
|
+
|
18
|
+
s.author = 'Seri'
|
19
|
+
s.email = 'seritrinh@gmail.com'
|
20
|
+
s.homepage = 'http://seriessays.blogspot.com'
|
21
|
+
|
22
|
+
s.files = FileList["{bin,dist,core/lib}/**/*"].to_a + ['Rakefile']
|
23
|
+
s.test_files = FileList["core/test/**/*_test.rb"].to_a
|
24
|
+
s.require_path = 'core/lib'
|
25
|
+
s.has_rdoc = false
|
26
|
+
|
27
|
+
s.bindir = 'bin'
|
28
|
+
s.executables = ['gettc']
|
29
|
+
|
30
|
+
s.add_dependency 'hpricot'
|
31
|
+
s.add_dependency 'bluecloth'
|
32
|
+
end
|
33
|
+
Gem::PackageTask.new spec do |pkg|
|
34
|
+
pkg.need_tar = true
|
35
|
+
end
|
36
|
+
|
37
|
+
task :clean do
|
38
|
+
if File.exists? 'pkg' then
|
39
|
+
FileUtils.rm_rf 'pkg'
|
40
|
+
end
|
41
|
+
end
|
data/bin/gettc
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
#! /usr/bin/ruby
|
2
|
+
|
3
|
+
require 'topcoder'
|
4
|
+
include TopCoder
|
5
|
+
|
6
|
+
require 'rubygems'
|
7
|
+
require 'fileutils'
|
8
|
+
require 'yaml'
|
9
|
+
|
10
|
+
def root_d
|
11
|
+
gem_d = Gem.loaded_specs['gettc']
|
12
|
+
if gem_d.nil? then
|
13
|
+
return File.join(File.basename(__FILE__), '../')
|
14
|
+
else
|
15
|
+
return gem_d.full_gem_path
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def load_config
|
20
|
+
config_d = File.join File.expand_path('~'), '.gettc'
|
21
|
+
unless Dir.exists? config_d then
|
22
|
+
FileUtils.mkdir config_d
|
23
|
+
default_d = File.join root_d, 'dist/.'
|
24
|
+
FileUtils.cp_r default_d, config_d
|
25
|
+
end
|
26
|
+
config = YAML.load_file File.join(config_d, 'config.yml')
|
27
|
+
account = Account.new config['username'], config['password']
|
28
|
+
source_d = File.join config_d, 'template'
|
29
|
+
return account, source_d
|
30
|
+
end
|
31
|
+
|
32
|
+
def main
|
33
|
+
prog = File.basename __FILE__
|
34
|
+
usage = "Usage: #{prog} <id>\nWhere <id> is the problem ID, eg 11138"
|
35
|
+
if ARGV.empty?
|
36
|
+
puts usage
|
37
|
+
else
|
38
|
+
id = ARGV[0].to_i
|
39
|
+
puts "You have given ID = #{id}"
|
40
|
+
begin
|
41
|
+
account, source_d = load_config
|
42
|
+
robot = Downloader.new account
|
43
|
+
parser = Parser.new robot
|
44
|
+
generator = Generator.new source_d, Dir.getwd
|
45
|
+
|
46
|
+
print 'Downloading problem to raw HTML ... '
|
47
|
+
html = robot.download_problem id
|
48
|
+
puts 'Done'
|
49
|
+
|
50
|
+
print 'Parsing problem from raw HTML ... '
|
51
|
+
prob = parser.parse html
|
52
|
+
puts 'Done'
|
53
|
+
|
54
|
+
print "Generating problem diectory for #{prob.name} ... "
|
55
|
+
generator.generate prob
|
56
|
+
puts 'Done'
|
57
|
+
rescue => err
|
58
|
+
$stderr.puts err
|
59
|
+
exit -1
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
main
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'net/https'
|
2
|
+
require 'cgi'
|
3
|
+
require 'uri'
|
4
|
+
|
5
|
+
module TopCoder
|
6
|
+
class Account
|
7
|
+
attr_accessor :username, :password
|
8
|
+
def initialize username, password
|
9
|
+
@username = username
|
10
|
+
@password = password
|
11
|
+
end
|
12
|
+
def to_s
|
13
|
+
return "#{@username}|#{@password}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
class DownloadError < StandardError
|
17
|
+
end
|
18
|
+
class LoginFailed < DownloadError
|
19
|
+
attr_accessor :account, :cookie
|
20
|
+
def initialize account, cookie, msg = 'Wrong username or password'
|
21
|
+
@account = account
|
22
|
+
@cookie = cookie
|
23
|
+
super "#{msg}\nAccount: #{@account}\nCookie: #{@cookie}\n"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
class IDNotAvailable < DownloadError
|
27
|
+
attr_accessor :id
|
28
|
+
def initialize id, msg = 'ID not available'
|
29
|
+
@id = id
|
30
|
+
super "#{msg} (#{id})"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
class Downloader
|
34
|
+
ROOT = 'http://community.topcoder.com'
|
35
|
+
LIMIT = 10
|
36
|
+
def initialize account
|
37
|
+
@account = account
|
38
|
+
@raw = get_cookie
|
39
|
+
end
|
40
|
+
def get_cookie
|
41
|
+
uri = URI.join(ROOT, 'tc?&module=Login')
|
42
|
+
|
43
|
+
req = Net::HTTP::Post.new uri.request_uri
|
44
|
+
req.set_form_data({'username' => @account.username,
|
45
|
+
'password' => @account.password,
|
46
|
+
'rem' => 'on' })
|
47
|
+
|
48
|
+
http = Net::HTTP.new uri.host, uri.port
|
49
|
+
res = http.request req
|
50
|
+
raw = res['set-cookie']
|
51
|
+
|
52
|
+
cookie = CGI::Cookie.parse raw
|
53
|
+
if cookie['main_user_id_1'].empty? or
|
54
|
+
cookie['main_tcsso_1'].empty? then
|
55
|
+
raise LoginFailed.new @account, cookie
|
56
|
+
end
|
57
|
+
|
58
|
+
return raw
|
59
|
+
end
|
60
|
+
def download url
|
61
|
+
uri = url
|
62
|
+
unless uri.is_a? URI then
|
63
|
+
uri = url.start_with?('http') ? URI.parse(url) : URI.join(ROOT, url)
|
64
|
+
end
|
65
|
+
LIMIT.times do
|
66
|
+
req = Net::HTTP::Get.new uri.request_uri
|
67
|
+
req['cookie'] = @raw
|
68
|
+
|
69
|
+
http = Net::HTTP.new uri.host, uri.port
|
70
|
+
res = http.request req
|
71
|
+
|
72
|
+
return res.body if res.is_a? Net::HTTPSuccess
|
73
|
+
unless res.is_a? Net::HTTPMovedPermanently then
|
74
|
+
raise DownloadError.new res.class.to_s
|
75
|
+
end
|
76
|
+
uri = URI.parse res['location']
|
77
|
+
end
|
78
|
+
raise DownloadError.new "Tried #{LIMIT} times without success"
|
79
|
+
end
|
80
|
+
def download_problem id
|
81
|
+
url = "/stat?c=problem_statement&pm=#{id}"
|
82
|
+
body = download url
|
83
|
+
if body.match('<h3>Problem Statement</h3>').nil? then
|
84
|
+
raise IDNotAvailable.new id
|
85
|
+
end
|
86
|
+
return body
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'erb'
|
3
|
+
|
4
|
+
require 'topcoder/problem'
|
5
|
+
require 'topcoder/signature'
|
6
|
+
require 'topcoder/print'
|
7
|
+
|
8
|
+
module TopCoder
|
9
|
+
class GenerateError < StandardError
|
10
|
+
end
|
11
|
+
class ProblemDirExists < GenerateError
|
12
|
+
attr_accessor :dir
|
13
|
+
def initialize dir, msg = nil
|
14
|
+
if msg.nil? then
|
15
|
+
msg = 'Cannot create problem directory because it already exists'
|
16
|
+
end
|
17
|
+
@dir = dir
|
18
|
+
super "#{msg} (#{dir})"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
class SourceDirNotExist < GenerateError
|
22
|
+
attr_accessor :dir
|
23
|
+
def initialize dir, msg = 'Source directory does not exist'
|
24
|
+
@dir = dir
|
25
|
+
super "#{msg} (#{dir})"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
class TargetDirNotExist < GenerateError
|
29
|
+
attr_accessor :dir
|
30
|
+
def initialize dir, msg = 'Target directory does not exist'
|
31
|
+
@dir = dir
|
32
|
+
super "#{msg} (#{dir})"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
class Generator
|
36
|
+
def initialize source_d, target_d
|
37
|
+
raise SourceDirNotExist.new source_d if not File.directory? source_d
|
38
|
+
raise TargetDirNotExist.new target_d if not File.directory? target_d
|
39
|
+
@source_d = source_d
|
40
|
+
@target_d = target_d
|
41
|
+
end
|
42
|
+
def gen_images images, images_d
|
43
|
+
images.each do |image|
|
44
|
+
filename = File.join images_d, image.name
|
45
|
+
File.open filename, 'wb' do |f| f.write image.content end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
def gen_cases cases, data_d
|
49
|
+
cases.each_index do |i|
|
50
|
+
c = cases[i]
|
51
|
+
File.open File.join(data_d, "#{i.to_s}.in"), 'w' do |f|
|
52
|
+
f.write c.input
|
53
|
+
end
|
54
|
+
File.open File.join(data_d, "#{i.to_s}.out"), 'w' do |f|
|
55
|
+
f.write c.output
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
def gen_template source, target
|
60
|
+
before = File.open source, 'r' do |f| f.read end
|
61
|
+
begin
|
62
|
+
after = ERB.new(before).result @context
|
63
|
+
rescue StandardError => err
|
64
|
+
puts "Template error (#{File.expand_path source}): "
|
65
|
+
puts err.backtrace.join "\n"
|
66
|
+
end
|
67
|
+
File.open target, 'w' do |f| f.write after end
|
68
|
+
end
|
69
|
+
def filter target_d, name
|
70
|
+
if name == '{images_d}' then
|
71
|
+
gen_images @prob.images, target_d
|
72
|
+
elsif name == '{examples_d}' then
|
73
|
+
gen_cases @prob.examples, target_d
|
74
|
+
elsif name == '{systests_d}' then
|
75
|
+
gen_cases @prob.systests, target_d
|
76
|
+
else
|
77
|
+
target_n = name.gsub /\{(\w*)\}/ do |match|
|
78
|
+
@prob.name if $1 == 'name'
|
79
|
+
end
|
80
|
+
return target_n
|
81
|
+
end
|
82
|
+
return nil
|
83
|
+
end
|
84
|
+
def load_engines
|
85
|
+
include_d = File.join File.expand_path('~'), '.gettc/include'
|
86
|
+
return if not File.exists? include_d
|
87
|
+
Dir.foreach include_d do |name|
|
88
|
+
child = File.join include_d, name
|
89
|
+
if File.directory? child then
|
90
|
+
engine = File.join child, 'engine.rb'
|
91
|
+
require engine if File.exists? engine
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
def walk source_d, target_d
|
96
|
+
Dir.foreach source_d do |name|
|
97
|
+
if name != '.' and name != '..' then
|
98
|
+
source_p = File.join source_d, name
|
99
|
+
target_n = filter target_d, name
|
100
|
+
if not target_n.nil? then
|
101
|
+
target_p = File.join target_d, target_n
|
102
|
+
if File.directory? source_p then
|
103
|
+
FileUtils.mkdir target_p if not File.exists? target_p
|
104
|
+
walk source_p, target_p
|
105
|
+
elsif File.file? source_p then
|
106
|
+
gen_template source_p, target_p
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
def generate prob
|
113
|
+
@prob = prob
|
114
|
+
@prob_d = File.join @target_d, prob.name
|
115
|
+
raise ProblemDirExists.new @prob_d if File.exists? @prob_d
|
116
|
+
FileUtils.mkdir @prob_d
|
117
|
+
|
118
|
+
method_sig = @prob.definitions['Method signature']
|
119
|
+
if method_sig.nil? then
|
120
|
+
$stderr.puts '[Warning] No definition for method signature found'
|
121
|
+
else
|
122
|
+
vars = parse_method_signature method_sig
|
123
|
+
func = vars.shift
|
124
|
+
end
|
125
|
+
@context = binding
|
126
|
+
|
127
|
+
load_engines
|
128
|
+
walk @source_d, @prob_d
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,231 @@
|
|
1
|
+
require 'topcoder/problem'
|
2
|
+
require 'topcoder/download'
|
3
|
+
|
4
|
+
require 'uri'
|
5
|
+
require 'pathname'
|
6
|
+
require 'hpricot'
|
7
|
+
|
8
|
+
module TopCoder
|
9
|
+
class Parser
|
10
|
+
def initialize downloader
|
11
|
+
@downloader = downloader
|
12
|
+
@images = []
|
13
|
+
end
|
14
|
+
|
15
|
+
## @section Utils
|
16
|
+
|
17
|
+
def indexes str, substr
|
18
|
+
from = str.index substr
|
19
|
+
return nil if from.nil?
|
20
|
+
to = from + substr.size
|
21
|
+
return from - 1, to
|
22
|
+
end
|
23
|
+
def filter html
|
24
|
+
unless html.valid_encoding? then
|
25
|
+
html = html.encode Encoding::UTF_8, invaid: :replace, undef: :replace, replace: ''
|
26
|
+
end
|
27
|
+
html.gsub! /<b>(\w*)<\/b>/ do |match| "*#{$1}*" end
|
28
|
+
html.gsub! /<sup>(\w*)<\/sup>/ do |match| "^(#{$1})" end
|
29
|
+
html.gsub! ' ', ''
|
30
|
+
html.gsub! ' ', ' '
|
31
|
+
text = Hpricot(html).to_plain_text
|
32
|
+
text.gsub! /\[img:(http:\/\/[^\]]*)\]/ do |match|
|
33
|
+
url = $1
|
34
|
+
image = Image.new
|
35
|
+
image.name = Pathname.new(url).basename
|
36
|
+
begin
|
37
|
+
image.content = @downloader.download url
|
38
|
+
@images << image
|
39
|
+
"![image](images/#{image.name})"
|
40
|
+
rescue StandardError
|
41
|
+
"![image](#{url})"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
return text
|
45
|
+
end
|
46
|
+
def h3 tag
|
47
|
+
return "<h3>#{tag}</h3>"
|
48
|
+
end
|
49
|
+
|
50
|
+
## @section Parse problem parts
|
51
|
+
|
52
|
+
def parse_name html
|
53
|
+
html.sub! 'Problem Statement for', ''
|
54
|
+
return filter html
|
55
|
+
end
|
56
|
+
def parse_statement html
|
57
|
+
return filter html
|
58
|
+
end
|
59
|
+
def parse_definitions html
|
60
|
+
defs = { }
|
61
|
+
Hpricot(html).search '/tr/td.statText/table/tr' do |tr|
|
62
|
+
tds = tr.search '/td.statText'
|
63
|
+
if tds.size == 2 then
|
64
|
+
key = tds[0].to_plain_text[0 .. -2]
|
65
|
+
value = tds[1].to_plain_text
|
66
|
+
defs[key] = value
|
67
|
+
end
|
68
|
+
end
|
69
|
+
return defs
|
70
|
+
end
|
71
|
+
def parse_notes html
|
72
|
+
notes = []
|
73
|
+
Hpricot(html).search '/tr' do |tr|
|
74
|
+
tds = tr.search '/td.statText'
|
75
|
+
notes << filter(tds[1].html) if tds.size == 2
|
76
|
+
end
|
77
|
+
return notes
|
78
|
+
end
|
79
|
+
def parse_constraints html
|
80
|
+
return parse_notes html
|
81
|
+
end
|
82
|
+
|
83
|
+
## @section Parse cases
|
84
|
+
|
85
|
+
def filter_inout text
|
86
|
+
text.gsub! '{', '['
|
87
|
+
text.gsub! '}', ']'
|
88
|
+
return text.strip
|
89
|
+
end
|
90
|
+
def parse_input html
|
91
|
+
text = nil
|
92
|
+
Hpricot(html).search '/table/tr/td.statText' do |td|
|
93
|
+
input = td.to_plain_text.strip
|
94
|
+
if text.nil? then
|
95
|
+
text = input
|
96
|
+
else
|
97
|
+
text << ",\n" << input
|
98
|
+
end
|
99
|
+
end
|
100
|
+
return filter_inout text
|
101
|
+
end
|
102
|
+
def parse_output html
|
103
|
+
text = Hpricot(html).to_plain_text
|
104
|
+
text.sub! 'Returns: ', ''
|
105
|
+
return filter_inout text
|
106
|
+
end
|
107
|
+
def parse_reason html
|
108
|
+
return filter html
|
109
|
+
end
|
110
|
+
def parse_examples html
|
111
|
+
examples = []
|
112
|
+
tds = Hpricot(html).search('/tr/td.statText/table/tr/td.statText')
|
113
|
+
i = 0
|
114
|
+
while i < tds.size do
|
115
|
+
example = Case.new
|
116
|
+
example.input = parse_input tds[i].html
|
117
|
+
example.output = parse_output tds[i += 1].html
|
118
|
+
example.reason = parse_reason tds[i += 1].html
|
119
|
+
examples << example
|
120
|
+
i += 1
|
121
|
+
end
|
122
|
+
return examples
|
123
|
+
end
|
124
|
+
def parse_systests html
|
125
|
+
systests = []
|
126
|
+
_, y = indexes html, '<!-- System Testing -->'
|
127
|
+
z, _ = indexes html, '<!-- End System Testing -->'
|
128
|
+
return systests if not y or not z
|
129
|
+
Hpricot(html[y .. z]).search '/table/tr[@valign=top]' do |tr|
|
130
|
+
tds = tr.search '/td.statText'
|
131
|
+
if tds.size == 3 then
|
132
|
+
test = Case.new
|
133
|
+
test.input = filter_inout tds[0].to_plain_text
|
134
|
+
test.output = filter_inout tds[1].to_plain_text
|
135
|
+
systests << test
|
136
|
+
end
|
137
|
+
end
|
138
|
+
return systests
|
139
|
+
end
|
140
|
+
def download_systests detail_url
|
141
|
+
detail = @downloader.download detail_url
|
142
|
+
Hpricot(detail).search 'a[@href^=/stat?c=problem_solution]' do |url|
|
143
|
+
solution = @downloader.download url.attributes['href']
|
144
|
+
systests = parse_systests solution
|
145
|
+
return systests if not systests.empty?
|
146
|
+
end
|
147
|
+
return []
|
148
|
+
end
|
149
|
+
def parse_details doc
|
150
|
+
url, source, systests = '', '', []
|
151
|
+
doc.search 'a[@href^=/tc?module=ProblemDetail]' do |elem|
|
152
|
+
url = URI.join(Downloader::ROOT, elem.attributes['href']).to_s
|
153
|
+
source = filter elem.html
|
154
|
+
begin
|
155
|
+
systests = download_systests url
|
156
|
+
unless systests.empty? then
|
157
|
+
return url, source, systests
|
158
|
+
end
|
159
|
+
rescue DownloadError
|
160
|
+
end
|
161
|
+
end
|
162
|
+
return url, source, systests
|
163
|
+
end
|
164
|
+
|
165
|
+
## @section Main method
|
166
|
+
|
167
|
+
def parse html
|
168
|
+
@images = []
|
169
|
+
prob = Problem.new
|
170
|
+
doc = Hpricot(html)
|
171
|
+
|
172
|
+
prob.name = parse_name doc.search('tr/td.statTextBig').html
|
173
|
+
prob.notes = nil
|
174
|
+
prob.constraints = nil
|
175
|
+
prob.examples = nil
|
176
|
+
|
177
|
+
html = doc.search('td.problemText/table').html
|
178
|
+
|
179
|
+
_, x = indexes html, h3('Problem Statement')
|
180
|
+
y, z = indexes html, h3('Definition')
|
181
|
+
prob.statement = parse_statement html[x .. y]
|
182
|
+
|
183
|
+
x, y = indexes html, h3('Notes')
|
184
|
+
if x.nil? then
|
185
|
+
prob.notes = []
|
186
|
+
x, y = indexes html, h3('Constraints')
|
187
|
+
if x.nil? then
|
188
|
+
prob.constraints = []
|
189
|
+
x, y = indexes html, h3('Examples')
|
190
|
+
if x.nil? then
|
191
|
+
prob.examples = []
|
192
|
+
x = -2
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
prob.definitions = parse_definitions html[z .. x]
|
197
|
+
|
198
|
+
if prob.notes.nil? then
|
199
|
+
z, x = indexes html, h3('Constraints')
|
200
|
+
if z.nil? then
|
201
|
+
prob.constraints = []
|
202
|
+
z, x = indexes html, h3('Examples')
|
203
|
+
if z.nil? then
|
204
|
+
prob.examples = []
|
205
|
+
z = - 2
|
206
|
+
end
|
207
|
+
end
|
208
|
+
prob.notes = parse_notes html[y .. z]
|
209
|
+
x, y = z, x
|
210
|
+
end
|
211
|
+
|
212
|
+
if prob.constraints.nil? then
|
213
|
+
z, x = indexes html, h3('Examples')
|
214
|
+
if z.nil? then
|
215
|
+
prob.examples = []
|
216
|
+
z = -2
|
217
|
+
end
|
218
|
+
prob.constraints = parse_constraints html[y .. z]
|
219
|
+
end
|
220
|
+
|
221
|
+
if prob.examples.nil? then
|
222
|
+
prob.examples = parse_examples html[x .. -2]
|
223
|
+
end
|
224
|
+
|
225
|
+
prob.images = @images
|
226
|
+
prob.url, prob.source, prob.systests = parse_details doc
|
227
|
+
|
228
|
+
return prob
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|