eventbox 0.1.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/.appveyor.yml +5 -3
- data/.travis.yml +4 -4
- data/.yardopts +2 -2
- data/CHANGELOG.md +19 -0
- data/README.md +91 -48
- data/docs/downloads.md +6 -5
- data/docs/images/my_queue_calls.svg +761 -0
- data/docs/my_queue_calls_github.md +1 -0
- data/docs/my_queue_calls_local.md +1 -0
- data/docs/server.md +25 -14
- data/docs/threadpool.md +4 -1
- data/eventbox.gemspec +3 -2
- data/lib/eventbox.rb +63 -11
- data/lib/eventbox/argument_wrapper.rb +11 -10
- data/lib/eventbox/boxable.rb +41 -33
- data/lib/eventbox/call_context.rb +47 -0
- data/lib/eventbox/event_loop.rb +167 -70
- data/lib/eventbox/sanitizer.rb +155 -39
- data/lib/eventbox/thread_pool.rb +10 -0
- data/lib/eventbox/timer.rb +17 -7
- data/lib/eventbox/version.rb +1 -1
- metadata +50 -30
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2cded1e660a5b8321b82e80dfec3bb02f66186d5e9befa33a9083773e67708a4
|
4
|
+
data.tar.gz: a49d8755319a94fc72d67ffbbf8aee6c2f3da6c1c35f8530f0ea3e2bd4cfe003
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1566416c8c226a188e21e5d79e6dcc8ca663854fc87062bc7a4600656bf35c75d81c46226b8ba165962f7730e34161c215cf15d3a1b5529ec74947d4a2b14831
|
7
|
+
data.tar.gz: 38f010998ef24d2b650264fcead255f905983948ecdbfd7c56afed59f1d36326ccc10015d6e6783fd8d54a757986be233fbe9fa31d25cd7795ed6a916e149bdc
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data.tar.gz.sig
CHANGED
Binary file
|
data/.appveyor.yml
CHANGED
@@ -1,8 +1,10 @@
|
|
1
|
+
image: Visual Studio 2019
|
2
|
+
|
1
3
|
build: off
|
2
4
|
|
3
5
|
init:
|
4
6
|
- set PATH=C:/Ruby%ruby_version%/bin;%PATH%
|
5
|
-
- set RUBYOPT=--verbose
|
7
|
+
- set RUBYOPT=--verbose --enable-frozen-string-literal
|
6
8
|
|
7
9
|
install:
|
8
10
|
- ps: |
|
@@ -24,5 +26,5 @@ environment:
|
|
24
26
|
RUBYDOWNLOAD: x64
|
25
27
|
- ruby_version: "head"
|
26
28
|
RUBYDOWNLOAD: x86
|
27
|
-
- ruby_version: "
|
28
|
-
- ruby_version: "
|
29
|
+
- ruby_version: "30-x64"
|
30
|
+
- ruby_version: "30"
|
data/.travis.yml
CHANGED
@@ -3,14 +3,14 @@ sudo: false
|
|
3
3
|
language: ruby
|
4
4
|
cache: bundler
|
5
5
|
matrix:
|
6
|
-
fast_finish:
|
6
|
+
fast_finish: false
|
7
7
|
include:
|
8
|
-
- rvm:
|
9
|
-
- rvm: 2.5.3
|
8
|
+
- rvm: 3.0.1
|
10
9
|
env: RUBYOPT=--verbose --enable-frozen-string-literal
|
11
|
-
- rvm: jruby-9.2.4.1
|
12
10
|
- rvm: ruby-head
|
13
11
|
env: RUBYOPT=--verbose --enable-frozen-string-literal
|
14
12
|
|
13
|
+
# JRuby and Truffleruby don't support keyword argument semantics of ruby-3.0
|
14
|
+
|
15
15
|
script:
|
16
16
|
- bundle exec rake test TESTOPTS=-v
|
data/.yardopts
CHANGED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
1.0.0 / 2021-07-07
|
2
|
+
-------------------
|
3
|
+
|
4
|
+
Changed:
|
5
|
+
* Requires ruby-3.0 or newer.
|
6
|
+
* More readable #inspect output of several classes.
|
7
|
+
|
8
|
+
Added:
|
9
|
+
* Allow calls to external objects and procs/lambdas from the event scope.
|
10
|
+
* Introduce Eventbox#call_context .
|
11
|
+
* Correct and consistent handling of keyword arguments to method/prod calls.
|
12
|
+
* Allow serialization by marshal_dump and marshal_load.
|
13
|
+
* Improved documentation.
|
14
|
+
|
15
|
+
|
16
|
+
0.1.0 / 2018-12-04
|
17
|
+
-------------------
|
18
|
+
|
19
|
+
* First release
|
data/README.md
CHANGED
@@ -5,21 +5,23 @@
|
|
5
5
|
|
6
6
|
_Manage multithreading with the safety of event based programming_
|
7
7
|
|
8
|
+
Eventbox is a model of concurrent computation that is used to build thread-safe objects with arbitrary interfaces.
|
9
|
+
It is [kind of advancement](#comparison-threading-abstractions) of the well known [actor model](https://en.wikipedia.org/wiki/Actor_model) leveraging the possibilities of the ruby language.
|
10
|
+
It is a small, consistent but powerful threading abstraction which **integrates well into existing environments**.
|
11
|
+
|
8
12
|
{Eventbox} objects are event based and single threaded from the inside but thread-safe and blocking from the outside.
|
9
|
-
Eventbox enforces a separation of code for event processing and code running blocking operations.
|
13
|
+
Eventbox enforces a **separation of code for event processing** and code running blocking operations.
|
10
14
|
Code inside an {Eventbox} object is executed non-concurrently and hence shouldn't do any blocking operations.
|
11
15
|
This is similar to the typical JavaScript programming style.
|
12
16
|
|
13
|
-
On the other hand all blocking operations can be executed in action threads spawned by the {Eventbox.action action} method type.
|
14
|
-
Communication between actions
|
17
|
+
On the other hand all **blocking operations can be executed in action threads** spawned by the {Eventbox.action action} method type.
|
18
|
+
Communication between actions, event processing and external environment is done through ordinary method and lambda calls.
|
19
|
+
They arbitrate between blocking versus event based scheme and ensure thread-safety.
|
15
20
|
|
16
21
|
An important task of Eventbox is to avoid race conditions through shared data.
|
17
|
-
Such data races between event scope and external/action scope are avoided through {Eventbox::Sanitizer filters} applied to all inputs and outputs
|
22
|
+
Such data races between event scope and external/action scope are avoided through **{Eventbox::Sanitizer filters} applied to all inputs and outputs**.
|
18
23
|
That way {Eventbox} guarantees stable states while event processing without a need for any locks.
|
19
24
|
|
20
|
-
Eventbox is a model of concurrent computation that is used to build thread-safe objects with arbitrary interfaces.
|
21
|
-
It is kind of [advancement](#comparison-threading-abstractions) of the well known [actor model](https://en.wikipedia.org/wiki/Actor_model) leveraging the possibilities of the ruby language.
|
22
|
-
|
23
25
|
* [API documentation](https://www.rubydoc.info/github/larskanis/eventbox/master)
|
24
26
|
|
25
27
|
|
@@ -53,22 +55,23 @@ It can therefore be used to build well known multithread abstractions like a Que
|
|
53
55
|
|
54
56
|
```ruby
|
55
57
|
require "eventbox"
|
56
|
-
class
|
57
|
-
# Called at
|
58
|
+
class MyQueue < Eventbox
|
59
|
+
# Called at MyQueue.new just like Object#initialize in ordinary ruby classes
|
58
60
|
async_call def init
|
59
61
|
@que = [] # List of values waiting for being fetched by deq
|
60
62
|
@waiting = [] # List of blocking deq calls waiting for new values to be pushed by enq
|
61
63
|
end
|
62
64
|
|
63
|
-
# Push a value to the queue
|
64
|
-
async_call def enq(€value) # €-variables are passed through as reference
|
65
|
-
@que << €value # Push
|
66
|
-
if w=@waiting.shift
|
67
|
-
w.yield @que.shift # Let
|
65
|
+
# Push a value to the queue - async methods always return immediately
|
66
|
+
async_call def enq(€value) # €-variables are passed through as reference instead of copies
|
67
|
+
@que << €value # Push the value to the queue
|
68
|
+
if w=@waiting.shift # Is there a thread already waiting for a value?
|
69
|
+
w.yield @que.shift # Let the waiting `deq' call return the oldest value in the queue
|
68
70
|
end
|
69
71
|
end
|
70
72
|
|
71
73
|
# Fetch a value from the queue or suspend the caller until a value has been enqueued
|
74
|
+
# yield methods are completely processed, but return not before a result has been yielded
|
72
75
|
yield_call def deq(result)
|
73
76
|
if @que.empty?
|
74
77
|
@waiting << result # Don't return a value now, but enqueue the request as waiting
|
@@ -78,13 +81,30 @@ class Queue < Eventbox
|
|
78
81
|
end
|
79
82
|
end
|
80
83
|
```
|
81
|
-
|
84
|
+
|
85
|
+
<a name="my_queue_image"></a>
|
86
|
+
A picture describes it best:
|
87
|
+
|
88
|
+
[![MyQueue calls](https://raw.github.com/larskanis/eventbox/master/docs/images/my_queue_calls.svg?sanitize=true)](https://www.rubydoc.info/github/larskanis/eventbox/master/file/README.md#my_queue_image)
|
89
|
+
{include:file:docs/my_queue_calls_github.md}
|
90
|
+
|
91
|
+
Although there are no mutex or condition variables in use, the implementation is thread-safe.
|
92
|
+
This is due to the wrapping that is activated by {Eventbox::Boxable.async_call async_call} and {Eventbox::Boxable.yield_call yield_call} prefixes.
|
93
|
+
The {Eventbox::Boxable.yield_call yield_call} method definition divides the single external call into two internal events: The event of the start of call and the event of releasing the call with a return value.
|
94
|
+
In contrast {Eventbox::Boxable.async_call async_call} defines a method which handles one event only - the start of the call: The external call completes immediately and always returns `self`.
|
95
|
+
|
96
|
+
The branch in `Queue#deq` shows a typical decision taking in Eventbox:
|
97
|
+
If the call can be processed immediately it yields the result, else wise the result is added to an internal list to be processes later.
|
98
|
+
This list must be checked at each event which could signal the ability to complete the enqueued processing.
|
99
|
+
This is done in `Queue#enq` in the above example.
|
100
|
+
|
101
|
+
Our new queue class unsurprisingly has semantics like ruby's builtin Queue implementation:
|
82
102
|
|
83
103
|
```ruby
|
84
|
-
q =
|
104
|
+
q = MyQueue.new
|
85
105
|
Thread.new do
|
86
106
|
5.times do |i|
|
87
|
-
q.enq i # Enqueue integers 0 to
|
107
|
+
q.enq i # Enqueue integers 0 to 4
|
88
108
|
end
|
89
109
|
end
|
90
110
|
|
@@ -100,22 +120,9 @@ end
|
|
100
120
|
4
|
101
121
|
```
|
102
122
|
|
103
|
-
Although there are no mutex or condition variables in use, the implementation is guaranteed to be thread-safe.
|
104
|
-
The key feature is the {Eventbox.yield_call} method definition.
|
105
|
-
It divides the single external call into two internal events: The event of the start of call and the event of releasing the call with a return value.
|
106
|
-
In contrast {Eventbox.async_call} defines a method which handles one event only - the start of the call.
|
107
|
-
The external call returns immediately, but can't return a value.
|
108
|
-
|
109
|
-
Seeing curly braces instead of links? Switch to the [API documentation](https://www.rubydoc.info/github/larskanis/eventbox/master).
|
110
|
-
|
111
|
-
The branch in `Queue#deq` shows a typical decision taking in Eventbox:
|
112
|
-
If the call can be processed immediately it yields the result, else wise the result is added to a list to be processes later.
|
113
|
-
It's important to check this list at each event which could signal the ability to complete the enqueued processing.
|
114
|
-
This is done in `Queue#enq` in the above example.
|
115
|
-
|
116
123
|
If you just need a queue it's better to stay at the Queue implementations of the standard library or [concurrent-ruby](https://github.com/ruby-concurrency/concurrent-ruby).
|
117
124
|
However if you want to cancel items in the queue for example, you need more control about waiting items or waiting callers than common thread abstractions offer.
|
118
|
-
The same if you want to query and visualize the internal state of processing
|
125
|
+
The same if you want to query and visualize the internal state of processing (the pending items in the queue).
|
119
126
|
|
120
127
|
|
121
128
|
### Hands on
|
@@ -127,9 +134,12 @@ It is recommended to work them through, in order to fully understand how Eventbo
|
|
127
134
|
* {file:docs/server.md TCP server} - Understand how to startup and shutdown blocking actions and to combine several Eventbox classes to handle parallel connections.
|
128
135
|
* {file:docs/threadpool.md Thread-pool} - Understand how parallel external requests can be serialized and scheduled.
|
129
136
|
|
137
|
+
Seeing curly braces instead of links? Switch to the [API documentation](https://www.rubydoc.info/github/larskanis/eventbox/master).
|
138
|
+
|
130
139
|
|
131
140
|
## Method types
|
132
141
|
|
142
|
+
<a name="event-scope"></a>
|
133
143
|
### Event Scope
|
134
144
|
|
135
145
|
Eventbox offers 3 different types of external callable methods:
|
@@ -148,11 +158,12 @@ There is no hard criteria for what is considered a blocking operation, but since
|
|
148
158
|
If the processing time of an event scope method or block exceeds the limit of 0.5 seconds, a warning is print to `STDERR`.
|
149
159
|
This limit can be changed by {Eventbox.with_options}.
|
150
160
|
|
151
|
-
Arguments of async, sync and yield calls can be prefixed by a
|
161
|
+
Arguments of async, sync and yield calls can be prefixed by a `€` sign.
|
152
162
|
This marks them as to be passed through as reference, instead of being copied.
|
153
|
-
A
|
163
|
+
A `€`-variable is wrapped and protected within the event scope, but unwrapped when passed to action or external scope.
|
164
|
+
It can be called within the event scope by {Eventbox::ExternalObject#send}.
|
154
165
|
|
155
|
-
In
|
166
|
+
In addition there are accessor methods usable as known from ordinary ruby objects: {Eventbox.attr_reader attr_reader}, {Eventbox.attr_writer attr_writer} and {Eventbox.attr_accessor attr_accessor}.
|
156
167
|
They allow thread-safe access to instance variables.
|
157
168
|
|
158
169
|
Beside {Eventbox.async_call async_call}, {Eventbox.sync_call sync_call} and {Eventbox.yield_call yield_call} methods it's possible to define plain `private` methods, since they are not accessible externally.
|
@@ -178,12 +189,21 @@ And all data generated by the action should be passed as arguments back to event
|
|
178
189
|
Some data shall just be managed as reference in some scope without being accessed there.
|
179
190
|
Or it is passed through a given scope only.
|
180
191
|
In such cases it can be marked as {Eventbox#shared_object shared_object}.
|
181
|
-
This wrapping is similar to
|
192
|
+
This wrapping is similar to `€` argument variables, however {Eventbox#shared_object shared_object} it more versatile.
|
182
193
|
It marks objects permanently and wraps them even when they are stored inside of a copied object.
|
183
194
|
|
195
|
+
<a name="external-scope"></a>
|
184
196
|
### External scope
|
185
197
|
|
186
198
|
Code outside of the Eventbox class is referred to as "external scope".
|
199
|
+
The external scope is recognized as one common space.
|
200
|
+
|
201
|
+
External objects can be directly called from action scope, since they are unwrapped when passed from event to action scope.
|
202
|
+
In this case the object to be called should be thread-safe.
|
203
|
+
See also [What is safe and what isn't?](#eventbox-safety) below.
|
204
|
+
|
205
|
+
External objects can also be called from event scope per {Eventbox::ExternalObject#send}, but with some restrictions.
|
206
|
+
The same restrictions apply to external closures too, which are callable from event scope per {Eventbox::ExternalProc#call}.
|
187
207
|
|
188
208
|
|
189
209
|
## Block and Proc types
|
@@ -197,8 +217,8 @@ Similary to the 3 method calls above there are 3 types of proc objects which act
|
|
197
217
|
|
198
218
|
These proc objects can be created within event scope, can be passed to external scope and called from there.
|
199
219
|
|
200
|
-
Arguments of async, sync and yield procs can be prefixed by a
|
201
|
-
In that case, they are passed as reference, equally to
|
220
|
+
Arguments of async, sync and yield procs can be prefixed by a `€` sign.
|
221
|
+
In that case, they are passed as reference, equally to `€`-variables of {Eventbox.async_call async_call}, {Eventbox.sync_call sync_call} and {Eventbox.yield_call yield_call} methods.
|
202
222
|
|
203
223
|
The other way around - Proc objects or blocks which are defined in external or action scope - can be passed to event scope.
|
204
224
|
Such a Proc object is wrapped as a {Eventbox::ExternalProc} object within the event scope.
|
@@ -207,6 +227,7 @@ Instead the event scope method is executed until its end, while the block is exe
|
|
207
227
|
Optionally the block can be called with a completion block as the last argument, which is called with the result of the external proc when it has finished.
|
208
228
|
|
209
229
|
|
230
|
+
<a name="exceptions"></a>
|
210
231
|
## Exceptions
|
211
232
|
|
212
233
|
Eventbox makes use of exceptions in several ways.
|
@@ -236,10 +257,14 @@ async_call def conn_failed(error)
|
|
236
257
|
end
|
237
258
|
```
|
238
259
|
|
260
|
+
Alternatively closures can be passed to the action which are called in case of success or failure.
|
261
|
+
See the {file:docs/downloads.md#exceptions-closure-style download example} for more description about this variation.
|
262
|
+
|
239
263
|
Another use of exceptions is for sending signals to running actions.
|
240
264
|
This is done by {Eventbox::Action#raise}.
|
241
265
|
|
242
266
|
|
267
|
+
<a name="eventbox-safety"></a>
|
243
268
|
## What is safe and what isn't?
|
244
269
|
|
245
270
|
At each transition of the scope all passing objects are sanitized by the {Eventbox::Sanitizer}.
|
@@ -247,7 +272,7 @@ It protects the event scope from data races and arbitrates between blocking and
|
|
247
272
|
This is done by copying or wrapping the objects conveniently as described in the {Eventbox::Sanitizer}.
|
248
273
|
That way event scope methods never get an inconsistent state regardless of the activities of external threads.
|
249
274
|
|
250
|
-
Obviously it's not safe to do things like using `send` to call private methods from external, access instance variables per `instance_variable_set` or use global variables in a multithreading context.
|
275
|
+
Obviously it's not safe to do things like using `send` to call private methods from external, access instance variables per `instance_variable_set` or use class or global variables in a multithreading context.
|
251
276
|
Such rough ways of communication with an Eventbox object are surely neither recommended nor supported.
|
252
277
|
Other than these the event scope of an Eventbox instance is pretty well protected against accident mistakes.
|
253
278
|
|
@@ -263,11 +288,20 @@ External libraries and objects must be thread-safe on its own if used from diffe
|
|
263
288
|
Protecting them is beyond the scope of Eventbox.
|
264
289
|
|
265
290
|
|
291
|
+
## Object distribution and persistence
|
292
|
+
|
293
|
+
Eventbox objects can be serialized to be stored persistent or distributed across the network.
|
294
|
+
This allows the utilization by job schedulers, messaging libraries and distributed object systems.
|
295
|
+
However there are the following restrictions:
|
296
|
+
|
297
|
+
1. Only objects without running actions can be serialized, since running code can not be serialized.
|
298
|
+
2. Objects with a custom {Eventbox.with_options thread-pool} can be serialized only, when the thread-pool can be serialized.
|
299
|
+
3. Objects with {Eventbox.with_options guard_time} set to a Proc object can not be serialized.
|
300
|
+
|
301
|
+
|
266
302
|
## Time based events
|
267
303
|
|
268
|
-
|
269
|
-
However that's not very convenient.
|
270
|
-
Therefore Eventbox provides a dedicated {Eventbox::Timer timer module} for simple timer functions.
|
304
|
+
Although timer events can be easily generated by an action with a `sleep` function, they are so common, that Eventbox bundles a dedicated {Eventbox::Timer timer module} for scheduling timer events.
|
271
305
|
It can be included into Eventbox classes by:
|
272
306
|
|
273
307
|
```ruby
|
@@ -275,6 +309,7 @@ It can be included into Eventbox classes by:
|
|
275
309
|
```
|
276
310
|
|
277
311
|
It offers {Eventbox::Timer#timer_after} and {Eventbox::Timer#timer_every} functions to schedule blocks to be called.
|
312
|
+
See the {Eventbox::Timer} module for further description.
|
278
313
|
|
279
314
|
|
280
315
|
## Derived classes and mixins
|
@@ -313,13 +348,13 @@ This was the primary motivation to develop this library.
|
|
313
348
|
Eventbox is kind of advancement of the well known [actor model](https://en.wikipedia.org/wiki/Actor_model) leveraging the possibilities of the ruby language.
|
314
349
|
While the actor model uses explicit message passing, Eventbox relies on method calls, closure calls and exceptions, which makes it much more natural to use.
|
315
350
|
Unlike an actor, Eventbox doesn't start a thread per object, but uses the thread of the caller to execute non-blocking code.
|
316
|
-
This makes instantiation of Eventbox objects
|
351
|
+
This makes instantiation of Eventbox objects cheaper than Actor objects.
|
317
352
|
Instead it can create and manage in-object private threads in form of {Eventbox.action actions} to be used for blocking operations.
|
318
353
|
|
319
354
|
Many actor implementations manage an inheritance tree of actor objects.
|
320
355
|
Parent actors are then notified about failures of child actors.
|
321
356
|
In contrast Eventbox objects maintain a list of all running internal actions instead, but are completely independent from each other.
|
322
|
-
Failures are handled object internal - see chapter
|
357
|
+
Failures are handled either object internal or by the caller - see chapter [Exceptions](#exceptions) above.
|
323
358
|
|
324
359
|
### Internal state
|
325
360
|
|
@@ -341,15 +376,23 @@ Beside this, Eventbox has an explicit specification where blocking and where non
|
|
341
376
|
This ensures that events are processed in time regardless of the current state.
|
342
377
|
Such a specification is not enforced by most other threading abstractions and can quickly lead to delayed reactions in particular situations.
|
343
378
|
|
379
|
+
### No global states
|
380
|
+
|
381
|
+
Eventbox doesn't manage or use any global states other than class definitions.
|
382
|
+
Even {Eventbox.with_options configuration options} are handled on a class basis.
|
383
|
+
This is why Eventbox can be combined with other threading abstractions and integrated in any applications without side effects.
|
384
|
+
Vice versa Eventbox objects can easily replaced by other threading abstractions, if these fit better.
|
344
385
|
|
345
|
-
|
386
|
+
### Comparison with other async libraries
|
346
387
|
|
347
|
-
Eventbox doesn't
|
388
|
+
Eventbox doesn't implement any own IO or other kinds of blocking operations.
|
348
389
|
Instead it encourages the use of blocking operations and threads for things which should run in parallel, while keeping the management code in safe internal methods written in an event based style.
|
349
|
-
Because IO is done in action threads, the only type of events handled by the event scope are method calls received from actions or external
|
350
|
-
They are processed by a kind of event loop which runs one per Eventbox object.
|
390
|
+
Because IO is done in action threads, the only type of events handled by the event scope are method or closure calls received from actions or external.
|
391
|
+
They are processed by a kind of local event loop which runs one per Eventbox object.
|
351
392
|
|
352
393
|
This is in contrast to libraries like [async](https://github.com/socketry/async), [EventMachine](https://github.com/eventmachine/eventmachine) or [Celluloid](https://github.com/celluloid/celluloid) which provide dozens of IO wrappers.
|
394
|
+
Due to these differences the focus of Eventbox is on a consistent, solid and accurate core that developers can rely on.
|
395
|
+
Intentionally there is no ecosystem around Eventbox.
|
353
396
|
|
354
397
|
|
355
398
|
## Eventbox performance
|
@@ -362,7 +405,7 @@ And it is written to act as a solid and consistent foundation for a wide range o
|
|
362
405
|
So if your use case requires raw performance more than implementation safety, Eventbox is probably not the right tool.
|
363
406
|
|
364
407
|
Still there is lots of room for performance improvements in Eventbox, like faster method invocations or copy-on-write objects.
|
365
|
-
If there's a stronger interest in Eventbox performance, it's possible to source relevant parts out to a C extension.
|
408
|
+
If there's a stronger interest in Eventbox performance, it's even possible to source relevant parts out to a C extension.
|
366
409
|
The introduction of guilds in ruby will probably be helpful for Eventbox as well.
|
367
410
|
|
368
411
|
|
data/docs/downloads.md
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
|
1
|
+
## Use Eventbox to download URLs concurrently
|
2
2
|
|
3
3
|
The following example illustrates how to use actions in order to download a list of URLs in parallel.
|
4
4
|
|
5
|
-
At first the
|
5
|
+
At first the {Eventbox#init init} method starts an action for each URL to be downloaded, initializes some variables and stores the `result` object for later use.
|
6
6
|
Since the `result` is not yielded in the method body, the external call to `ParallelDownloads.new` doesn't return to that point in time.
|
7
7
|
Instead it's suspended until `result` is yielded later on, when all URLs have been retrieved.
|
8
8
|
|
@@ -53,14 +53,14 @@ class ParallelDownloads < Eventbox.with_options(threadpool: Eventbox::ThreadPool
|
|
53
53
|
private action def start_download(url)
|
54
54
|
data = OpenURI.open_uri(url) # HTTP GET url
|
55
55
|
.read(100).each_line.first # Retrieve the first line but max 100 bytes
|
56
|
-
rescue
|
56
|
+
rescue => err # Catch any network errors
|
57
57
|
download_finished(url, err) # and store it in the result hash
|
58
58
|
else
|
59
59
|
download_finished(url, data) # ... or store the retrieved data when successful
|
60
60
|
end
|
61
61
|
|
62
62
|
# Called for each finished download
|
63
|
-
private
|
63
|
+
private async_call def download_finished(url, res)
|
64
64
|
@downloads[url] = res # Store the download result in the result hash
|
65
65
|
@progress&.yield(@downloads.size) # Notify the caller about our progress
|
66
66
|
if @downloads.size == @urls.size # All downloads finished?
|
@@ -97,6 +97,7 @@ The order depends on the particular response time of the URL.
|
|
97
97
|
Since Eventbox protects from data races, it's insignificant in which order events are emitted by an event scope method and whether objects are changed after being sent.
|
98
98
|
It's therefore OK to set `@downloads` both before or after starting the action threads per `start_download` in `init`.
|
99
99
|
|
100
|
+
<a name="exceptions-closure-style"></a>
|
100
101
|
### Change to closure style
|
101
102
|
|
102
103
|
There is another alternative way to transmit the result of an action to the event scope.
|
@@ -113,7 +114,7 @@ class ParallelDownloads < Eventbox.with_options(threadpool: Eventbox::ThreadPool
|
|
113
114
|
yield_call def init(urls, result, &progress)
|
114
115
|
urls.each do |url| # Start a download thread for each URL
|
115
116
|
|
116
|
-
on_finished =
|
117
|
+
on_finished = async_proc do |res| # Create a closure object comparable to sync_call
|
117
118
|
@downloads[url] = res # Store the download result in the result hash
|
118
119
|
progress&.yield(@downloads.size) # Notify the caller about our progress
|
119
120
|
if @downloads.size == urls.size # All downloads finished?
|
@@ -0,0 +1,761 @@
|
|
1
|
+
<!--
|
2
|
+
# @markup html
|
3
|
+
-->
|
4
|
+
|
5
|
+
<svg
|
6
|
+
xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
|
7
|
+
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
8
|
+
xmlns:cc="http://creativecommons.org/ns#"
|
9
|
+
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
10
|
+
xmlns:svg="http://www.w3.org/2000/svg"
|
11
|
+
xmlns="http://www.w3.org/2000/svg"
|
12
|
+
xmlns:xlink="http://www.w3.org/1999/xlink"
|
13
|
+
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
14
|
+
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
15
|
+
width="185mm"
|
16
|
+
height="142mm"
|
17
|
+
viewBox="0 0 129.5 99.400001"
|
18
|
+
version="1.1"
|
19
|
+
id="svg8"
|
20
|
+
inkscape:version="0.92.3 (2405546, 2018-03-11)"
|
21
|
+
sodipodi:docname="my_queue_calls.svg">
|
22
|
+
<defs
|
23
|
+
id="defs2">
|
24
|
+
<marker
|
25
|
+
inkscape:isstock="true"
|
26
|
+
style="overflow:visible;"
|
27
|
+
id="marker1378"
|
28
|
+
refX="0.0"
|
29
|
+
refY="0.0"
|
30
|
+
orient="auto"
|
31
|
+
inkscape:stockid="Arrow1Lend">
|
32
|
+
<path
|
33
|
+
transform="scale(0.8) rotate(180) translate(12.5,0)"
|
34
|
+
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
|
35
|
+
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
|
36
|
+
id="path1376" />
|
37
|
+
</marker>
|
38
|
+
<marker
|
39
|
+
inkscape:stockid="Arrow1Lend"
|
40
|
+
orient="auto"
|
41
|
+
refY="0.0"
|
42
|
+
refX="0.0"
|
43
|
+
id="marker1208"
|
44
|
+
style="overflow:visible;"
|
45
|
+
inkscape:isstock="true"
|
46
|
+
inkscape:collect="always">
|
47
|
+
<path
|
48
|
+
id="path948"
|
49
|
+
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
|
50
|
+
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
|
51
|
+
transform="scale(0.8) rotate(180) translate(12.5,0)" />
|
52
|
+
</marker>
|
53
|
+
<marker
|
54
|
+
inkscape:stockid="Arrow1Lend"
|
55
|
+
orient="auto"
|
56
|
+
refY="0"
|
57
|
+
refX="0"
|
58
|
+
id="marker1168"
|
59
|
+
style="overflow:visible"
|
60
|
+
inkscape:isstock="true">
|
61
|
+
<path
|
62
|
+
id="path908"
|
63
|
+
d="M 0,0 5,-5 -12.5,0 5,5 Z"
|
64
|
+
style="fill:#ffffeb;fill-opacity:1;fill-rule:evenodd;stroke:#ee0000;stroke-width:1.00000003pt;stroke-opacity:1"
|
65
|
+
transform="matrix(-0.8,0,0,-0.8,-10,0)"
|
66
|
+
inkscape:connector-curvature="0" />
|
67
|
+
</marker>
|
68
|
+
<marker
|
69
|
+
inkscape:isstock="true"
|
70
|
+
style="overflow:visible"
|
71
|
+
id="marker928"
|
72
|
+
refX="0"
|
73
|
+
refY="0"
|
74
|
+
orient="auto"
|
75
|
+
inkscape:stockid="Arrow1Lend">
|
76
|
+
<path
|
77
|
+
transform="matrix(-0.8,0,0,-0.8,-10,0)"
|
78
|
+
style="fill:#0000ff;fill-opacity:1;fill-rule:evenodd;stroke:#0000ff;stroke-width:1.00000003pt;stroke-opacity:1"
|
79
|
+
d="M 0,0 5,-5 -12.5,0 5,5 Z"
|
80
|
+
id="path926"
|
81
|
+
inkscape:connector-curvature="0" />
|
82
|
+
</marker>
|
83
|
+
<marker
|
84
|
+
inkscape:stockid="Arrow1Lend"
|
85
|
+
orient="auto"
|
86
|
+
refY="0"
|
87
|
+
refX="0"
|
88
|
+
id="marker10624"
|
89
|
+
style="overflow:visible"
|
90
|
+
inkscape:isstock="true"
|
91
|
+
inkscape:collect="always">
|
92
|
+
<path
|
93
|
+
id="path10622"
|
94
|
+
d="M 0,0 5,-5 -12.5,0 5,5 Z"
|
95
|
+
style="fill:#0000ff;fill-opacity:1;fill-rule:evenodd;stroke:#0000ff;stroke-width:1.00000003pt;stroke-opacity:1"
|
96
|
+
transform="matrix(-0.8,0,0,-0.8,-10,0)"
|
97
|
+
inkscape:connector-curvature="0" />
|
98
|
+
</marker>
|
99
|
+
<marker
|
100
|
+
inkscape:stockid="Arrow1Lend"
|
101
|
+
orient="auto"
|
102
|
+
refY="0"
|
103
|
+
refX="0"
|
104
|
+
id="marker10556"
|
105
|
+
style="overflow:visible"
|
106
|
+
inkscape:isstock="true">
|
107
|
+
<path
|
108
|
+
id="path10554"
|
109
|
+
d="M 0,0 5,-5 -12.5,0 5,5 Z"
|
110
|
+
style="fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.00000003pt;stroke-opacity:1"
|
111
|
+
transform="matrix(-0.8,0,0,-0.8,-10,0)"
|
112
|
+
inkscape:connector-curvature="0" />
|
113
|
+
</marker>
|
114
|
+
<marker
|
115
|
+
inkscape:stockid="Arrow1Lend"
|
116
|
+
orient="auto"
|
117
|
+
refY="0"
|
118
|
+
refX="0"
|
119
|
+
id="marker10502"
|
120
|
+
style="overflow:visible"
|
121
|
+
inkscape:isstock="true">
|
122
|
+
<path
|
123
|
+
id="path10500"
|
124
|
+
d="M 0,0 5,-5 -12.5,0 5,5 Z"
|
125
|
+
style="fill:#ff0000;fill-opacity:1;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.00000003pt;stroke-opacity:1"
|
126
|
+
transform="matrix(-0.8,0,0,-0.8,-10,0)"
|
127
|
+
inkscape:connector-curvature="0" />
|
128
|
+
</marker>
|
129
|
+
<marker
|
130
|
+
inkscape:stockid="Arrow1Lend"
|
131
|
+
orient="auto"
|
132
|
+
refY="0"
|
133
|
+
refX="0"
|
134
|
+
id="marker9930"
|
135
|
+
style="overflow:visible"
|
136
|
+
inkscape:isstock="true">
|
137
|
+
<path
|
138
|
+
id="path9928"
|
139
|
+
d="M 0,0 5,-5 -12.5,0 5,5 Z"
|
140
|
+
style="fill:#f90000;fill-opacity:1;fill-rule:evenodd;stroke:#f90000;stroke-width:1.00000003pt;stroke-opacity:1"
|
141
|
+
transform="matrix(-0.8,0,0,-0.8,-10,0)"
|
142
|
+
inkscape:connector-curvature="0" />
|
143
|
+
</marker>
|
144
|
+
<marker
|
145
|
+
inkscape:isstock="true"
|
146
|
+
style="overflow:visible"
|
147
|
+
id="marker4910"
|
148
|
+
refX="0"
|
149
|
+
refY="0"
|
150
|
+
orient="auto"
|
151
|
+
inkscape:stockid="Arrow1Lend">
|
152
|
+
<path
|
153
|
+
transform="matrix(-0.8,0,0,-0.8,-10,0)"
|
154
|
+
style="fill:#f50000;fill-opacity:1;fill-rule:evenodd;stroke:#f50000;stroke-width:1.00000003pt;stroke-opacity:1"
|
155
|
+
d="M 0,0 5,-5 -12.5,0 5,5 Z"
|
156
|
+
id="path4908"
|
157
|
+
inkscape:connector-curvature="0" />
|
158
|
+
</marker>
|
159
|
+
<marker
|
160
|
+
inkscape:stockid="Arrow1Lend"
|
161
|
+
orient="auto"
|
162
|
+
refY="0"
|
163
|
+
refX="0"
|
164
|
+
id="Arrow1Lend"
|
165
|
+
style="overflow:visible"
|
166
|
+
inkscape:isstock="true"
|
167
|
+
inkscape:collect="always">
|
168
|
+
<path
|
169
|
+
id="path4537"
|
170
|
+
d="M 0,0 5,-5 -12.5,0 5,5 Z"
|
171
|
+
style="fill:#fa0000;fill-opacity:1;fill-rule:evenodd;stroke:#fa0000;stroke-width:1.00000003pt;stroke-opacity:1"
|
172
|
+
transform="matrix(-0.8,0,0,-0.8,-10,0)"
|
173
|
+
inkscape:connector-curvature="0" />
|
174
|
+
</marker>
|
175
|
+
<linearGradient
|
176
|
+
id="linearGradient4522"
|
177
|
+
osb:paint="solid">
|
178
|
+
<stop
|
179
|
+
style="stop-color:#000000;stop-opacity:1;"
|
180
|
+
offset="0"
|
181
|
+
id="stop4520" />
|
182
|
+
</linearGradient>
|
183
|
+
</defs>
|
184
|
+
<sodipodi:namedview
|
185
|
+
id="base"
|
186
|
+
pagecolor="#ffffff"
|
187
|
+
bordercolor="#666666"
|
188
|
+
borderopacity="1.0"
|
189
|
+
inkscape:pageopacity="0.0"
|
190
|
+
inkscape:pageshadow="2"
|
191
|
+
inkscape:zoom="1"
|
192
|
+
inkscape:cx="373.74533"
|
193
|
+
inkscape:cy="265.12062"
|
194
|
+
inkscape:document-units="mm"
|
195
|
+
inkscape:current-layer="layer1"
|
196
|
+
showgrid="false"
|
197
|
+
inkscape:snap-nodes="false"
|
198
|
+
inkscape:window-width="1252"
|
199
|
+
inkscape:window-height="720"
|
200
|
+
inkscape:window-x="28"
|
201
|
+
inkscape:window-y="0"
|
202
|
+
inkscape:window-maximized="1"
|
203
|
+
scale-x="0.7" />
|
204
|
+
<metadata
|
205
|
+
id="metadata5">
|
206
|
+
<rdf:RDF>
|
207
|
+
<cc:Work
|
208
|
+
rdf:about="">
|
209
|
+
<dc:format>image/svg+xml</dc:format>
|
210
|
+
<dc:type
|
211
|
+
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
212
|
+
<dc:title />
|
213
|
+
</cc:Work>
|
214
|
+
</rdf:RDF>
|
215
|
+
</metadata>
|
216
|
+
<g
|
217
|
+
inkscape:label="Ebene 1"
|
218
|
+
inkscape:groupmode="layer"
|
219
|
+
id="layer1"
|
220
|
+
transform="translate(0,-167.6)">
|
221
|
+
<rect
|
222
|
+
id="rect10"
|
223
|
+
width="91.673447"
|
224
|
+
height="86.87912"
|
225
|
+
x="19.489588"
|
226
|
+
y="179.25435"
|
227
|
+
rx="0"
|
228
|
+
ry="0"
|
229
|
+
style="fill:#ffff25;fill-opacity:1;stroke:#000000;stroke-width:0.26458332;stroke-opacity:1" />
|
230
|
+
<rect
|
231
|
+
y="186.75443"
|
232
|
+
x="42.474762"
|
233
|
+
height="78.274651"
|
234
|
+
width="42.228584"
|
235
|
+
id="rect4528"
|
236
|
+
style="fill:#ffcfff;fill-opacity:1;stroke:#000000;stroke-width:0.26458335;stroke-opacity:1" />
|
237
|
+
<path
|
238
|
+
style="fill:none;fill-opacity:1;stroke:#fa0000;stroke-width:0.26499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow1Lend)"
|
239
|
+
d="M 6.9279211,181.36207 51.561932,205.15991"
|
240
|
+
id="path4532"
|
241
|
+
inkscape:connector-curvature="0" />
|
242
|
+
<rect
|
243
|
+
style="fill:none;fill-opacity:1;stroke:#fa0000;stroke-width:0.26500002;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
244
|
+
id="rect4816"
|
245
|
+
width="12.828883"
|
246
|
+
height="12.562"
|
247
|
+
x="47.018349"
|
248
|
+
y="206.254" />
|
249
|
+
<path
|
250
|
+
style="fill:none;stroke:#f50000;stroke-width:0.26499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker4910)"
|
251
|
+
d="M 51.830151,219.0522 8.5333361,235.09765"
|
252
|
+
id="path4824"
|
253
|
+
inkscape:connector-curvature="0"
|
254
|
+
sodipodi:nodetypes="cc" />
|
255
|
+
<path
|
256
|
+
sodipodi:type="spiral"
|
257
|
+
style="fill:#ffffeb;fill-opacity:1;fill-rule:evenodd;stroke:#ee0000;stroke-width:0.42626965;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker1168);image-rendering:auto"
|
258
|
+
id="path4942"
|
259
|
+
sodipodi:cx="18.441597"
|
260
|
+
sodipodi:cy="66.346397"
|
261
|
+
sodipodi:expansion="1"
|
262
|
+
sodipodi:revolution="3.0059199"
|
263
|
+
sodipodi:radius="17.37999"
|
264
|
+
sodipodi:argument="-17.866762"
|
265
|
+
sodipodi:t0="0.6560148"
|
266
|
+
d="M 26.332514,74.57612 C 21.896357,79.574502 14.036872,79.637691 9.1685147,75.23772 3.6278489,70.230124 3.5838485,61.445599 8.5498677,56.029955 14.128266,49.946488 23.838892,49.921766 29.801399,55.454262 c 6.626649,6.14874 6.632031,16.786244 0.53274,23.295297 -0.842512,0.899114 -1.781959,1.706899 -2.796296,2.406374"
|
267
|
+
transform="matrix(0.62478665,0,0,0.61857331,84.213942,200.00264)" />
|
268
|
+
<path
|
269
|
+
style="fill:none;stroke:#f90000;stroke-width:0.26499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker9930)"
|
270
|
+
d="m 96.207354,249.79477 22.454726,16.57189"
|
271
|
+
id="path9918"
|
272
|
+
inkscape:connector-curvature="0"
|
273
|
+
sodipodi:nodetypes="cc" />
|
274
|
+
<rect
|
275
|
+
style="fill:none;fill-opacity:1;stroke:#ee0000;stroke-width:0.26499999;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
276
|
+
id="rect10496"
|
277
|
+
width="13.096148"
|
278
|
+
height="12.561667"
|
279
|
+
x="66.796196"
|
280
|
+
y="206.25435" />
|
281
|
+
<path
|
282
|
+
style="fill:none;stroke:#ff0000;stroke-width:0.26499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker10502)"
|
283
|
+
d="M 117.84573,185.10297 74.281541,204.8956"
|
284
|
+
id="path10498"
|
285
|
+
inkscape:connector-curvature="0" />
|
286
|
+
<path
|
287
|
+
style="fill:none;stroke:#ff0000;stroke-width:0.26499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker10556)"
|
288
|
+
d="m 76.158622,219.01967 18.712932,12.59301"
|
289
|
+
id="path10552"
|
290
|
+
inkscape:connector-curvature="0" />
|
291
|
+
<a
|
292
|
+
id="a1025"
|
293
|
+
target=""
|
294
|
+
transform="translate(-0.555625,-23.151042)"
|
295
|
+
xlink:href="https://www.rubydoc.info/github/larskanis/eventbox/master/Eventbox/Sanitizer">
|
296
|
+
<ellipse
|
297
|
+
onclick=""
|
298
|
+
transform="matrix(0.89625618,-0.44353677,0.47919017,0.8777111,0,0)"
|
299
|
+
cx="-17.232189"
|
300
|
+
cy="238.3199"
|
301
|
+
rx="5.3748827"
|
302
|
+
ry="10.333156"
|
303
|
+
id="path10612"
|
304
|
+
style="fill:#ffffff;fill-opacity:1;stroke:#007800;stroke-width:0.34833023;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
305
|
+
</a>
|
306
|
+
<path
|
307
|
+
style="fill:none;stroke:#0000ff;stroke-width:0.26499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker10624)"
|
308
|
+
d="m 53.165548,215.24192 c 0,0 -9.262697,45.65359 32.874156,23.98422"
|
309
|
+
id="path10620"
|
310
|
+
inkscape:connector-curvature="0"
|
311
|
+
sodipodi:nodetypes="cc" />
|
312
|
+
<a
|
313
|
+
xlink:href="../Eventbox/Sanitizer"
|
314
|
+
transform="translate(0,6.2970833)"
|
315
|
+
id="a4631">
|
316
|
+
<path
|
317
|
+
onclick="https://www.rubydoc.info/github/larskanis/eventbox/master/Eventbox/Sanitizer"
|
318
|
+
sodipodi:open="true"
|
319
|
+
transform="matrix(0.92881568,0.37054207,-0.47054194,0.88237763,0,0)"
|
320
|
+
d="m 114.76537,172.63952 a 5.2028461,8.8422928 0 0 1 -3.99824,-10.43402 5.2028461,8.8422928 0 0 1 6.10517,-6.88361 5.2028461,8.8422928 0 0 1 4.10216,10.31685 5.2028461,8.8422928 0 0 1 -6.03535,7.05921"
|
321
|
+
sodipodi:end="1.7491596"
|
322
|
+
sodipodi:start="1.7832031"
|
323
|
+
sodipodi:ry="8.8422928"
|
324
|
+
sodipodi:rx="5.2028461"
|
325
|
+
sodipodi:cy="163.99594"
|
326
|
+
sodipodi:cx="115.8622"
|
327
|
+
sodipodi:type="arc"
|
328
|
+
id="path10686"
|
329
|
+
style="fill:#ffffff;fill-opacity:1;stroke:#007800;stroke-width:0.32815173;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
330
|
+
</a>
|
331
|
+
<a
|
332
|
+
xlink:href="../Eventbox/Sanitizer"
|
333
|
+
transform="translate(0,6.2970833)"
|
334
|
+
id="a925"
|
335
|
+
target="">
|
336
|
+
<path
|
337
|
+
onclick="https://www.rubydoc.info/github/larskanis/eventbox/master/Eventbox/Sanitizer"
|
338
|
+
sodipodi:open="true"
|
339
|
+
transform="matrix(0.8488041,0.52870748,-0.64396364,0.7650561,0,0)"
|
340
|
+
d="m 247.74739,159.80509 a 4.7844305,9.6128368 0 0 1 -4.70978,9.68959 4.7844305,9.6128368 0 0 1 -4.85765,-9.39028 4.7844305,9.6128368 0 0 1 4.63728,-9.82976 4.7844305,9.6128368 0 0 1 4.92686,9.24357"
|
341
|
+
sodipodi:end="6.2452272"
|
342
|
+
sodipodi:start="6.2750789"
|
343
|
+
sodipodi:ry="9.6128368"
|
344
|
+
sodipodi:rx="4.7844305"
|
345
|
+
sodipodi:cy="159.88301"
|
346
|
+
sodipodi:cx="242.96312"
|
347
|
+
sodipodi:type="arc"
|
348
|
+
id="path10694"
|
349
|
+
style="fill:#ffffff;fill-opacity:1;stroke:#007800;stroke-width:0.32306719;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
350
|
+
</a>
|
351
|
+
<text
|
352
|
+
xml:space="preserve"
|
353
|
+
style="font-style:normal;font-weight:normal;font-size:2.96333332px;line-height:1.25;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;"
|
354
|
+
x="-152.70258"
|
355
|
+
y="122.78255"
|
356
|
+
id="text10838"
|
357
|
+
transform="rotate(-59.850075)"><tspan
|
358
|
+
sodipodi:role="line"
|
359
|
+
x="-152.70258"
|
360
|
+
y="122.78255"
|
361
|
+
style="font-size:2.96333332px;text-align:center;text-anchor:middle;stroke-width:0.26458332;"
|
362
|
+
id="tspan10848">sanitize</tspan><tspan
|
363
|
+
sodipodi:role="line"
|
364
|
+
x="-152.70258"
|
365
|
+
y="127.19227"
|
366
|
+
style="font-size:2.96333332px;text-align:center;text-anchor:middle;stroke-width:0.26458332;"
|
367
|
+
id="tspan10852">args</tspan></text>
|
368
|
+
<text
|
369
|
+
transform="rotate(59.31363)"
|
370
|
+
id="text10858"
|
371
|
+
y="13.567711"
|
372
|
+
x="216.40395"
|
373
|
+
style="font-style:normal;font-weight:normal;font-size:2.96333332px;line-height:1.25;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;"
|
374
|
+
xml:space="preserve"><tspan
|
375
|
+
id="tspan10854"
|
376
|
+
style="font-size:2.96333332px;text-align:center;text-anchor:middle;stroke-width:0.26458332;"
|
377
|
+
y="13.567711"
|
378
|
+
x="216.40395"
|
379
|
+
sodipodi:role="line">sanitize</tspan><tspan
|
380
|
+
id="tspan10856"
|
381
|
+
style="font-size:2.96333332px;text-align:center;text-anchor:middle;stroke-width:0.26458332;"
|
382
|
+
y="17.977434"
|
383
|
+
x="216.40395"
|
384
|
+
sodipodi:role="line">args</tspan></text>
|
385
|
+
<text
|
386
|
+
transform="rotate(-46.618563)"
|
387
|
+
id="text10881"
|
388
|
+
y="250.48445"
|
389
|
+
x="-115.84221"
|
390
|
+
style="font-style:normal;font-weight:normal;font-size:2.96333332px;line-height:1.25;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;"
|
391
|
+
xml:space="preserve"><tspan
|
392
|
+
style="font-size:2.96333332px;text-align:center;text-anchor:middle;stroke-width:0.26458332;"
|
393
|
+
y="250.48445"
|
394
|
+
x="-115.84221"
|
395
|
+
sodipodi:role="line"
|
396
|
+
id="tspan867">sanitize</tspan><tspan
|
397
|
+
style="font-size:2.96333332px;text-align:center;text-anchor:middle;stroke-width:0.26458332;"
|
398
|
+
y="254.89418"
|
399
|
+
x="-115.84221"
|
400
|
+
sodipodi:role="line"
|
401
|
+
id="tspan923">result</tspan></text>
|
402
|
+
<text
|
403
|
+
xml:space="preserve"
|
404
|
+
style="font-style:normal;font-weight:normal;font-size:2.96333332px;line-height:1.25;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;"
|
405
|
+
x="96.894981"
|
406
|
+
y="237.41592"
|
407
|
+
id="text873"><tspan
|
408
|
+
sodipodi:role="line"
|
409
|
+
x="96.894981"
|
410
|
+
y="237.41592"
|
411
|
+
style="font-size:2.96333332px;text-align:center;text-anchor:middle;stroke-width:0.26458332;"
|
412
|
+
id="tspan903">wait for</tspan><tspan
|
413
|
+
sodipodi:role="line"
|
414
|
+
x="96.894981"
|
415
|
+
y="241.82565"
|
416
|
+
style="font-size:2.96333332px;text-align:center;text-anchor:middle;stroke-width:0.26458332;"
|
417
|
+
id="tspan884">result or</tspan><tspan
|
418
|
+
sodipodi:role="line"
|
419
|
+
x="96.894981"
|
420
|
+
y="246.23537"
|
421
|
+
style="font-size:2.96333332px;text-align:center;text-anchor:middle;stroke-width:0.26458332;"
|
422
|
+
id="tspan902">callback</tspan></text>
|
423
|
+
<path
|
424
|
+
inkscape:connector-curvature="0"
|
425
|
+
id="path924"
|
426
|
+
d="m 70.160202,215.24192 c 0,0 1.163455,23.98422 15.900542,23.98422"
|
427
|
+
style="fill:none;stroke:#0000ff;stroke-width:0.26499999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker928)" />
|
428
|
+
<path
|
429
|
+
style="fill:#ffffff;fill-opacity:1;stroke:#007800;stroke-width:0.2027204;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
430
|
+
id="path877"
|
431
|
+
sodipodi:type="arc"
|
432
|
+
sodipodi:cx="-81.083595"
|
433
|
+
sodipodi:cy="244.79619"
|
434
|
+
sodipodi:rx="10.626561"
|
435
|
+
sodipodi:ry="4.9516382"
|
436
|
+
sodipodi:start="3.8273013"
|
437
|
+
sodipodi:end="3.8141906"
|
438
|
+
d="m -89.30824,241.6607 a 10.626561,4.9516382 0 0 1 14.926619,-0.70719 10.626561,4.9516382 0 0 1 1.566604,6.95297 10.626561,4.9516382 0 0 1 -14.91635,0.75278 10.626561,4.9516382 0 0 1 -1.664385,-6.94804"
|
439
|
+
transform="matrix(0.8900354,-0.45589142,0.59689097,0.80232236,0,0)"
|
440
|
+
sodipodi:open="true" />
|
441
|
+
<text
|
442
|
+
xml:space="preserve"
|
443
|
+
style="font-style:normal;font-weight:normal;font-size:2.96333332px;line-height:1.25;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;"
|
444
|
+
x="-40.597473"
|
445
|
+
y="240.45992"
|
446
|
+
id="text881"
|
447
|
+
transform="rotate(-27.245601)"><tspan
|
448
|
+
sodipodi:role="line"
|
449
|
+
x="-40.597473"
|
450
|
+
y="240.45992"
|
451
|
+
style="font-size:2.96333332px;text-align:center;text-anchor:middle;stroke-width:0.26458332;"
|
452
|
+
id="tspan899">if someth.</tspan><tspan
|
453
|
+
sodipodi:role="line"
|
454
|
+
x="-40.597473"
|
455
|
+
y="244.86964"
|
456
|
+
style="font-size:2.96333332px;text-align:center;text-anchor:middle;stroke-width:0.26458332;"
|
457
|
+
id="tspan911">in queue</tspan></text>
|
458
|
+
<path
|
459
|
+
transform="matrix(0.88469021,-0.46617941,0.63817391,0.76989224,0,0)"
|
460
|
+
d="m -100.19975,237.55663 a 11.223675,5.1413383 0 0 1 -11.16623,5.14127 11.223675,5.1413383 0 0 1 -11.28053,-5.08865 11.223675,5.1413383 0 0 1 11.05077,-5.19336 11.223675,5.1413383 0 0 1 11.39364,5.03549"
|
461
|
+
sodipodi:end="6.2627144"
|
462
|
+
sodipodi:start="0"
|
463
|
+
sodipodi:ry="5.1413383"
|
464
|
+
sodipodi:rx="11.223675"
|
465
|
+
sodipodi:cy="237.55663"
|
466
|
+
sodipodi:cx="-111.42342"
|
467
|
+
sodipodi:type="arc"
|
468
|
+
id="path885"
|
469
|
+
style="fill:#ffffff;fill-opacity:1;stroke:#007800;stroke-width:0.21229133;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
470
|
+
sodipodi:open="true" />
|
471
|
+
<text
|
472
|
+
transform="rotate(-22.489804)"
|
473
|
+
id="text891"
|
474
|
+
y="236.29482"
|
475
|
+
x="-40.395329"
|
476
|
+
style="font-style:normal;font-weight:normal;font-size:2.96333332px;line-height:1.25;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;"
|
477
|
+
xml:space="preserve"><tspan
|
478
|
+
style="font-size:2.96333332px;text-align:center;text-anchor:middle;stroke-width:0.26458332;"
|
479
|
+
y="236.29482"
|
480
|
+
x="-40.395329"
|
481
|
+
sodipodi:role="line"
|
482
|
+
id="tspan915">if a deq</tspan><tspan
|
483
|
+
style="font-size:2.96333332px;text-align:center;text-anchor:middle;stroke-width:0.26458332;"
|
484
|
+
y="240.70454"
|
485
|
+
x="-40.395329"
|
486
|
+
sodipodi:role="line"
|
487
|
+
id="tspan919">call waits</tspan></text>
|
488
|
+
<text
|
489
|
+
xml:space="preserve"
|
490
|
+
style="font-style:normal;font-weight:normal;font-size:10.58333302px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
|
491
|
+
x="48.087425"
|
492
|
+
y="210.23882"
|
493
|
+
id="text909"><tspan
|
494
|
+
sodipodi:role="line"
|
495
|
+
id="tspan907"
|
496
|
+
x="48.087425"
|
497
|
+
y="219.60258"
|
498
|
+
style="stroke-width:0.26458332" /></text>
|
499
|
+
<text
|
500
|
+
xml:space="preserve"
|
501
|
+
style="font-style:normal;font-weight:normal;font-size:4.58611107px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
|
502
|
+
x="48.354698"
|
503
|
+
y="211.57516"
|
504
|
+
id="text875"><tspan
|
505
|
+
sodipodi:role="line"
|
506
|
+
id="tspan873"
|
507
|
+
x="48.354698"
|
508
|
+
y="211.57516"
|
509
|
+
style="font-size:4.58611107px;stroke-width:0.26458332">enq</tspan></text>
|
510
|
+
<text
|
511
|
+
xml:space="preserve"
|
512
|
+
style="font-style:normal;font-weight:normal;font-size:4.58611107px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
|
513
|
+
x="68.132637"
|
514
|
+
y="211.62103"
|
515
|
+
id="text879"><tspan
|
516
|
+
sodipodi:role="line"
|
517
|
+
id="tspan877"
|
518
|
+
x="68.132637"
|
519
|
+
y="211.62103"
|
520
|
+
style="font-size:4.58611107px;stroke-width:0.26458332">deq</tspan></text>
|
521
|
+
<a
|
522
|
+
xlink:href="../file/README.md#event-scope"
|
523
|
+
transform="translate(0,6.2970833)"
|
524
|
+
id="a4641">
|
525
|
+
<text
|
526
|
+
xml:space="preserve"
|
527
|
+
style="font-style:normal;font-weight:normal;font-size:3.52777767px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
|
528
|
+
x="53.247608"
|
529
|
+
y="184.36324"
|
530
|
+
id="text888"
|
531
|
+
onclick="../file/README.md#Event_Scope"><tspan
|
532
|
+
sodipodi:role="line"
|
533
|
+
id="tspan886"
|
534
|
+
x="53.247608"
|
535
|
+
y="184.36324"
|
536
|
+
style="font-size:3.52777767px;stroke-width:0.26458332">Event Scope</tspan></text>
|
537
|
+
</a>
|
538
|
+
<a
|
539
|
+
xlink:href="../Eventbox/Boxable#async_call-instance_method"
|
540
|
+
transform="translate(0,6.2970833)"
|
541
|
+
id="a4644">
|
542
|
+
<text
|
543
|
+
id="text892"
|
544
|
+
y="184.96559"
|
545
|
+
x="0.51345128"
|
546
|
+
style="font-style:normal;font-weight:normal;font-size:2.96333332px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;"
|
547
|
+
xml:space="preserve"><tspan
|
548
|
+
id="tspan894"
|
549
|
+
style="font-size:2.96333332px;stroke-width:0.26458332;"
|
550
|
+
y="184.96559"
|
551
|
+
x="0.51345128"
|
552
|
+
sodipodi:role="line">external</tspan><tspan
|
553
|
+
id="tspan898"
|
554
|
+
style="font-size:2.96333332px;stroke-width:0.26458332;"
|
555
|
+
y="189.37532"
|
556
|
+
x="0.51345128"
|
557
|
+
sodipodi:role="line">call to</tspan><tspan
|
558
|
+
id="tspan905"
|
559
|
+
style="font-size:2.96333332px;stroke-width:0.26458332;"
|
560
|
+
y="193.78503"
|
561
|
+
x="0.51345128"
|
562
|
+
sodipodi:role="line">async</tspan><tspan
|
563
|
+
id="tspan909"
|
564
|
+
style="font-size:2.96333332px;stroke-width:0.26458332;"
|
565
|
+
y="198.19476"
|
566
|
+
x="0.51345128"
|
567
|
+
sodipodi:role="line">method</tspan></text>
|
568
|
+
</a>
|
569
|
+
<text
|
570
|
+
xml:space="preserve"
|
571
|
+
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.96333332px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;"
|
572
|
+
x="0.71974826"
|
573
|
+
y="225.93076"
|
574
|
+
id="text902"
|
575
|
+
onclick="Eventbox/Boxable#yield_call-instance_method"><tspan
|
576
|
+
sodipodi:role="line"
|
577
|
+
x="0.71974826"
|
578
|
+
y="225.93076"
|
579
|
+
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.96333332px;font-family:sans-serif;-inkscape-font-specification:sans-serif;stroke-width:0.26458332;"
|
580
|
+
id="tspan904">... returns</tspan><tspan
|
581
|
+
sodipodi:role="line"
|
582
|
+
x="0.71974826"
|
583
|
+
y="230.34048"
|
584
|
+
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.96333332px;font-family:sans-serif;-inkscape-font-specification:sans-serif;stroke-width:0.26458332;"
|
585
|
+
id="tspan906">immediat.</tspan></text>
|
586
|
+
<a
|
587
|
+
xlink:href="../Eventbox/Boxable#yield_call-instance_method"
|
588
|
+
transform="translate(0,6.2970833)"
|
589
|
+
id="a4634">
|
590
|
+
<text
|
591
|
+
xml:space="preserve"
|
592
|
+
style="font-style:normal;font-weight:normal;font-size:2.96333332px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;"
|
593
|
+
x="112.76665"
|
594
|
+
y="185.76741"
|
595
|
+
id="text912"><tspan
|
596
|
+
sodipodi:role="line"
|
597
|
+
x="112.76665"
|
598
|
+
y="185.76741"
|
599
|
+
style="font-size:2.96333332px;stroke-width:0.26458332;"
|
600
|
+
id="tspan908">external</tspan><tspan
|
601
|
+
sodipodi:role="line"
|
602
|
+
x="112.76665"
|
603
|
+
y="190.17714"
|
604
|
+
style="font-size:2.96333332px;stroke-width:0.26458332;"
|
605
|
+
id="tspan910">call to</tspan><tspan
|
606
|
+
id="tspan927"
|
607
|
+
sodipodi:role="line"
|
608
|
+
x="112.76665"
|
609
|
+
y="194.58685"
|
610
|
+
style="font-size:2.96333332px;stroke-width:0.26458332;">yield</tspan><tspan
|
611
|
+
id="tspan929"
|
612
|
+
sodipodi:role="line"
|
613
|
+
x="112.76665"
|
614
|
+
y="198.99658"
|
615
|
+
style="font-size:2.96333332px;stroke-width:0.26458332;">method</tspan></text>
|
616
|
+
</a>
|
617
|
+
<text
|
618
|
+
id="text920"
|
619
|
+
y="243.64752"
|
620
|
+
x="113.03392"
|
621
|
+
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.96333332px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;"
|
622
|
+
xml:space="preserve"
|
623
|
+
onclick=""><tspan
|
624
|
+
id="tspan916"
|
625
|
+
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.96333332px;font-family:sans-serif;-inkscape-font-specification:sans-serif;stroke-width:0.26458332;"
|
626
|
+
y="243.64752"
|
627
|
+
x="113.03392"
|
628
|
+
sodipodi:role="line">... returns</tspan><tspan
|
629
|
+
id="tspan918"
|
630
|
+
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.96333332px;font-family:sans-serif;-inkscape-font-specification:sans-serif;stroke-width:0.26458332;"
|
631
|
+
y="248.05725"
|
632
|
+
x="113.03392"
|
633
|
+
sodipodi:role="line">when</tspan><tspan
|
634
|
+
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.96333332px;font-family:sans-serif;-inkscape-font-specification:sans-serif;stroke-width:0.26458332;"
|
635
|
+
y="252.46696"
|
636
|
+
x="113.03392"
|
637
|
+
sodipodi:role="line"
|
638
|
+
id="tspan925">value</tspan><tspan
|
639
|
+
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2.96333332px;font-family:sans-serif;-inkscape-font-specification:sans-serif;stroke-width:0.26458332;"
|
640
|
+
y="256.87668"
|
641
|
+
x="113.03392"
|
642
|
+
sodipodi:role="line"
|
643
|
+
id="tspan922">yielded</tspan></text>
|
644
|
+
<path
|
645
|
+
style="fill:#ffffff;fill-opacity:1;stroke:#007800;stroke-width:0.26499999;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
646
|
+
id="path936"
|
647
|
+
sodipodi:type="arc"
|
648
|
+
sodipodi:cx="202.16064"
|
649
|
+
sodipodi:cy="108.06693"
|
650
|
+
sodipodi:rx="9.7553377"
|
651
|
+
sodipodi:ry="5.6126599"
|
652
|
+
sodipodi:start="0"
|
653
|
+
sodipodi:end="6.2820258"
|
654
|
+
d="m 211.91598,108.06693 a 9.7553377,5.6126599 0 0 1 -9.75251,5.61266 9.7553377,5.6126599 0 0 1 -9.75816,-5.6094 9.7553377,5.6126599 0 0 1 9.74685,-5.61592 9.7553377,5.6126599 0 0 1 9.76382,5.60615"
|
655
|
+
transform="rotate(54.360684)"
|
656
|
+
sodipodi:open="true" />
|
657
|
+
<a
|
658
|
+
xlink:href="../file/README.md#external-scope"
|
659
|
+
transform="translate(-17.78)"
|
660
|
+
id="a4651">
|
661
|
+
<text
|
662
|
+
onclick="window.location.href='../file/README.md#External_Scope'"
|
663
|
+
id="text903"
|
664
|
+
y="170.53304"
|
665
|
+
x="51.607788"
|
666
|
+
style="font-style:normal;font-weight:normal;font-size:3.52777767px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
|
667
|
+
xml:space="preserve"><tspan
|
668
|
+
style="font-size:3.52777767px;stroke-width:0.26458332"
|
669
|
+
y="170.53304"
|
670
|
+
x="51.607788"
|
671
|
+
id="tspan901"
|
672
|
+
sodipodi:role="line">External Scope (outside of the class)</tspan></text>
|
673
|
+
</a>
|
674
|
+
<text
|
675
|
+
xml:space="preserve"
|
676
|
+
style="font-style:normal;font-weight:normal;font-size:2.96333332px;line-height:1.25;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332;"
|
677
|
+
x="202.64171"
|
678
|
+
y="107.0413"
|
679
|
+
id="text932"
|
680
|
+
transform="rotate(54.360684)"><tspan
|
681
|
+
sodipodi:role="line"
|
682
|
+
id="tspan930"
|
683
|
+
x="202.64171"
|
684
|
+
y="107.0413"
|
685
|
+
style="font-size:2.96333332px;text-align:center;text-anchor:middle;stroke-width:0.26458332;">return</tspan><tspan
|
686
|
+
sodipodi:role="line"
|
687
|
+
x="202.64171"
|
688
|
+
y="111.45102"
|
689
|
+
style="font-size:2.96333332px;text-align:center;text-anchor:middle;stroke-width:0.26458332;"
|
690
|
+
id="tspan934">self</tspan></text>
|
691
|
+
<text
|
692
|
+
xml:space="preserve"
|
693
|
+
style="font-style:normal;font-weight:normal;font-size:3.52636671px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.18520834"
|
694
|
+
x="23.706667"
|
695
|
+
y="182.73022"
|
696
|
+
id="text933"><tspan
|
697
|
+
sodipodi:role="line"
|
698
|
+
id="tspan931"
|
699
|
+
x="23.706667"
|
700
|
+
y="182.73022"
|
701
|
+
style="font-size:3.52636671px;stroke-width:0.18520834">Wrapping Layer around methods and closures</tspan></text>
|
702
|
+
<text
|
703
|
+
xml:space="preserve"
|
704
|
+
style="font-style:normal;font-weight:normal;font-size:2.96333332px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.18520834;"
|
705
|
+
x="56.858959"
|
706
|
+
y="196.80605"
|
707
|
+
id="text937"><tspan
|
708
|
+
sodipodi:role="line"
|
709
|
+
id="tspan935"
|
710
|
+
x="56.858959"
|
711
|
+
y="196.80605"
|
712
|
+
style="font-size:2.96333332px;stroke-width:0.18520834;">@que</tspan><tspan
|
713
|
+
sodipodi:role="line"
|
714
|
+
x="56.858959"
|
715
|
+
y="200.81889"
|
716
|
+
style="font-size:2.96333332px;stroke-width:0.18520834;"
|
717
|
+
id="tspan939">@waiting</tspan></text>
|
718
|
+
<path
|
719
|
+
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.1855;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker1378)"
|
720
|
+
d="m 55.377291,207.35367 3.889375,-5.74554"
|
721
|
+
id="path941"
|
722
|
+
inkscape:connector-curvature="0" />
|
723
|
+
<path
|
724
|
+
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.1855;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker1208)"
|
725
|
+
d="m 69.638332,207.36291 -2.2225,-5.92666"
|
726
|
+
id="path943"
|
727
|
+
inkscape:connector-curvature="0" />
|
728
|
+
<text
|
729
|
+
xml:space="preserve"
|
730
|
+
style="font-style:normal;font-weight:normal;font-size:2.96333332px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.18520834;"
|
731
|
+
x="43.709164"
|
732
|
+
y="255.8875"
|
733
|
+
id="text919"><tspan
|
734
|
+
sodipodi:role="line"
|
735
|
+
id="tspan917"
|
736
|
+
x="43.709164"
|
737
|
+
y="255.8875"
|
738
|
+
style="font-size:2.96333332px;stroke-width:0.18520834;">* non-blocking area</tspan><tspan
|
739
|
+
sodipodi:role="line"
|
740
|
+
x="43.709164"
|
741
|
+
y="259.90033"
|
742
|
+
style="font-size:2.96333332px;stroke-width:0.18520834;"
|
743
|
+
id="tspan921">* synchronized</tspan><tspan
|
744
|
+
sodipodi:role="line"
|
745
|
+
x="43.709164"
|
746
|
+
y="263.91318"
|
747
|
+
style="font-size:2.96333332px;stroke-width:0.18520834;"
|
748
|
+
id="tspan4773">* event driven</tspan></text>
|
749
|
+
<text
|
750
|
+
xml:space="preserve"
|
751
|
+
style="font-style:normal;font-weight:normal;font-size:2.96333332px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.18520834;"
|
752
|
+
x="34.263542"
|
753
|
+
y="175.32187"
|
754
|
+
id="text1060"><tspan
|
755
|
+
sodipodi:role="line"
|
756
|
+
x="34.263542"
|
757
|
+
y="175.32187"
|
758
|
+
style="font-size:2.96333332px;stroke-width:0.18520834;"
|
759
|
+
id="tspan4765">* blocking, thread-safe area</tspan></text>
|
760
|
+
</g>
|
761
|
+
</svg>
|