line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# -*- Mode: Perl -*- |
2
|
|
|
|
|
|
|
# $Basename: Base.pm $ |
3
|
|
|
|
|
|
|
# $Revision: 1.3 $ |
4
|
|
|
|
|
|
|
# Author : Ulrich Pfeifer |
5
|
|
|
|
|
|
|
# Created On : Mon Mar 25 09:58:31 1996 |
6
|
|
|
|
|
|
|
# Last Modified By: Ulrich Pfeifer |
7
|
|
|
|
|
|
|
# Last Modified On: Sun Feb 10 21:53:37 2002 |
8
|
|
|
|
|
|
|
# Language : Perl |
9
|
|
|
|
|
|
|
# |
10
|
|
|
|
|
|
|
# (C) Copyright 1996, Universität Dortmund, all rights reserved. |
11
|
|
|
|
|
|
|
# |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
package Logfile::Base; |
14
|
8
|
|
|
8
|
|
43
|
use Carp; |
|
8
|
|
|
|
|
15
|
|
|
8
|
|
|
|
|
857
|
|
15
|
8
|
|
|
8
|
|
39
|
use vars qw($VERSION $nextfh); |
|
8
|
|
|
|
|
13
|
|
|
8
|
|
|
|
|
471
|
|
16
|
8
|
|
|
8
|
|
93
|
use strict; |
|
8
|
|
|
|
|
11
|
|
|
8
|
|
|
|
|
19512
|
|
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
# $Format: "$\VERSION = sprintf '%5.3f', ($ProjectMajorVersion$ * 100 + ($ProjectMinorVersion$-1))/1000;"$ |
19
|
|
|
|
|
|
|
$VERSION = sprintf '%5.3f', (2 * 100 + (3-1))/1000; |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
$Logfile::MAXWIDTH = 40; |
22
|
|
|
|
|
|
|
my ($HaveParseDate, $HaveGetDate, $HaveDateGetDate); |
23
|
|
|
|
|
|
|
$nextfh = 'fh000'; |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
sub isafh { |
26
|
8
|
|
|
8
|
0
|
13
|
my $f = shift; |
27
|
8
|
50
|
33
|
|
|
147
|
ref $f eq 'GLOB' |
28
|
|
|
|
|
|
|
or ref \$f eq 'GLOB' |
29
|
|
|
|
|
|
|
or (ref $f) =~ /^IO::/ |
30
|
|
|
|
|
|
|
} |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
sub new { |
33
|
8
|
|
|
8
|
0
|
179
|
my $type = shift; |
34
|
8
|
|
|
|
|
42
|
my %par = @_; |
35
|
8
|
|
|
|
|
20
|
my $self = {}; |
36
|
8
|
|
|
|
|
22
|
my $file = $par{File}; |
37
|
|
|
|
|
|
|
|
38
|
8
|
50
|
|
|
|
35
|
if (ref $par{Group}) { |
39
|
8
|
|
|
|
|
24
|
$self->{Group} = $par{Group}; |
40
|
|
|
|
|
|
|
} else { |
41
|
0
|
|
|
|
|
0
|
$self->{Group} = [$par{Group}]; |
42
|
|
|
|
|
|
|
} |
43
|
8
|
50
|
|
|
|
24
|
if ($file) { |
44
|
8
|
50
|
|
|
|
35
|
if (isafh $file) { |
45
|
0
|
|
|
|
|
0
|
$self->{Fh} = $file; |
46
|
|
|
|
|
|
|
} else { |
47
|
8
|
|
|
|
|
88
|
*S = $self->{Fh} = "${type}::".++$nextfh; |
48
|
8
|
50
|
|
|
|
39
|
if ($file =~ /\.gz$/) { |
49
|
0
|
0
|
|
|
|
0
|
open(S, "gzip -cd $file|") |
50
|
|
|
|
|
|
|
or die "Could not open $file: $!\n"; |
51
|
|
|
|
|
|
|
} else { |
52
|
8
|
50
|
|
|
|
631
|
open(S, "$file") |
53
|
|
|
|
|
|
|
or die "Could not open $file: $!\n"; |
54
|
|
|
|
|
|
|
} |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
} |
57
|
|
|
|
|
|
|
} else { |
58
|
0
|
|
|
|
|
0
|
$self->{Fh} = *ARGV; |
59
|
|
|
|
|
|
|
} |
60
|
8
|
|
33
|
|
|
51
|
bless $self, $type || ref($type); |
61
|
8
|
|
|
|
|
72
|
$self->readfile; |
62
|
0
|
0
|
|
|
|
0
|
close S if $self->{File}; |
63
|
0
|
|
|
|
|
0
|
$self; |
64
|
|
|
|
|
|
|
} |
65
|
|
|
|
|
|
|
|
66
|
0
|
|
|
0
|
0
|
0
|
sub norm { $_[2]; } # dummy |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
sub group { |
69
|
0
|
|
|
0
|
0
|
0
|
my ($self, $group) = @_; |
70
|
|
|
|
|
|
|
|
71
|
0
|
0
|
|
|
|
0
|
if (ref($group)) { |
72
|
0
|
|
|
|
|
0
|
join $;, @{$group}; |
|
0
|
|
|
|
|
0
|
|
73
|
|
|
|
|
|
|
} else { |
74
|
0
|
|
|
|
|
0
|
$group; |
75
|
|
|
|
|
|
|
} |
76
|
|
|
|
|
|
|
} |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
sub key { |
79
|
0
|
|
|
0
|
0
|
0
|
my ($self, $group, $rec) = @_; |
80
|
0
|
|
|
|
|
0
|
my $key = ''; |
81
|
|
|
|
|
|
|
|
82
|
0
|
0
|
|
|
|
0
|
if (ref($group)) { |
83
|
0
|
|
|
|
|
0
|
$key = join $;, map($self->norm($_, $rec->{$_}), @{$group}); |
|
0
|
|
|
|
|
0
|
|
84
|
|
|
|
|
|
|
} else { |
85
|
0
|
|
|
|
|
0
|
$key = $self->norm($group, $rec->{$group}); |
86
|
|
|
|
|
|
|
} |
87
|
0
|
|
|
|
|
0
|
$key; |
88
|
|
|
|
|
|
|
} |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
sub readfile { |
91
|
8
|
|
|
8
|
0
|
364
|
my $self = shift; |
92
|
8
|
|
|
|
|
59
|
my $fh = $self->{Fh}; |
93
|
8
|
|
|
|
|
18
|
my @group = @{$self->{Group}}; |
|
8
|
|
|
|
|
32
|
|
94
|
8
|
|
|
|
|
13
|
my $group; |
95
|
|
|
|
|
|
|
|
96
|
8
|
|
|
|
|
265
|
while (!eof($fh)) { |
97
|
8
|
|
|
|
|
61
|
my $rec = $self->next; |
98
|
0
|
0
|
|
|
|
0
|
last unless $rec; |
99
|
0
|
|
|
|
|
0
|
for $group (@group) { |
100
|
0
|
|
|
|
|
0
|
my $gname = $self->group($group); |
101
|
0
|
|
|
|
|
0
|
my $key = $self->key($group, $rec); |
102
|
|
|
|
|
|
|
|
103
|
0
|
0
|
|
|
|
0
|
if (defined $self->{$gname}->{$key}) { |
104
|
0
|
|
|
|
|
0
|
$self->{$gname}->{$key}->add($rec,$group); # !! |
105
|
|
|
|
|
|
|
} else { |
106
|
0
|
|
|
|
|
0
|
$self->{$gname}->{$key} = $rec->copy; |
107
|
|
|
|
|
|
|
} |
108
|
|
|
|
|
|
|
} |
109
|
|
|
|
|
|
|
} |
110
|
|
|
|
|
|
|
} |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
sub report { |
113
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
114
|
0
|
|
|
|
|
0
|
my %par = @_; |
115
|
0
|
|
|
|
|
0
|
my $group = $self->group($par{Group}); |
116
|
0
|
|
0
|
|
|
0
|
my $sort = $par{Sort} || $group; |
117
|
0
|
|
0
|
|
|
0
|
my $rever = (($sort =~ /Date|Hour/) xor $par{Reverse}); |
118
|
0
|
|
|
|
|
0
|
my $list = $par{List}; |
119
|
0
|
|
|
|
|
0
|
my ($keys, $key, $val, %keys); |
120
|
0
|
|
|
|
|
0
|
my $mklen = length($group); |
121
|
0
|
0
|
|
|
|
0
|
my $direction = ($rever)?'increasing':'decreasing'; |
122
|
0
|
|
|
|
|
0
|
my (@list, %absolute); |
123
|
0
|
|
|
|
|
0
|
my @mklen = map(length($_), split($;, $group)); |
124
|
|
|
|
|
|
|
|
125
|
0
|
0
|
|
|
|
0
|
croak "No index for $group\n" unless $self->{$group}; |
126
|
|
|
|
|
|
|
|
127
|
0
|
0
|
|
|
|
0
|
if ($list) { |
128
|
0
|
0
|
|
|
|
0
|
if (ref($list)) { |
129
|
0
|
|
|
|
|
0
|
@list = @{$list}; |
|
0
|
|
|
|
|
0
|
|
130
|
|
|
|
|
|
|
} else { |
131
|
0
|
|
|
|
|
0
|
@list = ($list); |
132
|
|
|
|
|
|
|
} |
133
|
|
|
|
|
|
|
} else { |
134
|
0
|
|
|
|
|
0
|
@list = qw(Records); |
135
|
|
|
|
|
|
|
} |
136
|
|
|
|
|
|
|
|
137
|
0
|
|
|
|
|
0
|
@absolute{@list} = (0) x @list; |
138
|
0
|
|
|
|
|
0
|
$sort =~ s/$;.*//; |
139
|
|
|
|
|
|
|
#print STDERR "sort = $sort\n"; |
140
|
0
|
|
|
|
|
0
|
while (($key,$val) = each %{$self->{$group}}) { |
|
0
|
|
|
|
|
0
|
|
141
|
0
|
|
|
|
|
0
|
$keys{$key} = $val->{$sort}; |
142
|
0
|
0
|
|
|
|
0
|
if ($key =~ /$;/) { |
143
|
0
|
|
|
|
|
0
|
my @key = split $;, $key; |
144
|
0
|
|
|
|
|
0
|
for (0 .. $#key) { |
145
|
0
|
0
|
|
|
|
0
|
$mklen[$_] = length($key[$_]) |
146
|
|
|
|
|
|
|
if length($key[$_]) > $mklen[$_]; |
147
|
|
|
|
|
|
|
} |
148
|
0
|
|
|
|
|
0
|
$mklen = $#mklen; |
149
|
0
|
|
|
|
|
0
|
grep ($mklen += $_, @mklen); |
150
|
|
|
|
|
|
|
} else { |
151
|
0
|
0
|
|
|
|
0
|
$mklen = length($key) if length($key) > $mklen; |
152
|
|
|
|
|
|
|
} |
153
|
0
|
|
|
|
|
0
|
for (@list) { |
154
|
0
|
0
|
|
|
|
0
|
$absolute{$_} += $val->{$_} if defined $val->{$_}; |
155
|
|
|
|
|
|
|
} |
156
|
|
|
|
|
|
|
} |
157
|
|
|
|
|
|
|
# chop keys to $Logfile::MAXWIDTH chars maximum; |
158
|
0
|
0
|
|
|
|
0
|
grep (($_=($_>$Logfile::MAXWIDTH)?$Logfile::MAXWIDTH:$_), @mklen); |
159
|
0
|
0
|
|
|
|
0
|
if ($group =~ /$;/) { |
160
|
0
|
|
|
|
|
0
|
my @key = split $;, $group; |
161
|
0
|
|
|
|
|
0
|
for (0 .. $#key) { |
162
|
0
|
|
|
|
|
0
|
printf "%-${mklen[$_]}s ", $key[$_]; |
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
} else { |
165
|
0
|
|
|
|
|
0
|
printf ("%-${mklen}s ", $group); |
166
|
|
|
|
|
|
|
} |
167
|
0
|
|
|
|
|
0
|
for (@list) { |
168
|
0
|
|
|
|
|
0
|
printf("%16s ", $_); |
169
|
|
|
|
|
|
|
} |
170
|
0
|
|
|
|
|
0
|
print "\n"; |
171
|
0
|
|
|
|
|
0
|
print '=' x ($mklen + (@list * 17)); |
172
|
0
|
|
|
|
|
0
|
print "\n"; |
173
|
|
|
|
|
|
|
#for $key (keys %keys) { |
174
|
|
|
|
|
|
|
# print STDERR "** $key $keys{$key}\n"; |
175
|
|
|
|
|
|
|
#} |
176
|
0
|
|
|
|
|
0
|
for $key (sort {&srt($rever, $keys{$a}, $keys{$b})} |
|
0
|
|
|
|
|
0
|
|
177
|
|
|
|
|
|
|
keys %keys) { |
178
|
0
|
|
|
|
|
0
|
my $val = $self->{$group}->{$key}; |
179
|
0
|
0
|
|
|
|
0
|
if ($key =~ /$;/) { |
180
|
0
|
|
|
|
|
0
|
my @key = split $;, $key; |
181
|
0
|
|
|
|
|
0
|
for (0 .. $#key) { |
182
|
0
|
|
|
|
|
0
|
printf "%-${mklen[$_]}s ", substr($key[$_],0,$mklen[$_]); |
183
|
|
|
|
|
|
|
} |
184
|
|
|
|
|
|
|
} else { |
185
|
0
|
|
|
|
|
0
|
printf "%-${mklen}s ", $key; |
186
|
|
|
|
|
|
|
} |
187
|
0
|
|
|
|
|
0
|
for $list (@list) { |
188
|
0
|
0
|
|
|
|
0
|
my $ba = (defined $val->{$list})?$val->{$list}:0; |
189
|
0
|
0
|
|
|
|
0
|
if ($absolute{$list} > 0) { |
190
|
0
|
|
|
|
|
0
|
my $br = $ba/$absolute{$list}*100; |
191
|
0
|
|
|
|
|
0
|
printf "%9d%6.2f%% ", $ba, $br; |
192
|
|
|
|
|
|
|
} else { |
193
|
0
|
|
|
|
|
0
|
printf "%15s ", $ba; |
194
|
|
|
|
|
|
|
} |
195
|
|
|
|
|
|
|
} |
196
|
0
|
|
|
|
|
0
|
print "\n"; |
197
|
0
|
0
|
0
|
|
|
0
|
last if defined $par{Top} && --$par{Top} <= 0; |
198
|
|
|
|
|
|
|
} |
199
|
0
|
|
|
|
|
0
|
print "\f"; |
200
|
|
|
|
|
|
|
} |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
sub srt { |
203
|
0
|
|
|
0
|
0
|
0
|
my $rev = shift; |
204
|
0
|
|
|
|
|
0
|
my ($y,$x); |
205
|
0
|
0
|
|
|
|
0
|
if ($rev) { |
206
|
0
|
|
|
|
|
0
|
($x,$y) = @_; |
207
|
|
|
|
|
|
|
} else { |
208
|
0
|
|
|
|
|
0
|
($y,$x) = @_; |
209
|
|
|
|
|
|
|
} |
210
|
|
|
|
|
|
|
|
211
|
0
|
0
|
0
|
|
|
0
|
if ($x =~ /[^\d.]|^$/o or $y =~ /[^\d.]|^$/o) { |
212
|
0
|
|
|
|
|
0
|
lc $y cmp lc $x; |
213
|
|
|
|
|
|
|
} else { |
214
|
0
|
|
|
|
|
0
|
$x <=> $y; |
215
|
|
|
|
|
|
|
} |
216
|
|
|
|
|
|
|
} |
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
sub keys { |
219
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
220
|
0
|
|
|
|
|
0
|
my $group = shift; |
221
|
|
|
|
|
|
|
|
222
|
0
|
|
|
|
|
0
|
keys %{$self->{$group}}; |
|
0
|
|
|
|
|
0
|
|
223
|
|
|
|
|
|
|
} |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
sub all { |
226
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
227
|
0
|
|
|
|
|
0
|
my $group = shift; |
228
|
|
|
|
|
|
|
|
229
|
0
|
|
|
|
|
0
|
%{$self->{$group}}; |
|
0
|
|
|
|
|
0
|
|
230
|
|
|
|
|
|
|
} |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
package Logfile::Base::Record; |
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
BEGIN { |
235
|
8
|
|
|
8
|
|
36
|
eval {require GetDate;}; |
|
8
|
|
|
|
|
3686
|
|
236
|
8
|
50
|
|
|
|
66
|
$HaveGetDate = ($@ eq "") and import GetDate 'getdate'; |
237
|
8
|
50
|
|
|
|
38
|
unless ($HaveGetDate) { |
238
|
8
|
|
|
|
|
16
|
eval {require Date::GetDate}; |
|
8
|
|
|
|
|
3155
|
|
239
|
8
|
50
|
|
|
|
65
|
$HaveDateGetDate = ($@ eq "") and import GetDate 'getdate'; |
240
|
8
|
50
|
|
|
|
26
|
unless ($HaveDateGetDate) { |
241
|
8
|
|
|
|
|
14
|
eval { |
242
|
8
|
|
|
|
|
3389
|
require Time::ParseDate; |
243
|
0
|
|
|
0
|
|
0
|
sub parsedate { &Time::ParseDate::parsedate(@_) } |
244
|
|
|
|
|
|
|
}; |
245
|
8
|
|
|
|
|
570
|
$HaveParseDate = ($@ eq ""); |
246
|
|
|
|
|
|
|
} |
247
|
|
|
|
|
|
|
} |
248
|
|
|
|
|
|
|
}; |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
unless ($HaveGetDate or $HaveDateGetDate |
251
|
|
|
|
|
|
|
or $HaveParseDate) { |
252
|
8
|
|
|
8
|
|
8465
|
eval join '', ; |
|
8
|
|
|
|
|
17869
|
|
|
8
|
|
|
|
|
5057
|
|
253
|
|
|
|
|
|
|
} |
254
|
|
|
|
|
|
|
|
255
|
8
|
|
|
8
|
|
7148
|
use Net::Country; |
|
8
|
|
|
|
|
22
|
|
|
8
|
|
|
|
|
6213
|
|
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
sub new { |
258
|
8
|
|
|
8
|
|
22
|
my $type = shift; |
259
|
8
|
|
|
|
|
53
|
my %par = @_; |
260
|
8
|
|
|
|
|
14
|
my $self = {}; |
261
|
8
|
|
|
|
|
15
|
my ($sec,$min,$hours,$mday,$mon,$year, $time); |
262
|
|
|
|
|
|
|
|
263
|
8
|
|
|
|
|
32
|
%{$self} = %par; |
|
8
|
|
|
|
|
30
|
|
264
|
|
|
|
|
|
|
|
265
|
8
|
50
|
|
|
|
51
|
if ($par{Date}) { |
266
|
|
|
|
|
|
|
#print "$par{Date} => "; |
267
|
8
|
50
|
|
|
|
63
|
if ($HaveGetDate) { |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
268
|
0
|
|
|
|
|
0
|
$par{Date} =~ s!(\d\d\d\d):!$1 !o; |
269
|
0
|
|
|
|
|
0
|
$par{Date} =~ s!/! !go; |
270
|
0
|
|
|
|
|
0
|
$time = getdate($par{Date}); |
271
|
|
|
|
|
|
|
} elsif ($HaveDateGetDate) { |
272
|
0
|
|
|
|
|
0
|
$par{Date} =~ s!(\d\d\d\d):!$1 !o; |
273
|
0
|
|
|
|
|
0
|
$par{Date} =~ s!/! !go; |
274
|
0
|
|
|
|
|
0
|
$time = Date::GetDate::getdate($par{Date}); |
275
|
|
|
|
|
|
|
} elsif ($HaveParseDate) { |
276
|
|
|
|
|
|
|
|
277
|
0
|
|
|
|
|
0
|
$time = parsedate($par{Date}, |
278
|
|
|
|
|
|
|
FUZZY => 1, |
279
|
|
|
|
|
|
|
NO_RELATIVE => 1); |
280
|
|
|
|
|
|
|
} else { |
281
|
8
|
|
|
|
|
2567
|
$time = &Time::String::to_time($par{Date}); |
282
|
|
|
|
|
|
|
} |
283
|
0
|
|
|
|
|
|
($sec,$min,$hours,$mday,$mon,$year) = localtime($time); |
284
|
|
|
|
|
|
|
#print "$par{Date} => (s>$sec,m>$min,h>$hours,m>$mday,m>$mon,y>$year)\n"; |
285
|
0
|
|
0
|
|
|
|
$self->{Hour} = sprintf "%02d", $self->{Hour}||$hours; |
286
|
0
|
|
|
|
|
|
$self->{Date} = sprintf("%02d%02d%02d", $year%100, $mon+1, $mday); |
287
|
|
|
|
|
|
|
} |
288
|
0
|
0
|
|
|
|
|
if ($par{Host}) { |
289
|
0
|
|
|
|
|
|
my $host = $self->{Host} = lc($par{Host}); |
290
|
0
|
0
|
|
|
|
|
if ($host =~ /[^\d.]/) { |
291
|
0
|
0
|
|
|
|
|
if ($host =~ /\./) { |
292
|
0
|
|
|
|
|
|
$self->{Domain} = Net::Country::Name((split /\./, $host)[-1]); |
293
|
|
|
|
|
|
|
} else { |
294
|
0
|
|
|
|
|
|
$self->{Domain} = 'Local'; |
295
|
|
|
|
|
|
|
} |
296
|
|
|
|
|
|
|
} else { |
297
|
0
|
|
|
|
|
|
$self->{Domain} = 'Unresolved'; |
298
|
|
|
|
|
|
|
} |
299
|
|
|
|
|
|
|
} |
300
|
0
|
|
|
|
|
|
$self->{Records} = 1; |
301
|
|
|
|
|
|
|
|
302
|
0
|
|
|
|
|
|
bless $self, $type; |
303
|
|
|
|
|
|
|
} |
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
sub add { |
306
|
0
|
|
|
0
|
|
|
my $self = shift; |
307
|
0
|
|
|
|
|
|
my $other = shift; |
308
|
0
|
|
|
|
|
|
my $ignore = shift; |
309
|
|
|
|
|
|
|
|
310
|
0
|
|
|
|
|
|
for (keys %{$other}) { |
|
0
|
|
|
|
|
|
|
311
|
0
|
0
|
|
|
|
|
next if $_ eq $ignore; |
312
|
0
|
0
|
|
|
|
|
next unless defined $other->{$_}; |
313
|
0
|
0
|
|
|
|
|
next unless length($other->{$_}); |
314
|
0
|
0
|
|
|
|
|
next if $other->{$_} =~ /\D/; |
315
|
0
|
|
|
|
|
|
$self->{$_} += $other->{$_}; |
316
|
|
|
|
|
|
|
} |
317
|
|
|
|
|
|
|
|
318
|
0
|
|
|
|
|
|
$self; |
319
|
|
|
|
|
|
|
} |
320
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
sub copy { |
322
|
0
|
|
|
0
|
|
|
my $self = shift; |
323
|
0
|
|
|
|
|
|
my %new = %{$self}; |
|
0
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
|
325
|
0
|
|
|
|
|
|
bless \%new, ref($self); |
326
|
|
|
|
|
|
|
} |
327
|
|
|
|
|
|
|
|
328
|
0
|
|
|
0
|
|
|
sub requests {$_[0]->{Records};} |
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
1; |
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
__DATA__ |