|  line  | 
 stmt  | 
 bran  | 
 cond  | 
 sub  | 
 pod  | 
 time  | 
 code  | 
| 
1
 | 
  
 
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 package Chorus::Frame;  | 
| 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
3
 | 
7
 | 
 
 | 
 
 | 
  
7
  
 | 
 
 | 
135035
 | 
 use 5.006;  | 
| 
 
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
28
 | 
    | 
| 
4
 | 
7
 | 
 
 | 
 
 | 
  
7
  
 | 
 
 | 
38
 | 
 use strict;  | 
| 
 
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
13
 | 
    | 
| 
 
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
413
 | 
    | 
| 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 our $VERSION = '1.03';  | 
| 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 NAME  | 
| 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Chorus::Frame - A short implementation of frames from knowledge representation.   | 
| 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 VERSION  | 
| 
13
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Version 1.04  | 
| 
15
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
16
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut  | 
| 
17
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
18
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 SYNOPSIS  | 
| 
19
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
20
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   use Chorus::Frame;  | 
| 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           | 
| 
22
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   my $f1 = Chorus::Frame->new(  | 
| 
23
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
      b => {  | 
| 
24
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       	     _DEFAULT => 'inherited default for b'  | 
| 
25
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           }	  | 
| 
26
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   );  | 
| 
27
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
28
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   my $f2 = Chorus::Frame->new(  | 
| 
29
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     a => {   | 
| 
30
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
            b1 => sub { $SELF->get('a b2') }, # procedural attachment using context $SELF  | 
| 
31
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
            b2 => {  | 
| 
32
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                    _ISA    => $f1->{b},  | 
| 
33
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                    _NEEDED => 'needed for b  # needs mode Z to precede inherited _DEFAULT  | 
| 
34
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                  }  | 
| 
35
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
          }       | 
| 
36
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   );  | 
| 
37
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                       | 
| 
38
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   Chorus::Frame::setMode(GET => 'N');  | 
| 
39
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   print $f2->get('a b1') . "\n";       # print 'inherited default for b'  | 
| 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
41
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   Chorus::Frame::setMode(GET => 'Z');  | 
| 
42
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   print $f2->get('a b1') . "\n";       # print 'needed for b'  | 
| 
43
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     | 
| 
44
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut  | 
| 
45
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
46
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 DESCRIPTION  | 
| 
47
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
48
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   - A frame is a generic object structure described by slots (properties).  | 
| 
49
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   - A frame can inherit slots from other frames.  | 
| 
50
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   - A frame can have specific slots describing :  | 
| 
51
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     | 
| 
52
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     * how it can be associated to a target information,   | 
| 
53
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     * how he reacts when its target information changes  | 
| 
54
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     * what it can try when a missing property is requested.  | 
| 
55
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         | 
| 
56
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   - The slots _VALUE,_DEFAULT,_NEEDED are tested in this order to obtain the target information   | 
| 
57
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     of a given frame (can be inherited).  | 
| 
58
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   - Two other special slots _BEFORE & _AFTER can define what a frame has to do before or after   | 
| 
59
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     one of its properties changes.  | 
| 
60
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   - The slot _ISA is used to define the inheritance.   | 
| 
61
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
62
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   Two modes 'N' (default) or 'Z' are used to define the priority between a frame and its inherited   | 
| 
63
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   frames in order to process its target information  | 
| 
64
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                | 
| 
65
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   The globale variable $SELF returns the current CONTEXT which is the most recent frame called for the method get().  | 
| 
66
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   A slot defined by a function sub { .. } can refer to the current context $SELF in its body.  | 
| 
67
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     | 
| 
68
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   All frames are automaticaly referenced in a repository used to optimise the selection of frames for a given action.  | 
| 
69
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   The function fmatch() can be used to quicly select all the frames responding to a given test on their properties.    | 
| 
70
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut  | 
| 
71
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
72
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 BEGIN {  | 
| 
73
 | 
7
 | 
 
 | 
 
 | 
  
7
  
 | 
 
 | 
37
 | 
   use Exporter;  | 
| 
 
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
15
 | 
    | 
| 
 
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
422
 | 
    | 
| 
74
 | 
7
 | 
 
 | 
 
 | 
  
7
  
 | 
 
 | 
39
 | 
   use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);  | 
| 
 
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
13
 | 
    | 
| 
 
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
807
 | 
    | 
| 
75
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
76
 | 
7
 | 
 
 | 
 
 | 
  
7
  
 | 
 
 | 
69
 | 
   @ISA         = qw(Exporter);  | 
| 
77
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
17
 | 
   @EXPORT      = qw($SELF &fmatch REQUIRE_FAILED);  | 
| 
78
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
142
 | 
   @EXPORT_OK   = qw(%FMAP);	  | 
| 
79
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
80
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # %EXPORT_TAGS = ( );		# eg: TAG => [ qw!name1 name2! ];  | 
| 
81
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
82
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
83
 | 
7
 | 
 
 | 
 
 | 
  
7
  
 | 
 
 | 
46
 | 
 use strict;  | 
| 
 
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
37
 | 
    | 
| 
 
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
251
 | 
    | 
| 
84
 | 
7
 | 
 
 | 
 
 | 
  
7
  
 | 
 
 | 
36
 | 
 use Carp;			# warn of errors (from perspective of caller)  | 
| 
 
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
12
 | 
    | 
| 
 
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
473
 | 
    | 
| 
85
 | 
7
 | 
 
 | 
 
 | 
  
7
  
 | 
 
 | 
35
 | 
 use Digest::MD5;  | 
| 
 
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
14
 | 
    | 
| 
 
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
337
 | 
    | 
| 
86
 | 
7
 | 
 
 | 
 
 | 
  
7
  
 | 
 
 | 
36
 | 
 use Scalar::Util qw(weaken);  | 
| 
 
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
11
 | 
    | 
| 
 
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
517
 | 
    | 
| 
87
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
88
 | 
7
 | 
 
 | 
 
 | 
  
7
  
 | 
 
 | 
7871
 | 
 use Data::Dumper;  | 
| 
 
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
80320
 | 
    | 
| 
 
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
503
 | 
    | 
| 
89
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
90
 | 
7
 | 
 
 | 
 
 | 
  
