stupidedi 1.3.21 → 1.3.22

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.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/lib/stupidedi/builder/builder_dsl.rb +5 -0
  3. data/lib/stupidedi/builder/constraint_table.rb +100 -74
  4. data/lib/stupidedi/builder/generation.rb +73 -70
  5. data/lib/stupidedi/builder/instruction.rb +10 -0
  6. data/lib/stupidedi/builder/instruction_table.rb +19 -7
  7. data/lib/stupidedi/builder/state_machine.rb +9 -3
  8. data/lib/stupidedi/builder/states/abstract_state.rb +1 -1
  9. data/lib/stupidedi/builder/states/failure_state.rb +1 -1
  10. data/lib/stupidedi/builder/states/initial_state.rb +4 -4
  11. data/lib/stupidedi/contrib/002001/guides/SH856.rb +4 -4
  12. data/lib/stupidedi/contrib/002001/transaction_set_defs/PO830.rb +2 -2
  13. data/lib/stupidedi/contrib/003010/guides/PS830.rb +4 -4
  14. data/lib/stupidedi/contrib/003010/guides/RA820.rb +22 -12
  15. data/lib/stupidedi/contrib/003010/transaction_set_defs/PC860.rb +2 -2
  16. data/lib/stupidedi/contrib/003010/transaction_set_defs/PS830.rb +1 -1
  17. data/lib/stupidedi/contrib/003050/guides/PO850.rb +2 -2
  18. data/lib/stupidedi/contrib/003050/transaction_set_defs/PO850.rb +2 -2
  19. data/lib/stupidedi/contrib/004010/guides.rb +0 -1
  20. data/lib/stupidedi/contrib/004010/transaction_set_defs/AR943.rb +1 -1
  21. data/lib/stupidedi/contrib/004010/transaction_set_defs/IM210.rb +2 -2
  22. data/lib/stupidedi/contrib/004010/transaction_set_defs/RE944.rb +1 -1
  23. data/lib/stupidedi/contrib/004010/transaction_set_defs/SH856.rb +1 -7
  24. data/lib/stupidedi/editor.rb +0 -1
  25. data/lib/stupidedi/guides/004010/guide_builder.rb +1 -1
  26. data/lib/stupidedi/guides/005010/X223-HC837I.rb +1192 -1195
  27. data/lib/stupidedi/guides/005010/guide_builder.rb +1 -1
  28. data/lib/stupidedi/schema.rb +1 -0
  29. data/lib/stupidedi/schema/auditor.rb +435 -0
  30. data/lib/stupidedi/schema/loop_def.rb +18 -1
  31. data/lib/stupidedi/schema/transaction_set_def.rb +12 -0
  32. data/lib/stupidedi/version.rb +1 -1
  33. data/lib/stupidedi/versions/functional_groups/004010/transaction_set_defs/HP835.rb +3 -17
  34. data/lib/stupidedi/versions/functional_groups/005010/element_types/time_val.rb +3 -2
  35. data/lib/stupidedi/versions/functional_groups/005010/segment_defs.rb +9 -6
  36. data/lib/stupidedi/versions/functional_groups/005010/transaction_set_defs/HB271.rb +25 -9
  37. data/lib/stupidedi/versions/functional_groups/005010/transaction_set_defs/HP835.rb +2 -2
  38. data/lib/stupidedi/zipper.rb +20 -1
  39. data/lib/stupidedi/zipper/memoized_cursor.rb +2 -0
  40. data/lib/stupidedi/zipper/path.rb +10 -0
  41. data/lib/stupidedi/zipper/root_cursor.rb +1 -1
  42. data/lib/stupidedi/zipper/stack_cursor.rb +174 -0
  43. data/spec/examples/stupidedi/audit_spec.rb +58 -0
  44. data/spec/spec_helper.rb +21 -13
  45. data/spec/support/rcov.rb +9 -4
  46. metadata +4 -1
@@ -142,7 +142,24 @@ module Stupidedi
142
142
  raise Exceptions::InvalidSchemaError,
143
143
  "first child must be a SegmentUse"
144
144
  elsif header.head.repeat_count.include?(2)
