asciimath2unitsml 0.3.2 → 0.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f51b82e234fddaf66252f77a276a3acf68dae4356502a3c900253f5d4d4dffcf
4
- data.tar.gz: 59dd18f009952329c1c07af2132ec06123c06dd3caea4ee7f22f17c0f4ec1cbc
3
+ metadata.gz: 25adab652658a50b2747ff9087cffa7c1c2fa864a701b253e393359ad3091ff0
4
+ data.tar.gz: 20d02312fcef3908ef823a59d18c45e6e03bc0c9d7c33b221c680048add583ca
5
5
  SHA512:
6
- metadata.gz: 9a925e3db85d3086d676c07c101609e87674d620394f5fa0a536ab3652f3aa9c0cc6a74507d79264e0154bf51ea4121d47b7275a94212bc934b822b0392a9970
7
- data.tar.gz: 59d98ebd629a20e8f03dc32a1870474e5808b9d38f51a87feec5eae9f0746535bed9dcf38b1faf3939319bb3989b1d926088e8d834388e48f045070e3749312a
6
+ metadata.gz: f82a936470d1e3ade5b48da9ea7a14825e7e0c82aaf14082b6c5dc44e7f09a04bede324875ed94879e2eeb2f483fc78aee4920075ced0ee528cf143a71424c5e
7
+ data.tar.gz: e3c5e9b073e51c4c8ae860c5c43cc6d2c39333f5b87f9eb6df8b10b77a293a910c6e46b5b7f260468be8be6b4ce8677e9cd49cd19e05eae34e5158d272ab0352
@@ -16,21 +16,11 @@ jobs:
16
16
  strategy:
17
17
  fail-fast: false
18
18
  matrix:
19
- ruby: [ '2.7', '2.6', '2.5', '2.4' ]
19
+ ruby: [ '3.0', '2.7', '2.6', '2.5' ]
20
20
  os: [ ubuntu-latest, windows-latest, macos-latest ]
21
21
  experimental: [ false ]
22
- include:
23
- - ruby: '3.0'
24
- os: 'ubuntu-latest'
25
- experimental: true
26
- - ruby: '3.0'
27
- os: 'windows-latest'
28
- experimental: true
29
- - ruby: '3.0'
30
- os: 'macos-latest'
31
- experimental: true
32
22
  steps:
33
- - uses: actions/checkout@master
23
+ - uses: actions/checkout@v2
34
24
  with:
35
25
  submodules: true
36
26
 
@@ -40,14 +30,3 @@ jobs:
40
30
  bundler-cache: true
41
31
 
42
32
  - run: bundle exec rake
43
-
44
- tests-passed:
45
- needs: rake
46
- runs-on: ubuntu-latest
47
- steps:
48
- - uses: peter-evans/repository-dispatch@v1
49
- with:
50
- token: ${{ secrets.METANORMA_CI_PAT_TOKEN || secrets.GITHUB_TOKEN }}
51
- repository: ${{ github.repository }}
52
- event-type: notify
53
- client-payload: '{"ref": "${{ github.ref }}", "sha": "${{ github.sha }}"}'
data/.hound.yml ADDED
@@ -0,0 +1,5 @@
1
+ # Auto-generated by Cimas: Do not edit it manually!
2
+ # See https://github.com/metanorma/cimas
3
+ ruby:
4
+ enabled: true
5
+ config_file: .rubocop.yml
data/.rubocop.yml CHANGED
@@ -1,14 +1,10 @@
1
- # This project follows the Ribose OSS style guide.
2
- # https://github.com/riboseinc/oss-guides
3
- # All project-specific additions and overrides should be specified in this file.
1
+ # Auto-generated by Cimas: Do not edit it manually!
2
+ # See https://github.com/metanorma/cimas
4
3
  inherit_from:
5
4
  - https://raw.githubusercontent.com/riboseinc/oss-guides/master/ci/rubocop.yml
6
5
 
7
6
  # local repo-specific modifications
7
+ # ...
8
8
 
9
9
  AllCops:
10
- DisplayCopNames: false
11
- StyleGuideCopsOnly: false
12
- TargetRubyVersion: 2.4
13
- Rails:
14
- Enabled: true
10
+ TargetRubyVersion: 2.5
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
1
  source "https://rubygems.org"
