ctioga 1.11.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. data/COPYING +340 -0
  2. data/ctioga/bin/ctable +28 -0
  3. data/ctioga/bin/ctioga +37 -0
  4. data/ctioga/doc/ctable.1 +156 -0
  5. data/ctioga/doc/ctioga.1 +2363 -0
  6. data/ctioga/examples/README +46 -0
  7. data/ctioga/examples/ctioga.gnuplot +4 -0
  8. data/ctioga/examples/ctioga_within_tioga.rb +53 -0
  9. data/ctioga/examples/ctiogarc.rb +24 -0
  10. data/ctioga/examples/include_1.rb +15 -0
  11. data/ctioga/examples/noise.dat +100 -0
  12. data/ctioga/examples/noise.rb +13 -0
  13. data/ctioga/examples/trig.csv +100 -0
  14. data/ctioga/examples/trig.dat +100 -0
  15. data/ctioga/examples/trig.rb +14 -0
  16. data/ctioga/examples/trigh.dat +100 -0
  17. data/ctioga/examples/trigh.rb +10 -0
  18. data/ctioga/examples/tutorial +763 -0
  19. data/ctioga/examples/tutorial.sh +269 -0
  20. data/ctioga/tests/README +14 -0
  21. data/ctioga/tests/axes.sh +40 -0
  22. data/ctioga/tests/basic.sh +11 -0
  23. data/ctioga/tests/draw.sh +24 -0
  24. data/ctioga/tests/histograms.sh +14 -0
  25. data/ctioga/tests/insets.sh +41 -0
  26. data/ctioga/tests/layouts.sh +29 -0
  27. data/ctioga/tests/legends.sh +113 -0
  28. data/ctioga/tests/styles.sh +43 -0
  29. data/ctioga/tests/test_style.sh +8 -0
  30. data/ctioga/tests/tests.sh +24 -0
  31. data/ctioga/tests/text_backend.sh +83 -0
  32. data/ctioga/tests/tioga_defaults.rb +18 -0
  33. data/lib/CTioga/axes.rb +904 -0
  34. data/lib/CTioga/backends.rb +88 -0
  35. data/lib/CTioga/boundaries.rb +224 -0
  36. data/lib/CTioga/ctable.rb +134 -0
  37. data/lib/CTioga/curve_style.rb +246 -0
  38. data/lib/CTioga/debug.rb +199 -0
  39. data/lib/CTioga/dimension.rb +133 -0
  40. data/lib/CTioga/elements.rb +17 -0
  41. data/lib/CTioga/elements/base.rb +84 -0
  42. data/lib/CTioga/elements/containers.rb +578 -0
  43. data/lib/CTioga/elements/curves.rb +368 -0
  44. data/lib/CTioga/elements/tioga_primitives.rb +440 -0
  45. data/lib/CTioga/layout.rb +595 -0
  46. data/lib/CTioga/legends.rb +29 -0
  47. data/lib/CTioga/legends/cmdline.rb +187 -0
  48. data/lib/CTioga/legends/item.rb +164 -0
  49. data/lib/CTioga/legends/style.rb +257 -0
  50. data/lib/CTioga/log.rb +73 -0
  51. data/lib/CTioga/movingarrays.rb +131 -0
  52. data/lib/CTioga/partition.rb +271 -0
  53. data/lib/CTioga/plot_style.rb +230 -0
  54. data/lib/CTioga/plotmaker.rb +1677 -0
  55. data/lib/CTioga/shortcuts.rb +69 -0
  56. data/lib/CTioga/structures.rb +82 -0
  57. data/lib/CTioga/styles.rb +140 -0
  58. data/lib/CTioga/themes.rb +581 -0
  59. data/lib/CTioga/themes/classical.rb +82 -0
  60. data/lib/CTioga/themes/demo.rb +63 -0
  61. data/lib/CTioga/themes/fits.rb +91 -0
  62. data/lib/CTioga/themes/mono.rb +33 -0
  63. data/lib/CTioga/tioga.rb +32 -0
  64. data/lib/CTioga/utils.rb +173 -0
  65. data/lib/MetaBuilder/Parameters/dates.rb +38 -0
  66. data/lib/MetaBuilder/Parameters/lists.rb +132 -0
  67. data/lib/MetaBuilder/Parameters/numbers.rb +69 -0
  68. data/lib/MetaBuilder/Parameters/strings.rb +86 -0
  69. data/lib/MetaBuilder/Parameters/styles.rb +75 -0
  70. data/lib/MetaBuilder/Qt4/Parameters/dates.rb +51 -0
  71. data/lib/MetaBuilder/Qt4/Parameters/numbers.rb +65 -0
  72. data/lib/MetaBuilder/Qt4/Parameters/strings.rb +106 -0
  73. data/lib/MetaBuilder/Qt4/parameter.rb +172 -0
  74. data/lib/MetaBuilder/Qt4/parameters.rb +9 -0
  75. data/lib/MetaBuilder/descriptions.rb +603 -0
  76. data/lib/MetaBuilder/factory.rb +101 -0
  77. data/lib/MetaBuilder/group.rb +57 -0
  78. data/lib/MetaBuilder/metabuilder.rb +10 -0
  79. data/lib/MetaBuilder/parameter.rb +374 -0
  80. data/lib/MetaBuilder/parameters.rb +11 -0
  81. data/lib/MetaBuilder/qt4.rb +8 -0
  82. data/lib/SciYAG/Backends/backend.rb +379 -0
  83. data/lib/SciYAG/Backends/binner.rb +168 -0
  84. data/lib/SciYAG/Backends/cache.rb +102 -0
  85. data/lib/SciYAG/Backends/dataset.rb +158 -0
  86. data/lib/SciYAG/Backends/descriptions.rb +469 -0
  87. data/lib/SciYAG/Backends/filters.rb +25 -0
  88. data/lib/SciYAG/Backends/filters/average.rb +134 -0
  89. data/lib/SciYAG/Backends/filters/cumulate.rb +37 -0
  90. data/lib/SciYAG/Backends/filters/filter.rb +70 -0
  91. data/lib/SciYAG/Backends/filters/norm.rb +39 -0
  92. data/lib/SciYAG/Backends/filters/smooth.rb +63 -0
  93. data/lib/SciYAG/Backends/filters/sort.rb +43 -0
  94. data/lib/SciYAG/Backends/filters/strip.rb +34 -0
  95. data/lib/SciYAG/Backends/filters/trim.rb +64 -0
  96. data/lib/SciYAG/Backends/gnuplot.rb +131 -0
  97. data/lib/SciYAG/Backends/math.rb +108 -0
  98. data/lib/SciYAG/Backends/mdb.rb +462 -0
  99. data/lib/SciYAG/Backends/multitext.rb +96 -0
  100. data/lib/SciYAG/Backends/source.rb +64 -0
  101. data/lib/SciYAG/Backends/text.rb +339 -0
  102. data/lib/SciYAG/backends.rb +16 -0
  103. metadata +191 -0