145
- "first child must have RepeatCount.bounded(1)"
145
+ raise Exceptions::InvalidSchemaError,
146
+ "first child must have RepeatCount.bounded(1)"
147
+ end
148
+
149
+ trailer.each.with_index do |s, k|
150
+ unless s.segment?
151
+ if s.respond_to?(:pretty_inspect)
152
+ raise Exceptions::InvalidSchemaError,
153
+ "arguments after last child LoopDef (#{loop_defs.last.id}) " +
154
+ "must be segments, but #{k+1} arguments later is not a " +
155
+ "SegmentUse: #{s.pretty_inspect}"
156
+ else
157
+ raise Exceptions::InvalidSchemaError,
158
+ "arguments after last child LoopDef (#{loop_defs.last.id}) " +
159
+ "must be segments, but #{k+1} arguments later is not a " +
160
+ "SegmentUse: #{s.inspect}"
161
+ end
162
+ end
146
163
  end
147
164
 
148
165
  new(id, repeat_count, header, loop_defs, trailer, nil)
@@ -84,6 +84,18 @@ module Stupidedi
84
84
 
85
85
  # @return [TransactionSetDef]
86
86
  def build(functional_group, id, name, *table_defs)
87
+ table_defs.each.with_index do |t, k|
88
+ unless t.table?
89
+ if t.respond_to?(:pretty_inspect)
90
+ raise Exceptions::InvalidSchemaError,
91
+ "argument #{k+4} is not a TableDef: #{t.pretty_inspect}"
92
+ else
93
+ raise Exceptions::InvalidSchemaError,
94
+ "argument #{k+4} is not a TableDef: #{t.inspect}"
95
+ end
96
+ end
97
+ end
98
+
87
99
  new(functional_group, id, name, table_defs)
88
100
  end
89
101
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Stupidedi
4
- VERSION = "1.3.21"
4
+ VERSION = "1.3.22"
5
5
  end
@@ -20,21 +20,14 @@ module Stupidedi
20
20
  s::TRN.use(400, r::Optional, d::RepeatCount.bounded(1)),
21
21
  s::CUR.use(500, r::Optional, d::RepeatCount.bounded(1)),
22
22
  s::REF.use(600, r::Optional, d::RepeatCount.bounded(1)),
23
- s::REF.use(600, r::Optional, d::RepeatCount.bounded(1)),
24
23
  s::DTM.use(700, r::Optional, d::RepeatCount.bounded(1)),
25
24
 
26
- d::LoopDef.build("1000A", d::RepeatCount.bounded(1),
25
+ d::LoopDef.build("1000", d::RepeatCount.bounded(200),
27
26
  s:: N1.use( 800, r::Mandatory, d::RepeatCount.bounded(1)),
28
27
  s:: N3.use(1000, r::Mandatory, d::RepeatCount.bounded(1)),
29
28
  s:: N4.use(1100, r::Mandatory, d::RepeatCount.bounded(1)),
30
29
  s::REF.use(1200, r::Optional, d::RepeatCount.bounded(4)),
31
- s::PER.use(1300, r::Optional, d::RepeatCount.bounded(1))),
32
-
33
- d::LoopDef.build("1000B", d::RepeatCount.bounded(1),
34
- s:: N1.use( 800, r::Mandatory, d::RepeatCount.bounded(1)),
35
- s:: N3.use(1000, r::Optional, d::RepeatCount.bounded(1)),
36
- s:: N4.use(1100, r::Optional, d::RepeatCount.bounded(1)),
37
- s::REF.use(1200, r::Optional, d::RepeatCount.unbounded))),
30
+ s::PER.use(1300, r::Optional, d::RepeatCount.bounded(1)))),
38
31
 
