line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Farly::ASA::Annotator;
|
2
|
|
|
|
|
|
|
|
3
|
9
|
|
|
9
|
|
1511
|
use 5.008008;
|
|
9
|
|
|
|
|
37
|
|
|
9
|
|
|
|
|
367
|
|
4
|
9
|
|
|
9
|
|
55
|
use strict;
|
|
9
|
|
|
|
|
21
|
|
|
9
|
|
|
|
|
294
|
|
5
|
9
|
|
|
9
|
|
188
|
use warnings;
|
|
9
|
|
|
|
|
19
|
|
|
9
|
|
|
|
|
287
|
|
6
|
9
|
|
|
9
|
|
55
|
use Carp;
|
|
9
|
|
|
|
|
22
|
|
|
9
|
|
|
|
|
763
|
|
7
|
9
|
|
|
9
|
|
55
|
use Scalar::Util qw(blessed);
|
|
9
|
|
|
|
|
21
|
|
|
9
|
|
|
|
|
838
|
|
8
|
9
|
|
|
9
|
|
53
|
use Log::Any qw($log);
|
|
9
|
|
|
|
|
19
|
|
|
9
|
|
|
|
|
85
|
|
9
|
9
|
|
|
9
|
|
6288
|
use Farly::ASA::PortFormatter;
|
|
9
|
|
|
|
|
139
|
|
|
9
|
|
|
|
|
294
|
|
10
|
9
|
|
|
9
|
|
5437
|
use Farly::ASA::ProtocolFormatter;
|
|
9
|
|
|
|
|
30
|
|
|
9
|
|
|
|
|
302
|
|
11
|
9
|
|
|
9
|
|
5357
|
use Farly::ASA::ICMPFormatter;
|
|
9
|
|
|
|
|
25
|
|
|
9
|
|
|
|
|
22280
|
|
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
our $VERSION = '0.26';
|
14
|
|
|
|
|
|
|
our $AUTOLOAD;
|
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
#each token type maps to a class
|
17
|
|
|
|
|
|
|
our $Token_Class_Map = {
|
18
|
|
|
|
|
|
|
'STRING' => 'Farly::Value::String',
|
19
|
|
|
|
|
|
|
'DIGIT' => 'Farly::Value::Integer',
|
20
|
|
|
|
|
|
|
'NAME' => 'Farly::Value::String', #method replaces name with IP
|
21
|
|
|
|
|
|
|
'NAME_ID' => 'Farly::Value::String', #this is just the name string
|
22
|
|
|
|
|
|
|
'IF_REF' => 'Farly::Object::Ref',
|
23
|
|
|
|
|
|
|
'OBJECT_REF' => 'Farly::Object::Ref',
|
24
|
|
|
|
|
|
|
'GROUP_REF' => 'Farly::Object::Ref',
|
25
|
|
|
|
|
|
|
'RULE_REF' => 'Farly::Object::Ref',
|
26
|
|
|
|
|
|
|
'GROUP_TYPE' => 'Farly::Value::String',
|
27
|
|
|
|
|
|
|
'OBJECT_ENTRY' => 'Farly::Value::String',
|
28
|
|
|
|
|
|
|
'OBJECT_TYPE' => 'Farly::Value::String',
|
29
|
|
|
|
|
|
|
'ANY' => 'Farly::IPv4::Network', #method ANY = '0.0.0.0 0.0.0.0'
|
30
|
|
|
|
|
|
|
'IPADDRESS' => 'Farly::IPv4::Address',
|
31
|
|
|
|
|
|
|
'MASK' => 'Farly::IPv4::Address',
|
32
|
|
|
|
|
|
|
'IPNETWORK' => 'Farly::IPv4::Network',
|
33
|
|
|
|
|
|
|
'IPRANGE' => 'Farly::IPv4::Range',
|
34
|
|
|
|
|
|
|
'NAMED_NET' => 'Farly::Value::String', #method replaces name with IP
|
35
|
|
|
|
|
|
|
'PROTOCOL' => 'Farly::Transport::Protocol',
|
36
|
|
|
|
|
|
|
'GROUP_PROTOCOL' => 'Farly::Value::String', #not ::Protocol because of 'tcp-udp'
|
37
|
|
|
|
|
|
|
'ICMP_TYPE' => 'Farly::IPv4::ICMPType', #method maps string to int
|
38
|
|
|
|
|
|
|
'PORT_ID' => 'Farly::Transport::Port', #method maps string to int
|
39
|
|
|
|
|
|
|
'PORT_RANGE' => 'Farly::Transport::PortRange', #method maps string to int
|
40
|
|
|
|
|
|
|
'PORT_GT' => 'Farly::Transport::PortGT', #method maps string to int
|
41
|
|
|
|
|
|
|
'PORT_LT' => 'Farly::Transport::PortLT', #method maps string to int
|
42
|
|
|
|
|
|
|
'ACTIONS' => 'Farly::Value::String',
|
43
|
|
|
|
|
|
|
'ACL_TYPES' => 'Farly::Value::String',
|
44
|
|
|
|
|
|
|
'REMARKS' => 'Farly::Value::String',
|
45
|
|
|
|
|
|
|
'ACL_DIRECTION' => 'Farly::Value::String',
|
46
|
|
|
|
|
|
|
'ACL_GLOBAL' => 'Farly::Value::String',
|
47
|
|
|
|
|
|
|
'STATE' => 'Farly::Value::String',
|
48
|
|
|
|
|
|
|
'ACL_STATUS' => 'Farly::Value::String',
|
49
|
|
|
|
|
|
|
'LOG_LEVEL' => 'Farly::Value::String',
|
50
|
|
|
|
|
|
|
'DEFAULT_ROUTE' => 'Farly::IPv4::Network', #method DEFAULT_ROUTE sets '0.0.0.0 0.0.0.0'
|
51
|
|
|
|
|
|
|
'TUNNELED' => 'Farly::Value::String'
|
52
|
|
|
|
|
|
|
};
|
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
# 'ENTRY' is like a namespace in which an ID must be unique
|
55
|
|
|
|
|
|
|
# A _REF refers to a Farly::Object by ENTRY and ID
|
56
|
|
|
|
|
|
|
our $Entry_Map = {
|
57
|
|
|
|
|
|
|
'IF_REF' => 'INTERFACE',
|
58
|
|
|
|
|
|
|
'OBJECT_REF' => 'OBJECT',
|
59
|
|
|
|
|
|
|
'GROUP_REF' => 'GROUP',
|
60
|
|
|
|
|
|
|
'RULE_REF' => 'RULE',
|
61
|
|
|
|
|
|
|
};
|
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
sub new {
|
64
|
7
|
|
|
7
|
0
|
56
|
my ($class) = @_;
|
65
|
|
|
|
|
|
|
|
66
|
7
|
|
|
|
|
88
|
my $self = {
|
67
|
|
|
|
|
|
|
NAMES => {}, #name to address 'symbol table'
|
68
|
|
|
|
|
|
|
PORT_FMT => Farly::ASA::PortFormatter->new(),
|
69
|
|
|
|
|
|
|
PROTOCOL_FMT => Farly::ASA::ProtocolFormatter->new(),
|
70
|
|
|
|
|
|
|
ICMP_FMT => Farly::ASA::ICMPFormatter->new()
|
71
|
|
|
|
|
|
|
};
|
72
|
7
|
|
|
|
|
27
|
bless $self, $class;
|
73
|
|
|
|
|
|
|
|
74
|
7
|
|
|
|
|
96
|
$log->info("$self new");
|
75
|
|
|
|
|
|
|
|
76
|
7
|
|
|
|
|
39
|
return $self;
|
77
|
|
|
|
|
|
|
}
|
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
sub port_formatter {
|
80
|
120
|
|
|
120
|
0
|
855
|
return $_[0]->{PORT_FMT};
|
81
|
|
|
|
|
|
|
}
|
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
sub protocol_formatter {
|
84
|
321
|
|
|
321
|
0
|
1554
|
return $_[0]->{PROTOCOL_FMT};
|
85
|
|
|
|
|
|
|
}
|
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
sub icmp_formatter {
|
88
|
40
|
|
|
40
|
0
|
218
|
return $_[0]->{ICMP_FMT};
|
89
|
|
|
|
|
|
|
}
|
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
sub visit {
|
92
|
330
|
|
|
330
|
0
|
648
|
my ( $self, $node ) = @_;
|
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
# set s of explored vertices
|
95
|
330
|
|
|
|
|
546
|
my %seen;
|
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
#stack is all neighbors of s
|
98
|
|
|
|
|
|
|
my @stack;
|
99
|
330
|
|
|
|
|
650
|
push @stack, $node;
|
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
#my $key;
|
102
|
|
|
|
|
|
|
|
103
|
330
|
|
|
|
|
1054
|
while (@stack) {
|
104
|
|
|
|
|
|
|
|
105
|
4308
|
|
|
|
|
5570
|
$node = pop @stack;
|
106
|
|
|
|
|
|
|
|
107
|
4308
|
50
|
|
|
|
15544
|
next if ( $seen{$node}++ );
|
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
#visit this node if its a token
|
110
|
4308
|
100
|
|
|
|
9251
|
if ( exists( $node->{'__VALUE__'} ) ) {
|
111
|
1663
|
|
|
|
|
2267
|
my $method = ref($node);
|
112
|
1663
|
|
|
|
|
7608
|
$self->$method($node);
|
113
|
1663
|
|
|
|
|
4735
|
next;
|
114
|
|
|
|
|
|
|
}
|
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
# add name info the the names "symbol table"
|
117
|
2645
|
100
|
|
|
|
14127
|
if ( $node->isa('named_ip') ) {
|
118
|
12
|
|
|
|
|
62
|
$self->named_ip($node);
|
119
|
|
|
|
|
|
|
}
|
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
# continue walking the parse tree
|
122
|
2645
|
|
|
|
|
6923
|
foreach my $key ( keys %$node ) {
|
123
|
|
|
|
|
|
|
|
124
|
7976
|
100
|
|
|
|
13979
|
next if ( $key eq 'EOL' );
|
125
|
|
|
|
|
|
|
|
126
|
7568
|
|
|
|
|
9852
|
my $next = $node->{$key};
|
127
|
|
|
|
|
|
|
|
128
|
7568
|
100
|
|
|
|
22499
|
if ( blessed($next) ) {
|
129
|
|
|
|
|
|
|
|
130
|
3978
|
|
|
|
|
9547
|
push @stack, $next;
|
131
|
|
|
|
|
|
|
}
|
132
|
|
|
|
|
|
|
}
|
133
|
|
|
|
|
|
|
}
|
134
|
330
|
|
|
|
|
1781
|
return 1;
|
135
|
|
|
|
|
|
|
}
|
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
sub named_ip {
|
138
|
12
|
|
|
12
|
0
|
33
|
my ( $self, $node ) = @_;
|
139
|
|
|
|
|
|
|
|
140
|
12
|
50
|
|
|
|
62
|
my $name = $node->{name}->{NAME_ID}->{__VALUE__}
|
141
|
|
|
|
|
|
|
or confess "$self error: name not found for ", ref($node);
|
142
|
|
|
|
|
|
|
|
143
|
12
|
50
|
|
|
|
50
|
my $ip = $node->{IPADDRESS}->{__VALUE__}
|
144
|
|
|
|
|
|
|
or confess "$self error: IP address not found for ", ref($node);
|
145
|
|
|
|
|
|
|
|
146
|
12
|
|
|
|
|
268
|
$log->debug("name = $name : ip = $ip");
|
147
|
|
|
|
|
|
|
|
148
|
12
|
|
|
|
|
70
|
$self->{NAMES}->{$name} = $ip;
|
149
|
|
|
|
|
|
|
}
|
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
sub NAME {
|
152
|
26
|
|
|
26
|
0
|
70
|
my ( $self, $node ) = @_;
|
153
|
|
|
|
|
|
|
|
154
|
26
|
50
|
|
|
|
131
|
my $name = $node->{'__VALUE__'}
|
155
|
|
|
|
|
|
|
or confess "$self error: __VALUE__ not found for name";
|
156
|
|
|
|
|
|
|
|
157
|
26
|
50
|
|
|
|
152
|
my $ip = $self->{NAMES}->{$name}
|
158
|
|
|
|
|
|
|
or confess "$self error: IP address not found for name $name";
|
159
|
|
|
|
|
|
|
|
160
|
26
|
|
|
|
|
190
|
$node->{'__VALUE__'} = Farly::IPv4::Address->new($ip);
|
161
|
|
|
|
|
|
|
}
|
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
sub NAMED_NET {
|
164
|
6
|
|
|
6
|
0
|
18
|
my ( $self, $node ) = @_;
|
165
|
|
|
|
|
|
|
|
166
|
6
|
50
|
|
|
|
34
|
my $named_net = $node->{'__VALUE__'}
|
167
|
|
|
|
|
|
|
or confess "$self error: __VALUE__ not found for name";
|
168
|
|
|
|
|
|
|
|
169
|
6
|
|
|
|
|
31
|
my ( $name, $mask ) = split( /\s+/, $named_net );
|
170
|
|
|
|
|
|
|
|
171
|
6
|
50
|
|
|
|
43
|
my $ip = $self->{NAMES}->{$name}
|
172
|
|
|
|
|
|
|
or confess "$self error: IP address not found for name $name";
|
173
|
|
|
|
|
|
|
|
174
|
6
|
|
|
|
|
65
|
$node->{'__VALUE__'} = Farly::IPv4::Network->new("$ip $mask");
|
175
|
|
|
|
|
|
|
}
|
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
sub ANY {
|
178
|
72
|
|
|
72
|
0
|
169
|
my ( $self, $node ) = @_;
|
179
|
72
|
|
|
|
|
523
|
$node->{'__VALUE__'} = Farly::IPv4::Network->new("0.0.0.0 0.0.0.0");
|
180
|
|
|
|
|
|
|
}
|
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
sub DEFAULT_ROUTE {
|
183
|
5
|
|
|
5
|
0
|
13
|
my ( $self, $node ) = @_;
|
184
|
5
|
|
|
|
|
38
|
$node->{'__VALUE__'} = Farly::IPv4::Network->new("0.0.0.0 0.0.0.0");
|
185
|
|
|
|
|
|
|
}
|
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
sub ICMP_TYPE {
|
188
|
20
|
|
|
20
|
0
|
51
|
my ( $self, $node ) = @_;
|
189
|
|
|
|
|
|
|
|
190
|
20
|
|
|
|
|
60
|
my $icmp_type = $node->{'__VALUE__'};
|
191
|
|
|
|
|
|
|
|
192
|
20
|
50
|
|
|
|
81
|
$node->{'__VALUE__'} = defined( $self->icmp_formatter()->as_integer($icmp_type) )
|
193
|
|
|
|
|
|
|
? Farly::IPv4::ICMPType->new( $self->icmp_formatter()->as_integer($icmp_type) )
|
194
|
|
|
|
|
|
|
: Farly::IPv4::ICMPType->new($icmp_type);
|
195
|
|
|
|
|
|
|
}
|
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
sub PROTOCOL {
|
198
|
168
|
|
|
168
|
0
|
446
|
my ( $self, $node ) = @_;
|
199
|
|
|
|
|
|
|
|
200
|
168
|
|
|
|
|
336
|
my $protocol = $node->{'__VALUE__'};
|
201
|
|
|
|
|
|
|
|
202
|
168
|
100
|
|
|
|
555
|
$node->{'__VALUE__'} = defined( $self->protocol_formatter()->as_integer($protocol) )
|
203
|
|
|
|
|
|
|
? Farly::Transport::Protocol->new( $self->protocol_formatter()->as_integer($protocol) )
|
204
|
|
|
|
|
|
|
: Farly::Transport::Protocol->new($protocol);
|
205
|
|
|
|
|
|
|
}
|
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
sub PORT_ID {
|
208
|
65
|
|
|
65
|
0
|
159
|
my ( $self, $node ) = @_;
|
209
|
|
|
|
|
|
|
|
210
|
65
|
|
|
|
|
165
|
my $port = $node->{'__VALUE__'};
|
211
|
|
|
|
|
|
|
|
212
|
65
|
100
|
|
|
|
259
|
$node->{'__VALUE__'} = defined( $self->port_formatter()->as_integer($port) )
|
213
|
|
|
|
|
|
|
? Farly::Transport::Port->new( $self->port_formatter()->as_integer($port) )
|
214
|
|
|
|
|
|
|
: Farly::Transport::Port->new($port);
|
215
|
|
|
|
|
|
|
}
|
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
sub PORT_RANGE {
|
218
|
15
|
|
|
15
|
0
|
41
|
my ( $self, $node ) = @_;
|
219
|
|
|
|
|
|
|
|
220
|
15
|
|
|
|
|
48
|
my $port_range = $node->{'__VALUE__'};
|
221
|
|
|
|
|
|
|
|
222
|
15
|
|
|
|
|
71
|
my ( $low, $high ) = split( /\s+/, $port_range );
|
223
|
|
|
|
|
|
|
|
224
|
15
|
50
|
|
|
|
73
|
if ( defined $self->port_formatter()->as_integer($low) ) {
|
225
|
0
|
|
|
|
|
0
|
$low = $self->port_formatter()->as_integer($low);
|
226
|
|
|
|
|
|
|
}
|
227
|
|
|
|
|
|
|
|
228
|
15
|
50
|
|
|
|
52
|
if ( defined $self->port_formatter()->as_integer($high) ) {
|
229
|
0
|
|
|
|
|
0
|
$high = $self->port_formatter()->as_integer($high);
|
230
|
|
|
|
|
|
|
}
|
231
|
|
|
|
|
|
|
|
232
|
15
|
|
|
|
|
191
|
$node->{'__VALUE__'} = Farly::Transport::PortRange->new("$low $high");
|
233
|
|
|
|
|
|
|
}
|
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
sub PORT_GT {
|
236
|
15
|
|
|
15
|
0
|
40
|
my ( $self, $node ) = @_;
|
237
|
|
|
|
|
|
|
|
238
|
15
|
|
|
|
|
45
|
my $port = $node->{'__VALUE__'};
|
239
|
|
|
|
|
|
|
|
240
|
15
|
50
|
|
|
|
60
|
$node->{'__VALUE__'} = defined( $self->port_formatter()->as_integer($port) )
|
241
|
|
|
|
|
|
|
? Farly::Transport::PortGT->new( $self->port_formatter()->as_integer($port) )
|
242
|
|
|
|
|
|
|
: Farly::Transport::PortGT->new($port);
|
243
|
|
|
|
|
|
|
}
|
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
sub PORT_LT {
|
246
|
0
|
|
|
0
|
0
|
0
|
my ( $self, $node ) = @_;
|
247
|
|
|
|
|
|
|
|
248
|
0
|
|
|
|
|
0
|
my $port = $node->{'__VALUE__'};
|
249
|
|
|
|
|
|
|
|
250
|
0
|
0
|
|
|
|
0
|
$node->{'__VALUE__'} = defined( $self->port_formatter()->as_integer($port) )
|
251
|
|
|
|
|
|
|
? Farly::Transport::PortLT->new( $self->port_formatter()->as_integer($port) )
|
252
|
|
|
|
|
|
|
: Farly::Transport::PortLT->new($port);
|
253
|
|
|
|
|
|
|
}
|
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
sub _new_ObjectRef {
|
256
|
107
|
|
|
107
|
|
235
|
my ( $self, $token_class, $value ) = @_;
|
257
|
|
|
|
|
|
|
|
258
|
107
|
50
|
|
|
|
413
|
my $entry = $Entry_Map->{$token_class}
|
259
|
|
|
|
|
|
|
or confess "No token type to ENTRY mapping for token $token_class\n";
|
260
|
|
|
|
|
|
|
|
261
|
107
|
|
|
|
|
635
|
my $ce = Farly::Object::Ref->new();
|
262
|
|
|
|
|
|
|
|
263
|
107
|
|
|
|
|
447
|
$ce->set( 'ENTRY', Farly::Value::String->new($entry) );
|
264
|
107
|
|
|
|
|
397
|
$ce->set( 'ID', Farly::Value::String->new($value) );
|
265
|
|
|
|
|
|
|
|
266
|
107
|
|
|
|
|
457
|
return $ce;
|
267
|
|
|
|
|
|
|
}
|
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
sub AUTOLOAD {
|
270
|
1271
|
|
|
1271
|
|
1662
|
my ( $self, $node ) = @_;
|
271
|
|
|
|
|
|
|
|
272
|
1271
|
50
|
|
|
|
2847
|
my $type = ref($self)
|
273
|
|
|
|
|
|
|
or confess "$self is not an object";
|
274
|
|
|
|
|
|
|
|
275
|
1271
|
50
|
|
|
|
2535
|
confess "tree node for $type required"
|
276
|
|
|
|
|
|
|
unless defined($node);
|
277
|
|
|
|
|
|
|
|
278
|
1271
|
50
|
|
|
|
2856
|
confess "value not found in node ", ref($node)
|
279
|
|
|
|
|
|
|
unless defined( $node->{'__VALUE__'} );
|
280
|
|
|
|
|
|
|
|
281
|
1271
|
|
|
|
|
1714
|
my $token_class = ref($node);
|
282
|
|
|
|
|
|
|
|
283
|
1271
|
50
|
|
|
|
3813
|
my $class = $Token_Class_Map->{$token_class}
|
284
|
|
|
|
|
|
|
or confess "$self error: class not found for $token_class\n";
|
285
|
|
|
|
|
|
|
|
286
|
1271
|
|
|
|
|
1365
|
my $object;
|
287
|
|
|
|
|
|
|
|
288
|
1271
|
|
|
|
|
1933
|
my $value = $node->{'__VALUE__'};
|
289
|
|
|
|
|
|
|
|
290
|
1271
|
100
|
|
|
|
2482
|
if ( $class eq 'Farly::Object::Ref' ) {
|
291
|
|
|
|
|
|
|
#need to set 'ENTRY' and 'ID' properties
|
292
|
107
|
|
|
|
|
448
|
$object = $self->_new_ObjectRef( $token_class, $value );
|
293
|
|
|
|
|
|
|
}
|
294
|
|
|
|
|
|
|
else {
|
295
|
|
|
|
|
|
|
#create the object right away
|
296
|
1164
|
|
|
|
|
4926
|
$object = $class->new($value);
|
297
|
|
|
|
|
|
|
}
|
298
|
|
|
|
|
|
|
|
299
|
1271
|
|
|
|
|
3266
|
$node->{'__VALUE__'} = $object;
|
300
|
|
|
|
|
|
|
}
|
301
|
|
|
|
|
|
|
|
302
|
0
|
|
|
0
|
|
|
sub DESTROY { }
|
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
1;
|
305
|
|
|
|
|
|
|
__END__
|