cpee 1.3.129 → 1.3.130

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 (33) hide show
  1. checksums.yaml +7 -0
  2. data/cpee.gemspec +1 -1
  3. data/lib/cpee/processtransformation/bpel/Repository/booking.bpel +125 -0
  4. data/lib/cpee/processtransformation/bpel/Repository/booking.wsdl +72 -0
  5. data/lib/cpee/processtransformation/bpel/Repository/booking/airline.wsdl +71 -0
  6. data/lib/cpee/processtransformation/bpel/Repository/booking/hotel.wsdl +64 -0
  7. data/lib/cpee/processtransformation/bpel/Repository/booking/report.wsdl +71 -0
  8. data/lib/cpee/processtransformation/bpel/bpel2wee.rb +34 -0
  9. data/lib/cpee/processtransformation/bpel/bpelserver.ru +64 -0
  10. data/lib/cpee/processtransformation/bpel/bpelserver.xml +70 -0
  11. data/lib/cpee/processtransformation/bpel/lib/BPEL_Transform.rb +367 -0
  12. data/lib/cpee/processtransformation/bpmn2.rb +273 -0
  13. data/lib/cpee/processtransformation/cpee.rb +118 -0
  14. data/lib/cpee/processtransformation/structures.rb +426 -0
  15. data/server/instances/1/properties.xml +101 -69
  16. data/server/instances/10/properties.xml +109 -0
  17. data/server/instances/11/properties.xml +109 -0
  18. data/server/instances/2/properties.xml +44 -191
  19. data/server/instances/3/properties.xml +44 -70
  20. data/server/instances/4/properties.xml +68 -28
  21. data/server/instances/5/properties.xml +70 -10
  22. data/server/instances/6/properties.xml +55 -175
  23. data/server/instances/7/properties.xml +83 -0
  24. data/server/instances/8/properties.xml +83 -0
  25. data/server/instances/9/properties.xml +77 -0
  26. metadata +111 -111
  27. data/server/instances/1/notifications/d12eff1ac812661c05d7090ce7394cf9/consumer-secret +0 -1
  28. data/server/instances/1/notifications/d12eff1ac812661c05d7090ce7394cf9/producer-secret +0 -1
  29. data/server/instances/1/notifications/d12eff1ac812661c05d7090ce7394cf9/subscription.xml +0 -27
  30. data/server/instances/6/notifications/5c8c36c3dfcec8e36c3b25859a71778c/consumer-secret +0 -1
  31. data/server/instances/6/notifications/5c8c36c3dfcec8e36c3b25859a71778c/producer-secret +0 -1
  32. data/server/instances/6/notifications/5c8c36c3dfcec8e36c3b25859a71778c/subscription.xml +0 -27
  33. data/server/server.pid +0 -1
