rbsim 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.
Files changed (71) hide show
  1. checksums.yaml +7 -0
  2. data/.hgignore +6 -0
  3. data/.rspec +2 -0
  4. data/Gemfile +12 -0
  5. data/Gemfile.lock +66 -0
  6. data/LICENSE.txt +674 -0
  7. data/README.md +960 -0
  8. data/TODO +28 -0
  9. data/basic_sim.rb +62 -0
  10. data/fast-tcpn.rb +3 -0
  11. data/lib/rbsim.rb +14 -0
  12. data/lib/rbsim/dsl.rb +30 -0
  13. data/lib/rbsim/dsl/infrastructure.rb +48 -0
  14. data/lib/rbsim/dsl/mapping.rb +32 -0
  15. data/lib/rbsim/dsl/process.rb +129 -0
  16. data/lib/rbsim/dsl/program.rb +10 -0
  17. data/lib/rbsim/experiment.rb +110 -0
  18. data/lib/rbsim/hlmodel.rb +25 -0
  19. data/lib/rbsim/hlmodel/infrastructure.rb +116 -0
  20. data/lib/rbsim/hlmodel/mapping.rb +5 -0
  21. data/lib/rbsim/hlmodel/process.rb +152 -0
  22. data/lib/rbsim/numeric_units.rb +107 -0
  23. data/lib/rbsim/simulator.rb +184 -0
  24. data/lib/rbsim/statistics.rb +77 -0
  25. data/lib/rbsim/tokens.rb +146 -0
  26. data/lib/rbsim/version.rb +3 -0
  27. data/new_process.rb +49 -0
  28. data/rbsim.gemspec +42 -0
  29. data/show_readme.rb +15 -0
  30. data/sim.rb +142 -0
  31. data/sim_bamboo.rb +251 -0
  32. data/sim_process.rb +83 -0
  33. data/sim_process_dsl.rb +58 -0
  34. data/spec/dsl/infrastructure_nets_spec.rb +39 -0
  35. data/spec/dsl/infrastructure_nodes_spec.rb +72 -0
  36. data/spec/dsl/infrastructure_routes_spec.rb +44 -0
  37. data/spec/dsl/mapping_spec.rb +70 -0
  38. data/spec/dsl/process_spec.rb +56 -0
  39. data/spec/dsl/program_spec.rb +36 -0
  40. data/spec/dsl_and_hlmodel/new_process_spec.rb +235 -0
  41. data/spec/hlmodel/net_spec.rb +112 -0
  42. data/spec/hlmodel/process_spec.rb +242 -0
  43. data/spec/hlmodel/route_spec.rb +47 -0
  44. data/spec/hlmodel/routes_spec.rb +44 -0
  45. data/spec/integration/basic_simulation_spec.rb +104 -0
  46. data/spec/integration/net_spec.rb +44 -0
  47. data/spec/integration/process_spec.rb +117 -0
  48. data/spec/integration/rbsim_spec.rb +40 -0
  49. data/spec/simulator/logger_spec.rb +35 -0
  50. data/spec/simulator/stats_spec.rb +93 -0
  51. data/spec/spec_helper.rb +26 -0
  52. data/spec/statistics_spec.rb +300 -0
  53. data/spec/tcpn/add_route_spec.rb +55 -0
  54. data/spec/tcpn/cpu_spec.rb +53 -0
  55. data/spec/tcpn/map_data_spec.rb +37 -0
  56. data/spec/tcpn/network_spec.rb +163 -0
  57. data/spec/tcpn/register_event_spec.rb +48 -0
  58. data/spec/tcpn/route_to_self_spec.rb +53 -0
  59. data/spec/tcpn/stats_spec.rb +77 -0
  60. data/spec/tokens/data_queue_obsolete.rb +121 -0
  61. data/spec/tokens/data_queue_spec.rb +111 -0
  62. data/spec/units_spec.rb +48 -0
  63. data/tcpn/model.rb +6 -0
  64. data/tcpn/model/add_route.rb +78 -0
  65. data/tcpn/model/application.rb +250 -0
  66. data/tcpn/model/cpu.rb +75 -0
  67. data/tcpn/model/map_data.rb +42 -0
  68. data/tcpn/model/network.rb +108 -0
  69. data/tcpn/model/register_event.rb +89 -0
  70. data/tcpn/model/stats.rb +46 -0
  71. metadata +221 -0
