isodoc 1.7.1 → 1.7.4
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 +4 -4
- data/isodoc.gemspec +2 -1
- data/lib/isodoc/convert.rb +1 -0
- data/lib/isodoc/css.rb +3 -3
- data/lib/isodoc/function/blocks.rb +180 -168
- data/lib/isodoc/function/blocks_example_note.rb +85 -79
- data/lib/isodoc/function/cleanup.rb +181 -175
- data/lib/isodoc/function/inline.rb +110 -108
- data/lib/isodoc/function/inline_simple.rb +55 -55
- data/lib/isodoc/function/lists.rb +75 -71
- data/lib/isodoc/function/references.rb +165 -160
- data/lib/isodoc/function/reqt.rb +91 -85
- data/lib/isodoc/function/section.rb +140 -190
- data/lib/isodoc/function/section_titles.rb +82 -0
- data/lib/isodoc/function/table.rb +90 -87
- data/lib/isodoc/function/terms.rb +58 -56
- data/lib/isodoc/function/to_word_html.rb +208 -204
- data/lib/isodoc/html_convert.rb +0 -4
- data/lib/isodoc/html_function/mathvariant_to_plain.rb +5 -3
- data/lib/isodoc/presentation_function/inline.rb +1 -1
- data/lib/isodoc/presentation_function/math.rb +9 -0
- data/lib/isodoc/presentation_function/section.rb +12 -1
- data/lib/isodoc/presentation_xml_convert.rb +2 -0
- data/lib/isodoc/version.rb +1 -1
- data/lib/isodoc/word_function/body.rb +5 -5
- data/lib/isodoc/xslfo_convert.rb +2 -2
- data/lib/isodoc.rb +2 -1
- data/lib/metanorma/output/base.rb +13 -0
- data/lib/metanorma/output/utils.rb +17 -0
- data/lib/metanorma/output/xslfo.rb +21 -0
- data/lib/metanorma/output.rb +7 -0
- data/spec/assets/outputtest/a.xml +66 -0
- data/spec/assets/outputtest/iso.international-standard.xsl +3011 -0
- data/spec/isodoc/blocks_spec.rb +441 -243
- data/spec/isodoc/inline_spec.rb +197 -114
- data/spec/isodoc/postproc_spec.rb +2 -2
- data/spec/isodoc/presentation_xml_spec.rb +84 -0
- data/spec/isodoc/section_spec.rb +639 -0
- metadata +23 -18
- data/lib/isodoc/html_function/sectionsplit.rb +0 -244
- data/spec/isodoc/sectionsplit_spec.rb +0 -190
@@ -1,107 +1,113 @@
|
|
1
|
-
module IsoDoc
|
2
|
-
module
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
1
|
+
module IsoDoc
|
2
|
+
module Function
|
3
|
+
module Blocks
|
4
|
+
def example_label(_node, div, name)
|
5
|
+
return if name.nil?
|
6
|
+
|
7
|
+
div.p **{ class: "example-title" } do |_p|
|
8
|
+
name.children.each { |n| parse(n, div) }
|
9
|
+
end
|
7
10
|
end
|
8
|
-
end
|
9
11
|
|
10
|
-
|
11
|
-
|
12
|
+
EXAMPLE_TBL_ATTR =
|
13
|
+
{ class: "example_label", style: "width:82.8pt;padding:0 0 0 0;\
|
12
14
|
margin-left:0pt;vertical-align:top;" }.freeze
|
13
15
|
|
14
|
-
|
15
|
-
|
16
|
-
|
16
|
+
def example_div_attr(node)
|
17
|
+
attr_code(id: node["id"], class: "example", style: keep_style(node))
|
18
|
+
end
|
17
19
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
20
|
+
# used if we are boxing examples
|
21
|
+
def example_div_parse(node, out)
|
22
|
+
out.div **example_div_attr(node) do |div|
|
23
|
+
example_label(node, div, node.at(ns("./name")))
|
24
|
+
node.children.each do |n|
|
25
|
+
parse(n, div) unless n.name == "name"
|
26
|
+
end
|
24
27
|
end
|
25
28
|
end
|
26
|
-
end
|
27
29
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
30
|
+
def example_table_attr(node)
|
31
|
+
attr_code(id: node["id"], class: "example",
|
32
|
+
style: "border-collapse:collapse;border-spacing:0;"\
|
33
|
+
"#{keep_style(node)}")
|
34
|
+
end
|
33
35
|
|
34
|
-
|
35
|
-
|
36
|
+
EXAMPLE_TD_ATTR =
|
37
|
+
{ style: "vertical-align:top;padding:0;", class: "example" }.freeze
|
36
38
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
39
|
+
def example_table_parse(node, out)
|
40
|
+
out.table **example_table_attr(node) do |t|
|
41
|
+
t.tr do |tr|
|
42
|
+
tr.td **EXAMPLE_TBL_ATTR do |td|
|
43
|
+
example_label(node, td, node.at(ns("./name")))
|
44
|
+
end
|
45
|
+
tr.td **EXAMPLE_TD_ATTR do |td|
|
46
|
+
node.children.each { |n| parse(n, td) unless n.name == "name" }
|
47
|
+
end
|
45
48
|
end
|
46
49
|
end
|
47
50
|
end
|
48
|
-
end
|
49
51
|
|
50
|
-
|
51
|
-
|
52
|
-
|
52
|
+
def example_parse(node, out)
|
53
|
+
example_div_parse(node, out)
|
54
|
+
end
|
53
55
|
|
54
|
-
|
55
|
-
|
56
|
-
|
56
|
+
def note_delim
|
57
|
+
""
|
58
|
+
end
|
57
59
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
60
|
+
def note_p_parse(node, div)
|
61
|
+
name = node&.at(ns("./name"))&.remove
|
62
|
+
div.p do |p|
|
63
|
+
name and p.span **{ class: "note_label" } do |s|
|
64
|
+
name.children.each { |n| parse(n, s) }
|
65
|
+
s << note_delim
|
66
|
+
end
|
67
|
+
insert_tab(p, 1)
|
68
|
+
node.first_element_child.children.each { |n| parse(n, p) }
|
64
69
|
end
|
65
|
-
|
66
|
-
node.first_element_child.children.each { |n| parse(n, p) }
|
70
|
+
node.element_children[1..-1].each { |n| parse(n, div) }
|
67
71
|
end
|
68
|
-
node.element_children[1..-1].each { |n| parse(n, div) }
|
69
|
-
end
|
70
72
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
73
|
+
def note_parse1(node, div)
|
74
|
+
name = node&.at(ns("./name"))&.remove
|
75
|
+
name and div.p do |p|
|
76
|
+
p.span **{ class: "note_label" } do |s|
|
77
|
+
name.children.each { |n| parse(n, s) }
|
78
|
+
s << note_delim
|
79
|
+
end
|
80
|
+
insert_tab(p, 1)
|
77
81
|
end
|
78
|
-
|
82
|
+
node.children.each { |n| parse(n, div) }
|
79
83
|
end
|
80
|
-
node.children.each { |n| parse(n, div) }
|
81
|
-
end
|
82
84
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
ret
|
91
|
-
end
|
85
|
+
def keep_style(node)
|
86
|
+
ret = ""
|
87
|
+
node["keep-with-next"] == "true" and
|
88
|
+
ret += "page-break-after: avoid;"
|
89
|
+
node["keep-lines-together"] == "true" and
|
90
|
+
ret += "page-break-inside: avoid;"
|
91
|
+
return nil if ret.empty?
|
92
92
|
|
93
|
-
|
94
|
-
|
95
|
-
|
93
|
+
ret
|
94
|
+
end
|
95
|
+
|
96
|
+
def note_attrs(node)
|
97
|
+
attr_code(id: node["id"], class: "Note", style: keep_style(node))
|
98
|
+
end
|
96
99
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
100
|
+
def note_parse(node, out)
|
101
|
+
@note = true
|
102
|
+
out.div **note_attrs(node) do |div|
|
103
|
+
if node&.at(ns("./*[local-name() != 'name'][1]"))&.name == "p"
|
104
|
+
note_p_parse(node, div)
|
105
|
+
else
|
106
|
+
note_parse1(node, div)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
@note = false
|
103
110
|
end
|
104
|
-
@note = false
|
105
111
|
end
|
106
112
|
end
|
107
113
|
end
|
@@ -1,226 +1,232 @@
|
|
1
|
-
module IsoDoc
|
2
|
-
module
|
3
|
-
|
4
|
-
|
5
|
-
|
1
|
+
module IsoDoc
|
2
|
+
module Function
|
3
|
+
module Cleanup
|
4
|
+
def textcleanup(docxml)
|
5
|
+
termref_cleanup(passthrough_cleanup(docxml))
|
6
|
+
end
|
6
7
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
8
|
+
def termref_cleanup(docxml)
|
9
|
+
docxml
|
10
|
+
.gsub(/\s*\[MODIFICATION\]\s*\[\/TERMREF\]/,
|
11
|
+
l10n(", #{@i18n.modified} [/TERMREF]"))
|
12
|
+
.gsub(%r{\s*\[/TERMREF\]\s*</p>\s*<p>\s*\[TERMREF\]}, "; ")
|
13
|
+
.gsub(/\[TERMREF\]\s*/, l10n("[#{@i18n.source}: "))
|
14
|
+
.gsub(%r{\s*\[/TERMREF\]\s*}, l10n("]"))
|
15
|
+
.gsub(/\s*\[MODIFICATION\]/, l10n(", #{@i18n.modified} — "))
|
16
|
+
end
|
16
17
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
18
|
+
def passthrough_cleanup(docxml)
|
19
|
+
docxml.split(%r{(<passthrough>|</passthrough>)}).each_slice(4)
|
20
|
+
.map do |a|
|
21
|
+
a.size > 2 and a[2] = HTMLEntities.new.decode(a[2])
|
22
|
+
[a[0], a[2]]
|
23
|
+
end.join
|
24
|
+
end
|
23
25
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
26
|
+
def cleanup(docxml)
|
27
|
+
@i18n ||= i18n_init(@lang, @script)
|
28
|
+
comment_cleanup(docxml)
|
29
|
+
footnote_cleanup(docxml)
|
30
|
+
inline_header_cleanup(docxml)
|
31
|
+
figure_cleanup(docxml)
|
32
|
+
table_cleanup(docxml)
|
33
|
+
symbols_cleanup(docxml)
|
34
|
+
example_cleanup(docxml)
|
35
|
+
admonition_cleanup(docxml)
|
36
|
+
end
|
35
37
|
|
36
|
-
|
37
|
-
|
38
|
+
def table_long_strings_cleanup(docxml)
|
39
|
+
return unless @break_up_urls_in_tables == true
|
38
40
|
|
39
|
-
|
40
|
-
|
41
|
-
|
41
|
+
docxml.xpath("//td | //th").each do |d|
|
42
|
+
d.traverse do |n|
|
43
|
+
next unless n.text?
|
42
44
|
|
43
|
-
|
44
|
-
|
45
|
-
|
45
|
+
n.replace(HTMLEntities.new.encode(
|
46
|
+
break_up_long_strings(n.text),
|
47
|
+
))
|
48
|
+
end
|
46
49
|
end
|
47
50
|
end
|
48
|
-
end
|
49
51
|
|
50
|
-
|
51
|
-
|
52
|
+
def break_up_long_strings(text)
|
53
|
+
return text if /^\s*$/.match?(text)
|
54
|
+
|
55
|
+
text.split(/(?=\s)/).map do |w|
|
56
|
+
if /^\s*$/.match(text) || (w.size < 30) then w
|
57
|
+
else
|
58
|
+
w.scan(/.{,30}/).map do |w1|
|
59
|
+
w1.size < 30 ? w1 : break_up_long_strings1(w1)
|
60
|
+
end.join
|
61
|
+
end
|
62
|
+
end.join
|
63
|
+
end
|
52
64
|
|
53
|
-
text
|
54
|
-
|
65
|
+
def break_up_long_strings1(text)
|
66
|
+
s = text.split(%r{(?<=[,.?+;/=])})
|
67
|
+
if s.size == 1 then "#{text} "
|
55
68
|
else
|
56
|
-
|
57
|
-
|
58
|
-
end.join
|
69
|
+
s[-1] = " #{s[-1]}"
|
70
|
+
s.join
|
59
71
|
end
|
60
|
-
end.join
|
61
|
-
end
|
62
|
-
|
63
|
-
def break_up_long_strings1(text)
|
64
|
-
s = text.split(%r{(?<=[,.?+;/=])})
|
65
|
-
if s.size == 1 then "#{text} "
|
66
|
-
else
|
67
|
-
s[-1] = " #{s[-1]}"
|
68
|
-
s.join
|
69
72
|
end
|
70
|
-
end
|
71
73
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
74
|
+
def admonition_cleanup(docxml)
|
75
|
+
docxml.xpath("//div[@class = 'Admonition'][title]").each do |d|
|
76
|
+
title = d.at("./title")
|
77
|
+
n = title.next_element
|
78
|
+
n&.children&.first
|
79
|
+
&.add_previous_sibling("#{title.remove.text}—")
|
80
|
+
end
|
81
|
+
docxml
|
77
82
|
end
|
78
|
-
docxml
|
79
|
-
end
|
80
83
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
+
def example_cleanup(docxml)
|
85
|
+
docxml.xpath("//table[@class = 'example']//p[not(@class)]").each do |p|
|
86
|
+
p["class"] = "example"
|
87
|
+
end
|
88
|
+
docxml
|
84
89
|
end
|
85
|
-
docxml
|
86
|
-
end
|
87
90
|
|
88
|
-
|
89
|
-
dl = elem.at(".//dl")
|
90
|
-
if dl.nil?
|
91
|
-
elem.add_child("<p><b>#{@i18n.key}</b></p><dl></dl>")
|
91
|
+
def figure_get_or_make_dl(elem)
|
92
92
|
dl = elem.at(".//dl")
|
93
|
+
if dl.nil?
|
94
|
+
elem.add_child("<p><b>#{@i18n.key}</b></p><dl></dl>")
|
95
|
+
dl = elem.at(".//dl")
|
96
|
+
end
|
97
|
+
dl
|
93
98
|
end
|
94
|
-
dl
|
95
|
-
end
|
96
99
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
100
|
+
FIGURE_WITH_FOOTNOTES =
|
101
|
+
"//div[@class = 'figure'][descendant::aside]"\
|
102
|
+
"[not(descendant::div[@class = 'figure'])]".freeze
|
103
|
+
|
104
|
+
def figure_aside_process(elem, aside, key)
|
105
|
+
# get rid of footnote link, it is in diagram
|
106
|
+
elem&.at("./a[@class='TableFootnoteRef']")&.remove
|
107
|
+
fnref = elem.at(".//span[@class='TableFootnoteRef']/..")
|
108
|
+
dt = key.add_child("<dt></dt>").first
|
109
|
+
dd = key.add_child("<dd></dd>").first
|
110
|
+
fnref.parent = dt
|
111
|
+
aside.xpath(".//p").each do |a|
|
112
|
+
a.delete("class")
|
113
|
+
a.parent = dd
|
114
|
+
end
|
111
115
|
end
|
112
|
-
end
|
113
116
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
117
|
+
# move footnotes into key, and get rid of footnote reference
|
118
|
+
# since it is in diagram
|
119
|
+
def figure_cleanup(docxml)
|
120
|
+
docxml.xpath(FIGURE_WITH_FOOTNOTES).each do |f|
|
121
|
+
next unless f.at(".//aside[not(ancestor::p[@class = 'FigureTitle'])]")
|
119
122
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
+
key = figure_get_or_make_dl(f)
|
124
|
+
f.xpath(".//aside").each do |aside|
|
125
|
+
figure_aside_process(f, aside, key)
|
126
|
+
end
|
123
127
|
end
|
128
|
+
docxml
|
124
129
|
end
|
125
|
-
docxml
|
126
|
-
end
|
127
130
|
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
131
|
+
def inline_header_cleanup(docxml)
|
132
|
+
docxml.xpath('//span[@class="zzMoveToFollowing"]').each do |x|
|
133
|
+
x.delete("class")
|
134
|
+
n = x.next_element
|
135
|
+
if n.nil?
|
136
|
+
x.name = "p"
|
137
|
+
else
|
138
|
+
n.children.first.previous = x.remove
|
139
|
+
end
|
136
140
|
end
|
141
|
+
docxml
|
137
142
|
end
|
138
|
-
docxml
|
139
|
-
end
|
140
143
|
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
+
def footnote_cleanup(docxml)
|
145
|
+
docxml.xpath('//a[@class = "FootnoteRef"]/sup')
|
146
|
+
.each_with_index do |x, i|
|
147
|
+
x.content = (i + 1).to_s
|
148
|
+
end
|
149
|
+
docxml
|
144
150
|
end
|
145
|
-
docxml
|
146
|
-
end
|
147
151
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
152
|
+
def merge_fnref_into_fn_text(elem)
|
153
|
+
fn = elem.at('.//span[@class="TableFootnoteRef"]/..')
|
154
|
+
n = fn.next_element
|
155
|
+
n&.children&.first&.add_previous_sibling(fn.remove)
|
156
|
+
end
|
153
157
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
158
|
+
# preempt html2doc putting MsoNormal under TableFootnote class
|
159
|
+
def table_footnote_cleanup(docxml)
|
160
|
+
docxml.xpath("//table[descendant::aside]").each do |t|
|
161
|
+
t.xpath(".//aside").each do |a|
|
162
|
+
merge_fnref_into_fn_text(a)
|
163
|
+
a.name = "div"
|
164
|
+
a["class"] = "TableFootnote"
|
165
|
+
t << a.remove
|
166
|
+
end
|
167
|
+
end
|
168
|
+
docxml.xpath("//p[not(self::*[@class])]"\
|
169
|
+
"[ancestor::*[@class = 'TableFootnote']]").each do |p|
|
170
|
+
p["class"] = "TableFootnote"
|
162
171
|
end
|
163
172
|
end
|
164
|
-
docxml.xpath("//p[not(self::*[@class])]"\
|
165
|
-
"[ancestor::*[@class = 'TableFootnote']]").each do |p|
|
166
|
-
p["class"] = "TableFootnote"
|
167
|
-
end
|
168
|
-
end
|
169
173
|
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
+
def remove_bottom_border(cell)
|
175
|
+
cell["style"] =
|
176
|
+
cell["style"].gsub(/border-bottom:[^;]+;/, "border-bottom:0pt;")
|
177
|
+
end
|
174
178
|
|
175
|
-
|
176
|
-
tfoot = table.at(".//tfoot")
|
177
|
-
if tfoot.nil?
|
178
|
-
table.add_child("<tfoot></tfoot>")
|
179
|
+
def table_get_or_make_tfoot(table)
|
179
180
|
tfoot = table.at(".//tfoot")
|
180
|
-
|
181
|
-
|
181
|
+
if tfoot.nil?
|
182
|
+
table.add_child("<tfoot></tfoot>")
|
183
|
+
tfoot = table.at(".//tfoot")
|
184
|
+
else
|
185
|
+
tfoot.xpath(".//td | .//th").each { |td| remove_bottom_border(td) }
|
186
|
+
end
|
187
|
+
tfoot
|
182
188
|
end
|
183
|
-
tfoot
|
184
|
-
end
|
185
189
|
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
190
|
+
def new_fullcolspan_row(table, tfoot)
|
191
|
+
# how many columns in the table?
|
192
|
+
cols = 0
|
193
|
+
table.at(".//tr").xpath("./td | ./th").each do |td|
|
194
|
+
cols += (td["colspan"] ? td["colspan"].to_i : 1)
|
195
|
+
end
|
196
|
+
style =
|
197
|
+
%{border-top:0pt;border-bottom:#{IsoDoc::Function::Table::SW} 1.5pt;}
|
198
|
+
tfoot.add_child("<tr><td colspan='#{cols}' style='#{style}'/></tr>")
|
199
|
+
tfoot.xpath(".//td").last
|
191
200
|
end
|
192
|
-
style =
|
193
|
-
%{border-top:0pt;border-bottom:#{IsoDoc::Function::Table::SW} 1.5pt;}
|
194
|
-
tfoot.add_child("<tr><td colspan='#{cols}' style='#{style}'/></tr>")
|
195
|
-
tfoot.xpath(".//td").last
|
196
|
-
end
|
197
201
|
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
202
|
+
def table_note_cleanup(docxml)
|
203
|
+
docxml.xpath("//table[div[@class = 'Note' or "\
|
204
|
+
"@class = 'TableFootnote']]").each do |t|
|
205
|
+
tfoot = table_get_or_make_tfoot(t)
|
206
|
+
insert_here = new_fullcolspan_row(t, tfoot)
|
207
|
+
t.xpath("div[@class = 'Note' or @class = 'TableFootnote']")
|
208
|
+
.each do |d|
|
209
|
+
d.parent = insert_here
|
210
|
+
end
|
205
211
|
end
|
206
212
|
end
|
207
|
-
end
|
208
213
|
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
214
|
+
def table_cleanup(docxml)
|
215
|
+
table_footnote_cleanup(docxml)
|
216
|
+
table_note_cleanup(docxml)
|
217
|
+
table_long_strings_cleanup(docxml)
|
218
|
+
docxml
|
219
|
+
end
|
215
220
|
|
216
|
-
|
221
|
+
def symbols_cleanup(docxml); end
|
217
222
|
|
218
|
-
|
219
|
-
|
220
|
-
|
223
|
+
def table_footnote_reference_format(link)
|
224
|
+
link
|
225
|
+
end
|
221
226
|
|
222
|
-
|
223
|
-
|
227
|
+
def footnote_reference_format(link)
|
228
|
+
link
|
229
|
+
end
|
224
230
|
end
|
225
231
|
end
|
226
232
|
end
|