@@ -0,0 +1,273 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # This file is part of CPEE.
4
+ #
5
+ # Apache License, Version 2.0
6
+ #
7
+ # Copyright (c) 2013 Juergen Mangler
8
+ #
9
+ # Licensed under the Apache License, Version 2.0 (the "License");
10
+ # you may not use this file except in compliance with the License.
11
+ # You may obtain a copy of the License at
12
+ #
13
+ # http://www.apache.org/licenses/LICENSE-2.0
14
+ #
15
+ # Unless required by applicable law or agreed to in writing, software
16
+ # distributed under the License is distributed on an "AS IS" BASIS,
17
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
+ # See the License for the specific language governing permissions and
19
+ # limitations under the License.
20
+
21
+ require File.expand_path(File.dirname(__FILE__) + '/structures')
22
+ require 'rubygems'
23
+ require 'xml/smart'
24
+ require 'highline'
25
+
26
+ module CPEE
27
+
28
+ module ProcessTransformation
29
+
30
+ module Source
31
+
32
+ class BPMN2
33
+ attr_reader :dataelements, :endpoints, :start, :graph
34
+
35
+ def initialize(xml) #{{{
36
+ @tree = Tree.new
37
+ @hl = HighLine.new
38
+ @start = nil
39
+
40
+ doc = XML::Smart.string(xml)
41
+ doc.register_namespace 'bm', "http://www.omg.org/spec/BPMN/20100524/MODEL"
42
+
43
+ @dataelements = {}
44
+ @endpoints = {}
45
+ @graph = Graph.new
46
+
47
+ extract_dataelements(doc)
48
+ extract_endpoints(doc)
49
+ extract_nodelink(doc)
50
+
51
+ @traces = Traces.new [[@start]]
52
+ end #}}}
53
+
54
+ def extract_dataelements(doc)
55
+ doc.find("/bm:definitions/bm:process/bm:property[bm:dataState/@name='cpee:dataelement']").each do |ref|
56
+ if ref.attributes['itemSubjectRef']
57
+ doc.find("/bm:definitions/bm:itemDefinition[@id=\"" + ref.attributes['itemSubjectRef'] + "\"]").each do |sref|
58
+ @dataelements[ref.attributes['name']] = sref.attributes['structureRef'].to_s
59
+ end
60
+ else
61
+ @dataelements[ref.attributes['name']] = ''
62
+ end
63
+ end
64
+ end
65
+
66
+ def extract_endpoints(doc)
67
+ doc.find("/bm:definitions/bm:process/bm:property[bm:dataState/@name='cpee:endpoint']/@itemSubjectRef").each do |ref|
68
+ doc.find("/bm:definitions/bm:itemDefinition[@id=\"" + ref.value + "\"]/@structureRef").each do |sref|
69
+ @endpoints[ref.value] = sref.value
70
+ end
71
+ end
72
+ end
73
+
74
+ def extract_nodelink(doc)
75
+ doc.find("/bm:definitions/bm:process/bm:*[@id and @name and not(@itemSubjectRef) and not(name()='sequenceFlow')]").each do |e|
76
+ n = Node.new(e.attributes['id'],e.qname.name.to_sym,e.attributes['name'].strip,e.find('count(bm:incoming)'),e.find('count(bm:outgoing)'))
77
+
78
+ if e.attributes['scriptFormat'] != ''
79
+ n.script_type = e.attributes['scriptFormat']
80
+ end
81
+
82
+ e.find("bm:property[@name='cpee:endpoint']/@itemSubjectRef").each do |ep|
83
+ n.endpoints << ep.value
84
+ end
85
+ e.find("bm:property[@name='cpee:method']/@itemSubjectRef").each do |m|
86
+ n.methods << m.value
87
+ end
88
+ e.find("bm:script").each do |s|
89
+ n.script ||= ''
90
+ n.script << s.text.strip
91
+ end
92
+ e.find("bm:ioSpecification/bm:dataInput").each do |a|
93
+ name = a.attributes['name']
94
+ value = a.attributes['itemSubjectRef']
95
+ if @dataelements.keys.include?(value)
96
+ n.parameters[name] = 'data.' + value
97
+ else
98
+ n.parameters[name] = value
99
+ end
100
+ end
101
+ e.find("bm:ioSpecification/bm:dataOutput").each do |a|
102
+ ref = a.attributes['id']
103
+ e.find("bm:dataOutputAssociation[bm:sourceRef=\"#{ref}\"]").each do |d|
104
+ n.script_var = ref
105
+ n.script_id = d.find("string(bm:targetRef)")
106
+ end
107
+ end
108
+
109
+ @graph.add_node n
110
+ @start = n if n.type == :startEvent && @start == nil
111
+ end
112
+
113
+ # extract all sequences to a links
114
+ doc.find("/bm:definitions/bm:process/bm:sequenceFlow").each do |e|
115
+ source = e.attributes['sourceRef']
116
+ target = e.attributes['targetRef']
117
+ cond = e.find('bm:conditionExpression')
118
+ @graph.add_link Link.new(source, target, cond.empty? ? nil : cond.first.text.strip)
119
+ end
120
+
121
+ @graph.clean_up do |node|
122
+ if node.type == :scriptTask && (x = @graph.find_script_id(node.id)).any?
123
+ x.each do |k,n|
124
+ n.script = node.script
125
+ n.script_type = node.script_type
126
+ end
127
+ true
128
+ else
129
+ false
130
+ end
131
+ end
132
+ end
133
+
134
+ def build_traces #{{{
135
+ build_extraces @traces, @start
136
+ @traces
137
+ end #}}}
138
+ def build_tree(debug=false) #{{{
139
+ build_ttree @tree, @traces.dup, nil, debug
140
+ debug_print debug, 'Tree finished'
141
+ @tree
142
+ end #}}}
143
+
144
+ def build_extraces(traces, node) #{{{
145
+ dupt = traces.last.dup
146
+ @graph.next_nodes(node).each_with_index do |n,i|
147
+ traces << dupt.dup if i > 0
148
+ if traces.last.include?(n)
149
+ traces.last << n
150
+ else
151
+ traces.last << n
152
+ build_extraces(traces,n)
153
+ end
154
+ end
155
+ end #}}}
156
+ private :build_extraces
157
+
158
+ def map_node(node) #{{{
159
+ case node.type
160
+ when :parallelGateway
161
+ Parallel.new(node.id,node.type)
162
+ when :exclusiveGateway
163
+ Conditional.new(node.id,:exclusive,node.type)
164
+ when :eventBasedGateway
165
+ Parallel.new(node.id,node.type,1)
166
+ when :inclusiveGateway
167
+ Conditional.new(node.id,:inclusive,node.type)
168
+ when :endEvent, :startEvent, nil
169
+ nil
170
+ else
171
+ node
172
+ end
173
+ end #}}}
174
+ private :map_node
175
+
176
+ def build_ttree(branch,traces,enode=nil,debug=false)
177
+ while not traces.finished?
178
+ ### if traces exist more than once, make it so they exist only once
179
+ ### if somebody creates a modell with an inclusive/exclusive that
180
+ ### has identical branches with different conditions, we are fucked
181
+ ### but how are the odds? right? right?
182
+ traces.uniq!
183
+ debug_print debug, traces
184
+ if node = traces.same_first
185
+ if branch.condition?
186
+ li = @graph.link(branch.id,traces.first_node.id)
187
+ unless li.nil?
188
+ branch.condition << li.condition
189
+ branch.condition_type = "text/javascript"
190
+ end
191
+ end
192
+ if node == enode
193
+ traces.shift_all
194
+ elsif node.incoming <= 1
195
+ traces.shift_all
196
+ n = map_node(node)
197
+ if !(n.nil? || (n.container? && (node.outgoing <=1 || traces.finished?)))
198
+ (branch << n).compact!
199
+ end
200
+ else
201
+ loops = traces.loops
202
+ if node.type == :exclusiveGateway
203
+ ### as the first is a decision node, just remove and continue
204
+ if node.incoming == 2
205
+ node.incoming = 1
206
+ branch << Loop.new(node.id)
207
+ ### remove the gateway itself, as for a single loop it is no longer used.
208
+ ### the condition will the loop condition
209
+ traces.shift_all
210
+ loops.remove_empty
211
+ build_ttree branch.last, loops, nil, debug
212
+ else
213
+ ### dont remove it, treat it as a normal conditional
214
+ ### an infinite loop that can only be left by break is created
215
+ node.incoming = 1
216
+ branch << InfiniteLoop.new(node.id)
217
+ ### add the blank conditional to get a break
218
+ len = loops.length
219
+ loops.add_breaks
220
+ build_ttree branch.last, loops, nil, debug
221
+ ### set outgoing to number of loops (without the break) so that it can be ignored (should be 1 all the time)
222
+ node.outgoing -= len
223
+ end
224
+ else
225
+ node.incoming -= loops.length
226
+ ### throw away the loop traces, remove loop traces from front of all other traces
227
+ traces.segment_by_loops loops
228
+ build_ttree branch, loops, nil, debug
229
+ end
230
+ traces.remove(loops)
231
+ traces.remove_empty
232
+ end
233
+ else
234
+ endnode = traces.find_endnode || enode
235
+ tracesgroup, endnode = traces.segment_by endnode
236
+ tracesgroup.each do |trcs|
237
+ if trcs.finished?
238
+ build_ttree branch.last.new_branch, Traces.new([[Break.new(1)]]), endnode, debug
239
+ else
240
+ build_ttree branch.last.new_branch, trcs, endnode, debug
241
+ end
242
+ endnode.incoming -= 1 unless endnode.nil?
243
+ end
244
+ ### all before is reduced to one incoming arrow
245
+ ### if now there is still more than one incoming we have a loop situation
246
+ ### where the end of a branching statement is also the starting/endpoint
247
+ ### of a loop
248
+ endnode.incoming += 1 unless endnode.nil?
249
+ end
250
+ end
251
+ end
252
+ private :build_ttree
253
+
254
+ def debug_print(debug,traces) #{{{
255
+ if debug
256
+ puts '-' * @hl.output_cols, @tree.to_s
257
+ puts traces.to_s
258
+ @hl.ask('Continue ... '){ |q| q.echo = false }
259
+ end
260
+ end #}}}
261
+ private :debug_print
262
+
263
+ def generate_model(formater) #{{{
264
+ formater.new(@tree).generate
265
+ end #}}}
266
+
267
+ end
268
+
269
+ end
270
+
271
+ end
272
+
273
+ end
@@ -0,0 +1,118 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # This file is part of CPEE.
4
+ #
5
+ # Apache License, Version 2.0
6
+ #
7
+ # Copyright (c) 2013 Juergen Mangler
8
+ #
9
+ # Licensed under the Apache License, Version 2.0 (the "License");
10
+ # you may not use this file except in compliance with the License.
11
+ # You may obtain a copy of the License at
12
+ #
13
+ # http://www.apache.org/licenses/LICENSE-2.0
14
+ #
15
+ # Unless required by applicable law or agreed to in writing, software
16
+ # distributed under the License is distributed on an "AS IS" BASIS,
17
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
+ # See the License for the specific language governing permissions and
19
+ # limitations under the License.
20
+
21
+ module CPEE
22
+
23
+ module ProcessTransformation
24
+
25
+ module Target
26
+
27
+ class CPEE
28
+ def initialize(tree)
29
+ @tree = tree
30
+ end
31
+ def generate
32
+ res = XML::Smart.string("<description xmlns='http://cpee.org/ns/description/1.0'/>")
33
+ res.register_namespace 'd', 'http://cpee.org/ns/description/1.0'
34
+ generate_for_list(@tree,res.root)
35
+ res
36
+ end
37
+
38
+ def generate_for_list(list,res)
39
+ list.each do |e|
40
+ nam = e.class.name.gsub(/\w+:+/,'')
41
+ send("print_#{nam}".to_sym,e,res)
42
+ end
43
+ end
44
+ private :generate_for_list
45
+
46
+ def print_Break(node,res)
47
+ res.add('break')
48
+ end
49
+
50
+ def print_InfiniteLoop(node,res)
51
+ s1 = res.add('loop', 'pre_test' => 'true')
52
+ generate_for_list(node,s1)
53
+ end
54
+ def print_Loop(node,res)
55
+ s1 = res.add('loop', 'pre_test' => node.condition.join(' && '))
56
+ s1.attributes['language'] = node.condition_type unless node.condition_type.nil?
57
+ generate_for_list(node,s1)
58
+ end
59
+
60
+ def print_Node(node,res)
61
+ if node.endpoints.empty? && !node.script.nil? && node.script.strip != ''
62
+ n = res.add('d:manipulate', 'id' => "a#{node.niceid}")
63
+ n.text = node.script
64
+ n.attributes['output'] = node.script_var unless node.script_var.nil?
65
+ n.attributes['language'] = node.script_type unless node.script_type.nil?
66
+ else
67
+ n = res.add('d:call', 'id' => "a#{node.niceid}", 'endpoint' => node.endpoints.join(','))
68
+ p = n.add('d:parameters')
69
+ p.add('d:label',node.label)
70
+ p.add('d:method',node.methods.join(','))
71
+ p.add('d:type',node.type)
72
+ p.add('d:mid',node.id)
73
+ par = p.add('d:parameters')
74
+ node.parameters.each do |k,v|
75
+ par.add(k,v)
76
+ end
77
+ if !node.script.nil? && node.script.strip != ''
78
+ x = n.add('manipulate',node.script)
79
+ x.attributes['output'] = node.script_var unless node.script_var.nil?
80
+ x.attributes['language'] = node.script_type unless node.script_type.nil?
81
+ end
82
+ end
83
+ end
84
+ private :print_Node
85
+
86
+ def print_Parallel(node,res)
87
+ s1 = res.add('parallel','wait' => node.wait)
88
+ node.sub.each do |branch|
89
+ s2 = s1.add('parallel_branch')
90
+ generate_for_list(branch,s2)
91
+ end
92
+ end
93
+ private :print_Parallel
94
+
95
+ def print_Conditional(node,res)
96
+ s1 = res.add('d:choose', 'mode' => node.mode)
97
+ node.sub.each do |branch|
98
+ s2 = if branch.condition.any?
99
+ a = s1.add('d:alternative','condition' => branch.condition.join(' or '))
100
+ a.attributes['language'] = branch.condition_type unless branch.condition_type.nil?
101
+ a
102
+ else
103
+ s1.add('d:otherwise')
104
+ end
105
+ generate_for_list(branch,s2)
106
+ end
107
+ if (x = s1.find('d:otherwise')).any?
108
+ s1.add x
109
+ end
110
+ end
111
+ private :print_Conditional
112
+ end
113
+
114
+ end
115
+
116
+ end
117
+
118
+ end
@@ -0,0 +1,426 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # This file is part of CPEE.
4
+ #
5
+ # Apache License, Version 2.0
6
+ #
7
+ # Copyright (c) 2013 Juergen Mangler
8
+ #
9
+ # Licensed under the Apache License, Version 2.0 (the "License");
10
+ # you may not use this file except in compliance with the License.
11
+ # You may obtain a copy of the License at
12
+ #
13
+ # http://www.apache.org/licenses/LICENSE-2.0
14
+ #
15
+ # Unless required by applicable law or agreed to in writing, software
16
+ # distributed under the License is distributed on an "AS IS" BASIS,
17
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
+ # See the License for the specific language governing permissions and
19
+ # limitations under the License.
20
+
21
+ module CPEE
22
+
23
+ module ProcessTransformation
24
+
25
+ class Link #{{{
26
+ attr_accessor :from, :to
27
+ attr_reader :condition
28
+ def initialize(from,to,cond=nil)
29
+ @from = from
30
+ @to = to
31
+ @condition = cond
32
+ end
33
+ end #}}}
34
+
35
+ module Container
36
+ def container?
37
+ @container || false
38
+ end
39
+ end
40
+
41
+ class Node #{{{
42
+ include Container
43
+ @@niceid = -1
44
+ attr_reader :id, :label, :niceid
45
+ attr_reader :endpoints, :methods, :parameters
46
+ attr_accessor :script, :script_id, :script_var, :script_type, :incoming, :outgoing, :type
47
+ def initialize(id,type,label,incoming,outgoing)
48
+ @id = id
49
+ @niceid = (@@niceid += 1)
50
+ @type = type
51
+ @label = label
52
+ @endpoints = []
53
+ @methods = []
54
+ @script = nil
55
+ @script_type = nil
56
+ @script_id = nil
57
+ @script_var = 'result'
58
+ @parameters = {}
59
+ @incoming = incoming
60
+ @outgoing = outgoing
61
+ end
62
+ end # }}}
63
+
64
+ module Struct #{{{
65
+ def each(&a)
66
+ @sub.each{|s| a.call(s)}
67
+ end
68
+ def length
69
+ @sub.length
70
+ end
71
+ end #}}}
72
+
73
+ class Break < Node
74
+ def initialize(incoming)
75
+ super '-1', :break, 'BREAK', incoming, []
76
+ end
77
+ end
78
+
79
+ class Alternative < Array #{{{
80
+ include Container
81
+ attr_accessor :condition, :condition_type
82
+ attr_reader :id
83
+ def condition?; true; end
84
+ def initialize(id)
85
+ @container = true
86
+ @id = id
87
+ @condition = []
88
+ @condition_type = nil
89
+ end
90
+ end #}}}
91
+ class Branch < Array #{{{
92
+ include Container
93
+ attr_reader :id
94
+ def condition?; false; end
95
+ def initialize(id)
96
+ @container = true
97
+ @id = id
98
+ end
99
+ end #}}}
100
+ class InfiniteLoop < Array #{{{
101
+ include Container
102
+ def condition?; false; end
103
+ attr_accessor :id, :type
104
+ def initialize(id)
105
+ @container = true
106
+ @id = id
107
+ @type = :loop
108
+ end
109
+ end #}}}
110
+ class Loop < Array #{{{
111
+ include Container
112
+ attr_accessor :id, :type, :condition, :condition_type
113
+ def condition?; true; end
114
+ def initialize(id)
115
+ @container = true
116
+ @id = id
117
+ @type = :loop
118
+ @condition = []
119
+ @condition_type = nil
120
+ end
121
+ end #}}}
122
+
123
+ class Parallel #{{{
124
+ include Container
125
+ include Struct
126
+ include Enumerable
127
+ attr_reader :id, :sub
128
+ attr_accessor :type, :wait
129
+ def initialize(id,type,wait='-1')
130
+ @container = true
131
+ @id = id
132
+ @type = type
133
+ @sub = []
134
+ @wait = wait
135
+ end
136
+ def new_branch
137
+ (@sub << Branch.new(@id)).last
138
+ end
139
+ end #}}}
140
+
141
+ class Conditional #{{{
142
+ include Container
143
+ include Struct
144
+ include Enumerable
145
+ attr_reader :container
146
+ attr_reader :id, :sub, :mode
147
+ attr_accessor :type
148
+ def initialize(id,mode,type)
149
+ @container = true
150
+ @id = id
151
+ @sub = []
152
+ @mode = mode
153
+ @type = type
154
+ end
155
+ def new_branch
156
+ (@sub << Alternative.new(@id)).last
157
+ end
158
+ end #}}}
159
+
160
+ class Graph #{{{
161
+ attr_reader :flow, :nodes
162
+
163
+ def initialize
164
+ @nodes = {}
165
+ @links = []
166
+ end
167
+
168
+ def clean_up(&bl)
169
+ selnodes = []
170
+ @nodes.each do |k,n|
171
+ ret = bl.call(n)
172
+ selnodes << n if ret
173
+ end
174
+ selnodes.each do |n|
175
+ if n.incoming > 1 || n.outgoing > 1
176
+ raise "#{n.inspect} - not a simple node to remove"
177
+ end
178
+ to,from = nil
179
+ @links.each do |f|
180
+ to = f if f.to == n.id
181
+ from = f if f.from == n.id
182
+ end
183
+ if to && from
184
+ to.to = from.to
185
+ @links.delete(from)
186
+ @nodes.delete(n.id)
187
+ else
188
+ raise "#{n.inspect} - could not remove flow"
189
+ end
190
+ end
191
+ end
192
+
193
+ def find_script_id(s)
194
+ @nodes.find_all{|k,n| n.script_id == s}
195
+ end
196
+
197
+ def add_node(n)
198
+ @nodes[n.id] = n
199
+ end
200
+
201
+ def link(f,t)
202
+ @links.find{ |x| x.from == f && x.to == t }
203
+ end
204
+
205
+ def add_link(l)
206
+ @links << l
207
+ end
208
+
209
+ def next_nodes(from)
210
+ links = @links.find_all { |x| x.from == from.id }
211
+ links.map{|x| @nodes[x.to] }
212
+ end
213
+
214
+ def next_node(from)
215
+ if (nodes = next_nodes(from)).length == 1
216
+ nodes.first
217
+ else
218
+ raise "#{from.inspect} - multiple outgoing connections"
219
+ end
220
+ end
221
+ end #}}}
222
+
223
+ class Tree < Array #{{{
224
+ def condition?; false; end
225
+
226
+ def to_s
227
+ "TREE:\n" << print_tree(self)
228
+ end
229
+
230
+ def print_tree(ele,indent=' ')
231
+ ret = ''
232
+ ele.each_with_index do |e,i|
233
+ last = (i == ele.length - 1)
234
+ pchar = last ? '└' : '├'
235
+ if e.container?
236
+ ret << indent + pchar + ' ' + e.class.to_s.gsub(/[^:]*::/,'') + "\n"
237
+ ret << print_tree(e,indent + (last ? ' ' : '│ '))
238
+ elsif e.is_a?(Break) &&
239
+ ret << indent + pchar + ' ' + e.class.to_s.gsub(/[^:]*::/,'') + "\n"
240
+ else
241
+ ret << indent + pchar + ' ' + e.niceid.to_s + "\n"
242
+ end
243
+ end
244
+ ret
245
+ end
246
+ private :print_tree
247
+ end #}}}
248
+
249
+ class Traces < Array #{{{
250
+ def initialize_copy(other)
251
+ super
252
+ self.map!{ |t| t.dup }
253
+ end
254
+
255
+ def remove(trcs)
256
+ trcs.each do |t|
257
+ self.delete(t)
258
+ end
259
+ end
260
+
261
+ def remove_empty
262
+ self.delete_if{|t| t.empty? }
263
+ end
264
+
265
+ def first_node
266
+ self.first.first
267
+ end
268
+ def second_nodes
269
+ self.map { |t| t[1] }
270
+ end
271
+
272
+ def shortest
273
+ self.min_by{|e|e.length}
274
+ end
275
+
276
+ def to_s
277
+ "TRACES: " + self.collect { |t| t.empty? ? '∅' : t.collect{|n| "%2d" % n.niceid }.join('→ ') }.join("\n ")
278
+ end
279
+
280
+ def shift_all
281
+ self.each{ |tr| tr.shift }
282
+ end
283
+
284
+ def finished?
285
+ self.reduce(0){|sum,t| sum += t.length} == 0
286
+ end
287
+
288
+ def same_first
289
+ (n = self.map{|t| t.first }.uniq).length == 1 ? n.first : nil
290
+ end
291
+
292
+ def include_in_all?(e)
293
+ num = 0
294
+ self.each{|n| num += 1 if n.include?(e)}
295
+ num == self.length
296
+ end
297
+
298
+ def add_breaks
299
+ trueloops = self.find_all{ |t| t.last == t.first }.length
300
+ if trueloops == self.length
301
+ self << [self.first_node] ### the blank conditional so that we get a break
302
+ else
303
+ self.each do |t|
304
+ t << Break.new(1) unless t.last == t.first ### an explicit break
305
+ end
306
+ end
307
+ end
308
+
309
+ def loops
310
+ lo = Traces.new self.find_all{ |t| t.first == t.last }
311
+ self.each do |t|
312
+ lo << t if lo.second_nodes.include?(t[1])
313
+ end
314
+ lo.uniq
315
+ end
316
+
317
+ def eliminate(loops)
318
+ ### find nested loops
319
+ self.each_with_index do |t,i|
320
+ maxcut = 0
321
+ ### find out which common parts the traces share with theloops
322
+ loops.each do |l|
323
+ maxcut.upto(l.length) do |i|
324
+ maxcut = i if t[0...i] == l[0...i]
325
+ end
326
+ end
327
+ ### in case of nested loop (common part occurs at end of loop), include the whole
328
+ 0.upto (maxcut-1) do |j|
329
+ if self[i][j] == self[i].last
330
+ loops << self[i].shift(self[i].length)
331
+ end
332
+ end
333
+ end
334
+ loops.uniq!
335
+ loops.remove_empty
336
+ self.remove_empty
337
+
338
+ ### cut from non-nested loops
339
+ self.each_with_index do |t,i|
340
+ maxcut = 0
341
+ ### find out which common parts the traces share with theloops
342
+ loops.each do |l|
343
+ maxcut.upto(l.length) do |i|
344
+ maxcut = i if t[0...i] == l[0...i]
345
+ end
346
+ end
347
+ loops << self[i].shift(maxcut)
348
+ end
349
+ end
350
+
351
+ def extend
352
+ # find largest common
353
+ max = nil
354
+ sh = self.shortest
355
+ sh = sh[0..-2] if sh.first == sh.last
356
+ sh.each do |e,i|
357
+ if self.include_in_all?(e)
358
+ max = e
359
+ else
360
+ break
361
+ end
362
+ end
363
+
364
+ # if last is the largest common do nothing
365
+ # else append from last to largest common
366
+ self.each do |t|
367
+ unless t.last == max
368
+ last = t.last
369
+ t.last.incoming = 1
370
+ if t.index(last) && t.index(max)
371
+ (t.index(last) + 1).upto(t.index(max)) do |i|
372
+ t << t[i]
373
+ end
374
+ end
375
+ end
376
+ end
377
+
378
+ max.incoming = self.length
379
+ max
380
+ end
381
+
382
+ def segment_by_loops(loops)
383
+ # supress loops
384
+ self.delete_if { |t| loops.include?(t) }
385
+ self.eliminate(loops)
386
+ loops.extend
387
+ end
388
+
389
+ def find_endnode
390
+ # supress loops
391
+ trcs = self.dup
392
+ trcs.delete_if { |t| t.uniq.length < t.length }
393
+
394
+ # find common node (except loops)
395
+ enode = nil
396
+ trcs.first.each do |n|
397
+ if trcs.include_in_all?(n)
398
+ enode = n
399
+ break
400
+ end
401
+ end
402
+ enode
403
+ end
404
+
405
+ def segment_by(endnode)
406
+ # cut shit until common node, return the shit you cut away
407
+ tracesgroup = self.group_by{|t| t.first}.map do |k,trace|
408
+ coltrace = trace.map do |t|
409
+ # slice upto common node, collect the sliced away part
410
+ len = t.index(endnode)
411
+ if len
412
+ cut = t.slice!(0...len)
413
+ cut << t.first
414
+ else # if endnode is nil, then return the whole
415
+ t
416
+ end
417
+ end.uniq
418
+ Traces.new(coltrace)
419
+ end
420
+ [tracesgroup,endnode]
421
+ end
422
+ end #}}}
423
+
424
+ end
425
+
426
+ end