review 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +1 -2
- data/ChangeLog +65 -0
- data/Gemfile +5 -0
- data/README.rdoc +6 -1
- data/Rakefile +14 -28
- data/bin/review-check +9 -21
- data/bin/review-compile +45 -12
- data/bin/review-epubmaker +477 -220
- data/bin/review-epubmaker-ng +5 -14
- data/bin/review-index +4 -2
- data/bin/review-init +94 -0
- data/bin/review-pdfmaker +70 -287
- data/bin/review-preproc +5 -2
- data/bin/review-vol +4 -11
- data/debian/changelog +3 -3
- data/debian/copyright +5 -3
- data/debian/docs +1 -0
- data/doc/format.rdoc +57 -11
- data/doc/quickstart.rdoc +4 -4
- data/doc/sample.yaml +11 -7
- data/lib/epubmaker.rb +1 -1
- data/lib/epubmaker/epubv2.rb +26 -27
- data/lib/epubmaker/epubv3.rb +13 -13
- data/lib/epubmaker/producer.rb +1 -1
- data/lib/review.rb +3 -4
- data/lib/review/book.rb +17 -581
- data/lib/review/book/base.rb +247 -0
- data/lib/review/book/chapter.rb +81 -0
- data/lib/review/book/compilable.rb +163 -0
- data/lib/review/book/index.rb +339 -0
- data/lib/review/book/page_metric.rb +38 -0
- data/lib/review/book/parameters.rb +97 -0
- data/lib/review/book/part.rb +44 -0
- data/lib/review/book/volume.rb +65 -0
- data/lib/review/builder.rb +34 -40
- data/lib/review/compiler.rb +32 -13
- data/lib/review/configure.rb +38 -0
- data/lib/review/ewbbuilder.rb +23 -21
- data/lib/review/extentions.rb +3 -0
- data/lib/review/extentions/object.rb +9 -0
- data/lib/review/{compat.rb → extentions/string.rb} +11 -0
- data/lib/review/htmlbuilder.rb +162 -74
- data/lib/review/htmlutils.rb +28 -1
- data/lib/review/i18n.yaml +11 -0
- data/lib/review/idgxmlbuilder.rb +119 -35
- data/lib/review/inaobuilder.rb +355 -0
- data/lib/review/latexbuilder.rb +133 -59
- data/lib/review/latexutils.rb +15 -6
- data/lib/review/makerhelper.rb +59 -0
- data/lib/review/markdownbuilder.rb +129 -0
- data/lib/review/preprocessor.rb +20 -7
- data/lib/review/review.tex.erb +250 -0
- data/lib/review/textutils.rb +28 -3
- data/lib/review/tocparser.rb +20 -12
- data/lib/review/tocprinter.rb +7 -3
- data/lib/review/topbuilder.rb +44 -27
- data/lib/review/version.rb +3 -0
- data/review.gemspec +20 -117
- data/test/book_test_helper.rb +35 -0
- data/test/sample-book/README.md +5 -0
- data/test/sample-book/src/CHAPS +2 -0
- data/test/sample-book/src/PREDEF +1 -0
- data/test/sample-book/src/Rakefile +26 -0
- data/test/sample-book/src/_cover.html +3 -0
- data/test/sample-book/src/ch01.re +71 -0
- data/test/sample-book/src/ch02.re +3 -0
- data/test/sample-book/src/config.yml +55 -0
- data/test/sample-book/src/images/ch01-imgsample.jpg +0 -0
- data/test/sample-book/src/images/cover.jpg +0 -0
- data/test/sample-book/src/main.css +251 -0
- data/test/sample-book/src/preface.re +15 -0
- data/test/sample-book/src/sty/jumoline.sty +310 -0
- data/test/sample-book/src/sty/samplemacro.sty +21 -0
- data/test/sample-book/src/vendor/jumoline/README +29 -0
- data/test/sample-book/src/vendor/jumoline/jumoline.dtx +2988 -0
- data/test/sample-book/src/vendor/jumoline/jumoline.ins +6 -0
- data/test/test_book.rb +26 -646
- data/test/test_book_chapter.rb +418 -0
- data/test/test_book_parameter.rb +42 -0
- data/test/test_book_part.rb +53 -0
- data/test/test_builder.rb +17 -10
- data/test/test_compiler.rb +46 -0
- data/test/test_epubmaker.rb +1 -1
- data/test/test_epubmaker_cmd.rb +36 -0
- data/test/test_helper.rb +17 -0
- data/test/test_htmlbuilder.rb +156 -24
- data/test/test_htmlutils.rb +4 -0
- data/test/test_i18n.rb +6 -2
- data/test/test_idgxmlbuilder.rb +33 -11
- data/test/test_inaobuilder.rb +247 -0
- data/test/test_index.rb +31 -0
- data/test/test_latexbuilder.rb +115 -35
- data/test/test_makerhelper.rb +50 -0
- data/test/test_pdfmaker_cmd.rb +36 -0
- data/test/test_preprocessor.rb +7 -7
- data/test/test_topbuilder.rb +6 -7
- data/test/test_uuid.rb +1 -0
- metadata +117 -12
- data/lib/review/index.rb +0 -323
- data/lib/review/volume.rb +0 -66
@@ -0,0 +1,247 @@
|
|
1
|
+
#
|
2
|
+
# $Id: book.rb 4315 2009-09-02 04:15:24Z kmuto $
|
3
|
+
#
|
4
|
+
# Copyright (c) 2002-2008 Minero Aoki
|
5
|
+
# 2009 Minero Aoki, Kenshi Muto
|
6
|
+
#
|
7
|
+
# This program is free software.
|
8
|
+
# You can distribute or modify this program under the terms of
|
9
|
+
# the GNU LGPL, Lesser General Public License version 2.1.
|
10
|
+
# For details of the GNU LGPL, see the file "COPYING".
|
11
|
+
#
|
12
|
+
module ReVIEW
|
13
|
+
module Book
|
14
|
+
class Base
|
15
|
+
|
16
|
+
attr_accessor :param
|
17
|
+
|
18
|
+
def self.load_default
|
19
|
+
%w( . .. ../.. ).each do |basedir|
|
20
|
+
if File.file?("#{basedir}/CHAPS")
|
21
|
+
book = load(basedir)
|
22
|
+
if File.file?("#{basedir}/config.rb")
|
23
|
+
book.instance_variable_set("@parameters", Parameters.load("#{basedir}/config.rb"))
|
24
|
+
end
|
25
|
+
return book
|
26
|
+
end
|
27
|
+
end
|
28
|
+
new('.')
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.load(dir)
|
32
|
+
update_rubyenv dir
|
33
|
+
new(dir)
|
34
|
+
end
|
35
|
+
|
36
|
+
@basedir_seen = {}
|
37
|
+
|
38
|
+
def self.update_rubyenv(dir)
|
39
|
+
return if @basedir_seen.key?(dir)
|
40
|
+
if File.directory?("#{dir}/lib/review")
|
41
|
+
$LOAD_PATH.unshift "#{dir}/lib"
|
42
|
+
end
|
43
|
+
if File.file?("#{dir}/review-ext.rb")
|
44
|
+
Kernel.load File.expand_path("#{dir}/review-ext.rb")
|
45
|
+
end
|
46
|
+
@basedir_seen[dir] = true
|
47
|
+
end
|
48
|
+
|
49
|
+
def initialize(basedir, parameters = Parameters.default)
|
50
|
+
@basedir = basedir
|
51
|
+
@parameters = parameters
|
52
|
+
@parts = nil
|
53
|
+
@chapter_index = nil
|
54
|
+
end
|
55
|
+
|
56
|
+
extend Forwardable
|
57
|
+
def_delegators '@parameters',
|
58
|
+
:chapter_file,
|
59
|
+
:part_file,
|
60
|
+
:bib_file,
|
61
|
+
:reject_file,
|
62
|
+
:predef_file,
|
63
|
+
:postdef_file,
|
64
|
+
:ext,
|
65
|
+
:image_dir,
|
66
|
+
:image_types,
|
67
|
+
:page_metric
|
68
|
+
|
69
|
+
def parts
|
70
|
+
@parts ||= read_parts()
|
71
|
+
end
|
72
|
+
|
73
|
+
def parts_in_file
|
74
|
+
parts.find_all{|part|
|
75
|
+
part if part.present? and part.file?
|
76
|
+
}
|
77
|
+
end
|
78
|
+
|
79
|
+
def part(n)
|
80
|
+
parts.detect {|part| part.number == n }
|
81
|
+
end
|
82
|
+
|
83
|
+
def each_part(&block)
|
84
|
+
parts.each(&block)
|
85
|
+
end
|
86
|
+
|
87
|
+
def chapters
|
88
|
+
parts().map {|p| p.chapters }.flatten
|
89
|
+
end
|
90
|
+
|
91
|
+
def each_chapter(&block)
|
92
|
+
chapters.each(&block)
|
93
|
+
end
|
94
|
+
|
95
|
+
def chapter_index
|
96
|
+
@chapter_index ||= ChapterIndex.new(chapters())
|
97
|
+
@chapter_index
|
98
|
+
end
|
99
|
+
|
100
|
+
def chapter(id)
|
101
|
+
chapter_index()[id]
|
102
|
+
end
|
103
|
+
|
104
|
+
def volume
|
105
|
+
Volume.sum(chapters.map {|chap| chap.volume })
|
106
|
+
end
|
107
|
+
|
108
|
+
def read_CHAPS
|
109
|
+
read_FILE("chapter_file")
|
110
|
+
end
|
111
|
+
|
112
|
+
def read_PREDEF
|
113
|
+
read_FILE("predef_file")
|
114
|
+
end
|
115
|
+
|
116
|
+
def read_POSTDEF
|
117
|
+
read_FILE("postdef_file")
|
118
|
+
end
|
119
|
+
|
120
|
+
def read_PART
|
121
|
+
@read_PART ||= File.read("#{@basedir}/#{part_file}")
|
122
|
+
end
|
123
|
+
|
124
|
+
def part_exist?
|
125
|
+
File.exist?("#{@basedir}/#{part_file}")
|
126
|
+
end
|
127
|
+
|
128
|
+
def read_bib
|
129
|
+
File.read("#{@basedir}/#{bib_file}")
|
130
|
+
end
|
131
|
+
|
132
|
+
def bib_exist?
|
133
|
+
File.exist?("#{@basedir}/#{bib_file}")
|
134
|
+
end
|
135
|
+
|
136
|
+
def prefaces
|
137
|
+
if File.file?("#{@basedir}/#{predef_file}")
|
138
|
+
begin
|
139
|
+
return mkpart_from_namelistfile("#{@basedir}/#{predef_file}")
|
140
|
+
rescue FileNotFound => err
|
141
|
+
raise FileNotFound, "preface #{err.message}"
|
142
|
+
end
|
143
|
+
else
|
144
|
+
mkpart_from_namelist(%w(preface))
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def postscripts
|
149
|
+
if File.file?("#{@basedir}/#{postdef_file}")
|
150
|
+
begin
|
151
|
+
return mkpart_from_namelistfile("#{@basedir}/#{postdef_file}")
|
152
|
+
rescue FileNotFound => err
|
153
|
+
raise FileNotFound, "postscript #{err.message}"
|
154
|
+
end
|
155
|
+
else
|
156
|
+
mkpart_from_namelist(%w(appendix postscript))
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def basedir
|
161
|
+
@basedir
|
162
|
+
end
|
163
|
+
|
164
|
+
private
|
165
|
+
|
166
|
+
def read_parts
|
167
|
+
list = parse_chapters
|
168
|
+
if pre = prefaces
|
169
|
+
list.unshift pre
|
170
|
+
end
|
171
|
+
if post = postscripts
|
172
|
+
list.push post
|
173
|
+
end
|
174
|
+
list
|
175
|
+
end
|
176
|
+
|
177
|
+
def parse_chapters
|
178
|
+
part = 0
|
179
|
+
num = 0
|
180
|
+
chap = read_CHAPS()\
|
181
|
+
.strip.lines.map {|line| line.strip }.join("\n").split(/\n{2,}/)\
|
182
|
+
.map {|part_chunk|
|
183
|
+
chaps = part_chunk.split.map {|chapid|
|
184
|
+
Chapter.new(self, (num += 1), chapid, "#{@basedir}/#{chapid}")
|
185
|
+
}
|
186
|
+
if part_exist? && read_PART.split("\n").size >= part
|
187
|
+
Part.new(self, (part += 1), chaps, read_PART.split("\n")[part-1])
|
188
|
+
else
|
189
|
+
Part.new(self, (part += 1), chaps)
|
190
|
+
end
|
191
|
+
}
|
192
|
+
return chap
|
193
|
+
end
|
194
|
+
|
195
|
+
def mkpart_from_namelistfile(path)
|
196
|
+
chaps = []
|
197
|
+
File.read(path).split.each_with_index do |name, idx|
|
198
|
+
name.sub!(/\A\xEF\xBB\xBF/u, '') # remove BOM
|
199
|
+
if path =~ /PREDEF/
|
200
|
+
chaps << mkchap(name)
|
201
|
+
else
|
202
|
+
chaps << mkchap(name, idx + 1)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
mkpart(chaps)
|
206
|
+
end
|
207
|
+
|
208
|
+
def mkpart_from_namelist(names)
|
209
|
+
mkpart(names.map {|n| mkchap_ifexist(n) }.compact)
|
210
|
+
end
|
211
|
+
|
212
|
+
def mkpart(chaps)
|
213
|
+
chaps.empty? ? nil : Part.new(self, nil, chaps)
|
214
|
+
end
|
215
|
+
|
216
|
+
def mkchap(name, number = nil)
|
217
|
+
name += ext if File.extname(name) == ""
|
218
|
+
path = "#{@basedir}/#{name}"
|
219
|
+
raise FileNotFound, "file not exist: #{path}" unless File.file?(path)
|
220
|
+
Chapter.new(self, number, name, path)
|
221
|
+
end
|
222
|
+
|
223
|
+
def mkchap_ifexist(id)
|
224
|
+
name = "#{id}#{ext()}"
|
225
|
+
path = "#{@basedir}/#{name}"
|
226
|
+
File.file?(path) ? Chapter.new(self, nil, name, path) : nil
|
227
|
+
end
|
228
|
+
|
229
|
+
def read_FILE(filename)
|
230
|
+
res = ""
|
231
|
+
File.open("#{@basedir}/#{eval(filename)}") do |f|
|
232
|
+
while line = f.gets
|
233
|
+
line.sub!(/\A\xEF\xBB\xBF/u, '') # remove BOM
|
234
|
+
if /\A#/ =~ line
|
235
|
+
next
|
236
|
+
end
|
237
|
+
line.gsub!(/#.*$/, "")
|
238
|
+
res << line
|
239
|
+
end
|
240
|
+
end
|
241
|
+
res
|
242
|
+
rescue Errno::ENOENT
|
243
|
+
Dir.glob("#{@basedir}/*#{ext()}").sort.join("\n")
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
#
|
2
|
+
# $Id: book.rb 4315 2009-09-02 04:15:24Z kmuto $
|
3
|
+
#
|
4
|
+
# Copyright (c) 2002-2008 Minero Aoki
|
5
|
+
# 2009 Minero Aoki, Kenshi Muto
|
6
|
+
#
|
7
|
+
# This program is free software.
|
8
|
+
# You can distribute or modify this program under the terms of
|
9
|
+
# the GNU LGPL, Lesser General Public License version 2.1.
|
10
|
+
# For details of the GNU LGPL, see the file "COPYING".
|
11
|
+
#
|
12
|
+
require 'review/book/compilable'
|
13
|
+
module ReVIEW
|
14
|
+
module Book
|
15
|
+
class Chapter
|
16
|
+
include Compilable
|
17
|
+
|
18
|
+
def Chapter.intern_pathes(pathes)
|
19
|
+
books = {}
|
20
|
+
pathes.map {|path|
|
21
|
+
basedir = File.dirname(path)
|
22
|
+
book = (books[File.expand_path(basedir)] ||= Book.load(basedir))
|
23
|
+
begin
|
24
|
+
book.chapter(File.basename(path, '.*'))
|
25
|
+
rescue KeyError => err
|
26
|
+
raise FileNotFound, "no such file: #{path}"
|
27
|
+
end
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
def Chapter.for_stdin
|
32
|
+
new(nil, nil, '-', nil, $stdin)
|
33
|
+
end
|
34
|
+
|
35
|
+
def Chapter.for_path(number, path)
|
36
|
+
new(nil, number, File.basename(path), path)
|
37
|
+
end
|
38
|
+
|
39
|
+
attr_reader :number
|
40
|
+
|
41
|
+
def initialize(book, number, name, path, io = nil)
|
42
|
+
@book = book
|
43
|
+
@number = number
|
44
|
+
@name = name
|
45
|
+
@path = path
|
46
|
+
@io = io
|
47
|
+
@title = nil
|
48
|
+
@content = nil
|
49
|
+
@list_index = nil
|
50
|
+
@table_index = nil
|
51
|
+
@footnote_index = nil
|
52
|
+
@image_index = nil
|
53
|
+
@icon_index = nil
|
54
|
+
@numberless_image_index = nil
|
55
|
+
@indepimage_index = nil
|
56
|
+
@headline_index = nil
|
57
|
+
end
|
58
|
+
|
59
|
+
def inspect
|
60
|
+
"\#<#{self.class} #{@number} #{@path}>"
|
61
|
+
end
|
62
|
+
|
63
|
+
def on_CHAPS?
|
64
|
+
on_FILE?(@book.read_CHAPS())
|
65
|
+
end
|
66
|
+
|
67
|
+
def on_PREDEF?
|
68
|
+
on_FILE?(@book.read_PREDEF())
|
69
|
+
end
|
70
|
+
|
71
|
+
def on_POSTDEF?
|
72
|
+
on_FILE?(@book.read_POSTDEF())
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
def on_FILE?(contents)
|
77
|
+
contents.lines.map(&:strip).include?(id() + @book.ext())
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,163 @@
|
|
1
|
+
#
|
2
|
+
# $Id: book.rb 4315 2009-09-02 04:15:24Z kmuto $
|
3
|
+
#
|
4
|
+
# Copyright (c) 2002-2008 Minero Aoki
|
5
|
+
# 2009 Minero Aoki, Kenshi Muto
|
6
|
+
#
|
7
|
+
# This program is free software.
|
8
|
+
# You can distribute or modify this program under the terms of
|
9
|
+
# the GNU LGPL, Lesser General Public License version 2.1.
|
10
|
+
# For details of the GNU LGPL, see the file "COPYING".
|
11
|
+
#
|
12
|
+
require 'review/textutils'
|
13
|
+
module ReVIEW
|
14
|
+
module Book
|
15
|
+
module Compilable
|
16
|
+
include TextUtils
|
17
|
+
attr_reader :book
|
18
|
+
attr_reader :path
|
19
|
+
|
20
|
+
def env
|
21
|
+
@book
|
22
|
+
end
|
23
|
+
|
24
|
+
def dirname
|
25
|
+
return nil unless @path
|
26
|
+
File.dirname(@path)
|
27
|
+
end
|
28
|
+
|
29
|
+
def basename
|
30
|
+
return nil unless @path
|
31
|
+
File.basename(@path)
|
32
|
+
end
|
33
|
+
|
34
|
+
def name
|
35
|
+
File.basename(@name, '.*')
|
36
|
+
end
|
37
|
+
|
38
|
+
alias id name
|
39
|
+
|
40
|
+
def title
|
41
|
+
@title = ""
|
42
|
+
open {|f|
|
43
|
+
f.each_line {|l|
|
44
|
+
l = convert_inencoding(l, ReVIEW.book.param["inencoding"])
|
45
|
+
if l =~ /\A=+/
|
46
|
+
@title = l.sub(/\A=+/, '').strip
|
47
|
+
break
|
48
|
+
end
|
49
|
+
}
|
50
|
+
}
|
51
|
+
@title
|
52
|
+
end
|
53
|
+
|
54
|
+
def size
|
55
|
+
File.size(path())
|
56
|
+
end
|
57
|
+
|
58
|
+
def volume
|
59
|
+
@volume ||= Volume.count_file(path())
|
60
|
+
end
|
61
|
+
|
62
|
+
def open(&block)
|
63
|
+
return (block_given?() ? yield(@io) : @io) if @io
|
64
|
+
File.open(path(), &block)
|
65
|
+
end
|
66
|
+
|
67
|
+
attr_writer :content
|
68
|
+
|
69
|
+
def content
|
70
|
+
@content = convert_inencoding(File.read(path()),
|
71
|
+
ReVIEW.book.param["inencoding"])
|
72
|
+
rescue
|
73
|
+
@content
|
74
|
+
end
|
75
|
+
|
76
|
+
def lines
|
77
|
+
# FIXME: we cannot duplicate Enumerator on ruby 1.9 HEAD
|
78
|
+
(@lines ||= content().lines.to_a).dup
|
79
|
+
end
|
80
|
+
|
81
|
+
def list(id)
|
82
|
+
list_index()[id]
|
83
|
+
end
|
84
|
+
|
85
|
+
def list_index
|
86
|
+
@list_index ||= ListIndex.parse(lines())
|
87
|
+
@list_index
|
88
|
+
end
|
89
|
+
|
90
|
+
def table(id)
|
91
|
+
table_index()[id]
|
92
|
+
end
|
93
|
+
|
94
|
+
def table_index
|
95
|
+
@table_index ||= TableIndex.parse(lines())
|
96
|
+
@table_index
|
97
|
+
end
|
98
|
+
|
99
|
+
def footnote(id)
|
100
|
+
footnote_index()[id]
|
101
|
+
end
|
102
|
+
|
103
|
+
def footnote_index
|
104
|
+
@footnote_index ||= FootnoteIndex.parse(lines())
|
105
|
+
@footnote_index
|
106
|
+
end
|
107
|
+
|
108
|
+
def image(id)
|
109
|
+
return image_index()[id] if image_index().has_key?(id)
|
110
|
+
return icon_index()[id] if icon_index().has_key?(id)
|
111
|
+
return numberless_image_index()[id] if numberless_image_index().has_key?(id)
|
112
|
+
indepimage_index()[id]
|
113
|
+
end
|
114
|
+
|
115
|
+
def numberless_image_index
|
116
|
+
@numberless_image_index ||=
|
117
|
+
NumberlessImageIndex.parse(lines(), id(),
|
118
|
+
"#{book.basedir}#{@book.image_dir}",
|
119
|
+
@book.image_types)
|
120
|
+
end
|
121
|
+
|
122
|
+
def image_index
|
123
|
+
@image_index ||= ImageIndex.parse(lines(), id(),
|
124
|
+
"#{book.basedir}#{@book.image_dir}",
|
125
|
+
@book.image_types)
|
126
|
+
@image_index
|
127
|
+
end
|
128
|
+
|
129
|
+
def icon_index
|
130
|
+
@icon_index ||= IconIndex.parse(lines(), id(),
|
131
|
+
"#{book.basedir}#{@book.image_dir}",
|
132
|
+
@book.image_types)
|
133
|
+
@icon_index
|
134
|
+
end
|
135
|
+
|
136
|
+
def indepimage_index
|
137
|
+
@indepimage_index ||=
|
138
|
+
IndepImageIndex.parse(lines(), id(),
|
139
|
+
"#{book.basedir}#{@book.image_dir}",
|
140
|
+
@book.image_types)
|
141
|
+
end
|
142
|
+
|
143
|
+
def bibpaper(id)
|
144
|
+
bibpaper_index()[id]
|
145
|
+
end
|
146
|
+
|
147
|
+
def bibpaper_index
|
148
|
+
raise FileNotFound, "no such bib file: #{@book.bib_file}" unless @book.bib_exist?
|
149
|
+
@bibpaper_index ||= BibpaperIndex.parse(@book.read_bib.lines.to_a)
|
150
|
+
@bibpaper_index
|
151
|
+
end
|
152
|
+
|
153
|
+
def headline(caption)
|
154
|
+
headline_index()[caption]
|
155
|
+
end
|
156
|
+
|
157
|
+
def headline_index
|
158
|
+
@headline_index ||= HeadlineIndex.parse(lines(), self)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|