39
32
  d::TableDef.detail("Table 2 - Detail",
40
33
  d::LoopDef.build("2000", d::RepeatCount.unbounded,
@@ -45,15 +38,9 @@ module Stupidedi
45
38
  d::LoopDef.build("2100", d::RepeatCount.unbounded,
46
39
  s::CLP.use(100, r::Mandatory, d::RepeatCount.bounded(1)),
47
40
  s::CAS.use(200, r::Optional, d::RepeatCount.bounded(99)),
48
- s::NM1.use(300, r::Mandatory, d::RepeatCount.bounded(1)),
49
- s::NM1.use(300, r::Optional, d::RepeatCount.bounded(1)),
50
- s::NM1.use(300, r::Optional, d::RepeatCount.bounded(1)),
51
- s::NM1.use(300, r::Optional, d::RepeatCount.bounded(1)),
52
- s::NM1.use(300, r::Optional, d::RepeatCount.bounded(1)),
53
- s::NM1.use(300, r::Optional, d::RepeatCount.bounded(1)),
41
+ s::NM1.use(300, r::Mandatory, d::RepeatCount.bounded(9)),
54
42
  s::MIA.use(330, r::Optional, d::RepeatCount.bounded(1)),
55
43
  s::MOA.use(350, r::Optional, d::RepeatCount.bounded(1)),
56
- s::REF.use(400, r::Optional, d::RepeatCount.bounded(5)),
57
44
  s::REF.use(400, r::Optional, d::RepeatCount.bounded(10)),
58
45
  s::DTM.use(500, r::Optional, d::RepeatCount.bounded(4)),
59
46
  s::PER.use(600, r::Optional, d::RepeatCount.bounded(3)),
@@ -65,7 +52,6 @@ module Stupidedi
65
52
  s::DTM.use( 800, r::Optional, d::RepeatCount.bounded(3)),
66
53
  s::CAS.use( 900, r::Optional, d::RepeatCount.bounded(99)),
67
54
  s::REF.use(1000, r::Optional, d::RepeatCount.bounded(7)),
68
- s::REF.use(1000, r::Optional, d::RepeatCount.bounded(10)),
69
55
  s::AMT.use(1100, r::Optional, d::RepeatCount.bounded(12)),
70
56
  s::QTY.use(1200, r::Optional, d::RepeatCount.bounded(6)),
71
57
  s:: LQ.use(1300, r::Optional, d::RepeatCount.bounded(99))))),
@@ -289,9 +289,10 @@ module Stupidedi
289
289
  hour = object.to_s.slice(0, 2).to_i
290
290
  minute = object.to_s.slice(2, 2).try{|mm| mm.to_i unless mm.blank? }
291
291
  second = object.to_s.slice(4, 2).try{|ss| ss.to_d unless ss.blank? }
292
+ decimal = object.to_s.slice(6..-1).try{|dd| dd.to_d unless dd.blank? }
292
293
 
293
- if decimal = object.to_s.slice(6..-1)
294
- second += "0.#{decimal}".to_d
294
+ if decimal
295
+ second += ("0.%02d" % decimal).to_d
295
296
  end
296
297
 
297
298
  self::NonEmpty.new(hour, minute, second, usage, position)
@@ -10,8 +10,8 @@ module Stupidedi
10
10
  autoload :AAA,
11
11
  "stupidedi/versions/functional_groups/005010/segment_defs/AAA"
12
12
 
13
- autoload :ACT,
14
- "stupidedi/versions/functional_groups/005010/segment_defs/ACT"
13
+ autoload :ACT,
14
+ "stupidedi/versions/functional_groups/005010/segment_defs/ACT"
15
15
 
16
16
  autoload :AK1,
17
17
  "stupidedi/versions/functional_groups/005010/segment_defs/AK1"
@@ -91,9 +91,12 @@ module Stupidedi
91
91
  autoload :DTP,
92
92
  "stupidedi/versions/functional_groups/005010/segment_defs/DTP"
93
93
 
94
- autoload :EB,
94
+ autoload :EB,
95
95
  "stupidedi/versions/functional_groups/005010/segment_defs/EB"
96
96
 
97
+ autoload :EC,
98
+ "stupidedi/versions/functional_groups/005010/segment_defs/EC"
99
+
97
100
  autoload :EQ,
98
101
  "stupidedi/versions/functional_groups/005010/segment_defs/EQ"
99
102
 
@@ -114,9 +117,9 @@ module Stupidedi
114
117
 
115
118
  autoload :HLH,
116
119
  "stupidedi/versions/functional_groups/005010/segment_defs/HLH"
117
-
118
- autoload :III,
119
- "stupidedi/versions/functional_groups/005010/segment_defs/III"
120
+
121
+ autoload :III,
122
+ "stupidedi/versions/functional_groups/005010/segment_defs/III"
120
123
 
121
124
  autoload :ICM,
122
125
  "stupidedi/versions/functional_groups/005010/segment_defs/ICM"
