ara 0.0.2 → 0.0.3
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/Gemfile +1 -0
- data/Gemfile.lock +2 -0
- data/README.rdoc +19 -0
- data/VERSION +1 -1
- data/ara.gemspec +8 -3
- data/examples/logger_actor.rb +5 -5
- data/examples/pi.rb +70 -0
- data/examples/simple_actor.rb +10 -0
- data/examples/sync_actor.rb +1 -1
- data/lib/ara.rb +1 -0
- data/lib/ara/actor.rb +31 -24
- data/lib/ara/logger.rb +8 -0
- data/lib/ara/routing.rb +65 -0
- data/lib/ara/simple_actor.rb +3 -2
- data/lib/ext/{binding_of_caller.rb → boc.rb} +14 -17
- metadata +24 -11
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
data/README.rdoc
CHANGED
@@ -26,6 +26,15 @@ Because of akka[http://akka.io/] and my two parakeets ;)
|
|
26
26
|
sleep rand(10)
|
27
27
|
reply "Thanks @ #{Time.now}!"
|
28
28
|
end
|
29
|
+
|
30
|
+
private
|
31
|
+
def pre_start
|
32
|
+
# ...
|
33
|
+
end
|
34
|
+
|
35
|
+
def post_stop
|
36
|
+
# ...
|
37
|
+
end
|
29
38
|
end
|
30
39
|
|
31
40
|
# This method will receive the actor' replies after sending it an asynchronous message
|
@@ -99,6 +108,16 @@ Client :
|
|
99
108
|
|
100
109
|
== Changelog
|
101
110
|
|
111
|
+
=== 0.0.3
|
112
|
+
* Add pre_start and post_stop
|
113
|
+
* Change logger
|
114
|
+
* BindingOfCaller correction
|
115
|
+
* Add Routing
|
116
|
+
|
117
|
+
=== 0.0.2
|
118
|
+
* Add Scheduler support
|
119
|
+
* Add Remote actor support
|
120
|
+
|
102
121
|
=== 0.0.1
|
103
122
|
* Initial version
|
104
123
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.3
|
data/ara.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{ara}
|
8
|
-
s.version = "0.0.
|
8
|
+
s.version = "0.0.3"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Gregoire Lejeune"]
|
12
|
-
s.date = %q{2011-07-
|
12
|
+
s.date = %q{2011-07-17}
|
13
13
|
s.description = %q{Ara is a tiny class that’s allow you to use actors in Ruby}
|
14
14
|
s.email = %q{gregoire.lejeune@free.fr}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -32,6 +32,7 @@ Gem::Specification.new do |s|
|
|
32
32
|
"examples/async_block.rb",
|
33
33
|
"examples/async_meth.rb",
|
34
34
|
"examples/logger_actor.rb",
|
35
|
+
"examples/pi.rb",
|
35
36
|
"examples/simple_actor.rb",
|
36
37
|
"examples/simple_scheduler.rb",
|
37
38
|
"examples/sync_actor.rb",
|
@@ -45,9 +46,10 @@ Gem::Specification.new do |s|
|
|
45
46
|
"lib/ara/logger.rb",
|
46
47
|
"lib/ara/remote.rb",
|
47
48
|
"lib/ara/remote_actor.rb",
|
49
|
+
"lib/ara/routing.rb",
|
48
50
|
"lib/ara/scheduler.rb",
|
49
51
|
"lib/ara/simple_actor.rb",
|
50
|
-
"lib/ext/
|
52
|
+
"lib/ext/boc.rb",
|
51
53
|
"test/helper.rb",
|
52
54
|
"test/test_ara.rb"
|
53
55
|
]
|
@@ -62,17 +64,20 @@ Gem::Specification.new do |s|
|
|
62
64
|
s.specification_version = 3
|
63
65
|
|
64
66
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
67
|
+
s.add_runtime_dependency(%q<rack>, [">= 1.3.1"])
|
65
68
|
s.add_development_dependency(%q<shoulda>, [">= 0"])
|
66
69
|
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
|
67
70
|
s.add_development_dependency(%q<jeweler>, ["~> 1.6.2"])
|
68
71
|
s.add_development_dependency(%q<rcov>, [">= 0"])
|
69
72
|
else
|
73
|
+
s.add_dependency(%q<rack>, [">= 1.3.1"])
|
70
74
|
s.add_dependency(%q<shoulda>, [">= 0"])
|
71
75
|
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
72
76
|
s.add_dependency(%q<jeweler>, ["~> 1.6.2"])
|
73
77
|
s.add_dependency(%q<rcov>, [">= 0"])
|
74
78
|
end
|
75
79
|
else
|
80
|
+
s.add_dependency(%q<rack>, [">= 1.3.1"])
|
76
81
|
s.add_dependency(%q<shoulda>, [">= 0"])
|
77
82
|
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
78
83
|
s.add_dependency(%q<jeweler>, ["~> 1.6.2"])
|
data/examples/logger_actor.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
$:.unshift("../lib")
|
2
2
|
require 'ara'
|
3
3
|
|
4
|
-
Ara.logger = Logger.new("actor.log")
|
5
|
-
Ara.
|
4
|
+
# Ara.logger = Logger.new("actor.log")
|
5
|
+
Ara.debug "Starting..."
|
6
6
|
|
7
7
|
class MySimpleActor < SimpleActor
|
8
8
|
def receive( message )
|
9
|
-
Ara.
|
9
|
+
Ara.info "Actor #{self} receive message : #{message}"
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
@@ -24,11 +24,11 @@ mySimpleActor.stop
|
|
24
24
|
|
25
25
|
sleep 1
|
26
26
|
|
27
|
-
Ara.
|
27
|
+
Ara.debug "Ending..."
|
28
28
|
|
29
29
|
# This will raise an exception
|
30
30
|
begin
|
31
31
|
mySimpleActor | "Hum..."
|
32
32
|
rescue DeadActor => e
|
33
|
-
|
33
|
+
Ara.fatal e.message
|
34
34
|
end
|
data/examples/pi.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
# VERY UNSTABLE !!!
|
2
|
+
|
3
|
+
$:.unshift("../lib")
|
4
|
+
require 'ara'
|
5
|
+
|
6
|
+
class Worker < Actor
|
7
|
+
def calculate_pi_for(start, nb_of_elements)
|
8
|
+
acc = 0.0
|
9
|
+
(start...(start+nb_of_elements)).to_a.each { |i|
|
10
|
+
acc += 4.0 * (1 - (i % 2) * 2) / (2 * i + 1)
|
11
|
+
}
|
12
|
+
acc
|
13
|
+
end
|
14
|
+
|
15
|
+
def receive(message)
|
16
|
+
r = calculate_pi_for(message[:start], message[:nb_of_elements])
|
17
|
+
reply r
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class Master < Actor
|
22
|
+
def receive(message)
|
23
|
+
nb_of_workers = message[:nb_of_workers]
|
24
|
+
nb_of_elements = message[:nb_of_elements]
|
25
|
+
@nb_of_messages = message[:nb_of_messages]
|
26
|
+
|
27
|
+
@pi = 0.0
|
28
|
+
@nb_of_results = 1
|
29
|
+
|
30
|
+
actors = []
|
31
|
+
nb_of_workers.times { |_|
|
32
|
+
actors << Actors.actor_of(Worker).start
|
33
|
+
}
|
34
|
+
|
35
|
+
router = Routing.load_balancer_actor(actors)
|
36
|
+
@m = Mutex.new
|
37
|
+
|
38
|
+
@nb_of_messages.times { |i|
|
39
|
+
sleep 0.002
|
40
|
+
m = { :start => i * nb_of_elements, :nb_of_elements => nb_of_elements }
|
41
|
+
router < m
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
45
|
+
def actor_response(message)
|
46
|
+
@m.synchronize {
|
47
|
+
@pi += message
|
48
|
+
Ara.debug("*** Pi estimate : #{@pi}")
|
49
|
+
@nb_of_results += 1
|
50
|
+
self.stop if @nb_of_results >= @nb_of_messages
|
51
|
+
}
|
52
|
+
end
|
53
|
+
|
54
|
+
def post_stop
|
55
|
+
Ara.debug("Pi estimate : #{@pi}")
|
56
|
+
end
|
57
|
+
|
58
|
+
def pre_start
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def calculate(nb_of_workers, nb_of_elements, nb_of_messages)
|
63
|
+
master = Actors.actor_of(Master).start
|
64
|
+
m = { :nb_of_workers => nb_of_workers, :nb_of_elements => nb_of_elements, :nb_of_messages => nb_of_messages }
|
65
|
+
master | m
|
66
|
+
end
|
67
|
+
|
68
|
+
calculate(10, 1000, 100)
|
69
|
+
|
70
|
+
10.times { sleep 1 }
|
data/examples/simple_actor.rb
CHANGED
@@ -5,6 +5,16 @@ class MySimpleActor < SimpleActor
|
|
5
5
|
def receive( message )
|
6
6
|
puts "Actor #{self} receive message : #{message}"
|
7
7
|
end
|
8
|
+
|
9
|
+
private
|
10
|
+
def pre_start
|
11
|
+
puts "*** in pre_start"
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
def post_stop
|
16
|
+
puts "*** in post_stop"
|
17
|
+
end
|
8
18
|
end
|
9
19
|
|
10
20
|
mySimpleActor = Actors.actor_of(MySimpleActor).start
|
data/examples/sync_actor.rb
CHANGED
data/lib/ara.rb
CHANGED
data/lib/ara/actor.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
require '
|
1
|
+
require 'ext/boc'
|
2
|
+
#require 'ext/binding_of_caller'
|
2
3
|
require 'ara/simple_actor'
|
3
4
|
|
4
5
|
# Actor class
|
@@ -7,6 +8,7 @@ class Actor < SimpleActor
|
|
7
8
|
raise ActorInitializationError, "You can't initialize Actor directly, use Actors.actor_of" if self.class == ::Actor
|
8
9
|
super
|
9
10
|
@main = Queue.new
|
11
|
+
@mutex = Mutex.new
|
10
12
|
end
|
11
13
|
|
12
14
|
# Send a synchronous message
|
@@ -19,7 +21,7 @@ class Actor < SimpleActor
|
|
19
21
|
def <<(message)
|
20
22
|
if @thread.alive?
|
21
23
|
@actorQueue << message
|
22
|
-
@main.
|
24
|
+
@main.shift
|
23
25
|
else
|
24
26
|
raise DeadActor, "Actor is dead!"
|
25
27
|
end
|
@@ -34,28 +36,33 @@ class Actor < SimpleActor
|
|
34
36
|
#
|
35
37
|
# The code after this call will be executed without waiting the actor. You must add a <tt>result</tt> method to get the actor' reponse.
|
36
38
|
def <(message, response_method = nil)
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
39
|
+
_actor = self
|
40
|
+
if @thread.alive?
|
41
|
+
@actorQueue << message
|
42
|
+
|
43
|
+
BindingOfCaller.binding_of_caller do |bind|
|
44
|
+
self_of_caller = eval("self", bind)
|
45
|
+
Thread.new do
|
46
|
+
_result = @main.shift
|
47
|
+
begin
|
48
|
+
if block_given?
|
49
|
+
yield _result
|
50
|
+
elsif response_method != nil
|
51
|
+
self_of_caller.send( response_method.to_sym, _result )
|
52
|
+
elsif self_of_caller.respond_to? :actor_response_with_name
|
53
|
+
self_of_caller.send( :actor_response_with_name, _actor, _result )
|
54
|
+
else
|
55
|
+
self_of_caller.send( :actor_response, _result )
|
56
|
+
end
|
57
|
+
rescue => e
|
58
|
+
Ara.fatal(e)
|
59
|
+
raise ActorResponseError, "Error while sending response : #{e}"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
else
|
64
|
+
raise DeadActor, "Actor is dead!"
|
65
|
+
end
|
59
66
|
end
|
60
67
|
alias :async_message :<
|
61
68
|
|
data/lib/ara/logger.rb
CHANGED
@@ -10,6 +10,14 @@ module Ara
|
|
10
10
|
L.instance.logger=l
|
11
11
|
end
|
12
12
|
|
13
|
+
def self.method_missing(method_sym, *arguments, &block)
|
14
|
+
if self.logger.respond_to?(method_sym)
|
15
|
+
self.logger.send(method_sym, *arguments)
|
16
|
+
else
|
17
|
+
raise NoMethodError, "undefined method `#{method_sym.to_s}' for Ara:Module"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
13
21
|
class L #:nodoc:
|
14
22
|
include Singleton
|
15
23
|
|
data/lib/ara/routing.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
module Routing
|
2
|
+
def self.load_balancer_actor(actors)
|
3
|
+
router = Actors.actor_of(Dispatcher).start
|
4
|
+
router | ActorList.new(actors)
|
5
|
+
router
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.Broadcast(message)
|
9
|
+
return B.new(message)
|
10
|
+
end
|
11
|
+
|
12
|
+
class B #:nodoc:
|
13
|
+
def initialize(message)
|
14
|
+
@message = message
|
15
|
+
end
|
16
|
+
|
17
|
+
def message
|
18
|
+
@message
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class ActorList #:nodoc:
|
23
|
+
def initialize(actors)
|
24
|
+
@actors = actors
|
25
|
+
@free_actors = Queue.new
|
26
|
+
@actors.each { |actor| @free_actors << actor }
|
27
|
+
end
|
28
|
+
|
29
|
+
def broadcast(message)
|
30
|
+
@actors.each do |actor|
|
31
|
+
actor | message
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def get_actor
|
36
|
+
@free_actors.shift
|
37
|
+
end
|
38
|
+
|
39
|
+
def release_actor(actor)
|
40
|
+
@free_actors << actor
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class Dispatcher < Actor
|
45
|
+
def receive(message)
|
46
|
+
if message.instance_of? Routing::ActorList
|
47
|
+
@list = message
|
48
|
+
elsif message.instance_of? Routing::B
|
49
|
+
@list.broadcast(message.message)
|
50
|
+
else
|
51
|
+
f = @list.get_actor
|
52
|
+
unless f.nil?
|
53
|
+
f < message
|
54
|
+
else
|
55
|
+
Ara.debug("No free actor :(")
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def actor_response_with_name(actor, r)
|
61
|
+
@list.release_actor(actor)
|
62
|
+
reply r
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
data/lib/ara/simple_actor.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
require 'ext/binding_of_caller'
|
2
1
|
require 'ara/exception'
|
3
2
|
|
4
3
|
# This class allow you to create simple actors.
|
@@ -13,9 +12,10 @@ class SimpleActor
|
|
13
12
|
# myActor = Actors.actor_of(MyActor)
|
14
13
|
# myActor.start
|
15
14
|
def start
|
15
|
+
self.send(:pre_start) if self.respond_to?(:pre_start, true)
|
16
16
|
@thread = Thread.new do
|
17
17
|
loop do
|
18
|
-
receive(@actorQueue.
|
18
|
+
receive(@actorQueue.shift)
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
@@ -29,6 +29,7 @@ class SimpleActor
|
|
29
29
|
# myActor.stop
|
30
30
|
def stop
|
31
31
|
@thread.kill
|
32
|
+
self.send(:post_stop) if self.respond_to?(:post_stop, true)
|
32
33
|
end
|
33
34
|
|
34
35
|
# Send a simple message without expecting any response
|
@@ -23,21 +23,20 @@
|
|
23
23
|
require 'continuation'
|
24
24
|
|
25
25
|
module BindingOfCaller
|
26
|
-
VERSION = "0.1.3"
|
26
|
+
VERSION = "0.1.3"
|
27
27
|
|
28
|
-
module_function
|
28
|
+
# module_function
|
29
29
|
|
30
|
-
def binding_of_caller
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
Thread.current.set_trace_func(nil)
|
38
|
-
case event
|
30
|
+
def self.binding_of_caller
|
31
|
+
cont = nil
|
32
|
+
event_count = 0
|
33
|
+
tracer = lambda do |event, file, line, id, binding, classname|
|
34
|
+
event_count += 1
|
35
|
+
if event_count == 4
|
36
|
+
case event
|
39
37
|
when "return", "line", "end"
|
40
|
-
|
38
|
+
yield binding
|
39
|
+
set_trace_func(nil)
|
41
40
|
else
|
42
41
|
error_msg = "\n" <<
|
43
42
|
"Invalid use of binding_of_caller. One of the following:\n" <<
|
@@ -47,16 +46,14 @@ def binding_of_caller
|
|
47
46
|
" (3) the method using binding_of_caller is called from the\n" <<
|
48
47
|
" last line of a block or global scope.\n" <<
|
49
48
|
"See the documentation for binding_of_caller.\n"
|
50
|
-
cont.call(nil,
|
49
|
+
cont.call(nil, lambda { raise(ScriptError, error_msg) })
|
51
50
|
end
|
52
51
|
end
|
53
52
|
end
|
54
53
|
|
55
|
-
cont,
|
54
|
+
cont, error = callcc { |cc| cc }
|
56
55
|
if cont
|
57
|
-
|
58
|
-
elsif result
|
59
|
-
yield result
|
56
|
+
set_trace_func(tracer)
|
60
57
|
else
|
61
58
|
error.call
|
62
59
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ara
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,12 +9,23 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-07-
|
12
|
+
date: 2011-07-17 00:00:00.000000000 +02:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rack
|
17
|
+
requirement: &2154182500 !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ! '>='
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 1.3.1
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: *2154182500
|
15
26
|
- !ruby/object:Gem::Dependency
|
16
27
|
name: shoulda
|
17
|
-
requirement: &
|
28
|
+
requirement: &2154182020 !ruby/object:Gem::Requirement
|
18
29
|
none: false
|
19
30
|
requirements:
|
20
31
|
- - ! '>='
|
@@ -22,10 +33,10 @@ dependencies:
|
|
22
33
|
version: '0'
|
23
34
|
type: :development
|
24
35
|
prerelease: false
|
25
|
-
version_requirements: *
|
36
|
+
version_requirements: *2154182020
|
26
37
|
- !ruby/object:Gem::Dependency
|
27
38
|
name: bundler
|
28
|
-
requirement: &
|
39
|
+
requirement: &2154181540 !ruby/object:Gem::Requirement
|
29
40
|
none: false
|
30
41
|
requirements:
|
31
42
|
- - ~>
|
@@ -33,10 +44,10 @@ dependencies:
|
|
33
44
|
version: 1.0.0
|
34
45
|
type: :development
|
35
46
|
prerelease: false
|
36
|
-
version_requirements: *
|
47
|
+
version_requirements: *2154181540
|
37
48
|
- !ruby/object:Gem::Dependency
|
38
49
|
name: jeweler
|
39
|
-
requirement: &
|
50
|
+
requirement: &2154181060 !ruby/object:Gem::Requirement
|
40
51
|
none: false
|
41
52
|
requirements:
|
42
53
|
- - ~>
|
@@ -44,10 +55,10 @@ dependencies:
|
|
44
55
|
version: 1.6.2
|
45
56
|
type: :development
|
46
57
|
prerelease: false
|
47
|
-
version_requirements: *
|
58
|
+
version_requirements: *2154181060
|
48
59
|
- !ruby/object:Gem::Dependency
|
49
60
|
name: rcov
|
50
|
-
requirement: &
|
61
|
+
requirement: &2154180580 !ruby/object:Gem::Requirement
|
51
62
|
none: false
|
52
63
|
requirements:
|
53
64
|
- - ! '>='
|
@@ -55,7 +66,7 @@ dependencies:
|
|
55
66
|
version: '0'
|
56
67
|
type: :development
|
57
68
|
prerelease: false
|
58
|
-
version_requirements: *
|
69
|
+
version_requirements: *2154180580
|
59
70
|
description: Ara is a tiny class that’s allow you to use actors in Ruby
|
60
71
|
email: gregoire.lejeune@free.fr
|
61
72
|
executables: []
|
@@ -79,6 +90,7 @@ files:
|
|
79
90
|
- examples/async_block.rb
|
80
91
|
- examples/async_meth.rb
|
81
92
|
- examples/logger_actor.rb
|
93
|
+
- examples/pi.rb
|
82
94
|
- examples/simple_actor.rb
|
83
95
|
- examples/simple_scheduler.rb
|
84
96
|
- examples/sync_actor.rb
|
@@ -92,9 +104,10 @@ files:
|
|
92
104
|
- lib/ara/logger.rb
|
93
105
|
- lib/ara/remote.rb
|
94
106
|
- lib/ara/remote_actor.rb
|
107
|
+
- lib/ara/routing.rb
|
95
108
|
- lib/ara/scheduler.rb
|
96
109
|
- lib/ara/simple_actor.rb
|
97
|
-
- lib/ext/
|
110
|
+
- lib/ext/boc.rb
|
98
111
|
- test/helper.rb
|
99
112
|
- test/test_ara.rb
|
100
113
|
has_rdoc: true
|