sldb 0.1.0
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.
- data/README +257 -0
- data/README.tmpl +30 -0
- data/VERSION +1 -0
- data/gemspec.rb +23 -0
- data/gen_readme.rb +26 -0
- data/install.rb +206 -0
- data/lib/sldb-0.1.0.rb +1302 -0
- data/lib/sldb.rb +1302 -0
- data/sample/a.rb +22 -0
- data/sample/b.rb +29 -0
- data/sample/c.rb +35 -0
- data/sample/d.rb +37 -0
- data/sample/e.rb +19 -0
- data/white_box/test.rb +49 -0
- metadata +55 -0
data/README
ADDED
@@ -0,0 +1,257 @@
|
|
1
|
+
URLS
|
2
|
+
|
3
|
+
http://raa.ruby-lang.org/search.rhtml?search=sldb
|
4
|
+
http://codeforpeople.com/lib/ruby/sldb
|
5
|
+
|
6
|
+
ABOUT
|
7
|
+
|
8
|
+
sldb is a multi-thread, multi-process, and nfs safe abstraction of sqlite
|
9
|
+
databases. the sldb module is a class generator for concrete databases. the
|
10
|
+
programmer is freed from worrying about 'database locked' errors and
|
11
|
+
transactions are automatically retried using a linear cyclical backoff time.
|
12
|
+
in the case where all access is via the generated class sldb can even detect
|
13
|
+
certain bugs in nfs daemons and auto-recover. the class is not limited to nfs
|
14
|
+
use whatsover and can be a useful way to use an embedded sql based databases
|
15
|
+
in your ruby code with minimal effort while still providing
|
16
|
+
multi-process/multi-thread concurrency - something which is quite difficult if
|
17
|
+
using the raw sqlite-ruby interface.
|
18
|
+
|
19
|
+
AUTHOR
|
20
|
+
|
21
|
+
ara [dot] t [dot] howard [at] noaa [dot] gov
|
22
|
+
|
23
|
+
SAMPLES
|
24
|
+
|
25
|
+
<========< sample/a.rb >========>
|
26
|
+
|
27
|
+
~ > cat sample/a.rb
|
28
|
+
|
29
|
+
require 'sldb'
|
30
|
+
|
31
|
+
#
|
32
|
+
# use the factory method to specify your database class
|
33
|
+
#
|
34
|
+
DB =
|
35
|
+
SLDB::class {
|
36
|
+
schema 'create table t ( a, b, c )'
|
37
|
+
path 'sldb'
|
38
|
+
}
|
39
|
+
|
40
|
+
#
|
41
|
+
# create and instance and use it - it will be created and initialized with the
|
42
|
+
# schema on the first use
|
43
|
+
#
|
44
|
+
db = DB::new
|
45
|
+
|
46
|
+
db.transaction do
|
47
|
+
db.execute 'insert into t values (0,1,2)'
|
48
|
+
db.execute('select * from t'){|tuple| p tuple}
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
~ > ruby sample/a.rb
|
53
|
+
|
54
|
+
["0", "1", "2"]
|
55
|
+
|
56
|
+
|
57
|
+
<========< sample/b.rb >========>
|
58
|
+
|
59
|
+
~ > cat sample/b.rb
|
60
|
+
|
61
|
+
require 'csv'
|
62
|
+
require 'sldb'
|
63
|
+
|
64
|
+
DB = SLDB::class :schema => 'create table t ( a, b, c )'
|
65
|
+
db = DB::new 'sldb'
|
66
|
+
|
67
|
+
#
|
68
|
+
# sldb uses arrayfields so many operations are natural since tuples are arrays,
|
69
|
+
# yet can be indexed by field
|
70
|
+
#
|
71
|
+
db.transaction do
|
72
|
+
db.execute "insert into t values ( 'A', 'B', 'C' )"
|
73
|
+
db.execute('select * from t') do |tuple|
|
74
|
+
puts "tuple => #{ tuple.inspect }"
|
75
|
+
tuple.fields.each{|f| puts " tuple[#{ f }] => #{ tuple[f] }"}
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
puts
|
80
|
+
|
81
|
+
#
|
82
|
+
# csv generation is an example of something which is much more natural with
|
83
|
+
# arrays
|
84
|
+
#
|
85
|
+
CSV::generate('csv') do |csv|
|
86
|
+
db.ro_transaction{db.execute('select * from t'){|t| csv << t}}
|
87
|
+
end
|
88
|
+
puts(IO::read('csv'))
|
89
|
+
|
90
|
+
|
91
|
+
~ > ruby sample/b.rb
|
92
|
+
|
93
|
+
tuple => ["A", "B", "C"]
|
94
|
+
tuple[a] => A
|
95
|
+
tuple[b] => B
|
96
|
+
tuple[c] => C
|
97
|
+
|
98
|
+
A,B,C
|
99
|
+
|
100
|
+
|
101
|
+
<========< sample/c.rb >========>
|
102
|
+
|
103
|
+
~ > cat sample/c.rb
|
104
|
+
|
105
|
+
require 'yaml'
|
106
|
+
require 'sldb'
|
107
|
+
|
108
|
+
DB = SLDB::new {
|
109
|
+
schema <<-sql
|
110
|
+
create table t0 ( a, b, c);
|
111
|
+
create table t1 ( x, y, z);
|
112
|
+
sql
|
113
|
+
|
114
|
+
path 'sldb'
|
115
|
+
}
|
116
|
+
|
117
|
+
db = DB::new
|
118
|
+
|
119
|
+
#
|
120
|
+
# many utility methods exist to make working with the databases easier
|
121
|
+
#
|
122
|
+
db.transaction do
|
123
|
+
db.tablenames.each do |tablename|
|
124
|
+
tuple = db.tuple_for tablename
|
125
|
+
tuple.fields.each{|f| tuple[f] = db.timestamp 'local' => true}
|
126
|
+
values = db.quote tuple
|
127
|
+
sql = "insert into #{ tablename } values (#{ values.join ',' })"
|
128
|
+
db.execute sql
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
db.read_only_transaction do
|
133
|
+
db.tablenames.each do |tablename|
|
134
|
+
db.execute("select * from #{ tablename }") do |t|
|
135
|
+
t.map!{|f| db.stamptime f, 'local' => true}
|
136
|
+
y t.to_hash
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
~ > ruby sample/c.rb
|
142
|
+
|
143
|
+
---
|
144
|
+
a: 2005-05-13 14:13:40.754680 -06:00
|
145
|
+
b: 2005-05-13 14:13:40.754882 -06:00
|
146
|
+
c: 2005-05-13 14:13:40.754910 -06:00
|
147
|
+
---
|
148
|
+
x: 2005-05-13 14:13:40.755928 -06:00
|
149
|
+
y: 2005-05-13 14:13:40.755980 -06:00
|
150
|
+
z: 2005-05-13 14:13:40.756005 -06:00
|
151
|
+
|
152
|
+
|
153
|
+
<========< sample/d.rb >========>
|
154
|
+
|
155
|
+
~ > cat sample/d.rb
|
156
|
+
|
157
|
+
require 'yaml'
|
158
|
+
require 'sldb'
|
159
|
+
|
160
|
+
DB = SLDB::new { schema 'create table t ( tid, time )'; path 'sldb' }
|
161
|
+
db = DB::new
|
162
|
+
|
163
|
+
#
|
164
|
+
# multi-processed/multi-threaded applications may simoultaneously access the db
|
165
|
+
#
|
166
|
+
|
167
|
+
4.times do
|
168
|
+
unless fork
|
169
|
+
pid = $$
|
170
|
+
threads = []
|
171
|
+
2.times do |i|
|
172
|
+
threads <<
|
173
|
+
Thread::new(i, db) do |tid, db|
|
174
|
+
sleep rand
|
175
|
+
tuple = db.tuple_for 't'
|
176
|
+
tuple['tid'] = "#{ pid }:#{ tid }"
|
177
|
+
tuple['time'] = Time::now.to_f
|
178
|
+
values = db.quote tuple
|
179
|
+
db.transaction{db.execute "insert into t values(#{ values.join ',' })"}
|
180
|
+
end
|
181
|
+
end
|
182
|
+
threads.each{|t| t.join}
|
183
|
+
exit
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
4.times{ Process::wait }
|
188
|
+
|
189
|
+
report = Hash::new{|h,k| h[k] = []}
|
190
|
+
|
191
|
+
db.transaction{db.execute("select * from t"){|t| report['t'] << t.to_hash}}
|
192
|
+
|
193
|
+
y report
|
194
|
+
|
195
|
+
~ > ruby sample/d.rb
|
196
|
+
|
197
|
+
---
|
198
|
+
t:
|
199
|
+
-
|
200
|
+
time: "1116015221.16824"
|
201
|
+
tid: 9697:1
|
202
|
+
-
|
203
|
+
time: "1116015221.2326"
|
204
|
+
tid: 9697:0
|
205
|
+
-
|
206
|
+
time: "1116015221.64353"
|
207
|
+
tid: 9696:0
|
208
|
+
-
|
209
|
+
time: "1116015221.83744"
|
210
|
+
tid: 9695:0
|
211
|
+
-
|
212
|
+
time: "1116015221.85167"
|
213
|
+
tid: 9695:1
|
214
|
+
-
|
215
|
+
time: "1116015222.25714"
|
216
|
+
tid: 9698:0
|
217
|
+
-
|
218
|
+
time: "1116015222.27658"
|
219
|
+
tid: 9698:1
|
220
|
+
-
|
221
|
+
time: "1116015221.81659"
|
222
|
+
tid: 9696:1
|
223
|
+
|
224
|
+
|
225
|
+
<========< sample/e.rb >========>
|
226
|
+
|
227
|
+
~ > cat sample/e.rb
|
228
|
+
|
229
|
+
require 'sldb'
|
230
|
+
|
231
|
+
#
|
232
|
+
# the SLDB factory method handles - as a special case - a pathname being passed
|
233
|
+
# in as meaning : create the class AND give me and instance of it which allows
|
234
|
+
# connecting to dbs even when the schema is unknown
|
235
|
+
#
|
236
|
+
|
237
|
+
dbklass = SLDB::new 'schema' => 'create table t ( answer )',
|
238
|
+
'path' => 'sldb'
|
239
|
+
db = dbklass::new
|
240
|
+
db.transaction{ db.execute 'insert into t values ( 42 )' }
|
241
|
+
|
242
|
+
fork do
|
243
|
+
db = SLDB::new 'sldb' # here we don't know schema
|
244
|
+
db.transaction{ db.execute('select * from t'){|t| puts t['answer']}}
|
245
|
+
end
|
246
|
+
|
247
|
+
Process::wait
|
248
|
+
|
249
|
+
~ > ruby sample/e.rb
|
250
|
+
|
251
|
+
42
|
252
|
+
|
253
|
+
|
254
|
+
CAVEATS
|
255
|
+
|
256
|
+
this library is __highly__ experimental and subject to change.
|
257
|
+
|
data/README.tmpl
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
URLS
|
2
|
+
|
3
|
+
http://raa.ruby-lang.org/search.rhtml?search=sldb
|
4
|
+
http://codeforpeople.com/lib/ruby/sldb
|
5
|
+
|
6
|
+
ABOUT
|
7
|
+
|
8
|
+
sldb is a multi-thread, multi-process, and nfs safe abstraction of sqlite
|
9
|
+
databases. the sldb module is a class generator for concrete databases. the
|
10
|
+
programmer is freed from worrying about 'database locked' errors and
|
11
|
+
transactions are automatically retried using a linear cyclical backoff time.
|
12
|
+
in the case where all access is via the generated class sldb can even detect
|
13
|
+
certain bugs in nfs daemons and auto-recover. the class is not limited to nfs
|
14
|
+
use whatsover and can be a useful way to use an embedded sql based databases
|
15
|
+
in your ruby code with minimal effort while still providing
|
16
|
+
multi-process/multi-thread concurrency - something which is quite difficult if
|
17
|
+
using the raw sqlite-ruby interface.
|
18
|
+
|
19
|
+
AUTHOR
|
20
|
+
|
21
|
+
ara [dot] t [dot] howard [at] noaa [dot] gov
|
22
|
+
|
23
|
+
SAMPLES
|
24
|
+
|
25
|
+
@samples
|
26
|
+
|
27
|
+
CAVEATS
|
28
|
+
|
29
|
+
this library is __highly__ experimental and subject to change.
|
30
|
+
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
data/gemspec.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
lib, version = File::basename(File::dirname(File::expand_path(__FILE__))).split %r/-/, 2
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
|
5
|
+
Gem::Specification::new do |spec|
|
6
|
+
spec.name = lib
|
7
|
+
spec.version = version
|
8
|
+
spec.platform = Gem::Platform::RUBY
|
9
|
+
spec.summary = lib
|
10
|
+
|
11
|
+
spec.files = Dir::glob "**/**"
|
12
|
+
spec.executables = Dir::glob("bin/*").map{|exe| File::basename exe}
|
13
|
+
|
14
|
+
spec.require_path = "lib"
|
15
|
+
spec.autorequire = lib
|
16
|
+
|
17
|
+
spec.has_rdoc = File::exist? "doc"
|
18
|
+
spec.test_suite_file = "test/#{ lib }.rb" if File::directory? "test"
|
19
|
+
|
20
|
+
spec.author = "Ara T. Howard"
|
21
|
+
spec.email = "ara.t.howard@noaa.gov"
|
22
|
+
spec.homepage = "http://codeforpeople.com/lib/ruby/#{ lib }/"
|
23
|
+
end
|
data/gen_readme.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
$VERBOSE=nil
|
2
|
+
def indent s, n = 2
|
3
|
+
ws = ' ' * n
|
4
|
+
s.gsub %r/^/, ws
|
5
|
+
end
|
6
|
+
|
7
|
+
template = IO::read 'README.tmpl'
|
8
|
+
|
9
|
+
samples = ''
|
10
|
+
prompt = '~ > '
|
11
|
+
|
12
|
+
Dir['sample/*'].each do |sample|
|
13
|
+
samples << "\n" << " <========< #{ sample } >========>" << "\n\n"
|
14
|
+
cmd = "cat #{ sample }"
|
15
|
+
samples << indent(prompt + cmd, 2) << "\n\n"
|
16
|
+
samples << indent(`#{ cmd }`, 4) << "\n"
|
17
|
+
cmd = "ruby #{ sample }"
|
18
|
+
samples << indent(prompt + cmd, 2) << "\n\n"
|
19
|
+
cmd = "rm -rf ./sldb; rm -rf csv; ruby -I ./lib #{ sample }"
|
20
|
+
samples << indent(`#{ cmd }`, 4) << "\n"
|
21
|
+
end
|
22
|
+
|
23
|
+
#samples.gsub! %r/^/, ' '
|
24
|
+
|
25
|
+
readme = template.gsub %r/^\s*@samples\s*$/, samples
|
26
|
+
print readme
|
data/install.rb
ADDED
@@ -0,0 +1,206 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'rbconfig'
|
3
|
+
require 'find'
|
4
|
+
require 'ftools'
|
5
|
+
require 'tempfile'
|
6
|
+
include Config
|
7
|
+
|
8
|
+
LIBDIR = "lib"
|
9
|
+
LIBDIR_MODE = 0644
|
10
|
+
|
11
|
+
BINDIR = "bin"
|
12
|
+
BINDIR_MODE = 0755
|
13
|
+
|
14
|
+
|
15
|
+
$srcdir = CONFIG["srcdir"]
|
16
|
+
$version = CONFIG["MAJOR"]+"."+CONFIG["MINOR"]
|
17
|
+
$libdir = File.join(CONFIG["libdir"], "ruby", $version)
|
18
|
+
$archdir = File.join($libdir, CONFIG["arch"])
|
19
|
+
$site_libdir = $:.find {|x| x =~ /site_ruby$/}
|
20
|
+
$bindir = CONFIG["bindir"] || CONFIG['BINDIR']
|
21
|
+
$ruby_install_name = CONFIG['ruby_install_name'] || CONFIG['RUBY_INSTALL_NAME'] || 'ruby'
|
22
|
+
$ruby_ext = CONFIG['EXEEXT'] || ''
|
23
|
+
$ruby = File.join($bindir, ($ruby_install_name + $ruby_ext))
|
24
|
+
|
25
|
+
if !$site_libdir
|
26
|
+
$site_libdir = File.join($libdir, "site_ruby")
|
27
|
+
elsif $site_libdir !~ %r/#{Regexp.quote($version)}/
|
28
|
+
$site_libdir = File.join($site_libdir, $version)
|
29
|
+
end
|
30
|
+
|
31
|
+
def install_rb(srcdir=nil, destdir=nil, mode=nil, bin=nil)
|
32
|
+
#{{{
|
33
|
+
path = []
|
34
|
+
dir = []
|
35
|
+
Find.find(srcdir) do |f|
|
36
|
+
next unless FileTest.file?(f)
|
37
|
+
next if (f = f[srcdir.length+1..-1]) == nil
|
38
|
+
next if (/CVS$/ =~ File.dirname(f))
|
39
|
+
next if f =~ %r/\.lnk/
|
40
|
+
path.push f
|
41
|
+
dir |= [File.dirname(f)]
|
42
|
+
end
|
43
|
+
for f in dir
|
44
|
+
next if f == "."
|
45
|
+
next if f == "CVS"
|
46
|
+
File::makedirs(File.join(destdir, f))
|
47
|
+
end
|
48
|
+
for f in path
|
49
|
+
next if (/\~$/ =~ f)
|
50
|
+
next if (/^\./ =~ File.basename(f))
|
51
|
+
unless bin
|
52
|
+
File::install(File.join(srcdir, f), File.join(destdir, f), mode, true)
|
53
|
+
else
|
54
|
+
from = File.join(srcdir, f)
|
55
|
+
to = File.join(destdir, f)
|
56
|
+
shebangify(from) do |sf|
|
57
|
+
$deferr.print from, " -> ", File::catname(from, to), "\n"
|
58
|
+
$deferr.printf "chmod %04o %s\n", mode, to
|
59
|
+
File::install(sf, to, mode, false)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
#}}}
|
64
|
+
end
|
65
|
+
def shebangify f
|
66
|
+
#{{{
|
67
|
+
open(f) do |fd|
|
68
|
+
buf = fd.read 42
|
69
|
+
if buf =~ %r/^\s*#\s*!.*ruby/o
|
70
|
+
ftmp = Tempfile::new("#{ $$ }_#{ File::basename(f) }")
|
71
|
+
begin
|
72
|
+
fd.rewind
|
73
|
+
ftmp.puts "#!#{ $ruby }"
|
74
|
+
while((buf = fd.read(8192)))
|
75
|
+
ftmp.write buf
|
76
|
+
end
|
77
|
+
ftmp.close
|
78
|
+
yield ftmp.path
|
79
|
+
ensure
|
80
|
+
ftmp.close!
|
81
|
+
end
|
82
|
+
else
|
83
|
+
yield f
|
84
|
+
end
|
85
|
+
end
|
86
|
+
#}}}
|
87
|
+
end
|
88
|
+
def ARGV.switch
|
89
|
+
#{{{
|
90
|
+
return nil if self.empty?
|
91
|
+
arg = self.shift
|
92
|
+
return nil if arg == '--'
|
93
|
+
if arg =~ /^-(.)(.*)/
|
94
|
+
return arg if $1 == '-'
|
95
|
+
raise 'unknown switch "-"' if $2.index('-')
|
96
|
+
self.unshift "-#{$2}" if $2.size > 0
|
97
|
+
"-#{$1}"
|
98
|
+
else
|
99
|
+
self.unshift arg
|
100
|
+
nil
|
101
|
+
end
|
102
|
+
#}}}
|
103
|
+
end
|
104
|
+
def ARGV.req_arg
|
105
|
+
#{{{
|
106
|
+
self.shift || raise('missing argument')
|
107
|
+
#}}}
|
108
|
+
end
|
109
|
+
def linkify d, linked = []
|
110
|
+
#--{{{
|
111
|
+
if test ?d, d
|
112
|
+
versioned = Dir[ File::join(d, "*-[0-9].[0-9].[0-9].rb") ]
|
113
|
+
versioned.each do |v|
|
114
|
+
src, dst = v, v.gsub(%r/\-[\d\.]+\.rb$/, '.rb')
|
115
|
+
lnk = nil
|
116
|
+
begin
|
117
|
+
if test ?l, dst
|
118
|
+
lnk = "#{ dst }.lnk"
|
119
|
+
puts "#{ dst } -> #{ lnk }"
|
120
|
+
File::rename dst, lnk
|
121
|
+
end
|
122
|
+
unless test ?e, dst
|
123
|
+
puts "#{ src } -> #{ dst }"
|
124
|
+
File::copy src, dst
|
125
|
+
linked << dst
|
126
|
+
end
|
127
|
+
ensure
|
128
|
+
if lnk
|
129
|
+
at_exit do
|
130
|
+
puts "#{ lnk } -> #{ dst }"
|
131
|
+
File::rename lnk, dst
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
linked
|
138
|
+
#--}}}
|
139
|
+
end
|
140
|
+
|
141
|
+
|
142
|
+
#
|
143
|
+
# main program
|
144
|
+
#
|
145
|
+
|
146
|
+
libdir = $site_libdir
|
147
|
+
bindir = $bindir
|
148
|
+
no_linkify = false
|
149
|
+
linked = nil
|
150
|
+
help = false
|
151
|
+
|
152
|
+
usage = <<-usage
|
153
|
+
#{ File::basename $0 }
|
154
|
+
-d, --destdir <destdir>
|
155
|
+
-l, --libdir <libdir>
|
156
|
+
-b, --bindir <bindir>
|
157
|
+
-r, --ruby <ruby>
|
158
|
+
-n, --no_linkify
|
159
|
+
-s, --sudo
|
160
|
+
-h, --help
|
161
|
+
usage
|
162
|
+
|
163
|
+
begin
|
164
|
+
while switch = ARGV.switch
|
165
|
+
case switch
|
166
|
+
when '-d', '--destdir'
|
167
|
+
libdir = ARGV.req_arg
|
168
|
+
when '-l', '--libdir'
|
169
|
+
libdir = ARGV.req_arg
|
170
|
+
when '-b', '--bindir'
|
171
|
+
bindir = ARGV.req_arg
|
172
|
+
when '-r', '--ruby'
|
173
|
+
$ruby = ARGV.req_arg
|
174
|
+
when '-n', '--no_linkify'
|
175
|
+
no_linkify = true
|
176
|
+
when '-s', '--sudo'
|
177
|
+
sudo = 'sudo'
|
178
|
+
when '-h', '--help'
|
179
|
+
help = true
|
180
|
+
else
|
181
|
+
raise "unknown switch #{switch.dump}"
|
182
|
+
end
|
183
|
+
end
|
184
|
+
rescue
|
185
|
+
STDERR.puts $!.to_s
|
186
|
+
STDERR.puts usage
|
187
|
+
exit 1
|
188
|
+
end
|
189
|
+
|
190
|
+
if help
|
191
|
+
STDOUT.puts usage
|
192
|
+
exit
|
193
|
+
end
|
194
|
+
|
195
|
+
unless no_linkify
|
196
|
+
linked = linkify('lib') + linkify('bin')
|
197
|
+
end
|
198
|
+
|
199
|
+
system "#{ $ruby } extconf.rb && make && #{ sudo } make install" if test(?s, 'extconf.rb')
|
200
|
+
|
201
|
+
install_rb(LIBDIR, libdir, LIBDIR_MODE)
|
202
|
+
install_rb(BINDIR, bindir, BINDIR_MODE, bin=true)
|
203
|
+
|
204
|
+
if linked
|
205
|
+
linked.each{|path| File::rm_f path}
|
206
|
+
end
|