metanorma-mpfa 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/workflows/macos.yml +39 -0
- data/.github/workflows/ubuntu.yml +53 -0
- data/.github/workflows/windows.yml +41 -0
- data/.gitignore +1 -0
- data/.hound.yml +3 -0
- data/.rubocop.yml +10 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +11 -0
- data/LICENSE +25 -0
- data/README.adoc +79 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/manifest +146 -0
- data/bin/rspec +18 -0
- data/bin/setup +8 -0
- data/lib/asciidoctor/mpfa.rb +6 -0
- data/lib/asciidoctor/mpfa/basicdoc.rng +1059 -0
- data/lib/asciidoctor/mpfa/biblio.rng +1237 -0
- data/lib/asciidoctor/mpfa/converter.rb +113 -0
- data/lib/asciidoctor/mpfa/isodoc.rng +1504 -0
- data/lib/asciidoctor/mpfa/mpfd.rng +79 -0
- data/lib/asciidoctor/mpfa/reqt.rng +194 -0
- data/lib/asciidoctor/mpfa/section.rb +61 -0
- data/lib/asciidoctor/mpfa/validate.rb +30 -0
- data/lib/isodoc/mpfa/base_convert.rb +128 -0
- data/lib/isodoc/mpfa/html/header.html +242 -0
- data/lib/isodoc/mpfa/html/html_rsd_intro.html +8 -0
- data/lib/isodoc/mpfa/html/html_rsd_titlepage.html +58 -0
- data/lib/isodoc/mpfa/html/htmlstyle.scss +932 -0
- data/lib/isodoc/mpfa/html/logo.jpg +0 -0
- data/lib/isodoc/mpfa/html/logo.svg +1 -0
- data/lib/isodoc/mpfa/html/mpfa-logo-no-text@4x.png +0 -0
- data/lib/isodoc/mpfa/html/mpfa-logo@4x.png +0 -0
- data/lib/isodoc/mpfa/html/rsd.scss +763 -0
- data/lib/isodoc/mpfa/html/scripts.html +80 -0
- data/lib/isodoc/mpfa/html/word_rsd_intro.html +3 -0
- data/lib/isodoc/mpfa/html/word_rsd_titlepage.html +42 -0
- data/lib/isodoc/mpfa/html/wordstyle.scss +1157 -0
- data/lib/isodoc/mpfa/html_convert.rb +63 -0
- data/lib/isodoc/mpfa/i18n-en.yaml +2 -0
- data/lib/isodoc/mpfa/i18n-zh-Hans.yaml +2 -0
- data/lib/isodoc/mpfa/metadata.rb +74 -0
- data/lib/isodoc/mpfa/presentation_xml_convert.rb +10 -0
- data/lib/isodoc/mpfa/word_convert.rb +62 -0
- data/lib/isodoc/mpfa/xref.rb +102 -0
- data/lib/metanorma-mpfa.rb +11 -0
- data/lib/metanorma/mpfa.rb +7 -0
- data/lib/metanorma/mpfa/processor.rb +49 -0
- data/lib/metanorma/mpfa/version.rb +5 -0
- data/metanorma-mpfd.gemspec +46 -0
- metadata +280 -0
@@ -0,0 +1,79 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<grammar ns="https://www.metanorma.org/ns/mpfd" xmlns="http://relaxng.org/ns/structure/1.0">
|
3
|
+
<!--
|
4
|
+
Currently we inherit from a namespaced grammar, isostandard. Until we inherit from isodoc,
|
5
|
+
we cannot have a new default namespace: we will end up with a grammar with two different
|
6
|
+
namespaces, one for isostandard and one for csand additions. And we do not want that.
|
7
|
+
-->
|
8
|
+
<include href="isodoc.rng">
|
9
|
+
<start>
|
10
|
+
<ref name="mpfd-standard"/>
|
11
|
+
</start>
|
12
|
+
<define name="DocumentType">
|
13
|
+
<choice>
|
14
|
+
<value>policy-and-procedures</value>
|
15
|
+
<value>best-practices</value>
|
16
|
+
<value>supporting-document</value>
|
17
|
+
<value>report</value>
|
18
|
+
<value>legal</value>
|
19
|
+
<value>directives</value>
|
20
|
+
<value>proposal</value>
|
21
|
+
<value>standard</value>
|
22
|
+
</choice>
|
23
|
+
</define>
|
24
|
+
<define name="editorialgroup">
|
25
|
+
<element name="editorialgroup">
|
26
|
+
<oneOrMore>
|
27
|
+
<ref name="committee"/>
|
28
|
+
</oneOrMore>
|
29
|
+
</element>
|
30
|
+
</define>
|
31
|
+
<define name="BibDataExtensionType">
|
32
|
+
<optional>
|
33
|
+
<ref name="doctype"/>
|
34
|
+
</optional>
|
35
|
+
<ref name="editorialgroup"/>
|
36
|
+
<zeroOrMore>
|
37
|
+
<ref name="ics"/>
|
38
|
+
</zeroOrMore>
|
39
|
+
<optional>
|
40
|
+
<ref name="security"/>
|
41
|
+
</optional>
|
42
|
+
</define>
|
43
|
+
</include>
|
44
|
+
<define name="committee">
|
45
|
+
<element name="committee">
|
46
|
+
<attribute name="type">
|
47
|
+
<choice>
|
48
|
+
<value>technical</value>
|
49
|
+
<value>provisional</value>
|
50
|
+
</choice>
|
51
|
+
</attribute>
|
52
|
+
<text/>
|
53
|
+
</element>
|
54
|
+
</define>
|
55
|
+
<define name="security">
|
56
|
+
<element name="security">
|
57
|
+
<text/>
|
58
|
+
</element>
|
59
|
+
</define>
|
60
|
+
<define name="mpfd-standard">
|
61
|
+
<element name="mpfd-standard">
|
62
|
+
<ref name="bibdata"/>
|
63
|
+
<zeroOrMore>
|
64
|
+
<ref name="termdocsource"/>
|
65
|
+
</zeroOrMore>
|
66
|
+
<optional>
|
67
|
+
<ref name="boilerplate"/>
|
68
|
+
</optional>
|
69
|
+
<ref name="preface"/>
|
70
|
+
<oneOrMore>
|
71
|
+
<ref name="sections"/>
|
72
|
+
</oneOrMore>
|
73
|
+
<zeroOrMore>
|
74
|
+
<ref name="annex"/>
|
75
|
+
</zeroOrMore>
|
76
|
+
<ref name="bibliography"/>
|
77
|
+
</element>
|
78
|
+
</define>
|
79
|
+
</grammar>
|
@@ -0,0 +1,194 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
|
3
|
+
<!--
|
4
|
+
Presupposes isodoc.rnc, is included in it
|
5
|
+
include "isodoc.rnc" { }
|
6
|
+
-->
|
7
|
+
<define name="requirement">
|
8
|
+
<element name="requirement">
|
9
|
+
<ref name="RequirementType"/>
|
10
|
+
</element>
|
11
|
+
</define>
|
12
|
+
<define name="recommendation">
|
13
|
+
<element name="recommendation">
|
14
|
+
<ref name="RequirementType"/>
|
15
|
+
</element>
|
16
|
+
</define>
|
17
|
+
<define name="permission">
|
18
|
+
<element name="permission">
|
19
|
+
<ref name="RequirementType"/>
|
20
|
+
</element>
|
21
|
+
</define>
|
22
|
+
<define name="RequirementType">
|
23
|
+
<optional>
|
24
|
+
<attribute name="obligation">
|
25
|
+
<ref name="ObligationType"/>
|
26
|
+
</attribute>
|
27
|
+
</optional>
|
28
|
+
<optional>
|
29
|
+
<attribute name="unnumbered">
|
30
|
+
<data type="boolean"/>
|
31
|
+
</attribute>
|
32
|
+
</optional>
|
33
|
+
<optional>
|
34
|
+
<attribute name="number"/>
|
35
|
+
</optional>
|
36
|
+
<optional>
|
37
|
+
<attribute name="subsequence"/>
|
38
|
+
</optional>
|
39
|
+
<optional>
|
40
|
+
<attribute name="keep-with-next">
|
41
|
+
<data type="boolean"/>
|
42
|
+
</attribute>
|
43
|
+
</optional>
|
44
|
+
<optional>
|
45
|
+
<attribute name="keep-lines-together">
|
46
|
+
<data type="boolean"/>
|
47
|
+
</attribute>
|
48
|
+
</optional>
|
49
|
+
<attribute name="id">
|
50
|
+
<data type="ID"/>
|
51
|
+
</attribute>
|
52
|
+
<optional>
|
53
|
+
<attribute name="filename"/>
|
54
|
+
</optional>
|
55
|
+
<optional>
|
56
|
+
<attribute name="model"/>
|
57
|
+
</optional>
|
58
|
+
<optional>
|
59
|
+
<attribute name="type"/>
|
60
|
+
</optional>
|
61
|
+
<optional>
|
62
|
+
<ref name="reqtitle"/>
|
63
|
+
</optional>
|
64
|
+
<optional>
|
65
|
+
<ref name="label"/>
|
66
|
+
</optional>
|
67
|
+
<optional>
|
68
|
+
<ref name="subject"/>
|
69
|
+
</optional>
|
70
|
+
<zeroOrMore>
|
71
|
+
<ref name="reqinherit"/>
|
72
|
+
</zeroOrMore>
|
73
|
+
<zeroOrMore>
|
74
|
+
<ref name="classification"/>
|
75
|
+
</zeroOrMore>
|
76
|
+
<zeroOrMore>
|
77
|
+
<choice>
|
78
|
+
<ref name="measurementtarget"/>
|
79
|
+
<ref name="specification"/>
|
80
|
+
<ref name="verification"/>
|
81
|
+
<ref name="import"/>
|
82
|
+
<ref name="description"/>
|
83
|
+
</choice>
|
84
|
+
</zeroOrMore>
|
85
|
+
<optional>
|
86
|
+
<ref name="reqt_references"/>
|
87
|
+
</optional>
|
88
|
+
<zeroOrMore>
|
89
|
+
<choice>
|
90
|
+
<ref name="requirement"/>
|
91
|
+
<ref name="recommendation"/>
|
92
|
+
<ref name="permission"/>
|
93
|
+
</choice>
|
94
|
+
</zeroOrMore>
|
95
|
+
</define>
|
96
|
+
<define name="reqtitle">
|
97
|
+
<element name="title">
|
98
|
+
<ref name="FormattedString"/>
|
99
|
+
</element>
|
100
|
+
</define>
|
101
|
+
<define name="label">
|
102
|
+
<element name="label">
|
103
|
+
<text/>
|
104
|
+
</element>
|
105
|
+
</define>
|
106
|
+
<define name="subject">
|
107
|
+
<element name="subject">
|
108
|
+
<text/>
|
109
|
+
</element>
|
110
|
+
</define>
|
111
|
+
<define name="reqinherit">
|
112
|
+
<element name="inherit">
|
113
|
+
<text/>
|
114
|
+
</element>
|
115
|
+
</define>
|
116
|
+
<define name="measurementtarget">
|
117
|
+
<element name="measurement-target">
|
118
|
+
<ref name="RequirementSubpart"/>
|
119
|
+
</element>
|
120
|
+
</define>
|
121
|
+
<define name="specification">
|
122
|
+
<element name="specification">
|
123
|
+
<ref name="RequirementSubpart"/>
|
124
|
+
</element>
|
125
|
+
</define>
|
126
|
+
<define name="verification">
|
127
|
+
<element name="verification">
|
128
|
+
<ref name="RequirementSubpart"/>
|
129
|
+
</element>
|
130
|
+
</define>
|
131
|
+
<define name="import">
|
132
|
+
<element name="import">
|
133
|
+
<ref name="RequirementSubpart"/>
|
134
|
+
</element>
|
135
|
+
</define>
|
136
|
+
<define name="description">
|
137
|
+
<element name="description">
|
138
|
+
<ref name="RequirementSubpart"/>
|
139
|
+
</element>
|
140
|
+
</define>
|
141
|
+
<define name="reqt_references">
|
142
|
+
<element name="references">
|
143
|
+
<oneOrMore>
|
144
|
+
<ref name="bibitem"/>
|
145
|
+
</oneOrMore>
|
146
|
+
</element>
|
147
|
+
</define>
|
148
|
+
<define name="RequirementSubpart">
|
149
|
+
<optional>
|
150
|
+
<attribute name="type"/>
|
151
|
+
</optional>
|
152
|
+
<optional>
|
153
|
+
<attribute name="exclude">
|
154
|
+
<data type="boolean"/>
|
155
|
+
</attribute>
|
156
|
+
</optional>
|
157
|
+
<optional>
|
158
|
+
<attribute name="keep-with-next">
|
159
|
+
<data type="boolean"/>
|
160
|
+
</attribute>
|
161
|
+
</optional>
|
162
|
+
<optional>
|
163
|
+
<attribute name="keep-lines-together">
|
164
|
+
<data type="boolean"/>
|
165
|
+
</attribute>
|
166
|
+
</optional>
|
167
|
+
<oneOrMore>
|
168
|
+
<ref name="BasicBlock"/>
|
169
|
+
</oneOrMore>
|
170
|
+
</define>
|
171
|
+
<define name="ObligationType">
|
172
|
+
<choice>
|
173
|
+
<value>requirement</value>
|
174
|
+
<value>recommendation</value>
|
175
|
+
<value>permission</value>
|
176
|
+
</choice>
|
177
|
+
</define>
|
178
|
+
<define name="classification">
|
179
|
+
<element name="classification">
|
180
|
+
<ref name="classification_tag"/>
|
181
|
+
<ref name="classification_value"/>
|
182
|
+
</element>
|
183
|
+
</define>
|
184
|
+
<define name="classification_tag">
|
185
|
+
<element name="tag">
|
186
|
+
<text/>
|
187
|
+
</element>
|
188
|
+
</define>
|
189
|
+
<define name="classification_value">
|
190
|
+
<element name="value">
|
191
|
+
<text/>
|
192
|
+
</element>
|
193
|
+
</define>
|
194
|
+
</grammar>
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Asciidoctor
|
2
|
+
module MPFA
|
3
|
+
|
4
|
+
# A {Converter} implementation that generates MPFD output, and a document
|
5
|
+
# schema encapsulation of the document for validation
|
6
|
+
#
|
7
|
+
class Converter < Standoc::Converter
|
8
|
+
|
9
|
+
def sections_cleanup(x)
|
10
|
+
super
|
11
|
+
x.xpath("//*[@inline-header]").each do |h|
|
12
|
+
h.delete("inline-header")
|
13
|
+
end
|
14
|
+
x.xpath("//*[@guidance]").each do |h|
|
15
|
+
c = h.previous_element || next
|
16
|
+
c.add_child h.remove
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def sectiontype_streamline(ret)
|
21
|
+
case ret
|
22
|
+
when "glossary" then "terms and definitions"
|
23
|
+
else
|
24
|
+
super
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def term_def_title(_toplevel, node)
|
29
|
+
return node.title
|
30
|
+
end
|
31
|
+
|
32
|
+
def move_sections_into_preface(x, preface)
|
33
|
+
foreword = x.at("//foreword")
|
34
|
+
preface.add_child foreword.remove if foreword
|
35
|
+
introduction = x.at("//introduction")
|
36
|
+
preface.add_child introduction.remove if introduction
|
37
|
+
terms = x.at("//sections/clause[descendant::terms]") || x.at("//terms")
|
38
|
+
preface.add_child terms.remove if terms
|
39
|
+
move_clauses_into_preface(x, preface)
|
40
|
+
acknowledgements = x.at("//acknowledgements")
|
41
|
+
preface.add_child acknowledgements.remove if acknowledgements
|
42
|
+
end
|
43
|
+
|
44
|
+
def make_preface(x, s)
|
45
|
+
if x.at("//foreword | //introduction | //terms | //acknowledgements |"\
|
46
|
+
"//abstract[not(ancestor::bibitem)] | //clause[@preface]")
|
47
|
+
preface = s.add_previous_sibling("<preface/>").first
|
48
|
+
move_sections_into_preface(x, preface)
|
49
|
+
make_abstract(x, s)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def clause_parse(attrs, xml, node)
|
54
|
+
attrs[:guidance] = true if node.role == "guidance"
|
55
|
+
attrs[:container] = true if node.role == "container"
|
56
|
+
super
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Asciidoctor
|
2
|
+
module MPFA
|
3
|
+
class Converter < Standoc::Converter
|
4
|
+
def content_validate(doc)
|
5
|
+
super
|
6
|
+
bibdata_validate(doc.root)
|
7
|
+
end
|
8
|
+
|
9
|
+
def bibdata_validate(doc)
|
10
|
+
doctype_validate(doc)
|
11
|
+
stage_validate(doc)
|
12
|
+
end
|
13
|
+
|
14
|
+
def doctype_validate(xmldoc)
|
15
|
+
doctype = xmldoc&.at("//bibdata/ext/doctype")&.text
|
16
|
+
%w(policy-and-procedures best-practices supporting-document
|
17
|
+
report legal directives proposal standard).include? doctype or
|
18
|
+
@log.add("Document Attributes", nil, "#{doctype} is not a recognised document type")
|
19
|
+
end
|
20
|
+
|
21
|
+
def stage_validate(xmldoc)
|
22
|
+
stage = xmldoc&.at("//bibdata/status/stage")&.text
|
23
|
+
%w(proposal working-draft committee-draft draft-standard final-draft
|
24
|
+
published withdrawn).include? stage or
|
25
|
+
@log.add("Document Attributes", nil, "#{stage} is not a recognised status")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
@@ -0,0 +1,128 @@
|
|
1
|
+
require "isodoc"
|
2
|
+
require_relative "metadata"
|
3
|
+
require_relative "xref"
|
4
|
+
require "fileutils"
|
5
|
+
|
6
|
+
module IsoDoc
|
7
|
+
module MPFA
|
8
|
+
module BaseConvert
|
9
|
+
def metadata_init(lang, script, labels)
|
10
|
+
@meta = Metadata.new(lang, script, labels)
|
11
|
+
end
|
12
|
+
|
13
|
+
def xref_init(lang, script, klass, labels, options)
|
14
|
+
@xrefs = Xref.new(lang, script, klass, labels, options)
|
15
|
+
end
|
16
|
+
|
17
|
+
def annex_name(annex, name, div)
|
18
|
+
div.h1 **{ class: "Annex" } do |t|
|
19
|
+
t << "#{@xrefs.anchor(annex['id'], :label)} "
|
20
|
+
t.b do |b|
|
21
|
+
name&.children&.each { |c2| parse(c2, b) }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def fileloc(loc)
|
27
|
+
File.join(File.dirname(__FILE__), loc)
|
28
|
+
end
|
29
|
+
|
30
|
+
def i18n_init(lang, script)
|
31
|
+
super
|
32
|
+
y = if lang == "en"
|
33
|
+
YAML.load_file(File.join(File.dirname(__FILE__), "i18n-en.yaml"))
|
34
|
+
elsif lang == "zh" && script == "Hans"
|
35
|
+
YAML.load_file(File.join(File.dirname(__FILE__),
|
36
|
+
"i18n-zh-Hans.yaml"))
|
37
|
+
else
|
38
|
+
YAML.load_file(File.join(File.dirname(__FILE__), "i18n-en.yaml"))
|
39
|
+
end
|
40
|
+
@labels = @labels.merge(y)
|
41
|
+
@annex_lbl = y["annex"]
|
42
|
+
@clause_lbl = y["clause"]
|
43
|
+
end
|
44
|
+
|
45
|
+
def terms_defs_title(f)
|
46
|
+
return f&.at(ns("./title"))&.content
|
47
|
+
end
|
48
|
+
|
49
|
+
TERM_CLAUSE = "//preface/terms | "\
|
50
|
+
"//preface/clause[descendant::terms]".freeze
|
51
|
+
|
52
|
+
SECTIONS_XPATH =
|
53
|
+
"//foreword | //introduction | //preface/terms | //preface/clause | //annex | "\
|
54
|
+
"//sections/clause | //bibliography/references | //acknowledgements | "\
|
55
|
+
"//bibliography/clause".freeze
|
56
|
+
|
57
|
+
def terms_defs(isoxml, out, num)
|
58
|
+
f = isoxml.at(ns(self.class::TERM_CLAUSE)) or return num
|
59
|
+
out.div **attr_code(id: f["id"]) do |div|
|
60
|
+
clause_name(nil, terms_defs_title(f), div, nil)
|
61
|
+
f.elements.each do |e|
|
62
|
+
parse(e, div) unless %w{title source}.include? e.name
|
63
|
+
end
|
64
|
+
end
|
65
|
+
num
|
66
|
+
end
|
67
|
+
|
68
|
+
FRONT_CLAUSE = "//*[parent::preface]".freeze
|
69
|
+
|
70
|
+
def preface(isoxml, out)
|
71
|
+
isoxml.xpath(ns(self.class::FRONT_CLAUSE)).each do |c|
|
72
|
+
if c.name == "terms" || c.at(ns(".//terms")) then terms_defs isoxml, out, 0
|
73
|
+
else
|
74
|
+
out.div **attr_code(id: c["id"]) do |s|
|
75
|
+
clause_name(@xrefs.anchor(c['id'], :label),
|
76
|
+
c&.at(ns("./title"))&.content, s, nil)
|
77
|
+
c.elements.reject { |c1| c1.name == "title" }.each do |c1|
|
78
|
+
parse(c1, s)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def middle(isoxml, out)
|
86
|
+
middle_title(out)
|
87
|
+
middle_admonitions(isoxml, out)
|
88
|
+
clause isoxml, out
|
89
|
+
annex isoxml, out
|
90
|
+
bibliography isoxml, out
|
91
|
+
end
|
92
|
+
|
93
|
+
def termdef_parse(node, out)
|
94
|
+
set_termdomain("")
|
95
|
+
node.children.each { |n| parse(n, out) }
|
96
|
+
end
|
97
|
+
|
98
|
+
def clause(isoxml, out)
|
99
|
+
isoxml.xpath(ns(middle_clause)).each do |c|
|
100
|
+
out.div **attr_code(id: c["id"]) do |s|
|
101
|
+
clause_name(@xrefs.anchor(c['id'], :label),
|
102
|
+
c&.at(ns("./title"))&.content, s, class: c["container"] ? "containerhdr" : nil )
|
103
|
+
c.elements.reject { |c1| c1.name == "title" }.each do |c1|
|
104
|
+
parse(c1, s)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def clause_parse_title(node, div, c1, out)
|
111
|
+
if node["inline-header"] == "true"
|
112
|
+
inline_header_title(out, node, c1)
|
113
|
+
else
|
114
|
+
attrs = { class: node["container"] ? "containerhdr" : nil }
|
115
|
+
div.send "h#{@xrefs.anchor(node['id'], :level, :false) || '1'}", **attr_code(attrs) do |h|
|
116
|
+
lbl = @xrefs.anchor(node['id'], :label, false)
|
117
|
+
h << "#{lbl}. " if lbl && !@suppressheadingnumbers
|
118
|
+
c1&.children&.each { |c2| parse(c2, h) }
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def ol_depth(node)
|
124
|
+
ol_style(node["type"])
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|