2
-
2
+
3
3
  # Specify your gem's dependencies in ruby-vobject.gemspec
4
4
  gemspec
data/README.adoc CHANGED
@@ -59,6 +59,24 @@ units. The options are an XML entity, or the values `space` or `nospace` (for wh
59
59
  Standalone prefixes can be recognised by replacing the unit with hyphen; so `unitsml(p-)` corresponds
60
60
  to the standalone prefix "pico" (and is rendered as "p").
61
61
 
62
+ The gem also supports fundamental units, e.g. `unitsml(e)` for the atomic unit of charge, _e_,
63
+ and symbols for dimensions. The latter are entered as `dim_XXX`, where `XXX` is their established symbol:
64
+
65
+ |===
66
+ |Symbol | Dimension
67
+
68
+ |dim_L | Length
69
+ |dim_M | Mass
70
+ |dim_T | Time
71
+ |dim_I | Electric Current
72
+ |dim_Theta | Thermodynamic Temperature
73
+ |dim_N | Amount of Substance
74
+ |dim_J | Luminous Intensity
75
+ |dim_phi | Plane Angle (dimensionless)
76
+ |===
77
+
78
+ e.g. `unitsml(dim_I)` for the dimension of electric current, 𝖨.
79
+
62
80
  == Rendering
63
81
 
64
82
  The output of the gem is MathML, with MathML unit expressions (expressed as `<mi>`,
@@ -141,7 +159,7 @@ The converter is run as:
141
159
  [source,ruby]
142
160
  ----
143
161
  c = Asciimath2UnitsML::Conv.new()
144
- c.Asciimath2UnitsML(1 "unitsml(mm*s^-2)") # AsciiMath string containing UnitsML
162
+ c.Asciimath2UnitsML('1 "unitsml(mm*s^-2)"') # AsciiMath string containing UnitsML
145
163
  c.MathML2UnitsML("<math xmlns='http://www.w3.org/1998/Math/MathML'><mn>7</mn>"\
146
164
  "<mtext>unitsml(kg^-2)</mtext></math>") # AsciiMath string containing <mtext>unitsml()</mtext>
147
165
  c.MathML2UnitsML(Nokogiri::XML("<math xmlns='http://www.w3.org/1998/Math/MathML'><mn>7</mn>"\
data/Rakefile CHANGED
@@ -3,4 +3,4 @@ require "rspec/core/rake_task"
3
3
 
4
4
  RSpec::Core::RakeTask.new(:spec)
5
5
 
6
- task :default => :spec
6
+ task default: :spec
@@ -1,6 +1,6 @@
1
1
  # coding: utf-8
2
2
 
3
- lib = File.expand_path("../lib", __FILE__)
3
+ lib = File.expand_path("lib", __dir__)
4
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
5
  require "asciimath2unitsml/version"
6
6
 
@@ -22,44 +22,41 @@ Gem::Specification.new do |spec|
22
22
  spec.require_paths = ["lib"]
23
23
  spec.files = `git ls-files`.split("\n")
24
24
  spec.test_files = `git ls-files -- {spec}/*`.split("\n")
25
- spec.required_ruby_version = Gem::Requirement.new(">= 2.4.0")
25
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.5.0")
26
26
 
27
27
  # get an array of submodule dirs relatively to root repo
28
28
  `git config --file .gitmodules --get-regexp '\\.path$'`
29
29
  .split("\n")
30
30
  .map { |kv_str| kv_str.split(" ") }
31
31
  .each do |(_, submodule_path)|
32
+ # for each submodule, change working directory to that submodule
33
+ Dir.chdir(submodule_path) do
34
+ # issue git ls-files in submodule's directory
35
+ submodule_files = `git ls-files | grep -i '.yaml$'`.split($\)
32
36
 
33
- # for each submodule, change working directory to that submodule
34
- Dir.chdir(submodule_path) do
35
-
36
- # issue git ls-files in submodule's directory
37
- submodule_files = `git ls-files | grep -i '.yaml$'`.split($\)
38
-
39
- submodule_files_paths = submodule_files.map do |filename|
40
- File.join submodule_path, filename
41
- end
42
-
43
- # add relative paths to gem.files
44
- spec.files += submodule_files_paths
37
+ submodule_files_paths = submodule_files.map do |filename|
38
+ File.join submodule_path, filename
45
39
  end
40
+
41
+ # add relative paths to gem.files
42
+ spec.files += submodule_files_paths
43
+ end
46
44
  end
47
45
 
48
46
  spec.add_dependency "asciimath"
49
47
  spec.add_dependency "htmlentities"
50
- spec.add_dependency "nokogiri", "~> 1.10.4"
48
+ spec.add_dependency "nokogiri", "~> 1.12"
51
49
  spec.add_dependency "rsec", "~> 1.0.0"
52
50
 
53
51
  spec.add_development_dependency "bundler"
54
- spec.add_development_dependency "byebug", "~> 9.1"
52
+ spec.add_development_dependency "debug"
55
53
  spec.add_development_dependency "equivalent-xml", "~> 0.6"
56
54
  spec.add_development_dependency "guard", "~> 2.14"
57
55
  spec.add_development_dependency "guard-rspec", "~> 4.7"
58
56
  spec.add_development_dependency "rake", "~> 12.0"
57
+ spec.add_development_dependency "rexml"
59
58
  spec.add_development_dependency "rspec", "~> 3.6"
60
59
  spec.add_development_dependency "rubocop", "~> 1.5.2"
61
60
  spec.add_development_dependency "simplecov", "~> 0.15"
62
61
  spec.add_development_dependency "timecop", "~> 0.9"
63
- spec.add_development_dependency "rexml"
64
62
  end
65
-
data/bin/rspec CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
-
2
+
3
3
  # This file was generated by Bundler.
4
4
  #
5
5
  # The application 'rspec' is installed as part of a gem, and
@@ -15,4 +15,3 @@ require "rubygems"
15
15
  require "bundler/setup"
16
16
 
17
17
  load Gem.bin_path("rspec-core", "rspec")
18
-
@@ -3,6 +3,8 @@ require "nokogiri"
3
3
  require "htmlentities"
4
4
  require "yaml"
5
5
  require "rsec"
6
+ require_relative "read"
7
+ require_relative "dimensions"
6
8
  require_relative "string"
7
9
  require_relative "parse"
8
10
  require_relative "render"
@@ -19,6 +21,7 @@ module Asciimath2UnitsML
19
21
  .each_with_object({}) do |(k, v), m|
20
22
  m[k.to_s] = UnitsDB::Dimension.new(k, v)
21
23
  end
24
+ @dimensions = flip_name_and_symbols(@dimensions_id)
22
25
  @prefixes_id = read_yaml("../unitsdb/prefixes.yaml")
23
26
  .each_with_object({}) do |(k, v), m|
24
27
  m[k] = UnitsDB::Prefix.new(k, v)
@@ -33,10 +36,10 @@ module Asciimath2UnitsML
33
36
  m[k.to_s] = UnitsDB::Unit.new(k.to_s, v)
34
37
  end
35
38
  @units = flip_name_and_symbols(@units_id)
36
- @symbols = @units.each_with_object({}) do |(_k, v), m|
39
+ @symbols = @units.merge(@dimensions).each_with_object({}) do |(_k, v), m|
37
40
  v.symbolids.each { |x| m[x] = v.symbols_hash[x] }
38
41
  end
39
- @parser = parser
42
+ @parser, @dim_parser = parsers
40
43
  @multiplier = multiplier(options[:multiplier] || "\u22c5")
41
44
  end
42
45
 
@@ -46,7 +49,7 @@ module Asciimath2UnitsML
46
49
 
47
50
  def prefix(units)
48
51
  units.map { |u| u[:prefix] }.reject(&:nil?).uniq.map do |p|
49
- <<~END
52
+ <<~XML
50
53
  <Prefix xmlns='#{UNITSML_NS}' prefixBase='#{@prefixes[p].base}'
51
54
  prefixPower='#{@prefixes[p].power}' xml:id='#{@prefixes[p].id}'>
52
55
  <PrefixName xml:lang="en">#{@prefixes[p].name}</PrefixName>
@@ -55,74 +58,21 @@ module Asciimath2UnitsML
55
58
  <PrefixSymbol type="LaTeX">#{@prefixes[p].latex}</PrefixSymbol>
56
59
  <PrefixSymbol type="HTML">#{htmlent @prefixes[p].html}</PrefixSymbol>
57
60
  </Prefix>
58
- END
61
+ XML
59
62
  end.join("\n")
60
63
  end
61
64
 
62
- def dimension_components(dims)
63
- return if dims.nil? || dims.empty?
64
-
65
- <<~END
66
- <Dimension xmlns='#{UNITSML_NS}' xml:id="#{dim_id(dims)}">
67
- #{dims.map { |u| dimension1(u) }.join("\n")}
68
- </Dimension>
69
- END
70
- end
71
-
72
- U2D = {
73
- "m" => { dimension: "Length", order: 1, symbol: "L" },
74
- "g" => { dimension: "Mass", order: 2, symbol: "M" },
75
- "kg" => { dimension: "Mass", order: 2, symbol: "M" },
76
- "s" => { dimension: "Time", order: 3, symbol: "T" },
77
- "A" => { dimension: "ElectricCurrent", order: 4, symbol: "I" },
78
- "K" => { dimension: "ThermodynamicTemperature", order: 5,
79
- symbol: "Theta" },
80
- "degK" => { dimension: "ThermodynamicTemperature", order: 5,
81
- symbol: "Theta" },
82
- "mol" => { dimension: "AmountOfSubstance", order: 6, symbol: "N" },
83
- "cd" => { dimension: "LuminousIntensity", order: 7, symbol: "J" },
84
- "deg" => { dimension: "PlaneAngle", order: 8, symbol: "Phi" },
85
- }.freeze
86
-
87
- def units2dimensions(units)
88
- norm = decompose_units(units)
89
- return if norm.any? do |u|
90
- u[:unit] == "unknown" || u[:prefix] == "unknown" || u[:unit].nil?
91
- end
92
-
93
- norm.map do |u|
94
- { dimension: U2D[u[:unit]][:dimension],
95
- unit: u[:unit],
96
- exponent: u[:exponent] || 1,
97
- symbol: U2D[u[:unit]][:symbol] }
98
- end.sort { |a, b| U2D[a[:unit]][:order] <=> U2D[b[:unit]][:order] }
99
- end
100
-
101
- def dimension1(u)
102
- %(<#{u[:dimension]} symbol="#{u[:symbol]}"
103
- powerNumerator="#{float_to_display(u[:exponent])}"/>)
104
- end
105
-
106
- def dim_id(dims)
107
- return nil if dims.nil? || dims.empty?
108
-
109
- dimhash = dims.each_with_object({}) { |h, m| m[h[:dimension]] = h }
110
- dimsvector = %w(Length Mass Time ElectricCurrent ThermodynamicTemperature
111
- AmountOfSubstance LuminousIntensity PlaneAngle)
112
- .map { |h| dimhash.dig(h, :exponent) }.join(":")
113
- id = @dimensions_id&.values&.select { |d| d.vector == dimsvector }
114
- &.first&.id and return id.to_s
115
- "D_" + dims.map do |d|
116
- U2D[d[:unit]][:symbol] +
117
- (d[:exponent] == 1 ? "" : float_to_display(d[:exponent]))
118
- end.join("")
119
- end
120
-
121
65
  def decompose_units(units)
122
66
  gather_units(units_only(units).map { |u| decompose_unit(u) }.flatten)
123
67
  end
124
68
 
125
69
  def gather_units(units)
70
+ if units[0][:dim] then gather_dimensions(units)
71
+ else gather_units1(units)
72
+ end
73
+ end
74
+
75
+ def gather_units1(units)
126
76
  units.sort_by { |a| a[:unit] }.each_with_object([]) do |k, m|
127
77
  if m.empty? || m[-1][:unit] != k[:unit] then m << k
128
78
  else
@@ -138,12 +88,24 @@ module Asciimath2UnitsML
138
88
  end
139
89
  end
140
90
 
91
+ def gather_dimensions(units)
92
+ units.sort_by { |a| a[:dim] }.each_with_object([]) do |k, m|
93
+ if m.empty? || m[-1][:dim] != k[:dim] then m << k
94
+ else
95
+ m[-1] = {
96
+ dim: m[-1][:dim],
97
+ exponent: (k[:exponent]&.to_f || 1) +
98
+ (m[-1][:exponent]&.to_f || 1),
99
+ }
100
+ end
101
+ end
102
+ end
103
+
141
104
  # treat g not kg as base unit: we have stripped the prefix k in parsing
142
105
  # reduce units down to basic units
143
106
  def decompose_unit(u)
144
- if u[:unit].nil? then u
145
- elsif u[:unit] == "g" then u
146
- elsif @units[u[:unit]].system_type == "SI_base" then u
107
+ if u[:unit].nil? || u[:unit] == "g" ||
108
+ @units[u[:unit]].system_type == "SI_base" then u
147
109
  elsif !@units[u[:unit]].si_derived_bases
148
110
  { prefix: u[:prefix], unit: "unknown", exponent: u[:exponent] }
149
111
  else
@@ -188,41 +150,22 @@ module Asciimath2UnitsML
188
150
  id = quantity || @units[normtext].quantities.first
189
151
  @units[normtext]&.dimension and
190
152
  dim = %( dimensionURL="##{@units[normtext].dimension}")
191
- <<~END
153
+ <<~XML
192
154
  <Quantity xmlns='#{UNITSML_NS}' xml:id="#{id}"#{dim} quantityType="base">
193
155
  #{quantityname(id)}
194
156
  </Quantity>
195
- END
196
- end
197
-
198
- def dimid2dimensions(normtext)
199
- @dimensions_id[normtext].keys.map do |k|
200
- { dimension: k,
201
- symbol: U2D.values.select { |v| v[:dimension] == k }.first[:symbol],
202
- exponent: @dimensions_id[normtext].exponent(k) }
203
- end
204
- end
205
-
206
- def dimension(normtext)
207
- return unless @units[normtext]&.dimension
208
-
209
- dims = dimid2dimensions(@units[normtext]&.dimension)
210
- <<~END
211
- <Dimension xmlns='#{UNITSML_NS}' xml:id="#{@units[normtext]&.dimension}">
212
- #{dims.map { |u| dimension1(u) }.join("\n")}
213
- </Dimension>
214
- END
157
+ XML
215
158
  end
216
159
 
217
160
  def unitsml(units, origtext, normtext, quantity, name)
218
161
  dims = units2dimensions(units)
219
- <<~END
162
+ <<~XML
220
163
  #{unit(units, origtext, normtext, dims, name)}
221
164
  #{prefix(units)}
222
165
  #{dimension(normtext)}
223
166
  #{dimension_components(dims)}
224
167
  #{quantity(normtext, quantity)}
225
- END
168
+ XML
226
169
  end
227
170
  end
228
171
  end
@@ -0,0 +1,117 @@
1
+ module Asciimath2UnitsML
2
+ class Conv
3
+ def dimension_components(dims)
4
+ return if dims.nil? || dims.empty?
5
+
6
+ <<~XML
7
+ <Dimension xmlns='#{UNITSML_NS}' xml:id="#{dim_id(dims)}">
8
+ #{dims.map { |u| dimension1(u) }.join("\n")}
9
+ </Dimension>
10
+ XML
11
+ end
12
+
13
+ U2D = {
14
+ "m" => { dimension: "Length", order: 1, symbol: "L" },
15
+ "g" => { dimension: "Mass", order: 2, symbol: "M" },
16
+ "kg" => { dimension: "Mass", order: 2, symbol: "M" },
17
+ "s" => { dimension: "Time", order: 3, symbol: "T" },
18
+ "A" => { dimension: "ElectricCurrent", order: 4, symbol: "I" },
19
+ "K" => { dimension: "ThermodynamicTemperature", order: 5,
20
+ symbol: "Theta" },
21
+ "degK" => { dimension: "ThermodynamicTemperature", order: 5,
22
+ symbol: "Theta" },
23
+ "mol" => { dimension: "AmountOfSubstance", order: 6, symbol: "N" },
24
+ "cd" => { dimension: "LuminousIntensity", order: 7, symbol: "J" },
25
+ "deg" => { dimension: "PlaneAngle", order: 8, symbol: "phi" },
26
+ }.freeze
27
+
28
+ Dim2D = {
29
+ "dim_L" => U2D["m"],
30
+ "dim_M" => U2D["g"],
31
+ "dim_T" => U2D["s"],
32
+ "dim_I" => U2D["A"],
33
+ "dim_Theta" => U2D["K"],
34
+ "dim_N" => U2D["mol"],
35
+ "dim_J" => U2D["cd"],
36
+ "dim_phi" => U2D["deg"],
37
+ }.freeze
38
+
39
+ def units2dimensions(units)
40
+ norm = decompose_units(units)
41
+ return units2dimensions_dim_input(norm) if norm[0][:dim]
42
+ return if norm.any? do |u|
43
+ u[:unit] == "unknown" || u[:prefix] == "unknown" || u[:unit].nil?
44
+ end
45
+
46
+ norm.map do |u|
47
+ { dimension: U2D[u[:unit]][:dimension],
48
+ unit: u[:unit],
49
+ exponent: u[:exponent] || 1,
50
+ symbol: U2D[u[:unit]][:symbol] }
51
+ end.sort { |a, b| U2D[a[:unit]][:order] <=> U2D[b[:unit]][:order] }
52
+ end
53
+
54
+ def units2dimensions_dim_input(norm)
55
+ norm.map do |u|
56
+ { dimension: Dim2D[u[:dim]][:dimension],
57
+ exponent: u[:exponent] || 1,
58
+ id: u[:dim],
59
+ symbol: Dim2D[u[:dim]][:symbol] }
60
+ end.sort { |a, b| Dim2D[a[:id]][:order] <=> Dim2D[b[:id]][:order] }
61
+ end
62
+
63
+ def dimension1(dim)
64
+ %(<#{dim[:dimension]} symbol="#{dim[:symbol]}"
65
+ powerNumerator="#{float_to_display(dim[:exponent])}"/>)
66
+ end
67
+
68
+ def dim_id(dims)
69
+ return nil if dims.nil? || dims.empty?
70
+
71
+ dimhash = dims.each_with_object({}) { |h, m| m[h[:dimension]] = h }
72
+ dimsvector = %w(Length Mass Time ElectricCurrent ThermodynamicTemperature
73
+ AmountOfSubstance LuminousIntensity PlaneAngle)
74
+ .map { |h| dimhash.dig(h, :exponent) }.join(":")
75
+ id = @dimensions_id&.values&.select { |d| d.vector == dimsvector }
76
+ &.first&.id and return id.to_s
77
+ "D_" + dims.map do |d|
78
+ (U2D.dig(d[:unit], :symbol) || Dim2D.dig(d[:id], :symbol)) +
79
+ (d[:exponent] == 1 ? "" : float_to_display(d[:exponent]))
80
+ end.join("")
81
+ end
82
+
83
+ def decompose_units(units)
84
+ gather_units(units_only(units).map { |u| decompose_unit(u) }.flatten)
85
+ end
86
+
87
+ def dimid2dimensions(normtext)
88
+ @dimensions_id[normtext].keys.map do |k|
89
+ { dimension: k,
90
+ symbol: U2D.values.select { |v| v[:dimension] == k }.first[:symbol],
91
+ exponent: @dimensions_id[normtext].exponent(k) }
92
+ end
93
+ end
94
+
95
+ def dimension(normtext)
96
+ return unless @units[normtext]&.dimension
97
+
98
+ dims = dimid2dimensions(@units[normtext]&.dimension)
99
+ <<~XML
100
+ <Dimension xmlns='#{UNITSML_NS}' xml:id="#{@units[normtext]&.dimension}">
101
+ #{dims.map { |u| dimension1(u) }.join("\n")}
102
+ </Dimension>
103
+ XML
104
+ end
105
+
106
+ def unitsml(units, origtext, normtext, quantity, name)
107
+ dims = units2dimensions(units)
108
+ <<~XML
109
+ #{unit(units, origtext, normtext, dims, name)}
110
+ #{prefix(units)}
111
+ #{dimension(normtext)}
112
+ #{dimension_components(dims)}
113
+ #{quantity(normtext, quantity)}
114
+ XML
115
+ end
116
+ end
117
+ end