File Coverage

blib/lib/Algorithm/Merge.pm
Criterion Covered Total %
statement 267 279 95.7
branch 95 108 87.9
condition 49 60 81.6
subroutine 29 35 82.8
pod 3 4 75.0
total 443 486 91.1


line stmt bran cond sub pod time code
1             package Algorithm::Merge;
2              
3 3     3   5385 use Algorithm::Diff ();
  3         16563  
  3         63  
4 3     3   22 use Carp;
  3         6  
  3         285  
5 3     3   24 use strict;
  3         6  
  3         88  
6 3     3   228811 use Data::Dumper;
  3         24271  
  3         277  
7              
8 3     3   28 use vars qw(@EXPORT_OK @ISA $VERSION $REVISION);
  3         9  
  3         2676  
9              
10             $VERSION = '0.08';
11              
12             $REVISION = (qw$Revision: 1.11 $)[-1];
13              
14             @EXPORT_OK = qw(diff3 merge traverse_sequences3);
15              
16             @ISA = qw(Exporter);
17              
18             sub diag {
19 1547 50   1547 0 3584 main::diag(@_) if($Algorithm::Merge::DEBUG);
20             }
21              
22             sub diff3 {
23 61     61 1 18027 my $pivot = shift; # array ref
24 61         75 my $doca = shift; # array ref
25 61         72 my $docb = shift; # array ref
26 61         92 my $keyGen = shift;
27              
28 61         64 my @ret;
29              
30 61 100 100     193 if(@$doca == 0 && @$docb == 0 && @$pivot == 0) {
      100        
31 1         7 return [ [ ] ];
32             }
33              
34 60         81 my $no_change;
35              
36             # if($keyGen) {
37             # $no_change = sub {
38             # if($keyGen->($pivot -> [$_[0]]) ne $keyGen->($doca -> [$_[1]])
39             # || $keyGen->($pivot -> [$_[0]]) ne $keyGen->($docb -> [$_[2]])
40             # || $keyGen->($doca -> [$_[1]]) ne $keyGen->($docb -> [$_[2]]))
41             # {
42             # croak "No change detected, but elements differ between sequences. Please submit a bug report to jsmith\@cpan.org with a description of the set of sequences which lead to this error.\n";
43             # }
44             # push @ret, [ 'u', $pivot -> [$_[0]], $doca -> [$_[1]], $docb -> [$_[2]] ];
45             # };
46             # }
47             # else {
48             $no_change = sub {
49             # if($pivot -> [$_[0]] ne $doca -> [$_[1]]
50             # || $pivot -> [$_[0]] ne $docb -> [$_[2]]
51             # || $doca -> [$_[1]] ne $docb -> [$_[2]])
52             # {
53             # croak "No change detected, but elements differ between sequences. Please submit a bug report to jsmith\@cpan.org with a description of the set of sequences which lead to this error.\n";
54             # }
55 161     161   615 push @ret, [ 'u', $pivot -> [$_[0]], $doca -> [$_[1]], $docb -> [$_[2]] ];
56 60         247 };
57             # }
58              
59             my $conflict = sub {
60 31     31   41 my($a, $b, $c);
61 31 100       97 $a = $pivot -> [$_[0]] if defined $_[0];
62 31 100       86 $b = $doca -> [$_[1]] if defined $_[1];
63 31 100       76 $c = $docb -> [$_[2]] if defined $_[2];
64 31         117 push @ret, [ 'c', $a, $b, $c ];
65 60         217 };
66              
67             my $diff_a = sub {
68 46 100   46   131 if(@_ == 1) {
    100          
    50          
69 26         97 push @ret, [ 'o', $pivot -> [$_[0]], undef, undef ];
70             }
71             elsif(@_ == 2) {
72 15         50 push @ret, [ 'o', undef, $doca -> [$_[0]], $docb -> [$_[1]] ];
73             }
74             elsif(@_ == 3) {
75 5         25 push @ret, [ 'o', $pivot -> [$_[0]], $doca -> [$_[1]], $docb -> [$_[2]] ];
76             }
77 60         202 };
78              
79             my $diff_b = sub {
80 46 100   46   166 if(@_ == 1) {
    100          
    50          
81 14         50 push @ret, [ 'l', undef, $doca -> [$_[0]], undef ];
82             }
83             elsif(@_ == 2) {
84 22         85 push @ret, [ 'l', $pivot -> [$_[0]], undef, $docb -> [$_[1]] ];
85             }
86             elsif(@_ == 3) {
87 10         38 push @ret, [ 'l', $pivot -> [$_[0]], $doca -> [$_[1]], $docb -> [$_[2]] ];
88             }
89 60         189 };
90              
91             my $diff_c = sub {
92 46 100   46   158 if(@_ == 1) {
    100          
    50          
93 13 50       74 push @ret, [ 'r', undef, undef, (defined($_[0]) ? $docb -> [$_[0]] : undef) ];
94             }
95             elsif(@_ == 2) {
96 20 50       112 push @ret, [ 'r', (defined($_[0]) ? $pivot -> [$_[0]] : undef), (defined($_[1]) ? $doca -> [$_[1]] : undef), undef ];
    50          
97             }
98             elsif(@_ == 3) {
99 13 50       101 push @ret, [ 'r', (defined($_[0]) ? $pivot -> [$_[0]] : undef), (defined($_[1]) ? $doca -> [$_[1]] : undef), (defined($_[0]) ? $docb -> [$_[2]] : undef)];
    100          
    50          
100             }
101 60         192 };
102              
103 60         395 traverse_sequences3(
104             $pivot, $doca, $docb,
105             {
106             NO_CHANGE => $no_change,
107             A_DIFF => $diff_a,
108             B_DIFF => $diff_b,
109             C_DIFF => $diff_c,
110             CONFLICT => $conflict,
111             },
112             $keyGen, @_
113             );
114              
115 60 50       197 if(wantarray) {
116 0         0 return @ret;
117             }
118             else {
119 60         1387 return \@ret;
120             }
121             }
122              
123 3     3   21 use constant A => 4;
  3         6  
  3         609  