@@ -11,6 +11,15 @@ module Stupidedi
11
11
  r = SegmentReqs
12
12
  s = SegmentDefs
13
13
 
14
+ # NOTE: This definition is not usable as-is, because it references
15
+ # segments that we don't have definitions for. The HB270 and HB271
16
+ # *standards* refer to these, but the *implementation guide* doesn't
17
+ # use or include definitions for these: LUI, VEH, PID, PDR, PDP, EM,
18
+ # SD1, PKD, PCT.
19
+ #
20
+ # Furthermore, the 2120 NM1 loop is in conflict with the 2100 NM1
21
+ # loop because both don't have any constraints (the implementation
22
+ # guides do have the necessary constraints).
14
23
  HB271 = d::TransactionSetDef.build("HB", "271",
15
24
  "Eligibility, Coverage, or Benefit Information",
16
25
 
@@ -25,6 +34,9 @@ module Stupidedi
25
34
  s::AAA.use(250, r::Optional, d::RepeatCount.bounded(9)),
26
35
 
27
36
  d::LoopDef.build("2100", d::RepeatCount.unbounded,
37
+ # This NM1 needs to have a constraint on NM1-01 to avoid
38
+ # ambiguity with 2120 NM1, but the particular constraints
39
+ # need to be specified in the implementation guide
28
40
  s::NM1.use( 300, r::Mandatory, d::RepeatCount.bounded(1)),
29
41
  s::REF.use( 400, r::Optional, d::RepeatCount.bounded(9)),
30
42
  s:: N2.use( 500, r::Optional, d::RepeatCount.bounded(1)),
@@ -67,17 +79,21 @@ module Stupidedi
67
79
  s::AMT.use(3100, r::Optional, d::RepeatCount.bounded(5)))),
68
80
  # s::PCT.use(3200, r::Optional, d::RepeatCount.bounded(5)))),
69
81
 
70
- s:: LS.use(3300, r::Optional, d::RepeatCount.bounded(1)),
82
+ d::LoopDef.build("2120 LS", d::RepeatCount.bounded(1),
83
+ s:: LS.use(3300, r::Optional, d::RepeatCount.bounded(1)),
71
84
 
72
- d::LoopDef.build("2120", d::RepeatCount.unbounded,
73
- s::NM1.use(3400, r::Optional, d::RepeatCount.bounded(1)),
74
- s:: N2.use(3500, r::Optional, d::RepeatCount.bounded(1)),
75
- s:: N3.use(3600, r::Optional, d::RepeatCount.bounded(1)),
76
- s:: N4.use(3700, r::Optional, d::RepeatCount.bounded(1)),
77
- s::PER.use(3800, r::Optional, d::RepeatCount.bounded(3)),
78
- s::PRV.use(3900, r::Optional, d::RepeatCount.bounded(1))),
85
+ # d::LoopDef.build("2120", d::RepeatCount.unbounded,
86
+ # # This NM1 needs to have a constraint on NM1-01 to avoid
87
+ # # ambiguity with 2100 NM1, but the particular constraints
88
+ # # need to be specified in the implementation guide
89
+ # s::NM1.use(3400, r::Optional, d::RepeatCount.bounded(1)),
90
+ # s:: N2.use(3500, r::Optional, d::RepeatCount.bounded(1)),
91
+ # s:: N3.use(3600, r::Optional, d::RepeatCount.bounded(1)),
92
+ # s:: N4.use(3700, r::Optional, d::RepeatCount.bounded(1)),
93
+ # s::PER.use(3800, r::Optional, d::RepeatCount.bounded(3)),
94
+ # s::PRV.use(3900, r::Optional, d::RepeatCount.bounded(1))),
79
95
 
80
- s:: LE.use(4000, r::Optional, d::RepeatCount.bounded(1)))))),
96
+ s:: LE.use(4000, r::Optional, d::RepeatCount.bounded(1))))))),
81
97
 
82
98
  d::TableDef.summary("Table 3 - Summary",
83
99
  s:: SE.use(4100, r::Mandatory, d::RepeatCount.bounded(1))))
@@ -29,9 +29,9 @@ module Stupidedi
29
29
  s:: N3.use(1000, r::Optional, d::RepeatCount.unbounded),