7
  
 | 
 
 | 
52
 | 
 use constant DEBUG_MEMORY => 0;  | 
| 
 
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
13
 | 
    | 
| 
 
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
429
 | 
    | 
| 
91
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
92
 | 
7
 | 
 
 | 
 
 | 
  
7
  
 | 
 
 | 
39
 | 
 use vars qw($AUTOLOAD);  | 
| 
 
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
12
 | 
    | 
| 
 
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
301
 | 
    | 
| 
93
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
94
 | 
7
 | 
 
 | 
 
 | 
  
7
  
 | 
 
 | 
42
 | 
 use constant SUCCESS        =>  1;  | 
| 
 
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
14
 | 
    | 
| 
 
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
325
 | 
    | 
| 
95
 | 
7
 | 
 
 | 
 
 | 
  
7
  
 | 
 
 | 
38
 | 
 use constant FAILED         =>  0;  | 
| 
 
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
12
 | 
    | 
| 
 
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
324
 | 
    | 
| 
96
 | 
7
 | 
 
 | 
 
 | 
  
7
  
 | 
 
 | 
36
 | 
 use constant REQUIRE_FAILED => -1;  | 
| 
 
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
15
 | 
    | 
| 
 
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
375
 | 
    | 
| 
97
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
98
 | 
7
 | 
 
 | 
 
 | 
  
7
  
 | 
 
 | 
35
 | 
 use constant VALUATION_ORDER => ('_VALUE', '_DEFAULT', '_NEEDED');  | 
| 
 
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
13
 | 
    | 
| 
 
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
359
 | 
    | 
| 
99
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
100
 | 
7
 | 
 
 | 
 
 | 
  
7
  
 | 
 
 | 
38
 | 
 use constant MODE_N => 1;  | 
| 
 
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
14
 | 
    | 
| 
 
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
299
 | 
    | 
| 
101
 | 
7
 | 
 
 | 
 
 | 
  
7
  
 | 
 
 | 
34
 | 
 use constant MODE_Z => 2;  | 
| 
 
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
14
 | 
    | 
| 
 
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
27545
 | 
    | 