@@ -0,0 +1,96 @@
1
+ # multitext.rb : A simple backend to deal with multiple basic text files.
2
+ # Copyright (C) 2006 Jean-Julien Fleck
3
+ # Directly inspired from Vincent Fourmond's text.rb
4
+
5
+ # This program is free software; you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation; either version 2 of the License, or
8
+ # (at your option) any later version.
9
+
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with this program; if not, write to the Free Software
17
+ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
+
19
+
20
+
21
+ require 'SciYAG/Backends/text'
22
+ require 'Dobjects/Dvector'
23
+ require 'Dobjects/Function'
24
+
25
+ module SciYAG
26
+
27
+ module Backends
28
+
29
+ class MultiTextBackend < TextBackend
30
+
31
+ include Dobjects
32
+
33
+ describe 'multitext', 'MultiText format', <<EOD
34
+ This backend can read multiple text files in a format close to the one
35
+ understood by gnuplot and the like. Allows to plot one column form one file
36
+ with respect to another column of another file.
37
+ EOD
38
+
39
+ inherit_parameters :skip
40
+
41
+ def initialize
42
+ @dummy = nil
43
+ @current = nil
44
+ # @current is an array of Dvectors holding the contents of the most
45
+ # recently read files, so that there is no need to read it again.
46
+ @skip = 0
47
+ @included_modules = [] # to make sure we give them to
48
+ # compute_formula
49
+ super()
50
+ end
51
+
52
+ def extend(mod)
53
+ super
54
+ @included_modules << mod
55
+ end
56
+
57
+ # This is called by the architecture to get the data. It splits
58
+ # the set name into filename@cols, reads the file if necessary and
59
+ # calls get_data
60
+ def query_xy_data(set)
61
+ cols = []
62
+ files= []
63
+ nb_match = -1
64
+ new_set = set.gsub(/\[(.*?)@(.*?)\]/) do |match|
65
+ cols.push($2)
66
+ files.push($1)
67
+ nb_match += 1
68
+ "column[#{nb_match}]"
69
+ end
70
+ @current = Hash.new
71
+ files.uniq.each do |file|
72
+ @current[file] = Dvector.fancy_read(file, nil,
73
+ 'index_col' => true,
74
+ 'skip_first' => @skip)
75
+ end
76
+ return Function.new(*get_data(cols,files,new_set))
77
+ end
78
+
79
+ # Reads the data using the columns specification, provided that
80
+ # the appropriate files have already been loaded into @current. For now
81
+ # no single sanity check.
82
+ def get_data(cols,files,set)
83
+ vectors = []
84
+ cols.each_index do |i|
85
+ vectors.push(@current[files[i]][cols[i].to_i])
86
+ end
87
+ x_formula, y_formula = set.split(':')
88
+ mods = @included_modules
89
+ return [Dvector.compute_formula(x_formula,vectors,mods),
90
+ Dvector.compute_formula(y_formula,vectors,mods)]
91
+ end
92
+
93
+ end
94
+
95
+ end
96
+ end
@@ -0,0 +1,64 @@
1
+ # source.rb : The implementation of a data source
2
+ # Copyright (C) 2006 Vincent Fourmond
3
+
4
+ # This program is free software; you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation; either version 2 of the License, or
7
+ # (at your option) any later version.
8
+
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program; if not, write to the Free Software
16
+ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
+
18
+ module SciYAG
19
+
20
+ module Backends
21
+
22
+ # A data source is a class containing raw data, most probably under
23
+ # the form of a list of Dvectors. It is the job of Representations to
24
+ # transform that source into a 2D or 3D set.
25
+ class DataSource
26
+
27
+ # The list of the columns
28
+ attr_reader :columns
29
+
30
+ # A list of hashes of informations about the columns
31
+ attr_reader :columns_info
32
+
33
+ # Some informations about the source. Different possibilities:
34
+ # * :filename, the name of the file from where the source is
35
+ # coming;
36
+ # * :dataset, the name of dataset, if applicable.
37
+ # and so on...
38
+ attr_accessor :informations
39
+
40
+ # Creates a datasource, and fills it with the columns _columns_.
41
+ # It is better however to use directly #add_column to fill
42
+ # the source with Data.
43
+ def initialize(*columns)
44
+ @columns = []
45
+ @columns_info = []
46
+ @informations = {}
47
+ end
48
+
49
+ # Automatic naming of the columns
50
+ def auto_name(number)
51
+ return "$#{number}"
52
+ end
53
+
54
+ # Add a column and its information to the list.
55
+ def add_column(col, name = nil, infos = {})
56
+ name = auto_name(col.length) unless name
57
+ @columns << col
58
+ infos[:name] = name
59
+ @columns_info << infos
60
+ end
61
+ end
62
+
63
+ end
64
+ end
@@ -0,0 +1,339 @@
1
+ # text.rb : A simple backend to deal with basic text files.
2
+ # Copyright (C) 2006 Vincent Fourmond
3
+
4
+ # This program is free software; you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation; either version 2 of the License, or
7
+ # (at your option) any later version.
8
+
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program; if not, write to the Free Software
16
+ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
+
18
+
19
+
20
+ require 'SciYAG/Backends/backend'
21
+ require 'Dobjects/Dvector'
22
+ require 'Dobjects/Function'
23
+
24
+ # For separated sets
25
+ require 'stringio'
26
+
27
+ module SciYAG
28
+
29
+ # A module for easy use of NaN in operations
30
+ module NaN
31
+ NaN = 0.0/0.0
32
+ def nan
33
+ return NaN
34
+ end
35
+ end
36
+
37
+ module Backends
38
+
39
+ class TextBackend < Backend
40
+
41
+ # A constant holding a relation extension -> command to
42
+ # decompress (to be fed to sprintf with the filename as argument)
43
+ UNCOMPRESSORS = {
44
+ ".gz" => "gunzip -c %s",
45
+ ".bz2" => "bunzip2 -c %s",
46
+ ".lzma" => "unlzma -c %s",
47
+ }
48
+
49
+ include Dobjects
50
+
51
+ describe 'text', 'Text format', <<EOD
52
+ This backend can read text files in a format close to the one understood
53
+ by gnuplot and the like.
54
+ EOD
55
+
56
+ # Inherit the baseline handling, can be useful !
57
+ inherit_parameters :base_line
58
+
59
+ param_accessor :skip, 'skip', "Skip lines", {:type => :integer},
60
+ "Number of lines to be skipped at the beginning of the file"
61
+
62
+ param_accessor :default_column_spec, 'col',
63
+ "Default column specification", {:type => :string},
64
+ "Which columns to use when the @1:2 syntax is not used"
65
+
66
+ param_accessor :split, 'split', "Split into subsets",
67
+ {:type => :boolean},
68
+ "If true, splits files into subsets on blank/non number lines"
69
+
70
+
71
+ param_accessor :separator, 'separator', "Data columns separator",
72
+ {:type => :string_or_regexp},
73
+ "The columns separator. Defaults to /\s+/"
74
+
75
+ # param_accessor :select, 'select', "Select lines", {:type => :string},
76
+ # "Skips line where the code returns false"
77
+
78
+ def initialize
79
+ @dummy = nil
80
+ @current = nil
81
+ # Current is the name of the last file used. Necessary for '' specs.
82
+ @current_data = nil # The data of the last file used.
83
+ @skip = 0
84
+ @included_modules = [NaN] # to make sure we give them to
85
+ # Dvector.compute_formula
86
+ @default_column_spec = "1:2"
87
+
88
+ @separator = /\s+/
89
+
90
+ # We don't split data by default.
91
+ @split = false
92
+
93
+ super()
94
+
95
+ # Override Backend's cache - for now.
96
+ @cache = {} # A cache file_name -> data
97
+
98
+ end
99
+
100
+ def extend(mod)
101
+ super
102
+ @included_modules << mod
103
+ end
104
+
105
+ # Returns a IO object suitable to acquire data from it for
106
+ # the given _file_, which can be one of the following:
107
+ # * a real file name
108
+ # * a compressed file name
109
+ # * a pipe command.
110
+ def get_io_object(file)
111
+ if file == "-"
112
+ return $stdin
113
+ elsif file =~ /(.*?)\|\s*$/ # A pipe
114
+ return IO.popen($1)
115
+ elsif not File.readable?(file)
116
+ # Try to find a compressed version
117
+ for ext,method in UNCOMPRESSORS
118
+ if File.readable? "#{file}#{ext}"
119
+ info "Using compressed file #{name}#{ext} in stead of #{name}"
120
+ return IO.popen(method % "#{file}#{ext}")
121
+ end
122
+ end
123
+ else
124
+ for ext, method in UNCOMPRESSORS
125
+ if file =~ /#{ext}$/
126
+ info "Taking file #{file} as a compressed file"
127
+ return IO.popen(method % file)
128
+ end
129
+ end
130
+ return File::open(file)
131
+ end
132
+ error "Could not open #{file}"
133
+ return nil
134
+ end
135
+
136
+ # A line is invalid if it is blank or starts
137
+ # neither with a digit nor +, - or .
138
+ #
139
+ # Maybe to be improved later.
140
+ InvalidLineRE = /^\s*$|^\s*[^\d+.\s-]+/
141
+
142
+ # Returns a string corresponding to the given _set_ of the
143
+ # given _io_ object.
144
+ #
145
+ # Sets are 1-based.
146
+ def get_set_string(io, set)
147
+ cur_set = 1
148
+ last_line_is_invalid = true
149
+ str = ""
150
+ line_number = 0
151
+ while line = io.gets
152
+ line_number += 1
153
+ if line =~ InvalidLineRE
154
+ debug "Found invalid line at #{line_number}"
155
+ if ! last_line_is_invalid
156
+ # We begin a new set.
157
+ cur_set += 1
158
+ debug "Found set #{cur_set} at line #{line_number}"
159
+ if(cur_set > set)
160
+ return str
161
+ end
162
+ end
163
+ last_line_is_invalid = true
164
+ else
165
+ last_line_is_invalid = false
166
+ if cur_set == set
167
+ str += line
168
+ end
169
+ end
170
+ end
171
+ return str
172
+ end
173
+
174
+ # Returns an IO object corresponding to the given file.
175
+ def get_io_set(file)
176
+ if not @split
177
+ return get_io_object(file)
178
+ else
179
+ file =~ /(.*?)(?:#(\d+))?$/; # ; to make ruby-mode indent correctly.
180
+ filename = $1
181
+ if $2
182
+ set = $2.to_i
183
+ else
184
+ set = 1
185
+ end
186
+ debug "Trying to get set #{set} from file '#{filename}'"
187
+ str = get_set_string(get_io_object(filename), set)
188
+ return StringIO.new(str)
189
+ end
190
+ end
191
+
192
+ # Reads data from a file. If needed, extract the file from the columns
193
+ # specification.
194
+ def read_file(file)
195
+ if file =~ /(.*)@.*/
196
+ file = $1
197
+ end
198
+ name = file # As file will be modified.
199
+ if ! @cache.key?(file) # Read the file if it is not cached.
200
+ fancy_read_options = {'index_col' => true,
201
+ 'skip_first' => @skip,
202
+ 'sep' => @separator
203
+ }
204
+ io_set = get_io_set(file)
205
+ debug "Fancy read '#{file}', options #{fancy_read_options.inspect}"
206
+ @cache[name] = Dvector.fancy_read(io_set, nil, fancy_read_options)
207
+ end
208
+ return @cache[name]
209
+ end
210
+
211
+
212
+ # This is called by the architecture to get the data. It splits
213
+ # the set name into filename@cols, reads the file if necessary and
214
+ # calls get_data
215
+ def query_xy_data(set)
216
+ if set =~ /(.*)@(.*)/
217
+ col_spec = $2
218
+ file = $1
219
+ else
220
+ col_spec = @default_column_spec
221
+ file = set
222
+ end
223
+ if file.length > 0
224
+ @current_data = read_file(file)
225
+ @current = file
226
+ end
227
+ x,y,err = get_data(col_spec)
228
+ return [Function.new(x,y),err]
229
+ end
230
+
231
+ # Reads the data using the columns specification, provided that
232
+ # the appropriate fle has already been loaded into @current. For now
233
+ # no single sanity check.
234
+ def get_data(col_spec)
235
+ # First, we must split the column specification into what
236
+ # I would call target specifications. A target is in the form
237
+ # of stuff=spec, where stuff can be basically anything. x=, y=,
238
+ # yea= are implied for the first specifications.
239
+
240
+ defaults = [:x,:y,:yea]
241
+ specifications = {} # A hash value spec => column spec
242
+ col_spec.split(/:/).each do |spec|
243
+ d = defaults.shift
244
+ if spec =~ /^\s*(\w+)\s*=(.*)/
245
+ spec = $2
246
+ d = $1.to_sym
247
+ end
248
+ specifications[d] = spec
249
+ end
250
+
251
+ debug "spec #{col_spec} becomes #{specifications.inspect}"
252
+
253
+ values = {}
254
+ if col_spec =~ /\$/ # There is a formula in the specification
255
+ for key,spec in specifications
256
+ formula = spec.gsub(/\$(\d+)/, 'column[\1]')
257
+ debug "Using formula '#{formula}' for #{key}"
258
+ values[key] = Dvector.
259
+ compute_formula(formula,
260
+ @current_data,
261
+ @included_modules)
262
+ end
263
+ else
264
+ for key,spec in specifications
265
+ values[key] = @current_data[spec.to_i].dup
266
+ end
267
+ end
268
+ errors = compute_error_bars(values)
269
+ # Now, we're left with a hash...
270
+ return [values[:x],values[:y], errors]
271
+ end
272
+
273
+ # Turns a target => values specification into something usable as
274
+ # error bars, that is :xmin, :xmax and the like hashes. The rules
275
+ # are the following:
276
+ # * ?min/?max are passed on directly;
277
+ # * ?e(abs) are transformed into ?min = ? - ?eabs, ?max = ? + ?eabs
278
+ # * ?eu(p/?ed(own) are transformed respectively into ? +/- ?...
279
+ # * ?er(el) become ?min = ?*(1 - ?erel, ?max = ?(1 + ?erel)
280
+ # * ?erup/?erdown follow the same pattern...
281
+ def compute_error_bars(values)
282
+ target = {}
283
+ for key in values.keys
284
+ case key.to_s
285
+ when /^[xy](min|max)?$/
286
+ target[key] = values[key].dup # Just to make sure.
287
+ when /^(.)e(a(bs?)?)?$/
288
+ target["#{$1}min".to_sym] = values[$1.to_sym] - values[key]
289
+ target["#{$1}max".to_sym] = values[$1.to_sym] + values[key]
290
+ when /^(.)eu(p)?$/
291
+ target["#{$1}max".to_sym] = values[$1.to_sym] + values[key]
292
+ when /^(.)ed(o(wn?)?)?$/
293
+ target["#{$1}min".to_sym] = values[$1.to_sym] - values[key]
294
+ when /^(.)er(el?)?$/
295
+ target["#{$1}min".to_sym] = values[$1.to_sym] *
296
+ (values[key].neg + 1)
297
+ target["#{$1}max".to_sym] = values[$1.to_sym] *
298
+ (values[key] + 1)
299
+ when /^(.)erd(o(wn?)?)?$/
300
+ target["#{$1}min".to_sym] = values[$1.to_sym] *
301
+ (values[key].neg + 1)
302
+ when /^(.)erup?$/
303
+ target["#{$1}max".to_sym] = values[$1.to_sym] *
304
+ (values[key] + 1)
305
+ else
306
+ warn "Somehow, the target specification #{key} " +
307
+ "didn't make it through"
308
+ end
309
+ end
310
+ return target
311
+ end
312
+
313
+ # Expands specifications into few sets. This function will separate the
314
+ # set into a file spec and a col spec. Within the col spec, the 2##6
315
+ # keyword is used to expand to 2,3,4,5,6. 2## followed by a non-digit
316
+ # expands to 2,...,last column in the file. For now, the expansions
317
+ # stops on the first occurence found, and the second form doesn't
318
+ # work yet. But soon...
319
+ def expand_sets(spec)
320
+ if m = /(\d+)##(\D|$)/.match(spec)
321
+ a = m[1].to_i
322
+ trail = m[2]
323
+ b = read_file(spec)
324
+ b = (b.length - 1)
325
+ ret = []
326
+ a.upto(b) do |i|
327
+ ret << m.pre_match + i.to_s + trail + m.post_match
328
+ end
329
+ return ret
330
+ else
331
+ return super
332
+ end
333
+ end
334
+
335
+ end
336
+
337
+ end
338
+
339
+ end