30
30
  s:: N4.use(1100, r::Optional, d::RepeatCount.bounded(1)),
31
31
  s::REF.use(1200, r::Optional, d::RepeatCount.unbounded),
32
- s::PER.use(1300, r::Optional, d::RepeatCount.unbounded)),
32
+ s::PER.use(1300, r::Optional, d::RepeatCount.unbounded),
33
33
  s::RDM.use(1400, r::Optional, d::RepeatCount.bounded(1)),
34
- s::DTM.use(1500, r::Optional, d::RepeatCount.bounded(1))),
34
+ s::DTM.use(1500, r::Optional, d::RepeatCount.bounded(1)))),
35
35
 
36
36
  d::TableDef.detail("Table 2 - Detail",
37
37
  d::LoopDef.build("2000", d::RepeatCount.unbounded,
@@ -9,10 +9,29 @@ module Stupidedi
9
9
  autoload :EditedCursor, "stupidedi/zipper/edited_cursor"
10
10
  autoload :MemoizedCursor, "stupidedi/zipper/memoized_cursor"
11
11
  autoload :RootCursor, "stupidedi/zipper/root_cursor"
12
+ autoload :StackCursor, "stupidedi/zipper/stack_cursor"
12
13
 
13
14
  autoload :AbstractPath, "stupidedi/zipper/path"
14
15
  autoload :Hole, "stupidedi/zipper/path"
15
16
  autoload :Root, "stupidedi/zipper/path"
17
+
18
+ # @todo
19
+ module Tree
20
+ class << self
21
+ def build(node)
22
+ Zipper::RootCursor.new(node)
23
+ end
24
+ end
25
+ end
26
+
27
+ # @todo
28
+ module Stack
29
+ class << self
30
+ def build(node)
31
+ Zipper::StackCursor.new(node, Zipper::Root, nil)
32
+ end
33
+ end
34
+ end
16
35
  end
17
36
 
18
37
  class << Zipper
@@ -22,7 +41,7 @@ module Stupidedi
22
41
 
23
42
  # @return [AbstractCursor]
24
43
  def build(node)
25
- Zipper::RootCursor.new(node)
44
+ Zipper::Tree.build(node)
26
45
  end
27
46
  end
28
47
 
@@ -25,10 +25,12 @@ module Stupidedi
25
25
  # @group Querying the Tree Location
26
26
  #########################################################################
27
27
 
28
+ # (see AbstractCursor#leaf?)
28
29
  def leaf?
29
30
  @node.leaf? or @node.children.empty?
30
31
  end
31
32
 
33
+ # (see AbstractCursor#root?)
32
34
  def root?
33
35
  false
34
36
  end
@@ -7,6 +7,8 @@ module Stupidedi
7
7
 
8
8
  class AbstractPath
9
9
 
10
+ abstract :root?
11
+
10
12
  # @return [AbstractPath]
11
13
  abstract :parent
12
14
 
@@ -35,6 +37,10 @@ module Stupidedi
35
37
  # @private
36
38
  Root = Class.new(AbstractPath) do
37
39
 
40
+ def root?
41
+ true
42
+ end
43
+
38
44
  # @return self
39
45
  def parent
40
46
  self
@@ -93,6 +99,10 @@ module Stupidedi
93
99
  left, parent, right
94
100
  end
95
101
 
102
+ def root?
103
+ false
104
+ end
105
+
96
106
  # (see AbstractPath#last?)
97
107
  def last?
98
108
  @right.empty?
@@ -18,7 +18,7 @@ module Stupidedi
18
18
  node, Root
19
19
  end
20
20
 
21
- # @group Query the Tree Location
21
+ # @group Querying the Tree Location
22
22
  #########################################################################
23
23
 
24
24
  # (see AbstractCursor#depth)
@@ -0,0 +1,174 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Stupidedi
4
+ using Refinements
5
+
6
+ module Zipper
7
+
8
+ class StackCursor < AbstractCursor
9
+
10
+ # @return [#leaf?, #children, #copy]
11
+ attr_reader :node
12
+
13
+ # @return [Hole]
14
+ attr_reader :path
15
+
16
+ # @private
17
+ # @return [AbstractCursor]
18
+ attr_reader :parent
19
+
20
+ def initialize(node, path, parent)
21
+ @node, @path, @parent =
22
+ node, path, parent
23
+ end
24
+
25
+ def copy(changes = {})
26
+ StackCursor.new \
27
+ changes.fetch(:node, @node),
28
+ changes.fetch(:path, @path),
29
+ changes.fetch(:parent, @parent)
30
+ end
31
+
32
+ # @group Querying the Tree Location
33
+ #########################################################################
34
+
35
+ # (see AbstractCursor#leaf?)
36
+ def leaf?
37
+ @node.leaf? or @node.children.empty?
38
+ end
39
+
40
+ # (see AbstractCursor#root?)
41
+ def root?
42
+ @path.root?
43
+ end
44
+
45
+ def between(other)
46
+ raise Exceptions::ZipperError,
47
+ "stack cursor doesn't support this method"
48
+ end
49
+
50
+ # @group Traversing the Tree
51
+ #########################################################################
52
+
53
+ # (see AbstractCursor#first)
54
+ def first
55
+ self
56
+ end
57
+
58
+ # (see AbstractCursor#last)
59
+ def last
60
+ self
61
+ end
62
+
63
+ # (see AbstractCursor#next)
64
+ # @return [void]
65
+ def next
66
+ raise Exceptions::ZipperError,
67
+ "stack cursor doesn't maintain siblings"
68
+ end
69
+
70
+ # (see AbstractCursor#prev)
71
+ # @return [void]
72
+ def prev
73
+ raise Exceptions::ZipperError,
74
+ "stack cursor doesn't maintain siblings"
75
+ end
76
+
77
+ # (see AbstractCursor#up)
78
+ def up
79
+ if root?
80
+ raise Exceptions::ZipperError,
81
+ "root node has no siblings"
82
+ end
83
+
84
+ @parent
85
+ end
86
+
87
+ # (see AbstractCursor#down)
88
+ def down
89
+ if leaf?
90
+ raise Exceptions::ZipperError,
91
+ "cannot descend into leaf node"
92
+ end
93
+
94
+ head, *tail = @node.children
95
+
96
+ unless tail.empty?
97
+ raise Exceptions::ZipperError,
98
+ "stack cursor doesn't support nodes with multiple children"
99
+ end
100
+
101
+ StackCursor.new(head, Hole.new([], @path, []), self)
102
+ end
103
+
104
+ # @group Editing the Tree
105
+ #########################################################################
106
+
107
+ # (see AbstractCursor#append)
108
+ # @return [void]
109
+ def append(node)
110
+ if root?
111
+ raise Exceptions::ZipperError,
112
+ "root node has no siblings"
113
+ end
114
+
115
+ replace(node)
116
+ end
117
+
118
+ # (see AbstractCursor#prepend)
119
+ # @return [void]
120
+ def prepend(node)
121
+ if root?
122
+ raise Exceptions::ZipperError,
123
+ "root node has no siblings"
124
+ end
125
+
126
+ replace(node)
127
+ end
128
+
129
+ def prepend_child(child)
130
+ StackCursor.new(child, Hole.new([], @path, []), self)
131
+ end
132
+
133
+ def append_child(child)
134
+ StackCursor.new(child, Hole.new([], @path, []), self)
135
+ end
136
+
137
+ # (see AbstractCursor#replace)
138
+ # @return [RootCursor]
139
+ def replace(node)
140
+ StackCursor.new(node, @path, @parent)
141
+ end
142
+
143
+ # (see AbstractCursor#delete)
144
+ # @return [void]
145
+ def delete
146
+ if root?
147
+ raise Exceptions::ZipperError,
148
+ "cannot delete root node"
149
+ end
150
+
151
+ @parent
152
+ end
153
+
154
+ def dangle
155
+ if leaf?
156
+ StackCursor.new(nil, Hole.new([], @path, []), self)
157
+ else
158
+ head, *tail = @node.children
159
+
160
+ unless tail.empty?
161
+ raise Exceptions::ZipperError,
162
+ "stack cursor doesn't support nodes with multiple children"
163
+ end
164
+
165
+ StackCursor.new(head, Hole.new([], @path, []), self)
166
+ end
167
+ end
168
+
169
+ # @endgroup
170
+ #########################################################################
171
+ end
172
+
173
+ end
174
+ end