@@ -0,0 +1,121 @@
1
+ require 'spec_helper'
2
+
3
+ describe RBSim::Tokens::DataQueue do
4
+
5
+ let(:apache1_first) { RBSim::Tokens::DataToken.new(:node01, 'wget', size: 1024, to: 'apache1') }
6
+ let(:apache1_second) { RBSim::Tokens::DataToken.new(:node01, 'wget', size: 1024, to: 'apache1') }
7
+ let(:apache1_third) { RBSim::Tokens::DataToken.new(:node01, 'wget', size: 1024, to: 'apache1') }
8
+ let(:apache5_first) { RBSim::Tokens::DataToken.new(:node01, 'wget', size: 1024, to: 'apache5') }
9
+ let(:apache3_first) { RBSim::Tokens::DataToken.new(:node01, 'wget', size: 1024, to: 'apache3') }
10
+
11
+ describe "enqueues data for each process separatelly" do
12
+ subject do
13
+ queue = RBSim::Tokens::DataQueueToken.new
14
+ queue.put apache1_first
15
+ queue.put apache5_first
16
+ queue.put apache1_second
17
+ queue.put apache3_first
18
+ queue.put apache1_third
19
+ queue
20
+ end
21
+
22
+ it "has 3 data packages for apache1" do
23
+ expect(subject.get 'apache1').to eq apache1_first
24
+ expect(subject.get 'apache1').to eq apache1_second
25
+ expect(subject.get 'apache1').to eq apache1_third
26
+ expect(subject.get 'apache1').to be nil
27
+ end
28
+
29
+ it "has 1 data package for apache5" do
30
+ expect(subject.get 'apache5').to eq apache5_first
31
+ expect(subject.get 'apache5').to be nil
32
+ end
33
+
34
+ it "has 1 data package for apache3" do
35
+ expect(subject.get 'apache3').to eq apache3_first
36
+ expect(subject.get 'apache3').to be nil
37
+ end
38
+
39
+ it "has no data packages for apache0" do
40
+ expect(subject.get 'apache0').to be nil
41
+ end
42
+
43
+ end
44
+
45
+ describe "collects queue lengths for processes" do
46
+ context "when putting something to the queue" do
47
+ subject do
48
+ queue = RBSim::Tokens::DataQueueToken.new
49
+ queue.put RBSim::Tokens::DataToken.new(:node01, 'wget', size: 1024, to: 'apache1')
50
+ queue.put RBSim::Tokens::DataToken.new(:node01, 'wget', size: 1024, to: 'apache5')
51
+ queue.put RBSim::Tokens::DataToken.new(:node01, 'wget', size: 1024, to: 'apache1')
52
+ queue.put RBSim::Tokens::DataToken.new(:node01, 'wget', size: 1024, to: 'apache3')
53
+ queue.put RBSim::Tokens::DataToken.new(:node01, 'wget', size: 1024, to: 'apache1')
54
+ queue
55
+ end
56
+ it "has 3 packages for apache1" do
57
+ expect(subject.length_for('apache1')).to eq 3
58
+ end
59
+
60
+ it "has 1 package for apache5" do
61
+ expect(subject.length_for('apache5')).to eq 1
62
+ end
63
+
64
+ it "has 1 package for apache3" do
65
+ expect(subject.length_for('apache3')).to eq 1
66
+ end
67
+
68
+ it "has no packages for apache333" do
69
+ expect(subject.length_for('apache333')).to eq 0
70
+ end
71
+
72
+ end
73
+
74
+ context "when putting and getting from the queue" do
75
+ subject do
76
+ queue = RBSim::Tokens::DataQueueToken.new
77
+ queue.put RBSim::Tokens::DataToken.new(:node01, 'wget', size: 1024, to: 'apache0')
78
+ queue.put RBSim::Tokens::DataToken.new(:node01, 'wget', size: 1024, to: 'apache2')
79
+ queue.put RBSim::Tokens::DataToken.new(:node01, 'wget', size: 1024, to: 'apache2')
80
+ queue.get 'apache0'
81
+ queue.get 'apache2'
82
+ queue
83
+ end
84
+
85
+ it "has 1 package for apache2" do
86
+ expect(subject.length_for('apache2')).to eq 1
87
+ end
88
+
89
+ it "has no packages for apache0" do
90
+ expect(subject.length_for('apache0')).to eq 0
91
+ end
92
+ end
93
+
94
+ end
95
+
96
+ describe "remembers last involved process" do
97
+ context "when putting" do
98
+ subject do
99
+ queue = RBSim::Tokens::DataQueueToken.new
100
+ queue.put RBSim::Tokens::DataToken.new(:node01, 'wget', size: 1024, to: 'apache0')
101
+ queue.put RBSim::Tokens::DataToken.new(:node01, 'wget', size: 1024, to: 'apache2')
102
+ queue.put RBSim::Tokens::DataToken.new(:node01, 'wget', size: 1024, to: 'apache1')
103
+ queue
104
+ end
105
+ its(:last_involved_queue) { should eq 'apache1' }
106
+ end
107
+
108
+ context "when getting" do
109
+ subject do
110
+ queue = RBSim::Tokens::DataQueueToken.new
111
+ queue.put RBSim::Tokens::DataToken.new(:node01, 'wget', size: 1024, to: 'apache0')
112
+ queue.put RBSim::Tokens::DataToken.new(:node01, 'wget', size: 1024, to: 'apache2')
113
+ queue.put RBSim::Tokens::DataToken.new(:node01, 'wget', size: 1024, to: 'apache1')
114
+ queue.get 'apache0'
115
+ queue
116
+ end
117
+ its(:last_involved_queue) { should eq 'apache0' }
118
+ end
119
+ end
120
+
121
+ end
@@ -0,0 +1,111 @@
1
+ require 'spec_helper'
2
+
3
+ describe RBSim::Tokens::DataQueue do
4
+ subject { RBSim::Tokens::DataQueue.new(:apache) }
5
+
6
+ let(:data_id) { 12332432 }
7
+ let(:other_data_id) { 23634657 }
8
+
9
+ let(:data1) do
10
+ data = RBSim::Tokens::Data.new(data_id, :node01, :apache1, to: :apache, size: 1024)
11
+ data.fragments = 3
12
+ data
13
+ end
14
+
15
+ let(:data2) do
16
+ data = RBSim::Tokens::Data.new(data_id, :node01, :apache1, to: :apache, size: 1024)
17
+ data.fragments = 3
18
+ data
19
+ end
20
+
21
+ let(:data3) do
22
+ data = RBSim::Tokens::Data.new(data_id, :node01, :apache1, to: :apache, size: 1024)
23
+ data.fragments = 3
24
+ data
25
+ end
26
+
27
+ let(:other_data1) do
28
+ data = RBSim::Tokens::Data.new(other_data_id, :node01, :apache1, to: :apache, size: 1024)
29
+ data.fragments = 2
30
+ data
31
+ end
32
+
33
+ let(:other_data2) do
34
+ data = RBSim::Tokens::Data.new(other_data_id, :node01, :apache1, to: :apache, size: 1024)
35
+ data.fragments = 2
36
+ data
37
+ end
38
+
39
+ shared_examples_for "empty queue" do
40
+ it "is empty" do
41
+ expect(subject.empty?).to be true
42
+ end
43
+
44
+ it "has length 0" do
45
+ expect(subject.length).to eq 0
46
+ end
47
+
48
+ it "dequeues nil" do
49
+ expect(subject.get).to be_nil
50
+ end
51
+ end
52
+
53
+ it "raises error when fragment count is not set" do
54
+ data = RBSim::Tokens::Data.new(other_data_id, :node01, :apache1, to: :apache, size: 1024)
55
+ expect { subject.put data }.to raise_error
56
+ end
57
+
58
+ describe "until all fragments arrive" do
59
+ before :each do
60
+ subject.put data1
61
+ subject.put data2
62
+ subject.put other_data1
63
+ end
64
+
65
+ it_behaves_like "empty queue"
66
+
67
+ end
68
+
69
+ describe "when all fragments arrive" do
70
+ before :each do
71
+ subject.put data1
72
+ subject.put data2
73
+ subject.put other_data1
74
+ subject.put data3
75
+ end
76
+
77
+ it "is not empty" do
78
+ expect(subject.empty?).to be false
79
+ end
80
+
81
+ it "has length 1" do
82
+ expect(subject.length).to eq 1
83
+ end
84
+
85
+ it "dequeues data" do
86
+ expect(subject.get.data_id).to eq data_id
87
+ end
88
+
89
+ describe "when data is dequeued" do
90
+ before :each do
91
+ subject.get
92
+ end
93
+
94
+ it_behaves_like "empty queue"
95
+
96
+
97
+ describe "when another data arrives" do
98
+ before :each do
99
+ subject.put other_data2
100
+ end
101
+
102
+ it "dequeues data" do
103
+ expect(subject.get.data_id).to eq other_data_id
104
+ end
105
+
106
+ end
107
+
108
+ end
109
+ end
110
+
111
+ end
@@ -0,0 +1,48 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Numeric units" do
4
+
5
+ let(:jiffies) { Numeric::RBSIM_JIFFIES_PER_SECOND }
6
+
7
+ shared_examples "has correct units" do
8
+ # volume units
9
+ its(:bits) { should eq subject }
10
+ its(:bytes) { should eq subject * 8 }
11
+ its(:in_bits) { should eq subject }
12
+ its(:in_bytes) { should eq subject / 8 }
13
+
14
+ # network units
15
+ its(:bps) { should eq subject.to_f / jiffies}
16
+ its(:Bps) { should eq subject.to_f * 8 / jiffies }
17
+ its(:in_bps) { should eq subject * jiffies }
18
+ its(:in_Bps) { should eq subject / 8 * jiffies }
19
+
20
+ # time units
21
+ its(:seconds) { should eq subject * jiffies }
22
+ its(:miliseconds) { should eq subject * jiffies / 1000 }
23
+ its(:microseconds) { should eq subject * jiffies / 1000000 }
24
+ its(:minutes) { should eq subject * jiffies * 60 }
25
+ its(:hours) { should eq subject * jiffies * 60 * 60 }
26
+ its(:days) { should eq subject * jiffies * 60 * 60 * 24 }
27
+
28
+ its(:in_seconds) { should eq subject / jiffies }
29
+ its(:in_miliseconds) { should eq subject * 1000 / jiffies }
30
+ its(:in_microseconds) { should eq subject * 1000 * 1000 / jiffies }
31
+ its(:in_minutes) { should be_within(1.0/jiffies).of( subject / (jiffies * 60) ) }
32
+ its(:in_hours) { should be_within(1.0/jiffies).of( subject / (jiffies * 60 * 60) ) }
33
+ its(:in_days) { should be_within(1.0/jiffies).of( subject / (jiffies * 60 * 60 * 24) ) }
34
+ end
35
+
36
+ describe 128 do
37
+ include_examples 'has correct units'
38
+ end
39
+
40
+ describe 1.5 do
41
+ include_examples 'has correct units'
42
+ end
43
+
44
+ describe 50000 do
45
+ include_examples 'has correct units'
46
+ end
47
+
48
+ end
data/tcpn/model.rb ADDED
@@ -0,0 +1,6 @@
1
+ page "rbsim model" do
2
+ sub_page "model/application.rb"
3
+ sub_page "model/map_data.rb"
4
+ sub_page "model/add_route.rb"
5
+ sub_page "model/network.rb"
6
+ end
@@ -0,0 +1,78 @@
1
+ # add route to data
2
+ # before network transmission
3
+ page 'add route' do
4
+ RouteNotFound = Class.new RuntimeError
5
+
6
+ data_for_network = place 'data for network'
7
+ routes = place 'routes'
8
+ data_with_route = place 'data with route'
9
+ data_to_receive = place 'data to receive', process_name: :process_name
10
+
11
+ class TCPNAddRouteToData
12
+ def initialize(binding)
13
+ @data = binding['data for network'].value
14
+ @queue = binding['data to receive'].value
15
+ @routes = binding['routes'].value
16
+ end
17
+
18
+ def with_route_token(clock)
19
+ if to_self?
20
+ nil
21
+ else
22
+ @data.route = route
23
+ { ts: clock, val: @data }
24
+ end
25
+ end
26
+
27
+ def to_self_token(clock)
28
+ if to_self?
29
+ @queue.put @data
30
+ end
31
+ { ts: clock, val: @queue }
32
+ end
33
+
34
+ private
35
+
36
+ def to_self?
37
+ @data.src_node == @data.dst_node
38
+ end
39
+
40
+ def route
41
+ r = @routes.find @data.src_node, @data.dst_node
42
+ if r.nil?
43
+ raise RouteNotFound.new("from #{@data.src_node} to #{@data.dst_node}")
44
+ end
45
+ r
46
+ end
47
+ end
48
+
49
+ transition 'add_route' do
50
+ input data_for_network
51
+ input routes
52
+ input data_to_receive
53
+
54
+ output routes do |binding, clock|
55
+ binding['routes']
56
+ end
57
+
58
+ output data_with_route do |binding, clock|
59
+ TCPNAddRouteToData.new(binding).with_route_token(clock)
60
+ end
61
+
62
+ output data_to_receive do |binding, clock|
63
+ TCPNAddRouteToData.new(binding).to_self_token(clock)
64
+ end
65
+
66
+ sentry do |marking_for, clock, result|
67
+ marking_for['data for network'].each do |data|
68
+ marking_for['data to receive'].each(:process_name, data.value.dst) do |queue|
69
+ routes = marking_for['routes'].first
70
+ result << { 'data for network' => data,
71
+ 'data to receive' => queue,
72
+ 'routes' => routes }
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
78
+
@@ -0,0 +1,250 @@
1
+ page 'application' do
2
+ process = timed_place 'process', { first_event: :first_event, user_event: :has_user_event?, name: :name }
3
+ data_to_send = place 'data to send'
4
+ mapping = place 'mapping'
5
+ data_to_receive = place 'data to receive', empty: :empty?
6
+
7
+ # model of CPU load by application logic
8
+ sub_page "cpu.rb"
9
+
10
+ # statistics
11
+ sub_page "stats.rb"
12
+
13
+ # new event from user (register_event statement)
14
+ sub_page "register_event.rb"
15
+
16
+ # Delay process execution for specified time.
17
+ # args: { time: time for which we should wait }
18
+ class EventDelayFor
19
+ def initialize(binding)
20
+ @process = binding['process'].value
21
+ @event = @process.serve_system_event :delay_for
22
+ end
23
+
24
+ def process_token(clock)
25
+ ts = clock + @event[:args][:time].to_i
26
+ { val: @process, ts: ts }
27
+ end
28
+ end
29
+
30
+ transition 'event::delay_for' do
31
+ input process
32
+ output process do |binding, clock|
33
+ EventDelayFor.new(binding).process_token(clock)
34
+ end
35
+
36
+ sentry do |marking_for, clock, result|
37
+ marking_for['process'].each(:first_event, :delay_for) do |p|
38
+ result << { 'process' => p }
39
+ end
40
+ end
41
+ =begin
42
+ guard do |binding, clock|
43
+ binding[:process][:val].has_event? :delay_for
44
+ end
45
+ =end
46
+ end
47
+
48
+ transition 'event::serve_user' do
49
+ input process
50
+
51
+ output process do |binding, clock|
52
+ process = binding['process'].value
53
+ process.serve_user_event
54
+ process
55
+ end
56
+
57
+ sentry do |marking_for, clock, result|
58
+ marking_for['process'].each(:user_event, true) do |p|
59
+ result << { 'process' => p }
60
+ end
61
+ end
62
+
63
+ =begin
64
+ guard do |binding, clock|
65
+ binding[:process][:val].has_user_event?
66
+ end
67
+ =end
68
+ end
69
+
70
+ transition 'event::send_data' do
71
+ input process
72
+
73
+ # Sending data to anothe node.
74
+ # args: { to: destination process name,
75
+ # size: volume of send data,
76
+ # type: type of send data (to use in HLModel),
77
+ # content: content of send data (to use in HLModel) }
78
+ class EventSendData
79
+ def initialize(bndng)
80
+ @process = bndng['process'].value
81
+ @event = @process.serve_system_event :send_data
82
+ fragments = [
83
+ @process.data_fragmentation,
84
+ @event[:args][:size].to_i / 1500.bytes
85
+ ].min
86
+ fragments = 1 if fragments == 0
87
+ @data = fragments.times.map do
88
+ d = RBSim::Tokens::DataToken.new(self.object_id, @process.node, @process.name, @event[:args])
89
+ d.fragments = fragments
90
+ d
91
+ end
92
+ end
93
+
94
+ def data_token(clock)
95
+ @data.map { |d| { val: d, ts: clock } }
96
+ end
97
+
98
+ def process_token(clock)
99
+ { val: @process, ts: clock }
100
+ end
101
+ end
102
+
103
+ output process do |binding, clock|
104
+ EventSendData.new(binding).process_token clock
105
+ end
106
+
107
+ output data_to_send do |binding, clock|
108
+ EventSendData.new(binding).data_token clock
109
+ end
110
+
111
+ sentry do |marking_for, clock, result|
112
+ marking_for['process'].each(:first_event, :send_data) do |p|
113
+ result << { 'process' => p }
114
+ end
115
+ end
116
+
117
+ =begin
118
+ guard do |binding, clock|
119
+ binding[:process][:val].has_event? :send_data
120
+ end
121
+ =end
122
+ end
123
+
124
+ transition 'event::new_process' do
125
+ input process
126
+ input mapping
127
+
128
+ # Creating new process on the same node
129
+ # args: { program: program name for new process (optional),
130
+ # constructor: block called as constructor of new process (adds initial events),
131
+ # constructor_args: args passed to the constructor }
132
+ class EventNewProcess
133
+ def initialize(binding)
134
+ @process = binding['process'].value
135
+ @event = @process.serve_system_event :new_process
136
+ @new_process = @event[:args][:constructor].call @event[:args][:constructor_args]
137
+ @mapping = binding['mapping'].value
138
+ @mapping[@new_process.name] = @new_process.node
139
+ end
140
+
141
+ def process_tokens(clock)
142
+ [ { ts: clock, val: @process }, { ts: clock, val: @new_process } ]
143
+ end
144
+
145
+ def mapping_token(clock)
146
+ { ts: clock, val: @mapping }
147
+ end
148
+ end
149
+
150
+ output process do |binding, clock|
151
+ EventNewProcess.new(binding).process_tokens(clock)
152
+ end
153
+
154
+ output mapping do |binding, clock|
155
+ EventNewProcess.new(binding).mapping_token(clock)
156
+ end
157
+
158
+ sentry do |marking_for, clock, result|
159
+ marking_for['process'].each(:first_event, :new_process) do |p|
160
+ mapping = marking_for['mapping'].first
161
+ result << { 'process' => p , 'mapping' => mapping}
162
+ end
163
+ end
164
+ =begin
165
+ guard do |binding, clock|
166
+ binding[:process][:val].has_event? :new_process
167
+ end
168
+ =end
169
+ end
170
+
171
+ transition 'event::data_received' do
172
+ input process
173
+ input data_to_receive
174
+
175
+ class EventDataReceived
176
+ def initialize(binding)
177
+ @process = binding['process'].value
178
+ @queue = binding['data to receive'].value
179
+ @data = @queue.get
180
+ @process.enqueue_event :data_received, @data
181
+ end
182
+
183
+ def process_token(clock)
184
+ { ts: clock, val: @process }
185
+ end
186
+
187
+ def queue_token(clock)
188
+ { ts: clock, val: @queue }
189
+ end
190
+ end
191
+
192
+ output process do |binding, clock|
193
+ EventDataReceived.new(binding).process_token(clock)
194
+ end
195
+
196
+ output data_to_receive do |binding, clock|
197
+ EventDataReceived.new(binding).queue_token(clock)
198
+ end
199
+
200
+ sentry do |marking_for, clock, result|
201
+ marking_for['data to receive'].each(:empty, false) do |queue|
202
+ marking_for['process'].each(:name, queue.value.process_name) do |process|
203
+ result << { 'process' => process, 'data to receive' => queue }
204
+ end
205
+ end
206
+ end
207
+
208
+ =begin
209
+ guard do |binding, clock|
210
+ process = binding[:process][:val]
211
+ data = binding[:queue][:val].get process.name
212
+ !data.nil?
213
+ end
214
+ =end
215
+ end
216
+
217
+ transition 'event::log' do
218
+ input process
219
+
220
+ # Log message from process
221
+ # args: log message
222
+ class EventLog
223
+ def initialize(binding)
224
+ @process = binding['process'].value
225
+ @event = @process.serve_system_event :log
226
+ end
227
+
228
+ def process_token(clock)
229
+ { val: @process, ts: clock }
230
+ end
231
+ end
232
+
233
+ output process do |binding, clock|
234
+ EventLog.new(binding).process_token(clock)
235
+ end
236
+
237
+ sentry do |marking_for, clock, result|
238
+ marking_for['process'].each(:first_event, :log) do |p|
239
+ result << { 'process' => p }
240
+ end
241
+ end
242
+
243
+ =begin
244
+ guard do |binding, clock|
245
+ binding[:process][:val].has_event? :log
246
+ end
247
+ =end
248
+ end
249
+
250
+ end