hornetseye-linalg 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,23 @@
1
+ hornetseye-linalg
2
+ =================
3
+
4
+ **Author**: Jan Wedekind
5
+ **Copyright**: 2011
6
+ **License**: GPL
7
+
8
+ Synopsis
9
+ --------
10
+
11
+ This Ruby extension implements conversions between {Linalg::DMatrix} and {Hornetseye::MultiArray}.
12
+
13
+ Installation
14
+ ------------
15
+ To install this Ruby extension, use the following command:
16
+
17
+ $ sudo gem install hornetseye-linalg
18
+
19
+ Alternatively you can build and install the Ruby extension from source as follows:
20
+
21
+ $ rake
22
+ $ sudo rake install
23
+
@@ -0,0 +1,184 @@
1
+ #!/usr/bin/env ruby
2
+ require 'date'
3
+ require 'rake/clean'
4
+ require 'rake/testtask'
5
+ require 'rake/packagetask'
6
+ require 'rake/loaders/makefile'
7
+ require 'rbconfig'
8
+
9
+ PKG_NAME = 'hornetseye-linalg'
10
+ PKG_VERSION = '0.1.0'
11
+ CFG = RbConfig::CONFIG
12
+ CXX = ENV[ 'CXX' ] || 'g++'
13
+ RB_FILES = FileList[ 'lib/**/*.rb' ]
14
+ CC_FILES = FileList[ 'ext/*.cc' ]
15
+ HH_FILES = FileList[ 'ext/*.hh' ] + FileList[ 'ext/*.tcc' ]
16
+ TC_FILES = FileList[ 'test/tc_*.rb' ]
17
+ TS_FILES = FileList[ 'test/ts_*.rb' ]
18
+ SO_FILE = "ext/#{PKG_NAME.tr '\-', '_'}.#{CFG[ 'DLEXT' ]}"
19
+ PKG_FILES = [ 'Rakefile', 'README.md', 'COPYING', '.document' ] +
20
+ RB_FILES + CC_FILES + HH_FILES + TS_FILES + TC_FILES
21
+ BIN_FILES = [ 'README.md', 'COPYING', '.document', SO_FILE ] +
22
+ RB_FILES + TS_FILES + TC_FILES
23
+ SUMMARY = %q{Linalg integration for Hornetseye}
24
+ DESCRIPTION = %q{This Ruby extension provides conversion from Hornetseye::MultiArray to Linalg::DMatrix and vice versa.}
25
+ AUTHOR = %q{Jan Wedekind}
26
+ EMAIL = %q{jan@wedesoft.de}
27
+ HOMEPAGE = %q{http://wedesoft.github.com/hornetseye-linalg/}
28
+
29
+ OBJ = CC_FILES.ext 'o'
30
+ $CXXFLAGS = "-DNDEBUG #{CFG[ 'CPPFLAGS' ]} #{CFG[ 'CFLAGS' ]}"
31
+ if CFG[ 'rubyhdrdir' ]
32
+ $CXXFLAGS = "#{$CXXFLAGS} -I#{CFG[ 'rubyhdrdir' ]} " +
33
+ "-I#{CFG[ 'rubyhdrdir' ]}/#{CFG[ 'arch' ]}"
34
+ else
35
+ $CXXFLAGS = "#{$CXXFLAGS} -I#{CFG[ 'archdir' ]}"
36
+ end
37
+ $LIBRUBYARG = "-L#{CFG[ 'libdir' ]} #{CFG[ 'LIBRUBYARG' ]} #{CFG[ 'LDFLAGS' ]} " +
38
+ "#{CFG[ 'SOLIBS' ]} #{CFG[ 'DLDLIBS' ]}"
39
+ $SITELIBDIR = CFG[ 'sitelibdir' ]
40
+ $SITEARCHDIR = CFG[ 'sitearchdir' ]
41
+ $LDSHARED = CFG[ 'LDSHARED' ][ CFG[ 'LDSHARED' ].index( ' ' ) .. -1 ]
42
+
43
+ task :default => :all
44
+
45
+ desc 'Compile Ruby extension (default)'
46
+ task :all => [ SO_FILE ]
47
+
48
+ file SO_FILE => OBJ do |t|
49
+ sh "#{CXX} -shared -o #{t.name} #{OBJ} #{$LIBRUBYARG}"
50
+ end
51
+
52
+ task :test => [ SO_FILE ]
53
+
54
+ desc 'Install Ruby extension'
55
+ task :install => :all do
56
+ verbose true do
57
+ for f in RB_FILES do
58
+ FileUtils.mkdir_p "#{$SITELIBDIR}/#{File.dirname f.gsub( /^lib\//, '' )}"
59
+ FileUtils.cp_r f, "#{$SITELIBDIR}/#{f.gsub( /^lib\//, '' )}"
60
+ end
61
+ FileUtils.mkdir_p $SITEARCHDIR
62
+ FileUtils.cp SO_FILE, "#{$SITEARCHDIR}/#{File.basename SO_FILE}"
63
+ end
64
+ end
65
+
66
+ desc 'Uninstall Ruby extension'
67
+ task :uninstall do
68
+ verbose true do
69
+ for f in RB_FILES do
70
+ FileUtils.rm_f "#{$SITELIBDIR}/#{f.gsub /^lib\//, ''}"
71
+ end
72
+ FileUtils.rm_f "#{$SITEARCHDIR}/#{File.basename SO_FILE}"
73
+ end
74
+ end
75
+
76
+ Rake::TestTask.new do |t|
77
+ t.libs << 'ext'
78
+ t.test_files = TC_FILES
79
+ end
80
+
81
+ begin
82
+ require 'yard'
83
+ YARD::Rake::YardocTask.new :yard do |y|
84
+ y.files << RB_FILES
85
+ end
86
+ rescue LoadError
87
+ STDERR.puts 'Please install \'yard\' if you want to generate documentation'
88
+ end
89
+
90
+ Rake::PackageTask.new PKG_NAME, PKG_VERSION do |p|
91
+ p.need_tar = true
92
+ p.package_files = PKG_FILES
93
+ end
94
+
95
+ begin
96
+ require 'rubygems'
97
+ require 'rubygems/builder'
98
+ $SPEC = Gem::Specification.new do |s|
99
+ s.name = PKG_NAME
100
+ s.version = PKG_VERSION
101
+ s.platform = Gem::Platform::RUBY
102
+ s.date = Date.today.to_s
103
+ s.summary = SUMMARY
104
+ s.description = DESCRIPTION
105
+ s.author = AUTHOR
106
+ s.email = EMAIL
107
+ s.homepage = HOMEPAGE
108
+ s.files = PKG_FILES
109
+ s.test_files = TC_FILES
110
+ s.require_paths = [ 'lib', 'ext' ]
111
+ s.rubyforge_project = %q{hornetseye}
112
+ s.extensions = %w{Rakefile}
113
+ s.has_rdoc = 'yard'
114
+ s.extra_rdoc_files = []
115
+ s.rdoc_options = %w{--no-private}
116
+ s.add_dependency %<malloc>, [ '~> 1.1' ]
117
+ s.add_dependency %<multiarray>, [ '~> 0.23' ]
118
+ s.add_dependency %<hornetseye-frame>, [ '~> 0.11' ]
119
+ s.add_development_dependency %q{rake}
120
+ end
121
+ GEM_SOURCE = "#{PKG_NAME}-#{PKG_VERSION}.gem"
122
+ $BINSPEC = Gem::Specification.new do |s|
123
+ s.name = PKG_NAME
124
+ s.version = PKG_VERSION
125
+ s.platform = Gem::Platform::CURRENT
126
+ s.date = Date.today.to_s
127
+ s.summary = SUMMARY
128
+ s.description = DESCRIPTION
129
+ s.author = AUTHOR
130
+ s.email = EMAIL
131
+ s.homepage = HOMEPAGE
132
+ s.files = BIN_FILES
133
+ s.test_files = TC_FILES
134
+ s.require_paths = [ 'lib', 'ext' ]
135
+ s.rubyforge_project = %q{hornetseye}
136
+ s.has_rdoc = 'yard'
137
+ s.extra_rdoc_files = []
138
+ s.rdoc_options = %w{--no-private}
139
+ s.add_dependency %<malloc>, [ '~> 1.1' ]
140
+ s.add_dependency %<multiarray>, [ '~> 0.23' ]
141
+ s.add_dependency %<hornetseye-frame>, [ '~> 0.11' ]
142
+ end
143
+ GEM_BINARY = "#{PKG_NAME}-#{PKG_VERSION}-#{$BINSPEC.platform}.gem"
144
+ desc "Build the gem file #{GEM_SOURCE}"
145
+ task :gem => [ "pkg/#{GEM_SOURCE}" ]
146
+ file "pkg/#{GEM_SOURCE}" => [ 'pkg' ] + $SPEC.files do
147
+ when_writing 'Creating GEM' do
148
+ Gem::Builder.new( $SPEC ).build
149
+ verbose true do
150
+ FileUtils.mv GEM_SOURCE, "pkg/#{GEM_SOURCE}"
151
+ end
152
+ end
153
+ end
154
+ desc "Build the gem file #{GEM_BINARY}"
155
+ task :gem_binary => [ "pkg/#{GEM_BINARY}" ]
156
+ file "pkg/#{GEM_BINARY}" => [ 'pkg' ] + $BINSPEC.files do
157
+ when_writing 'Creating binary GEM' do
158
+ Gem::Builder.new( $BINSPEC ).build
159
+ verbose true do
160
+ FileUtils.mv GEM_BINARY, "pkg/#{GEM_BINARY}"
161
+ end
162
+ end
163
+ end
164
+ rescue LoadError
165
+ STDERR.puts 'Please install \'rubygems\' if you want to create Gem packages'
166
+ end
167
+
168
+ rule '.o' => '.cc' do |t|
169
+ sh "#{CXX} #{$CXXFLAGS} -c -o #{t.name} #{t.source}"
170
+ end
171
+
172
+ file ".depends.mf" do |t|
173
+ sh "g++ -MM #{CC_FILES.join ' '} | " +
174
+ "sed -e :a -e N -e 's/\\n/\\$/g' -e ta | " +
175
+ "sed -e 's/ *\\\\\\$ */ /g' -e 's/\\$/\\n/g' | sed -e 's/^/ext\\//' > #{t.name}"
176
+ end
177
+ CC_FILES.each do |t|
178
+ file t.ext(".o") => t
179
+ end
180
+ import ".depends.mf"
181
+
182
+ CLEAN.include 'ext/*.o'
183
+ CLOBBER.include SO_FILE, 'doc', '.yardoc', '.depends.mf'
184
+
@@ -0,0 +1,60 @@
1
+ /* HornetsEye - Computer Vision with Ruby
2
+ Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Jan Wedekind
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 3 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, see <http://www.gnu.org/licenses/>. */
16
+ #include <algorithm>
17
+ #include <boost/shared_array.hpp>
18
+ #include "error.hh"
19
+ #include "rubytools.hh"
20
+ #include "dmatrix.hh"
21
+
22
+ using namespace std;
23
+
24
+ VALUE DMatrix::mModule = Qnil;
25
+
26
+ VALUE DMatrix::cRubyClass = Qnil;
27
+
28
+ VALUE DMatrix::registerRubyClass(VALUE module)
29
+ {
30
+ mModule = module;
31
+ cRubyClass = rb_define_class_under(module, "DMatrix", rb_cObject);
32
+ rb_define_method(cRubyClass, "to_multiarray", RUBY_METHOD_FUNC(wrapToMultiArray), 0);
33
+ return cRubyClass;
34
+ }
35
+
36
+ void DMatrix::deleteRubyObject(void *ptr)
37
+ {
38
+ free((DMatrix *)ptr);
39
+ }
40
+
41
+ VALUE DMatrix::wrapToMultiArray(VALUE rbSelf)
42
+ {
43
+ VALUE rbRetVal = Qnil;
44
+ try {
45
+ VALUE mHornetseye = rb_define_module( "Hornetseye" );
46
+ DMatrix_ *dmatrix;
47
+ dataGetStruct(rbSelf, cRubyClass, DMatrix_, dmatrix);
48
+ int width = dmatrix->hsize;
49
+ int height = dmatrix->vsize;
50
+ VALUE cMalloc = rb_define_class_under(mHornetseye, "Malloc", rb_cObject);
51
+ VALUE rbMemory = Data_Wrap_Struct(cMalloc, 0, 0, dmatrix->data);
52
+ rb_ivar_set(rbMemory, rb_intern("@size"), INT2NUM(width * height * sizeof(double)));
53
+ VALUE rbTypecode = rb_const_get(mHornetseye, rb_intern("DFLOAT"));
54
+ rbRetVal = rb_funcall(rb_const_get(mHornetseye, rb_intern("MultiArray")),
55
+ rb_intern("import"), 4, rbTypecode, rbMemory, INT2NUM(height), INT2NUM(width));
56
+ } catch( std::exception &e ) {
57
+ rb_raise( rb_eRuntimeError, "%s", e.what() );
58
+ };
59
+ return rbRetVal;
60
+ }
@@ -0,0 +1,36 @@
1
+ /* HornetsEye - Computer Vision with Ruby
2
+ Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Jan Wedekind
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 3 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, see <http://www.gnu.org/licenses/>. */
16
+ #ifndef HORNETSEYE_DMATRIX_HH
17
+ #define HORNETSEYE_DMATRIX_HH
18
+ #include "rubyinc.hh"
19
+
20
+ typedef struct {
21
+ int vsize;
22
+ int hsize;
23
+ double *data;
24
+ } DMatrix_;
25
+
26
+ class DMatrix {
27
+ public:
28
+ static VALUE cRubyClass;
29
+ static VALUE mModule;
30
+ static VALUE registerRubyClass(VALUE module);
31
+ static void deleteRubyObject(void *ptr);
32
+ static VALUE wrapToMultiArray(VALUE rbSelf);
33
+ };
34
+
35
+ #endif
36
+
@@ -0,0 +1,50 @@
1
+ /* HornetsEye - Computer Vision with Ruby
2
+ Copyright (C) 2006, 2007, 2008, 2009, 2010 Jan Wedekind
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 3 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, see <http://www.gnu.org/licenses/>. */
16
+ #ifndef ERROR_HH
17
+ #define ERROR_HH
18
+
19
+ #include <exception>
20
+ #include <sstream>
21
+
22
+ class Error: public std::exception
23
+ {
24
+ public:
25
+ Error(void) {}
26
+ Error( Error &e ): std::exception( e )
27
+ { m_message << e.m_message.str(); }
28
+ virtual ~Error(void) throw() {}
29
+ template< typename T >
30
+ std::ostream &operator<<( const T &t )
31
+ { m_message << t; return m_message; }
32
+ std::ostream &operator<<( std::ostream& (*__pf)(std::ostream&) )
33
+ { (*__pf)( m_message ); return m_message; }
34
+ virtual const char* what(void) const throw() {
35
+ temp = m_message.str();
36
+ return temp.c_str();
37
+ }
38
+ protected:
39
+ std::ostringstream m_message;
40
+ mutable std::string temp;
41
+ };
42
+
43
+ #define ERRORMACRO( condition, class, params, message ) \
44
+ if ( !( condition ) ) { \
45
+ class _e params; \
46
+ _e << message; \
47
+ throw _e; \
48
+ };
49
+
50
+ #endif
@@ -0,0 +1,44 @@
1
+ /* HornetsEye - Computer Vision with Ruby
2
+ Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Jan Wedekind
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 3 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, see <http://www.gnu.org/licenses/>. */
16
+ #include "rubyinc.hh"
17
+ #include "node.hh"
18
+ #include "dmatrix.hh"
19
+ #include "smatrix.hh"
20
+
21
+ #ifdef WIN32
22
+ #define DLLEXPORT __declspec(dllexport)
23
+ #define DLLLOCAL
24
+ #else
25
+ #define DLLEXPORT __attribute__ ((visibility("default")))
26
+ #define DLLLOCAL __attribute__ ((visibility("hidden")))
27
+ #endif
28
+
29
+ extern "C" DLLEXPORT void Init_hornetseye_linalg(void);
30
+
31
+ extern "C" {
32
+
33
+ void Init_hornetseye_linalg(void)
34
+ {
35
+ rb_eval_string("require 'multiarray'");
36
+ VALUE rbHornetseye = rb_define_module("Hornetseye");
37
+ Node::registerRubyClass(rbHornetseye);
38
+ VALUE rbLinalg = rb_define_module("Linalg");
39
+ DMatrix::registerRubyClass(rbLinalg);
40
+ SMatrix::registerRubyClass(rbLinalg);
41
+ rb_require("hornetseye_linalg_ext.rb");
42
+ }
43
+
44
+ }
@@ -0,0 +1,103 @@
1
+ /* HornetsEye - Computer Vision with Ruby
2
+ Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Jan Wedekind
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 3 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, see <http://www.gnu.org/licenses/>. */
16
+ #include <algorithm>
17
+ #include "error.hh"
18
+ #include "rubytools.hh"
19
+ #include "dmatrix.hh"
20
+ #include "smatrix.hh"
21
+ #include "node.hh"
22
+
23
+ using namespace std;
24
+
25
+ VALUE Node::mModule = Qnil;
26
+
27
+ VALUE Node::cRubyClass = Qnil;
28
+
29
+ VALUE Node::registerRubyClass(VALUE module)
30
+ {
31
+ mModule = module;
32
+ cRubyClass = rb_define_class_under(module, "Node", rb_cObject);
33
+ rb_define_method(cRubyClass, "to_dmatrix", RUBY_METHOD_FUNC(wrapToDMatrix), 0);
34
+ rb_define_method(cRubyClass, "to_smatrix", RUBY_METHOD_FUNC(wrapToSMatrix), 0);
35
+ return cRubyClass;
36
+ }
37
+
38
+ VALUE Node::wrapToDMatrix(VALUE rbSelf)
39
+ {
40
+ VALUE rbRetVal = Qnil;
41
+ try {
42
+ VALUE rbMalloc = rb_funcall(rbSelf, rb_intern("memory"), 0);
43
+ VALUE rbTypecode = rb_funcall(rbSelf, rb_intern("typecode"), 0);
44
+ VALUE rbShape = rb_funcall(rbSelf, rb_intern("shape"), 0);
45
+ Check_Type(rbShape, T_ARRAY);
46
+ int rank = RARRAY_LEN(rbShape);
47
+ ERRORMACRO(rank == 2, Error, ,
48
+ "Array needs to have two dimensions for conversion to "
49
+ "DMatrix (but had " << rank << " dimension(s))");
50
+ int
51
+ width = NUM2INT(RARRAY_PTR(rbShape)[0]),
52
+ height = NUM2INT(RARRAY_PTR(rbShape)[1]);
53
+ ERRORMACRO(rb_funcall(rbTypecode, rb_intern("=="), 1,
54
+ rb_const_get(mModule, rb_intern("DFLOAT"))) == Qtrue, Error, ,
55
+ "Element-type of array must be DFLOAT");
56
+ VALUE cMalloc = rb_define_class_under(mModule, "Malloc", rb_cObject);
57
+ unsigned char *source;
58
+ dataGetStruct(rbMalloc, cMalloc, unsigned char, source);
59
+ VALUE rbLinalg = rb_define_module("Linalg");
60
+ DMatrix_ *dmatrix = (DMatrix_ *)ALLOC(DMatrix_);
61
+ dmatrix->hsize = height;
62
+ dmatrix->vsize = width;
63
+ dmatrix->data = (double *)source;
64
+ rbRetVal = Data_Wrap_Struct(DMatrix::cRubyClass, 0, DMatrix::deleteRubyObject, dmatrix);
65
+ } catch ( std::exception &e ) {
66
+ rb_raise( rb_eRuntimeError, "%s", e.what() );
67
+ };
68
+ return rbRetVal;
69
+ }
70
+
71
+ VALUE Node::wrapToSMatrix(VALUE rbSelf)
72
+ {
73
+ VALUE rbRetVal = Qnil;
74
+ try {
75
+ VALUE rbMalloc = rb_funcall(rbSelf, rb_intern("memory"), 0);
76
+ VALUE rbTypecode = rb_funcall(rbSelf, rb_intern("typecode"), 0);
77
+ VALUE rbShape = rb_funcall(rbSelf, rb_intern("shape"), 0);
78
+ Check_Type(rbShape, T_ARRAY);
79
+ int rank = RARRAY_LEN(rbShape);
80
+ ERRORMACRO(rank == 2, Error, ,
81
+ "Array needs to have two dimensions for conversion to "
82
+ "SMatrix (but had " << rank << " dimension(s))");
83
+ int
84
+ width = NUM2INT(RARRAY_PTR(rbShape)[0]),
85
+ height = NUM2INT(RARRAY_PTR(rbShape)[1]);
86
+ ERRORMACRO(rb_funcall(rbTypecode, rb_intern("=="), 1,
87
+ rb_const_get(mModule, rb_intern("SFLOAT"))) == Qtrue, Error, ,
88
+ "Element-type of array must be SFLOAT");
89
+ VALUE cMalloc = rb_define_class_under(mModule, "Malloc", rb_cObject);
90
+ unsigned char *source;
91
+ dataGetStruct(rbMalloc, cMalloc, unsigned char, source);
92
+ VALUE rbLinalg = rb_define_module("Linalg");
93
+ SMatrix_ *smatrix = (SMatrix_ *)ALLOC(SMatrix_);
94
+ smatrix->hsize = height;
95
+ smatrix->vsize = width;
96
+ smatrix->data = (float *)source;
97
+ rbRetVal = Data_Wrap_Struct(SMatrix::cRubyClass, 0, SMatrix::deleteRubyObject, smatrix);
98
+ } catch ( std::exception &e ) {
99
+ rb_raise( rb_eRuntimeError, "%s", e.what() );
100
+ };
101
+ return rbRetVal;
102
+ }
103
+