gettc 1.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
""
|
40
|
+
rescue StandardError
|
41
|
+
""
|
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
|