metanorma-standoc 1.9.2 → 1.9.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/asciidoctor/standoc/biblio.rng +1 -0
- data/lib/asciidoctor/standoc/cleanup.rb +33 -13
- data/lib/asciidoctor/standoc/cleanup_section.rb +84 -80
- data/lib/asciidoctor/standoc/front.rb +1 -1
- data/lib/asciidoctor/standoc/isodoc.rng +1 -3
- data/lib/asciidoctor/standoc/term_lookup_cleanup.rb +31 -16
- data/lib/metanorma/standoc/version.rb +1 -1
- data/metanorma-standoc.gemspec +1 -1
- data/spec/asciidoctor/base_spec.rb +11 -11
- data/spec/asciidoctor/blocks_spec.rb +0 -2
- data/spec/asciidoctor/cleanup_sections_spec.rb +14 -14
- data/spec/asciidoctor/cleanup_spec.rb +60 -60
- data/spec/asciidoctor/inline_spec.rb +14 -14
- data/spec/asciidoctor/lists_spec.rb +3 -3
- data/spec/asciidoctor/macros_plantuml_spec.rb +8 -8
- data/spec/asciidoctor/macros_spec.rb +13 -13
- data/spec/asciidoctor/refs_dl_spec.rb +4 -4
- data/spec/asciidoctor/refs_spec.rb +18 -18
- data/spec/asciidoctor/section_spec.rb +58 -22
- data/spec/asciidoctor/table_spec.rb +6 -6
- data/spec/asciidoctor/validate_spec.rb +21 -21
- data/spec/spec_helper.rb +2 -0
- data/spec/vcr_cassettes/dated_iso_ref_joint_iso_iec.yml +45 -45
- data/spec/vcr_cassettes/isobib_get_123.yml +12 -12
- data/spec/vcr_cassettes/isobib_get_123_1.yml +23 -23
- data/spec/vcr_cassettes/isobib_get_123_1_fr.yml +31 -31
- data/spec/vcr_cassettes/isobib_get_123_2001.yml +12 -12
- data/spec/vcr_cassettes/isobib_get_124.yml +11 -11
- data/spec/vcr_cassettes/rfcbib_get_rfc8341.yml +14 -14
- data/spec/vcr_cassettes/separates_iev_citations_by_top_level_clause.yml +46 -46
- metadata +4 -8
- data/lib/liquid/custom_blocks/key_iterator.rb +0 -21
- data/lib/liquid/custom_blocks/with_json_nested_context.rb +0 -18
- data/lib/liquid/custom_blocks/with_yaml_nested_context.rb +0 -19
- data/lib/liquid/custom_filters/values.rb +0 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fb0657fc8f9c086fa560b509e2e7e5829b9ab5d902e727ce221c040f2aad3ec4
|
4
|
+
data.tar.gz: eac14431d7f0317023a49993dee40a440fbc47d32136091cd4adfea5a5d36823
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 72d1aece1ed13421fa2fdcd87f8d4468cae148cc415b3a982fc9fea236cbf5f01113e87b11fc88b0aa68ce52f057d5dcdc1441b37c028798cd66458146d0b540
|
7
|
+
data.tar.gz: b736bd6de43ace4da0c31f14b1f7f28349eb7272baf073e5b68558f68cd88e68b84fb72c76d578f0a69c8b56ae8021b5dfe75792dde64fae1a121eeaa156cfc6
|
@@ -72,24 +72,39 @@ module Asciidoctor
|
|
72
72
|
xmldoc
|
73
73
|
end
|
74
74
|
|
75
|
+
IGNORE_DUMBQUOTES = "//pre | //pre//* | //tt | //tt//* | "\
|
76
|
+
"//sourcecode | //sourcecode//* | //bibdata//* | //stem | "\
|
77
|
+
"//stem//* | //figure[@class = 'pseudocode'] | "\
|
78
|
+
"//figure[@class = 'pseudocode']//*".freeze
|
79
|
+
|
75
80
|
def smartquotes_cleanup(xmldoc)
|
76
81
|
xmldoc.xpath("//date").each { |d| Metanorma::Utils::endash_date(d) }
|
77
|
-
|
78
|
-
|
82
|
+
if @smartquotes then smartquotes_cleanup1(xmldoc)
|
83
|
+
else dumbquote_cleanup(xmldoc)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def smartquotes_cleanup1(xmldoc)
|
88
|
+
(xmldoc.xpath("//*[child::text()]") - xmldoc.xpath(IGNORE_DUMBQUOTES))
|
89
|
+
.each do |x|
|
90
|
+
x.children.each do |n|
|
91
|
+
next unless n.text?
|
79
92
|
|
80
|
-
if @smartquotes
|
81
93
|
/[-'"(<>]|\.\.|\dx/.match(n) or next
|
82
94
|
|
83
|
-
n.ancestors("pre, tt, sourcecode, bibdata, on, "\
|
84
|
-
"stem, figure[@class = 'pseudocode']").empty? or next
|
85
95
|
n.replace(Metanorma::Utils::smartformat(n.text))
|
86
|
-
else
|
87
|
-
n.replace(n.text.gsub(/(?<=\p{Alnum})\u2019(?=\p{Alpha})/, "'")) # .
|
88
|
-
# gsub(/</, "<").gsub(/>/, ">"))
|
89
96
|
end
|
90
97
|
end
|
91
98
|
end
|
92
99
|
|
100
|
+
def dumbquote_cleanup(xmldoc)
|
101
|
+
xmldoc.traverse do |n|
|
102
|
+
next unless n.text?
|
103
|
+
|
104
|
+
n.replace(n.text.gsub(/(?<=\p{Alnum})\u2019(?=\p{Alpha})/, "'")) # .
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
93
108
|
def docidentifier_cleanup(xmldoc); end
|
94
109
|
|
95
110
|
TEXT_ELEMS =
|
@@ -125,11 +140,7 @@ module Asciidoctor
|
|
125
140
|
end
|
126
141
|
|
127
142
|
def variant_cleanup(xmldoc)
|
128
|
-
xmldoc
|
129
|
-
c&.next&.text? && c&.next&.next&.name == "variant" &&
|
130
|
-
c.next.text.gsub(/\s/, "").empty? and
|
131
|
-
c.next.remove
|
132
|
-
end
|
143
|
+
variant_space_cleanup(xmldoc)
|
133
144
|
xmldoc.xpath("//*[variant]").each do |c|
|
134
145
|
next unless c.children.any? do |n|
|
135
146
|
n.name != "variant" && (!n.text? || !n.text.gsub(/\s/, "").empty?)
|
@@ -147,6 +158,15 @@ module Asciidoctor
|
|
147
158
|
end
|
148
159
|
xmldoc.xpath("//variantwrap").each { |n| n.name = "variant" }
|
149
160
|
end
|
161
|
+
|
162
|
+
def variant_space_cleanup(xmldoc)
|
163
|
+
xmldoc.xpath("//*[variant]").each do |c|
|
164
|
+
if c&.next&.text? && c&.next&.next&.name == "variant"
|
165
|
+
c.next.text.gsub(/\s/, "").empty? and
|
166
|
+
c.next.remove
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
150
170
|
end
|
151
171
|
end
|
152
172
|
end
|
@@ -7,32 +7,32 @@ require "mathml2asciimath"
|
|
7
7
|
module Asciidoctor
|
8
8
|
module Standoc
|
9
9
|
module Cleanup
|
10
|
-
def make_preface(
|
11
|
-
if
|
10
|
+
def make_preface(xml, s)
|
11
|
+
if xml.at("//foreword | //introduction | //acknowledgements | "\
|
12
12
|
"//*[@preface]")
|
13
13
|
preface = s.add_previous_sibling("<preface/>").first
|
14
|
-
f =
|
15
|
-
f =
|
16
|
-
move_clauses_into_preface(
|
17
|
-
f =
|
14
|
+
f = xml.at("//foreword") and preface.add_child f.remove
|
15
|
+
f = xml.at("//introduction") and preface.add_child f.remove
|
16
|
+
move_clauses_into_preface(xml, preface)
|
17
|
+
f = xml.at("//acknowledgements") and preface.add_child f.remove
|
18
18
|
end
|
19
|
-
make_abstract(
|
19
|
+
make_abstract(xml, s)
|
20
20
|
end
|
21
21
|
|
22
|
-
def move_clauses_into_preface(
|
23
|
-
|
22
|
+
def move_clauses_into_preface(xml, preface)
|
23
|
+
xml.xpath("//*[@preface]").each do |c|
|
24
24
|
c.delete("preface")
|
25
25
|
preface.add_child c.remove
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
|
-
def make_abstract(
|
30
|
-
if
|
29
|
+
def make_abstract(xml, s)
|
30
|
+
if xml.at("//abstract[not(ancestor::bibitem)]")
|
31
31
|
preface = s.at("//preface") ||
|
32
32
|
s.add_previous_sibling("<preface/>").first
|
33
|
-
abstract =
|
33
|
+
abstract = xml.at("//abstract[not(ancestor::bibitem)]").remove
|
34
34
|
preface.prepend_child abstract.remove
|
35
|
-
bibabstract = bibabstract_location(
|
35
|
+
bibabstract = bibabstract_location(xml)
|
36
36
|
dupabstract = abstract.dup
|
37
37
|
dupabstract.traverse { |n| n.remove_attribute("id") }
|
38
38
|
dupabstract.remove_attribute("language")
|
@@ -42,40 +42,41 @@ module Asciidoctor
|
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
45
|
-
def bibabstract_location(
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
45
|
+
def bibabstract_location(xml)
|
46
|
+
xml.at("//bibdata/script") || xml.at("//bibdata/language") ||
|
47
|
+
xml.at("//bibdata/contributor[not(following-sibling::contributor)]") ||
|
48
|
+
xml.at("//bibdata/date[not(following-sibling::date)]") ||
|
49
|
+
xml.at("//docnumber") ||
|
50
|
+
xml.at("//bibdata/docidentifier"\
|
51
|
+
"[not(following-sibling::docidentifier)]") ||
|
52
|
+
xml.at("//bibdata/uri[not(following-sibling::uri)]") ||
|
53
|
+
xml.at("//bibdata/title[not(following-sibling::title)]")
|
54
54
|
end
|
55
55
|
|
56
|
-
def make_bibliography(
|
57
|
-
if
|
56
|
+
def make_bibliography(xml, s)
|
57
|
+
if xml.at("//sections/references")
|
58
58
|
biblio = s.add_next_sibling("<bibliography/>").first
|
59
|
-
|
59
|
+
xml.xpath("//sections/references").each do |r|
|
60
60
|
biblio.add_child r.remove
|
61
61
|
end
|
62
62
|
end
|
63
63
|
end
|
64
64
|
|
65
|
-
def make_indexsect(
|
66
|
-
|
65
|
+
def make_indexsect(xml, s)
|
66
|
+
xml.xpath("//sections/indexsect").reverse_each { |r| s.next = r.remove }
|
67
67
|
end
|
68
68
|
|
69
|
-
def sections_order_cleanup(
|
70
|
-
s =
|
71
|
-
make_preface(
|
72
|
-
make_annexes(
|
73
|
-
make_indexsect(
|
74
|
-
make_bibliography(
|
75
|
-
|
69
|
+
def sections_order_cleanup(xml)
|
70
|
+
s = xml.at("//sections")
|
71
|
+
make_preface(xml, s)
|
72
|
+
make_annexes(xml)
|
73
|
+
make_indexsect(xml, s)
|
74
|
+
make_bibliography(xml, s)
|
75
|
+
xml.xpath("//sections/annex").reverse_each { |r| s.next = r.remove }
|
76
76
|
end
|
77
|
-
|
78
|
-
|
77
|
+
|
78
|
+
def make_annexes(xml)
|
79
|
+
xml.xpath("//*[@annex]").each do |y|
|
79
80
|
y.delete("annex")
|
80
81
|
next if y.name == "annex" || !y.ancestors("annex").empty?
|
81
82
|
|
@@ -87,60 +88,61 @@ module Asciidoctor
|
|
87
88
|
end
|
88
89
|
end
|
89
90
|
|
90
|
-
def maxlevel(
|
91
|
+
def maxlevel(xml)
|
91
92
|
max = 5
|
92
|
-
|
93
|
+
xml.xpath("//clause[@level]").each do |c|
|
93
94
|
max = c["level"].to_i if max < c["level"].to_i
|
94
95
|
end
|
95
96
|
max
|
96
97
|
end
|
97
98
|
|
98
|
-
def sections_level_cleanup(
|
99
|
-
m = maxlevel(
|
99
|
+
def sections_level_cleanup(xml)
|
100
|
+
m = maxlevel(xml)
|
100
101
|
return if m < 6
|
101
102
|
|
102
103
|
m.downto(6).each do |l|
|
103
|
-
|
104
|
+
xml.xpath("//clause[@level = '#{l}']").each do |c|
|
104
105
|
c.delete("level")
|
105
106
|
c.previous_element << c.remove
|
106
107
|
end
|
107
108
|
end
|
108
109
|
end
|
109
110
|
|
110
|
-
def sections_cleanup(
|
111
|
-
sections_order_cleanup(
|
112
|
-
sections_level_cleanup(
|
113
|
-
sections_names_cleanup(
|
114
|
-
change_clauses(
|
111
|
+
def sections_cleanup(xml)
|
112
|
+
sections_order_cleanup(xml)
|
113
|
+
sections_level_cleanup(xml)
|
114
|
+
sections_names_cleanup(xml)
|
115
|
+
change_clauses(xml)
|
115
116
|
end
|
116
117
|
|
117
|
-
def obligations_cleanup(
|
118
|
-
obligations_cleanup_info(
|
119
|
-
obligations_cleanup_norm(
|
120
|
-
obligations_cleanup_inherit(
|
118
|
+
def obligations_cleanup(xml)
|
119
|
+
obligations_cleanup_info(xml)
|
120
|
+
obligations_cleanup_norm(xml)
|
121
|
+
obligations_cleanup_inherit(xml)
|
121
122
|
end
|
122
123
|
|
123
|
-
def obligations_cleanup_info(
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
124
|
+
def obligations_cleanup_info(xml)
|
125
|
+
s = xml.at("//foreword") and s["obligation"] = "informative"
|
126
|
+
s = xml.at("//introduction") and s["obligation"] = "informative"
|
127
|
+
s = xml.at("//acknowledgements") and s["obligation"] = "informative"
|
128
|
+
xml.xpath("//references").each { |r| r["obligation"] = "informative" }
|
129
|
+
xml.xpath("//preface//clause").each do |r|
|
129
130
|
r["obligation"] = "informative"
|
130
131
|
end
|
131
132
|
end
|
132
133
|
|
133
|
-
def obligations_cleanup_norm(
|
134
|
-
|
135
|
-
|
136
|
-
|
134
|
+
def obligations_cleanup_norm(xml)
|
135
|
+
s = xml.at("//clause[@type = 'scope']") and
|
136
|
+
s["obligation"] = "normative"
|
137
|
+
xml.xpath("//terms").each { |r| r["obligation"] = "normative" }
|
138
|
+
xml.xpath("//definitions").each { |r| r["obligation"] = "normative" }
|
137
139
|
end
|
138
140
|
|
139
|
-
def obligations_cleanup_inherit(
|
140
|
-
|
141
|
+
def obligations_cleanup_inherit(xml)
|
142
|
+
xml.xpath("//annex | //clause[not(ancestor::boilerplate)]").each do |r|
|
141
143
|
r["obligation"] = "normative" unless r["obligation"]
|
142
144
|
end
|
143
|
-
|
145
|
+
xml.xpath(Utils::SUBCLAUSE_XPATH).each do |r|
|
144
146
|
o = r&.at("./ancestor::*/@obligation")&.text and r["obligation"] = o
|
145
147
|
end
|
146
148
|
end
|
@@ -150,7 +152,7 @@ module Asciidoctor
|
|
150
152
|
sections_clausebefore_cleanup(xmldoc)
|
151
153
|
end
|
152
154
|
|
153
|
-
|
155
|
+
def preface_clausebefore_cleanup(xmldoc)
|
154
156
|
return unless xmldoc.at("//preface")
|
155
157
|
|
156
158
|
unless ins = xmldoc.at("//preface").children.first
|
@@ -177,14 +179,14 @@ module Asciidoctor
|
|
177
179
|
end
|
178
180
|
|
179
181
|
def get_or_make_title(node)
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
end
|
182
|
+
unless node.at("./title")
|
183
|
+
if node.children.empty?
|
184
|
+
node << "<title/>"
|
185
|
+
else
|
186
|
+
node.children.first.previous = "<title/>"
|
186
187
|
end
|
187
|
-
|
188
|
+
end
|
189
|
+
node.at("./title")
|
188
190
|
end
|
189
191
|
|
190
192
|
def replace_title(doc, xpath, text, first = false)
|
@@ -195,7 +197,7 @@ module Asciidoctor
|
|
195
197
|
|
196
198
|
title = get_or_make_title(node)
|
197
199
|
fn = title.xpath("./fn")
|
198
|
-
fn.each
|
200
|
+
fn.each(&:remove)
|
199
201
|
title.content = text
|
200
202
|
fn.each { |n| title << n }
|
201
203
|
end
|
@@ -219,12 +221,12 @@ module Asciidoctor
|
|
219
221
|
end
|
220
222
|
|
221
223
|
NO_SYMABBR = "[.//definitions[not(@type)]]".freeze
|
222
|
-
SYMABBR = "[.//definitions[@type = 'symbols']"\
|
223
|
-
"[@type = 'abbreviated_terms']]".freeze
|
224
|
-
SYMnoABBR = "[.//definitions[@type = 'symbols']"\
|
225
|
-
"[not(@type = 'abbreviated_terms')]
|
226
|
-
ABBRnoSYM = "[.//definitions[
|
227
|
-
"[@type = '
|
224
|
+
SYMABBR = "[.//definitions[@type = 'symbols']]"\
|
225
|
+
"[.//definitions[@type = 'abbreviated_terms']]".freeze
|
226
|
+
SYMnoABBR = "[.//definitions[@type = 'symbols']]"\
|
227
|
+
"[not(.//definitions[@type = 'abbreviated_terms'])]".freeze
|
228
|
+
ABBRnoSYM = "[.//definitions[@type = 'abbreviated_terms']]"\
|
229
|
+
"[not(.//definitions[@type = 'symbols'])]".freeze
|
228
230
|
|
229
231
|
def section_names_terms_cleanup(x)
|
230
232
|
replace_title(x, "//definitions[@type = 'symbols']", @i18n&.symbols)
|
@@ -240,8 +242,10 @@ module Asciidoctor
|
|
240
242
|
replace_title(x, "//terms#{NO_SYMABBR} | //clause[.//terms]#{NO_SYMABBR}",
|
241
243
|
@i18n&.termsdefsymbolsabbrev, true)
|
242
244
|
replace_title(
|
243
|
-
x,
|
244
|
-
|
245
|
+
x,
|
246
|
+
"//terms[not(.//definitions)] | //clause[.//terms][not(.//definitions)]",
|
247
|
+
@i18n&.termsdef, true
|
248
|
+
)
|
245
249
|
end
|
246
250
|
end
|
247
251
|
end
|
@@ -6,8 +6,8 @@ module Asciidoctor
|
|
6
6
|
# Lookup all `term` and `calause` tags and replace `termxref` tags with
|
7
7
|
# `xref`:target tag
|
8
8
|
class TermLookupCleanup
|
9
|
-
AUTOMATIC_GENERATED_ID_REGEXP = /\A_
|
10
|
-
EXISTING_TERM_REGEXP = /\Aterm
|
9
|
+
AUTOMATIC_GENERATED_ID_REGEXP = /\A_/.freeze
|
10
|
+
EXISTING_TERM_REGEXP = /\Aterm-/.freeze
|
11
11
|
|
12
12
|
attr_reader :xmldoc, :termlookup, :log
|
13
13
|
|
@@ -15,17 +15,27 @@ module Asciidoctor
|
|
15
15
|
@xmldoc = xmldoc
|
16
16
|
@log = log
|
17
17
|
@termlookup = {}
|
18
|
+
@idhash = {}
|
18
19
|
end
|
19
20
|
|
20
21
|
def call
|
22
|
+
@idhash = populate_idhash
|
21
23
|
@termlookup = replace_automatic_generated_ids_terms
|
22
24
|
set_termxref_tags_target
|
23
25
|
end
|
24
26
|
|
25
27
|
private
|
26
28
|
|
29
|
+
def populate_idhash
|
30
|
+
xmldoc.xpath("//*[@id]").each_with_object({}) do |n, mem|
|
31
|
+
next unless /^term-/.match?(n["id"])
|
32
|
+
|
33
|
+
mem[n["id"]] = true
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
27
37
|
def set_termxref_tags_target
|
28
|
-
xmldoc.xpath(
|
38
|
+
xmldoc.xpath("//termxref").each do |node|
|
29
39
|
target = normalize_ref_id(node.text)
|
30
40
|
if termlookup[target].nil?
|
31
41
|
remove_missing_ref(node, target)
|
@@ -36,7 +46,7 @@ module Asciidoctor
|
|
36
46
|
end
|
37
47
|
|
38
48
|
def remove_missing_ref(node, target)
|
39
|
-
log.add(
|
49
|
+
log.add("AsciiDoc Input", node,
|
40
50
|
%(Error: Term reference in `term[#{target}]` missing: \
|
41
51
|
"#{target}" is not defined in document))
|
42
52
|
term_name_node = node.previous.previous
|
@@ -49,34 +59,39 @@ module Asciidoctor
|
|
49
59
|
end
|
50
60
|
|
51
61
|
def modify_ref_node(node, target)
|
52
|
-
node.name =
|
53
|
-
node[
|
62
|
+
node.name = "xref"
|
63
|
+
node["target"] = termlookup[target]
|
54
64
|
node.children.remove
|
55
|
-
node.remove_attribute(
|
65
|
+
node.remove_attribute("defaultref")
|
56
66
|
end
|
57
67
|
|
58
68
|
def replace_automatic_generated_ids_terms
|
59
|
-
xmldoc.xpath(
|
60
|
-
normalize_id_and_memorize(term_node, res,
|
69
|
+
xmldoc.xpath("//term").each.with_object({}) do |term_node, res|
|
70
|
+
normalize_id_and_memorize(term_node, res, "./preferred")
|
61
71
|
end
|
62
72
|
end
|
63
73
|
|
64
74
|
def normalize_id_and_memorize(term_node, res_table, text_selector)
|
65
75
|
term_text = normalize_ref_id(term_node.at(text_selector).text)
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
76
|
+
unless AUTOMATIC_GENERATED_ID_REGEXP.match(term_node["id"]).nil?
|
77
|
+
id = unique_text_id(term_text)
|
78
|
+
term_node["id"] = id
|
79
|
+
@idhash[id] = true
|
80
|
+
end
|
81
|
+
res_table[term_text] = term_node["id"]
|
70
82
|
end
|
71
83
|
|
72
84
|
def normalize_ref_id(text)
|
73
|
-
text.downcase.gsub(/[[:space:]]/,
|
85
|
+
text.downcase.gsub(/[[:space:]]/, "-")
|
74
86
|
end
|
75
87
|
|
76
88
|
def unique_text_id(text)
|
77
|
-
|
89
|
+
unless @idhash["term-#{text}"]
|
90
|
+
return "term-#{text}"
|
91
|
+
end
|
92
|
+
|
78
93
|
(1..Float::INFINITY).lazy.each do |index|
|
79
|
-
|
94
|
+
unless @idhash["term-#{text}-#{index}"]
|
80
95
|
break("term-#{text}-#{index}")
|
81
96
|
end
|
82
97
|
end
|