| 
102
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
103
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 my $getMode = MODE_N;       # DEFAULT IS N !!!  | 
| 
104
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
105
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 my %REPOSITORY;  | 
| 
106
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 my %FMAP;  | 
| 
107
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 my %INSTANCES;  | 
| 
108
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
109
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 our $SELF;  | 
| 
110
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 my @Heap = ();  | 
| 
111
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
112
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub AUTOLOAD {  | 
| 
113
 | 
15
 | 
 
 | 
  
 33
  
 | 
  
15
  
 | 
 
 | 
129
 | 
   my $frame = shift || $SELF;  | 
| 
114
 | 
15
 | 
 
 | 
 
 | 
 
 | 
 
 | 
26
 | 
   my $slotName = $AUTOLOAD;  | 
| 
115
 | 
15
 | 
 
 | 
 
 | 
 
 | 
 
 | 
61
 | 
   $slotName =~ s/.*://;           # strip fully-qualified portion  | 
| 
116
 | 
15
 | 
 
 | 
 
 | 
 
 | 
 
 | 
43
 | 
   get($frame, $slotName, @_); # or getN or getZ !!  | 
| 
117
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
118
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
119
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub _isa {  | 
| 
120
 | 
482
 | 
 
 | 
 
 | 
  
482
  
 | 
 
 | 
814
 | 
   my ($ref, $str) = @_;  | 
| 
121
 | 
482
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1866
 | 
   return (ref($ref) eq $str);  | 
| 
122
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
123
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
124
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 SUBROUTINES  | 
| 
125
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut  | 
| 
126
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
127
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head2 setMode  | 
| 
128
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
129
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
  Defines the inheritance mode of methods get() for the special slots _VALUE,_DEFAULT,_NEEDED  | 
| 
130
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
  the default mode is 'N'.  | 
| 
131
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
      | 
| 
132
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'N' : ex. a single slot from the sequence _VALUE,_DEFAULT,_NEEDED will be tested in all inherited  | 
| 
133
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
               frames before trying the next one.  | 
| 
134
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 | 
| 
135
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'Z' : the whole sequence _VALUE,_DEFAULT,_NEEDED will be tested from the frame before being   | 
| 
136
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           tested from the inherited frames  | 
| 
137
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             | 
| 
138
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     ex. Chorus::Frame::setMode(GET => 'Z');  | 
| 
139
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
140
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut  | 
| 
141
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
142
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub setMode {  | 
| 
143
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
  
1
  
 | 
11
 | 
 	my (%opt) = @_;  | 
| 
144
 | 
2
 | 
  
100
  
 | 
  
 66
  
 | 
 
 | 
 
 | 
18
 | 
 	$getMode = MODE_N if defined($opt{GET}) and uc($opt{GET}) eq 'N';  | 
| 
145
 | 
2
 | 
  
100
  
 | 
  
 66
  
 | 
 
 | 
 
 | 
17
 | 
 	$getMode = MODE_Z if defined($opt{GET}) and uc($opt{GET}) eq 'Z';  | 
| 
146
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
147
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
148
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 METHODS  | 
| 
149
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut  | 
| 
150
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
151
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head2 _keys  | 
| 
152
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
153
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   my @k = $f->_keys;  | 
| 
154
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   same as CORE::keys but excludes the special slot '_KEY' specific to all frames  | 
| 
155
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut  | 
| 
156
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
157
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub _keys {  | 
| 
158
 | 
  
0
  
 | 
 
 | 
 
 | 
  
0
  
 | 
 
 | 
0
 | 
   my ($this) = @_;  | 
| 
159
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
   grep { $_ ne '_KEY' } keys %{$this};  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
160
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
161
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
162
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub pushself {  | 
| 
163
 | 
26
 | 
  
100
  
 | 
 
 | 
  
26
  
 | 
  
0
  
 | 
83
 | 
   unshift(@Heap, $SELF) if $SELF;  | 
| 
164
 | 
26
 | 
 
 | 
 
 | 
 
 | 
 
 | 
50
 | 
   $SELF = shift;  | 
| 
165
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
166
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
167
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub popself {  | 
| 
168
 | 
26
 | 
 
 | 
 
 | 
  
26
  
 | 
  
0
  
 | 
52
 | 
   $SELF = shift @Heap;  | 
| 
169
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
170
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
171
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub expand {  | 
| 
172
 | 
79
 | 
 
 | 
 
 | 
  
79
  
 | 
  
0
  
 | 
148
 | 
     my ($info, @args) = @_;  | 
| 
173
 | 
79
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
156
 | 
     return expand(&$info(@args)) if _isa($info, 'CODE');  | 
| 
174
 | 
75
 | 
 
 | 
 
 | 
 
 | 
 
 | 
230
 | 
     return $info;         | 
| 
175
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
176
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
177
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head2 _push  | 
| 
178
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
179
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   push new elements to a given slot (becomes an array if necessary)  | 
| 
180
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut  | 
| 
181
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
182
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub _push {  | 
| 
183
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
 
 | 
5
 | 
   my ($this, $slot, @elems) = @_;  | 
| 
184
 | 
1
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
4
 | 
   return unless scalar(@elems);  | 
| 
185
 | 
1
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
7
 | 
   $this->{$slot} = [ $this->{$slot} || () ] unless ref($this->{$slot}) eq 'ARRAY';   | 
| 
186
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
   unshift @{$this->{$slot}}, @elems;  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
    | 
| 
187
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
188
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
189
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub _addInstance {  | 
| 
190
 | 
14
 | 
 
 | 
 
 | 
  
14
  
 | 
 
 | 
37
 | 
   my ($this, $instance) = @_;  | 
| 
191
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
29
 | 
   my $k = $instance->{_KEY};  | 
| 
192
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     | 
| 
193
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
49
 | 
   $INSTANCES{$this->{_KEY}}->{$k} = $instance;  | 
| 
194
 | 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
104
 | 
   weaken($INSTANCES{$this->{_KEY}}->{$k});      # will not increase garbage ref counter to $instance !!  | 
| 
195
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
196
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
197
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head2 _inherits  | 
| 
198
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
199
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   add inherited new frame(s) outside constructor  | 
| 
200
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   ex. $f->_inherits($F1,$F2);  | 
| 
201
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut  | 
| 
202
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     | 
| 
203
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub _inherits {  | 
| 
204
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
 
 | 
5
 | 
   my ($this, @inherited) = @_;  | 
| 
205
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
   my $k = $this->{_KEY};  | 
| 
206
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
   for (grep { ! $INSTANCES{$_->{_KEY}}->{$k} } @inherited) { # clean list  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
    | 
| 
207
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
   	$_->_addInstance($this);  | 
| 
208
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
   	$this->_push('_ISA', $_);  | 
| 
209
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
210
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
   return $this;  | 
| 
211
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
212
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
213
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub _removeInstance {  | 
| 
214
 | 
  
0
  
 | 
 
 | 
 
 | 
  
0
  
 | 
 
 | 
0
 | 
   my ($this, $instance) = @_;  | 
| 
215
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
   my $k = $instance->{_KEY};  | 
| 
216
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
   (warn "Instance NOT FOUND !?", return) unless $INSTANCES{$this->{_KEY}}->{$k};  | 
| 
217
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
   delete $INSTANCES{$this->{_KEY}}->{$k};  | 
| 
218
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
219
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
220
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub blessToFrame {  | 
| 
221
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
222
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   sub register {  | 
| 
223
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
224
 | 
39
 | 
 
 | 
 
 | 
  
39
  
 | 
  
0
  
 | 
63
 | 
     my ($this) = @_;  | 
| 
225
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
226
 | 
39
 | 
 
 | 
 
 | 
 
 | 
 
 | 
59
 | 
     my $k;  | 
| 
227
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     do {  | 
| 
228
 | 
39
 | 
 
 | 
 
 | 
 
 | 
 
 | 
718
 | 
     	$k = Digest::MD5::md5_base64( rand );  | 
| 
229
 | 
39
 | 
 
 | 
 
 | 
 
 | 
 
 | 
57
 | 
     } while(exists($FMAP{$k}));  | 
| 
230
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
231
 | 
39
 | 
 
 | 
 
 | 
 
 | 
 
 | 
174
 | 
     foreach my $slot (keys(%$this)) { # register all slots  | 
| 
232
 | 
68
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
207
 | 
       $REPOSITORY{$slot} = {} unless exists $REPOSITORY{$slot};  | 
| 
233
 | 
68
 | 
 
 | 
 
 | 
 
 | 
 
 | 
216
 | 
       $REPOSITORY{$slot}->{$k} = 'Y';  | 
| 
234
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
235
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       | 
| 
236
 | 
39
 | 
 
 | 
 
 | 
 
 | 
 
 | 
90
 | 
     $this->{_KEY} = $k;  | 
| 
237
 | 
39
 | 
 
 | 
 
 | 
 
 | 
 
 | 
91
 | 
     $FMAP{$k} = $this;  | 
| 
238
 | 
39
 | 
 
 | 
 
 | 
 
 | 
 
 | 
111
 | 
     weaken($FMAP{$k}); # will not increase garbage ref counter to $this !!  | 
| 
239
 | 
39
 | 
 
 | 
 
 | 
 
 | 
 
 | 
76
 | 
     return $this;   | 
| 
240
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
241
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
242
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   sub blessToFrameRec {  | 
| 
243
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
244
 | 
39
 | 
 
 | 
 
 | 
  
39
  
 | 
  
0
  
 | 
67
 | 
     local $_ = shift;  | 
| 
245
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
246
 | 
39
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
82
 | 
     if (_isa($_,'Chorus::Frame')) {  | 
| 
247
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         | 
| 
248
 | 
39
 | 
 
 | 
 
 | 
 
 | 
 
 | 
154
 | 
       while(my ($k, $val) = each %$_) {  | 
| 
249
 | 
107
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
204
 | 
          if (_isa($val,'HASH')) {  | 
| 
250
 | 
15
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
49
 | 
             next if $val->{_NOFRAME};  | 
| 
251
 | 
15
 | 
 
 | 
 
 | 
 
 | 
 
 | 
32
 | 
             bless($val, 'Chorus::Frame');  | 
| 
252
 | 
15
 | 
 
 | 
 
 | 
 
 | 
 
 | 
45
 | 
             $val->register();  | 
| 
253
 | 
15
 | 
 
 | 
 
 | 
 
 | 
 
 | 
59
 | 
             blessToFrameRec($val);  | 
| 
254
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
          } else {  | 
| 
255
 | 
92
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
159
 | 
             if (_isa($val,'ARRAY')) {  | 
| 
256
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
                blessToFrameRec($_->{$k});  | 
| 
257
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }  | 
| 
258
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
          }  | 
| 
259
 | 
107
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
515
 | 
          if ($k eq '_ISA') {  | 
| 
260
 | 
13
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
34
 | 
            foreach my $inherited (_isa($val,'ARRAY') ? map \&expand, @{$val}   | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
261
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                                                          : (expand($val))) {  | 
| 
262
 | 
13
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
59
 | 
               $inherited->_addInstance($_) if $inherited;  | 
| 
263
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
            }  | 
| 
264
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
          }  | 
| 
265
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       }  | 
| 
266
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
267
 | 
39
 | 
 
 | 
 
 | 
 
 | 
 
 | 
86
 | 
       return;  | 
| 
268
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
269
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
270
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     if (_isa($_,'ARRAY')) { # à revoir (sans $idx)  | 
| 
271
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       foreach my $idx (0 .. scalar(@$_) - 1) {  | 
| 
272
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	    if (_isa($_[$idx], 'HASH')) {  | 
| 
273
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	      next if exists $_[$idx]->{_NOFRAME};  | 
| 
274
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	      bless($_[$idx], 'Chorus::Frame');  | 
| 
275
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	      $_[$idx]->register();  | 
| 
276
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	      blessToFrameRec($_[$idx]);  | 
| 
277
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	    } else {  | 
| 
278
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	      if (_isa($_[$idx],'ARRAY')) {  | 
| 
279
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	        blessToFrameRec($_[$idx]);  | 
| 
280
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	      }  | 
| 
281
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	    }  | 
| 
282
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       }  | 
| 
283
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
284
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
285
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
286
 | 
28
 | 
 
 | 
 
 | 
  
28
  
 | 
  
0
  
 | 
47
 | 
   my $res = shift;  | 
| 
287
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
288
 | 
28
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
72
 | 
   return $res if _isa($res, 'Chorus::Frame'); # already blessed  | 
| 
289
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
290
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   SWITCH: {  | 
| 
291
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
292
 | 
28
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
50
 | 
     _isa($res, 'HASH') && do {  | 
| 
 
 | 
28
 | 
 
 | 
 
 | 
 
 | 
 
 | 
121
 | 
    | 
| 
293
 | 
24
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
85
 | 
 	  return $res if exists $res->{_NOFRAME};  | 
| 
294
 | 
24
 | 
 
 | 
 
 | 
 
 | 
 
 | 
81
 | 
 	  bless($res, 'Chorus::Frame')->register();  | 
| 
295
 | 
24
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
99
 | 
 	  blessToFrameRec $res if keys(%$res);  | 
| 
296
 | 
24
 | 
 
 | 
 
 | 
 
 | 
 
 | 
58
 | 
 	  last SWITCH;;  | 
| 
297
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     };  | 
| 
298
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
299
 | 
4
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
14
 | 
     _isa($res, 'ARRAY') && do {  | 
| 
300
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       return $res unless scalar(@$res);  | 
| 
301
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	  blessToFrameRec $res;  | 
| 
302
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	  last SWITCH;  | 
| 
303
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     };  | 
| 
304
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
305
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }; # SWITCH  | 
| 
306
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
307
 | 
28
 | 
 
 | 
 
 | 
 
 | 
 
 | 
120
 | 
   return $res;  | 
| 
308
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
309
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
310
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head2 new  | 
| 
311
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
312
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   Constructor : Converts a hashtable definition into a Chorus::Frame object.  | 
| 
313
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     | 
| 
314
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   Important - All nested hashtables are recursively converted to Chorus::Frame,    | 
| 
315
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
               except those providing a slot _NO_FRAME  | 
| 
316
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 | 
| 
317
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   All frames are associated to a unique key and registered in an internal repository (see fmatch)  | 
| 
318
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
      | 
| 
319
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   Ex. $f = Chorus::Frame->new(  | 
| 
320
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                        slotA1 => {  | 
| 
321
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         	              _ISA   => [ $f2->slotA, $f3->slotA ] # multiple inheritance  | 
| 
322
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         	              slotA2 => sub { $SELF };             # procedural attachements  | 
| 
323
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         	              slotA3 => 'value for A3'  | 
| 
324
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                        },  | 
| 
325
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                        slotB => {  | 
| 
326
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         	              _NEEDED => sub { .. }  | 
| 
327
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                        }        | 
| 
328
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     );  | 
| 
329
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut  | 
| 
330
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
331
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub new {  | 
| 
332
 | 
24
 | 
 
 | 
 
 | 
  
24
  
 | 
  
1
  
 | 
3311
 | 
   my ($this, @desc) = @_;  | 
| 
333
 | 
24
 | 
 
 | 
 
 | 
 
 | 
 
 | 
106
 | 
   return blessToFrame({@desc});  | 
| 
334
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
335
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
336
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # WARN - Should be automatically called by carbage collector EVEN with those 2 remaining references : $INSTANCES{$k} AND $FMAP{$k} !!!  | 
| 
337
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 #  | 
| 
338
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub DESTROY {   | 
| 
339
 | 
37
 | 
 
 | 
 
 | 
  
37
  
 | 
 
 | 
744
 | 
   my ($this) = @_;  | 
| 
340
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
341
 | 
37
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
131
 | 
     my $k = $this->{_KEY} or warn "Undefined _KEY(1) for " . Dumper($this);  | 
| 
342
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
343
 | 
37
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
117
 | 
     delete $INSTANCES{$k} if exists $INSTANCES{$k};  | 
| 
344
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
345
 | 
37
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
111
 | 
     foreach my $inherited (_isa($this->{_ISA}, 'ARRAY') ? map \&expand, @{$this->{_ISA}} : (expand($this->{_ISA}))) {	    | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
    | 
| 
346
 | 
37
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
143
 | 
       my $ik = $inherited->{_KEY} or next;  | 
| 
347
 | 
12
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
75
 | 
       delete $INSTANCES{$ik}->{$k} if exists $INSTANCES{$ik}->{$k};  | 
| 
348
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
349
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
350
 | 
36
 | 
 
 | 
 
 | 
 
 | 
 
 | 
122
 | 
     foreach my $slot (keys(%$this)) {  | 
| 
351
 | 
92
 | 
  
 50
  
 | 
  
 66
  
 | 
 
 | 
 
 | 
409
 | 
       delete($REPOSITORY{$slot}->{$k}) if exists $REPOSITORY{$slot} and exists $REPOSITORY{$slot}->{$k};  | 
| 
352
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
353
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
354
 | 
36
 | 
 
 | 
 
 | 
 
 | 
 
 | 
300
 | 
     delete $FMAP{$k}; # is a weak reference (not counted by garbage collector)  | 
| 
355
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
356
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
357
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head2 get  | 
| 
358
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
359
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 This method provides the information associated to a sequence of slots.  | 
| 
360
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 This sequence is given in a string composed with slot names separated by spaces.  | 
| 
361
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 The last slot is tested for the target information with the sequence _VALUE,_DEFAULT,_NEEDED.  | 
| 
362
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 If a frame doesn't provide any of those slots, the target information is the frame itself.  | 
| 
363
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
364
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 A frame called with the method get() becomes the current context wich can be referred with the variable $SELF.  | 
| 
365
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     | 
| 
366
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Note - The short form $f->SLOTNAME() can by used instead of $f->get('SLOTNAME');  | 
| 
367
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     | 
| 
368
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Ex. $f->foo;                   # equiv to $f->get('foo');  | 
| 
369
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     $f->foo(@args);            # equiv to $f->get('foo')(@args);  | 
| 
370
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
371
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     $f->get('foo bar');        # $SELF (context) is $f while processing 'bar'  | 
| 
372
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
373
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     $f->get('foo')->get('bar') # $SELF (context) is $f->foo while processing 'bar'  | 
| 
374
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     $f->foo->bar;              # short form  | 
| 
375
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         | 
| 
376
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut  | 
| 
377
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
378
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub get {  | 
| 
379
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	  | 
| 
380
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   sub expandInherits {  | 
| 
381
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
382
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     sub first { # uses expand  | 
| 
383
 | 
12
 | 
 
 | 
 
 | 
  
12
  
 | 
  
0
  
 | 
22
 | 
 	  my ($this, $slots, @args) = @_;  | 
| 
384
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
14
 | 
           for (@{$slots}) {  | 
| 
 
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
29
 | 
    | 
| 
385
 | 
14
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
50
 | 
   	     return { ret => SUCCESS, res => expand($this->{$_}, @args) } if exists $this->{$_};  | 
| 
386
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           }  | 
| 
387
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
14
 | 
 	  return undef;   | 
| 
388
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
389
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
390
 | 
12
 | 
 
 | 
 
 | 
  
12
  
 | 
  
0
  
 | 
21
 | 
     my ($this,$tryValuations,@args) = @_;	  | 
| 
391
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
392
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
35
 | 
     my $res = $this->first($tryValuations,@args);  | 
| 
393
 | 
12
 | 
  
 50
  
 | 
  
 66
  
 | 
 
 | 
 
 | 
47
 | 
     return $res if defined($res) and $res->{ret};  | 
| 
394
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
395
 | 
7
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
25
 | 
     if (exists($this->{_ISA})) {  | 
| 
396
 | 
2
 | 
  
  0
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
5
 | 
       my @h = _isa($this->{_ISA}, 'ARRAY') ? map { expand($_) || () } @{$this->{_ISA}} : (expand($this->{_ISA}) || ());  | 
| 
 
 | 
  
0
  
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
397
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
       for (@h) { # upper level  | 
| 
398
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
         $res = $_->expandInherits($tryValuations,@args);  | 
| 
399
 | 
2
 | 
  
100
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
22
 | 
         return $res if defined($res) and $res->{ret};  | 
| 
400
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       }  | 
| 
401
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
402
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
18
 | 
     return { ret => FAILED };  | 
| 
403
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   } # expandInherits  | 
| 
404
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
405
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   sub inherited {  | 
| 
406
 | 
41
 | 
 
 | 
 
 | 
  
41
  
 | 
  
0
  
 | 
89
 | 
 	my ($this,$slot,@rest) = @_;  | 
| 
407
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
408
 | 
41
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
178
 | 
 	return $this->{$slot} if exists($this->{$slot}); # first that match (better than buildtree) !!  | 
| 
409
 | 
12
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
44
 | 
         $this->{_ISA} and push @rest, _isa($this->{_ISA}, 'ARRAY') ? @{$this->{_ISA}} : $this->{_ISA}; # see expand  | 
| 
 
 | 
1
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
3
 | 
    | 
| 
410
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
411
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
21
 | 
 	my $next = shift @rest;  | 
| 
412
 | 
12
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
39
 | 
 	return undef unless $next;  | 
| 
413
 | 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
33
 | 
 	return $next->inherited($slot,@rest);  | 
| 
414
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }   | 
| 
415
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
416
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   sub getZ {  | 
| 
417
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   	  | 
| 
418
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   	sub value_Z {  | 
| 
419
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
  
0
  
 | 
15
 | 
       my ($info, @args) = @_;  | 
| 
420
 | 
2
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
5
 | 
       return expand($info,@args) unless _isa($info,'Chorus::Frame');  | 
| 
421
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
       my $res = $info->expandInherits([VALUATION_ORDER], @args);  | 
| 
422
 | 
1
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
11
 | 
       return $res->{res} if defined($res) and $res->{ret};  | 
| 
423
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       return $info;  | 
| 
424
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
425
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       | 
| 
426
 | 
4
 | 
 
 | 
 
 | 
  
4
  
 | 
  
0
  
 | 
9
 | 
     my ($this, $way, @args) = @_;  | 
| 
427
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
428
 | 
4
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
11
 | 
     return $this->value_Z(@args) unless $way;  | 
| 
429
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
430
 | 
4
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
25
 | 
     $way =~ /^\s*(\S*)\s*(.*?)\s*$/o or die "Unexpected way format : '$way'";  | 
| 
431
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
12
 | 
     my ($nextStep, $followWay) = ($1,$2);  | 
| 
432
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
433
 | 
4
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
14
 | 
     return value_Z($this->inherited($nextStep), @args) unless $followWay;  | 
| 
434
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
435
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
     my $next = $this->inherited($nextStep);    | 
| 
436
 | 
2
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
6
 | 
     return _isa($next,'Chorus::Frame') ? $next->getZ($followWay, @args) : undef;  | 
| 
437
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
438
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
439
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   sub getN {  | 
| 
440
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   	  | 
| 
441
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     sub value_N {  | 
| 
442
 | 
22
 | 
 
 | 
 
 | 
  
22
  
 | 
  
0
  
 | 
42
 | 
       my ($info, @args) = @_;  | 
| 
443
 | 
22
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
54
 | 
       return expand($info,@args) unless _isa($info,'Chorus::Frame');  | 
| 
444
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
14
 | 
       for (VALUATION_ORDER) {  | 
| 
445
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
30
 | 
   	    my $res = $info->expandInherits([$_], @args);  | 
| 
446
 | 
9
 | 
  
100
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
66
 | 
   	    return $res->{res} if defined($res) and $res->{ret};  | 
| 
447
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       }    | 
| 
448
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       return $info;  | 
| 
449
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
450
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       | 
| 
451
 | 
26
 | 
 
 | 
 
 | 
  
26
  
 | 
  
0
  
 | 
69
 | 
     my ($this, $way, @args) = @_;  | 
| 
452
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
453
 | 
26
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
81
 | 
     return $this->value_N(@args) unless $way;  | 
| 
454
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
455
 | 
26
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
140
 | 
     $way =~ /^\s*(\S*)\s*(.*?)\s*$/o or die "Unexpected way format : '$way'";  | 
| 
456
 | 
26
 | 
 
 | 
 
 | 
 
 | 
 
 | 
81
 | 
     my ($nextStep, $followWay) = ($1,$2);  | 
| 
457
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
458
 | 
26
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
95
 | 
     return value_N($this->inherited($nextStep), @args) unless $followWay;  | 
| 
459
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
460
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
14
 | 
     my $next = $this->inherited($nextStep);  | 
| 
461
 | 
4
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
11
 | 
     return _isa($next,'Chorus::Frame') ? $next->getN($followWay, @args) : undef;  | 
| 
462
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
463
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
464
 | 
21
 | 
 
 | 
 
 | 
  
21
  
 | 
  
1
  
 | 
66
 | 
   pushself(shift);  | 
| 
465
 | 
21
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
81
 | 
   my $res = $getMode == MODE_N ? getN($SELF,@_) : getZ($SELF,@_);  | 
| 
466
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
55
 | 
   popself();  | 
| 
467
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
101
 | 
   return $res;  | 
| 
468
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
469
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
470
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head2 delete  | 
| 
471
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
472
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    All Frames properties are registered in a single table, especially to optimize the method fmatch().  | 
| 
473
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    This why frames have to use the form $f->delete($slotname) instead of delete($f->{$slotname})  | 
| 
474
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    otherwise a frame will be considered by fmatch() as providing a slot even after this one have been removed.  | 
| 
475
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
476
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut  | 
| 
477
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       | 
| 
478
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub delete {  | 
| 
479
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	  | 
| 
480
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   sub deleteSlot {  | 
| 
481
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
482
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     sub unregisterSlot {  | 
| 
483
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
  
0
  
 | 
3
 | 
       my ($this,$slot) = @_;  | 
| 
484
 | 
1
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
6
 | 
       return unless exists $REPOSITORY{$slot};  | 
| 
485
 | 
1
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
9
 | 
 	  delete $REPOSITORY{$slot}->{$this->{_KEY}} if exists $REPOSITORY{$slot}->{$this->{_KEY}};  | 
| 
486
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
487
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
488
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
  
0
  
 | 
4
 | 
     my ($this,$slot) = @_;  | 
| 
489
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
490
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
     $this->unregisterSlot($slot);	  | 
| 
491
 | 
1
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
20
 | 
     delete($this->{$slot}) if exists $this->{$slot};     | 
| 
492
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
493
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	  | 
| 
494
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   sub deleteN {  | 
| 
495
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
496
 | 
2
 | 
 
 | 
 
 | 
  
2
  
 | 
  
0
  
 | 
6
 | 
     my ($this, $way) = @_;  | 
| 
497
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
498
 | 
2
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
8
 | 
     return undef unless $way;  | 
| 
499
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
500
 | 
2
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
16
 | 
     $way =~ /^\s*(\S*)\s*(.*?)\s*$/o or die "Unexpected way format : '$way'";  | 
| 
501
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8
 | 
     my ($nextStep, $followWay) = ($1,$2);  | 
| 
502
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
503
 | 
2
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
11
 | 
     return $this->deleteSlot($nextStep) unless $followWay;  | 
| 
504
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
505
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
     my $next = $this->inherited($nextStep);  | 
| 
506
 | 
1
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
4
 | 
     return _isa($next,'Chorus::Frame') ? $next->deleteN($followWay) : undef;  | 
| 
507
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
508
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	  | 
| 
509
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
  
1
  
 | 
4
 | 
   pushself(shift);  | 
| 
510
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
   my $res = $SELF->deleteN(@_);  | 
| 
511
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
   popself();  | 
| 
512
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
   return $res;  | 
| 
513
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
514
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
515
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head2 set  | 
| 
516
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
517
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    This method tells a frame to associated target information to a sequence of slots  | 
| 
518
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    A frame called for this method becomes the new context.  | 
| 
519
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
520
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     Ex. $f1 = Chorus::Frame->new(  | 
| 
521
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           a => {  | 
| 
522
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           	  b => {   | 
| 
523
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           	  	c => 'C'  | 
| 
524
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           	  }  | 
| 
525
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           }  | 
| 
526
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         );  | 
| 
527
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                   | 
| 
528
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     $f1->set('a b', 'B');  # 'B' becomes the target _VALUE for $f1->get('a b')  | 
| 
529
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     $f1->get('a b');       # returns 'B'  | 
| 
530
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
531
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     $f1->get('a b c');     # still returns 'C'  | 
| 
532
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     $f1->delete('a b c');  | 
| 
533
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     $f1->get('a b c');     # undef  | 
| 
534
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
535
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     $f2 = Chorus::Frame->new(  | 
| 
536
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           _ISA => $1,  | 
| 
537
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     );  | 
| 
538
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
539
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     $f2->get('a b c');     # returns 'C'  | 
| 
540
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       | 
| 
541
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     $f2->set('a b', 'AB'); # cancel inheritance for first slot 'a'  | 
| 
542
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     $f2->get('a b');       # returns 'AB'  | 
| 
543
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
544
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     $f2->get('a b c');     # undefined  | 
| 
545
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           | 
| 
546
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut  | 
| 
547
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
548
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub set {  | 
| 
549
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
550
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   sub registerSlot {  | 
| 
551
 | 
4
 | 
 
 | 
 
 | 
  
4
  
 | 
  
0
  
 | 
9
 | 
 	my ($this,$slot) = @_;  | 
| 
552
 | 
4
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
23
 | 
 	$REPOSITORY{$slot} = {} unless exists $REPOSITORY{$slot};  | 
| 
553
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
15
 | 
 	$REPOSITORY{$slot}->{$this->{_KEY}} = 'Y';  | 
| 
554
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
555
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       | 
| 
556
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   sub setValue {  | 
| 
557
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
  
0
  
 | 
2
 | 
     my ($this, $val) = @_;  | 
| 
558
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
559
 | 
1
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
5
 | 
     return undef if $this->getN('_REQUIRE', $val) == REQUIRE_FAILED;  | 
| 
560
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       | 
| 
561
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
     $this->getN('_BEFORE', $val); # or return undef;  | 
| 
562
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
563
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
     blessToFrame($val);  | 
| 
564
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
     $this->{'_VALUE'} = $val;  | 
| 
565
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4
 | 
     $this->registerSlot('_VALUE');  | 
| 
566
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
567
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
     $this->getN('_AFTER', $val); # or return undef;  | 
| 
568
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
569
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
     return $val;  | 
| 
570
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
571
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
572
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   sub setSlot {  | 
| 
573
 | 
3
 | 
 
 | 
 
 | 
  
3
  
 | 
  
0
  
 | 
9
 | 
     my ($this, $slot, $info) = @_;  | 
| 
574
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
9
 | 
     blessToFrame($info);  | 
| 
575
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
9
 | 
     $this->{$slot} = $info;  | 
| 
576
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
11
 | 
     $this->registerSlot($slot);    | 
| 
577
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
23
 | 
     return $info;  | 
| 
578
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
579
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   	  | 
| 
580
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   sub setN {  | 
| 
581
 | 
6
 | 
 
 | 
 
 | 
  
6
  
 | 
  
0
  
 | 
14
 | 
     my ($this, $way, $info) = @_;  | 
| 
582
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
583
 | 
6
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
26
 | 
     return $this->setValue($info) unless $way;  | 
| 
584
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
585
 | 
5
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
34
 | 
     $way =~ /^\s*(\S*)\s*(.*?)\s*$/o or die "Unexpected way format : '$way'";  | 
| 
586
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
23
 | 
     my ($nextStep, $followWay) = ($1,$2);  | 
| 
587
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10
 | 
     my $crossedValue = $this->{$nextStep};  | 
| 
588
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
589
 | 
5
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
11
 | 
     return $crossedValue->setN($followWay, $info) if _isa($crossedValue,'Chorus::Frame');  | 
| 
590
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       | 
| 
591
 | 
3
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
14
 | 
     unless ($followWay) {  | 
| 
592
 | 
3
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
11
 | 
       if ($nextStep eq '_VALUE') {  | 
| 
593
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         return $this->setValue($info);  | 
| 
594
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       } else {  | 
| 
595
 | 
3
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
13
 | 
         if (_isa($this->{$nextStep}, 'Chorus::Frame') and exists($this->{$nextStep}->{_VALUE})) {  | 
| 
596
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	      return $this->{$nextStep}->setValue($info)  | 
| 
597
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         } else {  | 
| 
598
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
16
 | 
 	      return $this->setSlot($nextStep, $info);  | 
| 
599
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
600
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       }  | 
| 
601
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
602
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
603
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     $this->{$nextStep} = (exists($this->{$nextStep})) ? new Chorus::Frame (_VALUE => $crossedValue)  | 
| 
604
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                                                       : new Chorus::Frame;  | 
| 
605
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       | 
| 
606
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     return $this->{$nextStep}->setN($followWay, $info); # (keep current context)  | 
| 
607
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       | 
| 
608
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   } # set is setN !!!!  | 
| 
609
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	  | 
| 
610
 | 
4
 | 
 
 | 
 
 | 
  
4
  
 | 
  
1
  
 | 
29
 | 
   pushself(shift);  | 
| 
611
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
13
 | 
   my %desc = @_;  | 
| 
612
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
613
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
   my $res;  | 
| 
614
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
615
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
20
 | 
   while(my($k,$val) = each %desc) {  | 
| 
616
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
18
 | 
     $res = $SELF->setN($k, $val);    # set is setN !!  | 
| 
617
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
618
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     | 
| 
619
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
12
 | 
   popself();  | 
| 
620
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
17
 | 
   return $res;  # wil return last set if multiple pairs (key=>val) !!  | 
| 
621
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
  }  | 
| 
622
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
623
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head2 fmatch  | 
| 
624
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
625
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
  This function returns the list of the frames providing all the slots given as argument.  | 
| 
626
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
  The result can contains the frames providing these the slots by inheritance.  | 
| 
627
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
  This function can be used to minimise the list of frames that should be candidate for a given process.  | 
| 
628
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
629
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
  An optional argument 'from' can provide a list of frames as search space  | 
| 
630
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
631
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
  ex. @l = grep { $_->score > 5 } fmatch(  | 
| 
632
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                                          slot => ['foo', 'score'],  | 
| 
633
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                                          from => \@framelist       # optional : limit search scope  | 
| 
634
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                                        );  | 
| 
635
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
      #  | 
| 
636
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
      # all frames, optionnaly from @framelist, providing both slots 'foo' and 'score' (possible   | 
| 
637
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
      # inheritance) and on which the method get('score') returns a value > 5  | 
| 
638
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
639
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut  | 
| 
640
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
641
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub firstInheriting {  | 
| 
642
 | 
10
 | 
 
 | 
 
 | 
  
10
  
 | 
  
0
  
 | 
54
 | 
           my ($this) = @_;  | 
| 
643
 | 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
19
 | 
           my $k = $this->{_KEY};  | 
| 
644
 | 
10
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
65
 | 
           return () unless $INSTANCES{$k};  | 
| 
645
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
           return(values(%{$INSTANCES{$k}}));  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
646
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             | 
| 
647
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 } # firstInheriting  | 
| 
648
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
649
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub fmatch {  | 
| 
650
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     | 
| 
651
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   sub framesProvidingSlot { # inheritance ok  | 
| 
652
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     | 
| 
653
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     sub hasSlot {  | 
| 
654
 | 
5
 | 
 
 | 
 
 | 
  
5
  
 | 
  
0
  
 | 
7
 | 
        my ($slot) = @_;  | 
| 
655
 | 
5
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
7
 | 
        return map { $FMAP{$_} || () } keys(%{$REPOSITORY{$slot}})     | 
| 
 
 | 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
42
 | 
    | 
| 
 
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
19
 | 
    | 
| 
656
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
657
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
658
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     sub wholeTree {   | 
| 
659
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           | 
| 
660
 | 
5
 | 
 
 | 
 
 | 
  
5
  
 | 
  
0
  
 | 
10
 | 
        my ($res, @dig) = @_;  | 
| 
661
 | 
5
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
25
 | 
          return $res unless $dig[0];  | 
| 
662
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
          my @inheriting = map { $_->firstInheriting || () } @dig;  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
663
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
          push(@$res, @inheriting);  | 
| 
664
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
          return wholeTree($res,@inheriting);  | 
| 
665
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
            | 
| 
666
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } # wholeTree  | 
| 
667
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     | 
| 
668
 | 
5
 | 
 
 | 
 
 | 
  
5
  
 | 
  
0
  
 | 
11
 | 
     my ($slot) = @_;  | 
| 
669
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       | 
| 
670
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
13
 | 
     my @res = hasSlot($slot);  | 
| 
671
 | 
5
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
11
 | 
     my @inheriting = map { $_->firstInheriting || () } @res;  | 
| 
 
 | 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
21
 | 
    | 
| 
672
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     | 
| 
673
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10
 | 
     push @res, @inheriting;  | 
| 
674
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
13
 | 
     return wholeTree(\@res, @inheriting);  | 
| 
675
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	  | 
| 
676
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   } # framesProvidingSlot  | 
| 
677
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
678
 | 
4
 | 
 
 | 
 
 | 
  
4
  
 | 
  
1
  
 | 
1283
 | 
   my %opts = @_;  | 
| 
679
 | 
4
 | 
  
100
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
11
 | 
   $opts{slot} = [ $opts{slot} || () ] unless _isa($opts{slot},'ARRAY');  | 
| 
680
 | 
4
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
10
 | 
   my ($firstslot,@otherslots) = @{$opts{slot} || []};  | 
| 
 
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
19
 | 
    | 
| 
681
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
682
 | 
4
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
11
 | 
   return () unless $firstslot;  | 
| 
683
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     | 
| 
684
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
   my %filter = map { $_->{_KEY} => 'Y' || () } @{framesProvidingSlot($firstslot)};  | 
| 
 
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
28
 | 
    | 
| 
 
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
11
 | 
    | 
| 
685
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     | 
| 
686
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
15
 | 
   for(@otherslots) {  | 
| 
687
 | 
1
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
3
 | 
     %filter = map { $filter{$_->{_KEY}} ? ($_->{_KEY} => 'Y') : () } @{framesProvidingSlot($_)};  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
9
 | 
    | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
    | 
| 
688
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
689
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     | 
| 
690
 | 
4
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
13
 | 
   if ($opts{from}) {  | 
| 
691
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
     return grep { $filter{$_->{_KEY}} } @{$opts{from}};  | 
| 
 
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10
 | 
    | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
    | 
| 
692
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
693
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     | 
| 
694
 | 
3
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
11
 | 
   return map { $FMAP{$_} || ()} keys(%filter);  | 
| 
 
 | 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
19
 | 
    | 
| 
695
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     | 
| 
696
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 } # fmatch  | 
| 
697
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
698
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 AUTHOR  | 
| 
699
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
700
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Christophe Ivorra, C<<  >>  | 
| 
701
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
702
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 BUGS  | 
| 
703
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
704
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Please report any bugs or feature requests to C, or through  | 
| 
705
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 the web interface at L.  I will be notified, and then you'll  | 
| 
706
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 automatically be notified of progress on your bug as I make changes.  | 
| 
707
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
708
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 SUPPORT  | 
| 
709
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
710
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 You can find documentation for this module with the perldoc command.  | 
| 
711
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
712
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     perldoc Chorus::Frame  | 
| 
713
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
714
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
715
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 You can also look for information at:  | 
| 
716
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
717
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =over 4  | 
| 
718
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
719
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =item * RT: CPAN's request tracker (report bugs here)  | 
| 
720
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
721
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 L  | 
| 
722
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
723
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =item * AnnoCPAN: Annotated CPAN documentation  | 
| 
724
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
725
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 L  | 
| 
726
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
727
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =item * CPAN Ratings  | 
| 
728
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
729
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 L  | 
| 
730
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
731
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =item * Search CPAN  | 
| 
732
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
733
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 L  | 
| 
734
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
735
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =back  | 
| 
736
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
737
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
738
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 ACKNOWLEDGEMENTS  | 
| 
739
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
740
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
741
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 LICENSE AND COPYRIGHT  | 
| 
742
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
743
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Copyright 2013 Christophe Ivorra.  | 
| 
744
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
745
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 This program is free software; you can redistribute it and/or modify it  | 
| 
746
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 under the terms of either: the GNU General Public License as published  | 
| 
747
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 by the Free Software Foundation; or the Artistic License.  | 
| 
748
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
749
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 See http://dev.perl.org/licenses/ for more information.  | 
| 
750
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
751
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
752
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut  | 
| 
753
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
754
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 1; # End of Chorus::Frame  |