124 3     3   20 use constant B => 2;
  3         12  
  3         680  
125 3     3   597 use constant C => 1;
  3         6  
  3         145  
126 3     3   14 use constant D => 8; # should be an undef
  3         5  
  3         132  
127              
128 3     3   17 use constant AB_A => 32;
  3         4  
  3         143  
129 3     3   15 use constant AB_B => 16;
  3         5  
  3         112  
130 3     3   643 use constant AC_A => 8;
  3         5  
  3         123  
131 3     3   15 use constant AC_C => 4;
  3         5  
  3         108  
132 3     3   14 use constant BC_B => 2;
  3         3  
  3         98  
133 3     3   19 use constant BC_C => 1;
  3         5  
  3         102  
134 3     3   13 use constant CB_C => 3; # not used in calculations
  3         5  
  3         113  
135 3     3   13 use constant CB_B => 5; # not used in calculations
  3         5  
  3         11992  
136              
137             my @abc_s;
138             $abc_s[(A|B)*8+A] = AB_A;
139             $abc_s[(A|B)*8+B] = AB_B;
140             $abc_s[(A|C)*8+A] = AC_A;
141             $abc_s[(A|C)*8+C] = AC_C;
142             $abc_s[(B|C)*8+B] = BC_B;
143             $abc_s[(B|C)*8+C] = BC_C;
144              
145             sub traverse_sequences3 {
146 60     60 1 93 my $adoc = shift; # array ref
147 60         71 my $bdoc = shift; # array ref
148 60         79 my $cdoc = shift; # array ref
149 60   50     128 my $callbacks = shift || {};
150 60         78 my $keyGen = shift;
151 60   50 0   156 my $a_diff = $callbacks->{'A_DIFF'} || sub { };
  0         0  
152 60   50 0   138 my $b_diff = $callbacks->{'B_DIFF'} || sub { };
  0         0  
153 60   50 0   128 my $c_diff = $callbacks->{'C_DIFF'} || sub { };
  0         0  
154 60   50 0   142 my $no_change = $callbacks->{'NO_CHANGE'} || sub { };
  0         0  
155 60   50 0   110 my $conflict = $callbacks->{'CONFLICT'} || sub { };
  0         0  
156              
157 60         61 my $b_len = scalar(@{$bdoc});
  60         104  
158 60         65 my $c_len = scalar(@{$cdoc});
  60         75  
159 60 100       124 my $target_len = $b_len < $c_len ? $b_len : $c_len;
160 60         90 my $bc_different_lengths = $b_len != $c_len;
161              
162 60         60 my(@bdoc_save, @cdoc_save);
163              
164             # make these into traverse_sequences calls
165 0         0 my($left, $right);
166 0         0 my %diffs;
167              
168             my $ts_callbacks = {
169             DISCARD_A => sub { # discard left
170 384     384   23947 push @{$diffs{$left}}, $_[0];
  384         1261  
171             },
172             DISCARD_B => sub { # discard right
173 352     352   8625 push @{$diffs{$right}}, $_[1];
  352         1087  
174             },
175 60         355 };
176              
177 60         180 @diffs{(AB_A, AB_B)} = ([], []);
178 60         89 $left = AB_A; $right = AB_B;
  60         74  
179 60         191 Algorithm::Diff::traverse_sequences( $adoc, $bdoc, $ts_callbacks, $keyGen, @_);
180              
181 60         1282 @diffs{(AC_A, AC_C)} = ([], []);
182 60         87 $left = AC_A; $right = AC_C;
  60         76  
183 60         164 Algorithm::Diff::traverse_sequences( $adoc, $cdoc, $ts_callbacks, $keyGen, @_);
184              
185 60 100       1098 if($bc_different_lengths) {
186            
187 35         109 @diffs{(CB_C, CB_B)} = ([], []);
188 35         64 $left = CB_C; $right = CB_B;
  35         51  
189 35         111 Algorithm::Diff::traverse_sequences( $cdoc, $bdoc, $ts_callbacks, $keyGen, @_);
190              
191 35         560 @diffs{(BC_B, BC_C)} = ([], []);
192 35         55 $left = BC_B; $right = BC_C;
  35         53  
193 35         100 Algorithm::Diff::traverse_sequences( $bdoc, $cdoc, $ts_callbacks, $keyGen, @_);
194              
195 35 100 66     434 if(join(",", @{$diffs{&CB_B}}) ne join(",", @{$diffs{&BC_B}}) ||
  35         140  
  35         172  
  31         112  
196 31         179 join(",", @{$diffs{&CB_C}}) ne join(",", @{$diffs{&BC_C}}))
197             {
198 4         8 @bdoc_save = splice @{$bdoc}, $target_len;
  4         15  
199 4         7 @cdoc_save = splice @{$cdoc}, $target_len;
  4         12  
200            
201 4         964 carp "Algorithm::Diff::diff is not symmetric for second and third sequences - results might not be correct";
202             }
203              
204 35         609 @diffs{(BC_B, BC_C)} = ([], []);
205 35         77 $left = BC_B; $right = BC_C;
  35         46  
206 35         111 Algorithm::Diff::traverse_sequences( $bdoc, $cdoc, $ts_callbacks, $keyGen, @_);
207              
208 35 100 100     593 if(scalar(@bdoc_save) || scalar(@cdoc_save)) {
209 4 100       13 push @{$diffs{&BC_B}}, ($target_len .. $b_len) if $target_len < $b_len;
  2         10  
210 4 100       19 push @{$diffs{&BC_C}}, ($target_len .. $c_len) if $target_len < $c_len;
  2         10  
211            
212 4         8 push @{$bdoc}, @bdoc_save; undef @bdoc_save;
  4         7  
  4         10  
213 4         5 push @{$cdoc}, @cdoc_save; undef @cdoc_save;
  4         7  
  4         9  
214             }
215             }
216             else {
217 25         88 @diffs{(BC_B, BC_C)} = ([], []);
218 25         39 $left = BC_B; $right = BC_C;
  25         31  
219 25         62 Algorithm::Diff::traverse_sequences( $bdoc, $cdoc, $ts_callbacks, $keyGen, @_);
220             }
221              
222 60         442 my @pos;
223 60         141 @pos[A, B, C] = (0, 0, 0);
224              
225 60         82 my @sizes;
226 60         63 @sizes[A, B, C] = ( scalar(@{$adoc}), scalar(@{$bdoc}), scalar(@{$cdoc}) );
  60         89  
  60         76  
  60         135  
227              
228 60         79 my @matches;
229 60         159 $#matches = 32;
230              
231 60         83 my $callback = 0;
232              
233 60     3   216 my $noop = sub { };
  3         5  
234              
235             # Callback_Map is indexed by the sum of AB_A, AB_B, ..., as indicated by @matches
236             # this isn't the most efficient, but it's a bit easier to maintain and
237             # read than if it were broken up into separate arrays
238             # half the entries are not $noop - it would seem then that no
239             # entries should be $noop. I need patterns to figure out what the
240             # other entries are.
241              
242 60         2577 my @Callback_Map = (
243             [ $no_change, A, B, C ], # 0 - no matches
244             #[ $noop, ], # 1 - BC_C
245             [ $b_diff, A, C ], # 1 - BC_C
246             [ $b_diff, B ], #*2 - BC_B
247             [ $noop, ], # 3 - BC_B BC_C
248             [ $noop, ], # 4 - AC_C
249             [ $c_diff, C ], # 5 - AC_C BC_C
250             [ $noop, ], # 6 - AC_C BC_B
251             [ $noop, ], # 7 - AC_C BC_B BC_C
252             [ $a_diff, A ], # 8 - AC_A
253             [ $noop, ], # 9 - AC_A BC_C
254             [ $c_diff, A, B ], # 10 - AC_A BC_B
255             [ $c_diff, A, B, ], # 11 - AC_A BC_B BC_C
256             [ $noop, ], # 12 - AC_A AC_C
257             [ $noop, ], # 13 - AC_A AC_C BC_C
258             [ $c_diff, A, B, ], # 14 - AC_A AC_C BC_B
259             [ $c_diff, A, B, C ], # 15 - AC_A AC_C BC_B BC_C
260             [ $noop, ], # 16 - AB_B
261             [ $no_change, ], # 17 - AB_B BC_C
262             [ $b_diff, B ], # 18 - AB_B BC_B
263             [ $noop, ], # 19 - AB_B BC_B BC_C
264             [ $a_diff, B, C ], # 20 - AB_B AC_C
265             [ $noop, ], # 21 - AB_B AC_C BC_C
266             [ $noop, ], # 22 - AB_B AC_C BC_B
267             [ $conflict, D, B, C ], # 23 - AB_B AC_C BC_B BC_C
268             [ $b_diff, B ], # 24 - AB_B AC_A
269             [ $noop, ], # 25 - AB_B AC_A BC_C
270             [ $c_diff, D, B, C ], # 26 - AB_B AC_A BC_B
271             [ $noop, ], # 27 - AB_B AC_A BC_B BC_C
272             [ $a_diff, B, C ], # 28 - AB_B AC_A AC_C
273             [ $noop, ], # 29 - AB_B AC_A AC_C BC_C
274             [ $noop, ], # 30 - AB_B AC_A AC_C BC_B
275             [ $b_diff, B ], # 31 - AB_B AC_A AC_C BC_B BC_C
276             [ $no_change, A, B, C ], # 32 - AB_A
277             [ $b_diff, A, C ], # 33 - AB_A BC_C
278             [ $noop, ], # 34 - AB_A BC_B
279             [ $b_diff, A, C ], # 35 - AB_A BC_B BC_C
280             [ $noop, ], # 36 - AB_A AC_C
281             [ $noop, ], # 37 - AB_A AC_C BC_C
282             [ $noop, ], # 38 - AB_A AC_C BC_B
283             [ $noop, ], # 39 - AB_A AC_C BC_B BC_C
284             [ $a_diff, A, ], # 40 - AB_A AC_A
285             [ $noop, ], # 41 - AB_A AC_A BC_C
286             [ $a_diff, A ], # 42 - AB_A AC_A BC_B
287             [ $noop, ], # 43 - AB_A AC_A BC_B BC_C
288             [ $noop, ], # 44 - AB_A AC_A AC_C
289             [ $c_diff, A, D, C ], # 45 - AB_A AC_A AC_C BC_C
290             [ $noop, ], # 46 - AB_A AC_A AC_C BC_B
291             [ $noop, ], # 47 - AB_A AC_A AC_C BC_B BC_C
292             [ $noop, ], # 48 - AB_A AB_B
293             [ $b_diff, A, C ], # 49 - AB_A AB_B BC_C
294             [ $noop, ], # 50 - AB_A AB_B BC_B
295             [ $b_diff, A, B, C ], # 51 - AB_A AB_B BC_B BC_C
296             [ $a_diff, B, C ], # 52 - AB_A AB_B AC_C
297             [ $noop, ], # 53 - AB_A AB_B AC_C BC_C
298             [ $noop, ], # 54 - AB_A AB_B AC_C BC_B
299             [ $c_diff, C ], # 55 - AB_A AB_B AC_C BC_B BC_C
300             [ $b_diff, A, C ], # 56 - AB_A AB_B AC_A
301             [ $noop, ], # 57 - AB_A AB_B AC_A BC_C
302             [ $b_diff, A, B, D ], # 58 - AB_A AB_B AC_A BC_B
303             [ $noop, ], # 59 - AB_A AB_B AC_A BC_B BC_C
304             [ $a_diff, A, B, C ], # 60 - AB_A AB_B AC_A AC_C
305             [ $conflict, A, D, C ], # 61 - AB_A AB_B AC_A AC_C BC_C
306             [ $conflict, A, B, D ], # 62 - AB_A AB_B AC_A AC_C BC_B
307             [ $conflict, A, B, C ], # 63 - AB_A AB_B AC_A AC_C BC_B BC_C
308             );
309              
310 60         187 my $t; # temporary values
311              
312             # while we have something to work with...
313 60   100     151 while((grep { scalar(@{$_}) > 0 } values %diffs)
  2756         2588  
  2756         6672  
  1032         2791  
314             && (grep { $pos[$_] < $sizes[$_] } (A, B, C)))
315             {
316              
317 309         665 @matches[AB_A, AB_B, AC_A, AC_C, BC_B, BC_C] = undef;
318              
319 309         465 foreach my $i (A, B, C) {
320 927         1166 foreach my $j (A, B, C) {
321 2781 100       5732 next if $i == $j;
322 1854         2873 $t = $abc_s[($i|$j) * 8 | $i];
323 1854 100 100     2109 $matches[$t] = 1 if @{$diffs{$t}} && $pos[$i] == $diffs{$t} -> [0];
  1854         8355  
324             }
325             }
326            
327 309         389 $callback = 0;
328 309         432 $callback |= $_ foreach grep { $matches[$_] } ( AB_A, AB_B, AC_A, AC_C, BC_B, BC_C );
  1854         3050  
329              
330 309         381 my @args = @{$Callback_Map[$callback]};
  309         941  
331 309 100       666 diag(">>>>>> We hit a noop") if @args == 1;
332 309         414 my $f = shift @args;
333 309         1631 diag(join "", "callback: $callback - \@pos: ", join(", ", @pos[A, B, C]), "\n");
334 309 100       718 diag(">>>>>> Callback is a no-op") unless @args;
335 309 100       665 diag(join "", " matches: ", join(", ", map { defined($_) ? $_ : 'undef' } @matches[AB_A, AB_B, AC_A, AC_C, BC_B, BC_C]), "\n");
  1854         4516  
336 309 100       630 diag(join "", " diffs: ", join(", ", map { defined($_) ? $_ : 'undef' } map { $diffs{$_}->[0] } (AB_A, AB_B, AC_A, AC_C, BC_B, BC_C)), "\n");
  1854         4314  
  1854         3366  
337 309 100       725 diag(join "", "args: ", join(", ", map { (qw(- C B - A - - - D))[$_] } @args), "(", join(", ", map { defined($_) ? $_ : 'undef' } @pos[@args]), ")\n");
  762         1878  
  762         2140  
338 309         686 diag('--------------------');
339 309         399 &{$f}(@pos[@args]);
  309         607  
340 309         581 foreach (@args) {
341 762 100       1673 $pos[$_]++ unless $_ == D;
342 762 100       2150 if($_ eq A) {
    100          
    100          
343 259   100     371 shift @{$diffs{&AB_A}} while @{$diffs{&AB_A}} && $diffs{&AB_A}[0] < $pos[$_];# if $matches[AB_A];
  350         5952  
  91         221  
344 259   100     602 shift @{$diffs{&AC_A}} while @{$diffs{&AC_A}} && $diffs{&AC_A}[0] < $pos[$_];#if $matches[AC_A];
  348         1895  
  89         208  
345             } elsif($_ eq B) {
346 241   100     286 shift @{$diffs{&AB_B}} while @{$diffs{&AB_B}} && $diffs{&AB_B}[0] < $pos[$_];#if $matches[AB_B];
  314         1512  
  73         193  
347 241   100     315 shift @{$diffs{&BC_B}} while @{$diffs{&BC_B}} && $diffs{&BC_B}[0] < $pos[$_];#if $matches[BC_B];
  323         1701  
  82         204  
348             } elsif($_ eq C) {
349 245   100     252 shift @{$diffs{&AC_C}} while @{$diffs{&AC_C}} && $diffs{&AC_C}[0] < $pos[$_];#if $matches[AC_C];
  320         1561  
  75         164  
350 245   100     306 shift @{$diffs{&BC_C}} while @{$diffs{&BC_C}} && $diffs{&BC_C}[0] < $pos[$_];#if $matches[BC_C];
  331         2193  
  86         189  
351             }
352             }
353 309 100       1448 last unless @args;
354             }
355              
356 60         70 my $switch;
357             my @args;
358              
359 60         91 while(grep { $pos[$_] < $sizes[$_] } (A, B, C)) {
  252         2282  
360 24         28 $switch = 0;
361 24         36 @args = ();
362 24         41 foreach my $i (A, B, C) {
363 72 100       145 if($pos[$i] < $sizes[$i]) {
364             #warn "$i: $pos[$i] < $sizes[$i]\n";
365 67         79 $switch |= $i;
366             #warn "switch: $switch\n";
367 67         139 push @args, $pos[$i]++;
368             }
369             }
370              
371 24         34 my $match = $switch;
372 24         35 $switch = ( 0, 5, 24, 17, 34, 8, 10, 0 )[$switch];
373             #main::diag(join"", "callback: $switch - \@pos: ", join(", ", @pos[A, B, C]));
374             #main::diag(join"", " match: $match");
375 24 50       59 &{$Callback_Map[$switch][0]}(@args)
  24         57  
376             if $Callback_Map[$switch];
377             }
378             }
379              
380             sub merge {
381 40     40 1 39767 my $pivot = shift; # array ref
382 40         72 my $doca = shift; # array ref
383 40         53 my $docb = shift; # array ref
384 40   50     106 my $callbacks = shift || {};
385 40         56 my $keyGen = shift;
386              
387             my $conflictCallback = $callbacks -> {'CONFLICT'} || sub ($$) { (
388 0           q{},
389 0           (@{$_[0]}),
390             q{},
391 0     0     (@{$_[1]}),
392             q{},
393 40   50     116 ) };
394              
395 40         103 my $diff = diff3($pivot, $doca, $docb, $keyGen, @_);
396              
397             # print Data::Dumper -> Dump([$diff]), "\n";
398              
399 40         57 my @ret;
400              
401 40         97 my @conflict = ( [], [] );
402              
403 40         60 foreach my $h (@{$diff}) {
  40         141  
404 282         321 my $i = 0;
405             #print "op: ", $h -> [0];
406 282 100       510 if($h -> [0] eq 'c') { # conflict
407 22 100       61 push @{$conflict[0]}, $h -> [2] if defined $h -> [2];
  21         54  
408 22 100       61 push @{$conflict[1]}, $h -> [3] if defined $h -> [3];
  21         57  
409             }
410             else {
411 260 100 100     251 if(@{$conflict[0]} || @{$conflict[1]}) {
  260         1058  
  243         690  
412 18         64 push @ret, &$conflictCallback(@conflict);
413 18         190 @conflict = ( [], [] );
414             }
415 260 100       729 if($h -> [0] eq 'u') { # unchanged
    100          
    100          
    50          
416 140   66     563 push @ret, $h -> [2] || $h -> [3];
417             }
418             elsif($h -> [0] eq 'o') { # added
419 41 100       138 push @ret, $h -> [2] if defined $h -> [2];
420             }
421             elsif($h -> [0] eq 'l') { # added by left
422 39 100       107 push @ret, $h -> [2] if defined $h -> [2];
423             }
424             elsif($h -> [0] eq 'r') { # added by right
425 40 100       120 push @ret, $h -> [3] if defined $h -> [3];
426             }
427             }
428             #print " : ", join(" ", @ret), " [$$h[1],$$h[2],$$h[3]]\n";
429             }
430              
431 40 100 66     58 if(@{$conflict[0]} || @{$conflict[1]}) {
  40         92  
  38         107  
432 2         8 push @ret, &$conflictCallback(@conflict);
433             }
434              
435 40 50       107 if(wantarray) {
436 0         0 return @ret;
437             }
438 40         489 return \@ret;
439             }
440              
441              
442             __END__