~ubuntu-branches/ubuntu/oneiric/bioperl/oneiric

« back to all changes in this revision

Viewing changes to examples/exceptions/Bio/Seq.pm

  • Committer: Bazaar Package Importer
  • Author(s): Matt Hope
  • Date: 2004-04-18 14:24:11 UTC
  • mfrom: (1.2.1 upstream) (2.1.1 warty)
  • Revision ID: james.westby@ubuntu.com-20040418142411-gr92uexquw4w8liq
Tags: 1.4-1
* New upstream release
* Examples and working code are installed by default to usr/bin,
  this has been moved to usr/share/doc/bioperl/bin

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# $Id: Seq.pm,v 1.1.1.1 2001/12/27 16:32:42 sac Exp $
2
 
#
3
 
# BioPerl module for Bio::Seq
4
 
#
5
 
# Cared for by Ewan Birney <birney@sanger.ac.uk>
6
 
#
7
 
# Copyright Ewan Birney
8
 
#
9
 
# You may distribute this module under the same terms as perl itself
10
 
 
11
 
# POD documentation - main docs before the code
12
 
 
13
 
=head1 NAME
14
 
 
15
 
Bio::Seq - Sequence object, with features
16
 
 
17
 
=head1 SYNOPSIS
18
 
 
19
 
    $seqio  = Bio::SeqIO->new ( '-format' => 'embl' , -file => 'myfile.dat');
20
 
    $seqobj = $seqio->next_seq();
21
 
 
22
 
    # features must implement Bio::SeqFeatureI
23
 
 
24
 
    @features = $seqobj->top_SeqFeatures(); # just top level
25
 
    @features = $seqobj->all_SeqFeatures(); # descend into sub features
26
 
 
27
 
    $seq      = $seqobj->seq(); # actual sequence as a string
28
 
    $seqstr   = $seqobj->subseq(10,50);
29
 
    $ann      = $seqobj->annotation(); # annotation object
30
 
 
31
 
=head1 DESCRIPTION
32
 
 
33
 
A Seq object is a sequence with sequence features placed on them. The
34
 
Seq object contains a PrimarySeq object for the actual sequence and
35
 
also implements its interface.
36
 
 
37
 
In bioperl we have 3 main players that people are going to use
38
 
 
39
 
  Bio::PrimarySeq - just the sequence and its names, nothing else.
40
 
  Bio::SeqFeatureI - a location on a sequence, potentially with a sequence.
41
 
                    and annotation
42
 
  Bio::Seq        - A sequence and a collection of seqfeatures (an aggregate) with
43
 
                    its own annotation.
44
 
 
45
 
Although bioperl is not tied to file formats heavily, these distinctions do
46
 
map to file formats sensibly and for some bioinformaticians this might help
47
 
you:
48
 
 
49
 
  Bio::PrimarySeq - Fasta file of a sequence
50
 
  Bio::SeqFeatureI - A single entry in an EMBL/GenBank/DDBJ feature table
51
 
  Bio::Seq        - A single EMBL/GenBank/DDBJ entry
52
 
 
53
 
By having this split we avoid alot of nasty ciricular references
54
 
(seqfeatures can hold a reference to a sequence without the sequence
55
 
holding a reference to the seqfeature).
56
 
 
57
 
Ian Korf really helped in the design of the Seq and SeqFeature system.
58
 
 
59
 
=head1 FEEDBACK
60
 
 
61
 
=head2 Mailing Lists
62
 
 
63
 
User feedback is an integral part of the evolution of this
64
 
and other Bioperl modules. Send your comments and suggestions preferably
65
 
 to one of the Bioperl mailing lists.
66
 
Your participation is much appreciated.
67
 
 
68
 
  bioperl-l@bioperl.org                 - General discussion
69
 
  http://bio.perl.org/MailList.html  - About the mailing lists
70
 
 
71
 
=head2 Reporting Bugs
72
 
 
73
 
Report bugs to the Bioperl bug tracking system to help us keep track
74
 
 the bugs and their resolution.
75
 
 Bug reports can be submitted via email or the web:
76
 
 
77
 
  bioperl-bugs@bioperl.org
78
 
  http://bio.perl.org/bioperl-bugs/
79
 
 
80
 
=head1 AUTHOR - Ewan Birney, inspired by Ian Korf objects
81
 
 
82
 
Email birney@sanger.ac.uk
83
 
 
84
 
Describe contact details here
85
 
 
86
 
=head1 APPENDIX
87
 
 
88
 
The rest of the documentation details each of the object methods. Internal methods are usually preceded with a _
89
 
 
90
 
=cut
91
 
 
92
 
 
93
 
# Let the code begin...
94
 
 
95
 
 
96
 
package Bio::Seq;
97
 
use vars qw(@ISA);
98
 
use strict;
99
 
use Bio::SeqI;
100
 
 
101
 
# Object preamble - inheriets from Bio::Root::Object
102
 
 
103
 
use Bio::Root::RootI;
104
 
use Bio::Annotation;
105
 
use Bio::PrimarySeq;
106
 
 
107
 
@ISA = qw(Bio::Root::RootI Bio::SeqI);
108
 
 
109
 
 
110
 
=head2 new
111
 
 
112
 
 Title   : new
113
 
 Usage   : $seq    = Bio::Seq->new( -seq => 'ATGGGGGTGGTGGTACCCT',
114
 
                                    -id  => 'human_id',
115
 
                                    -accession_number => 'AL000012',
116
 
                                   );
117
 
 
118
 
 Function: Returns a new seq object from
119
 
           basic constructors, being a string for the sequence
120
 
           and strings for id and accession_number
121
 
 Returns : a new Bio::Seq object
122
 
 
123
 
=cut
124
 
 
125
 
sub new {
126
 
    # standard new call..
127
 
    my($caller,@args) = @_;
128
 
    my $self = $caller->SUPER::new(@args);
129
 
    # this is way too sneaky probably. We delegate the construction of
130
 
    # the Seq object onto PrimarySeq and then pop primary_seq into
131
 
    # our primary_seq slot
132
 
 
133
 
    my $pseq = Bio::PrimarySeq->new(@args);
134
 
    $self->{'_as_feat'} = [];
135
 
 
136
 
    my $ann = new Bio::Annotation;
137
 
    $self->annotation($ann);
138
 
    $self->primary_seq($pseq);
139
 
 
140
 
    return $self;
141
 
}
142
 
 
143
 
=head1 PrimarySeq interface
144
 
 
145
 
The primaryseq interface is the basic sequence getting
146
 
and setting methods found on all sequences.
147
 
 
148
 
These methods implement the PrimarySeq interface by delegating
149
 
to the primary_seq inside the object. This means that you
150
 
can use a Seq object wherever there is a PrimarySeq, and
151
 
of course, you are free to use these functions anyway.
152
 
 
153
 
=cut
154
 
 
155
 
=head2 seq
156
 
 
157
 
 Title   : seq
158
 
 Usage   : $string    = $obj->seq()
159
 
 Function: Returns the sequence as a string of letters. The
160
 
           case of the letters is left up to the implementer.
161
 
           Suggested cases are upper case for proteins and lower case for
162
 
           DNA sequence (IUPAC standard),
163
 
           but implementations are suggested to keep an open mind about
164
 
           case (some users... want mixed case!)
165
 
 Returns : A scalar
166
 
 
167
 
 
168
 
=cut
169
 
 
170
 
sub seq {
171
 
   my ($self,$value) = @_;
172
 
   if( defined $value ) {
173
 
       return $self->primary_seq()->seq($value);
174
 
   }
175
 
   return $self->primary_seq()->seq();
176
 
}
177
 
 
178
 
=head2 length
179
 
 
180
 
 Title   : length
181
 
 Usage   : $len = $seq->length()
182
 
 Function:
183
 
 Example :
184
 
 Returns : integer representing the length of the sequence.
185
 
 Args    :
186
 
 
187
 
=cut
188
 
 
189
 
sub length {
190
 
   my ($self) = @_;
191
 
   return $self->primary_seq()->length();
192
 
}
193
 
 
194
 
=head2 subseq
195
 
 
196
 
 Title   : subseq
197
 
 Usage   : $substring = $obj->subseq(10,40);
198
 
 Function: returns the subseq from start to end, where the first base
199
 
           is 1 and the number is inclusive, ie 1-2 are the first two
200
 
           bases of the sequence
201
 
 
202
 
           Start cannot be larger than end but can be equal
203
 
 
204
 
 Returns : a string
205
 
 Args    :
206
 
 
207
 
 
208
 
=cut
209
 
 
210
 
sub subseq {
211
 
   my ($self,$s,$e) = @_;
212
 
   return $self->primary_seq()->subseq($s,$e);
213
 
}
214
 
 
215
 
=head2 display_id
216
 
 
217
 
 Title   : display_id
218
 
 Usage   : $id_string = $obj->display_id($newid);
219
 
 Function: returns or sets the display id, aka the common name of the
220
 
           Sequence object.
221
 
 
222
 
           The semantics of this is that it is the most likely string
223
 
           to be used as an identifier of the sequence, and likely to
224
 
           have "human" readability.  The id is equivalent to the ID
225
 
           field of the GenBank/EMBL databanks and the id field of the
226
 
           Swissprot/sptrembl database. In fasta format, the >(\S+) is
227
 
           presumed to be the id, though some people overload the id
228
 
           to embed other information. Bioperl does not use any
229
 
           embedded information in the ID field, and people are
230
 
           encouraged to use other mechanisms (accession field for
231
 
           example, or extending the sequence object) to solve this.
232
 
 
233
 
           Notice that $seq->id() maps to this function, mainly for
234
 
           legacy/convience issues
235
 
 Returns : A string
236
 
 Args    : newid (optional)
237
 
 
238
 
 
239
 
=cut
240
 
 
241
 
sub display_id {
242
 
   my ($self,$value) = @_;
243
 
   if( defined $value ) {
244
 
       return $self->primary_seq->display_id($value);
245
 
   }
246
 
   return $self->primary_seq->display_id();
247
 
}
248
 
 
249
 
 
250
 
 
251
 
=head2 accession_number
252
 
 
253
 
 Title   : accession_number
254
 
 Usage   : $unique_biological_key = $obj->accession_number;
255
 
 Function: Returns the unique biological id for a sequence, commonly
256
 
           called the accession_number. For sequences from established
257
 
           databases, the implementors should try to use the correct
258
 
           accession number. Notice that primary_id() provides the
259
 
           unique id for the implemetation, allowing multiple objects
260
 
           to have the same accession number in a particular implementation.
261
 
 
262
 
           For sequences with no accession number, this method should return
263
 
           "unknown".
264
 
 Returns : A string
265
 
 Args    : None
266
 
 
267
 
 
268
 
=cut
269
 
 
270
 
sub accession_number {
271
 
   my ($self,$value) = @_;
272
 
   if( defined $value ) {
273
 
       return $self->primary_seq->accession_number($value);
274
 
   }
275
 
   return $self->primary_seq->accession_number();
276
 
}
277
 
 
278
 
 
279
 
=head2 desc
280
 
 
281
 
 Title   : desc
282
 
 Usage   : $seqobj->desc()
283
 
 Function: Sets/Gets the description of the sequnce
284
 
 Example :
285
 
 Returns :
286
 
 Args    :
287
 
 
288
 
 
289
 
=cut
290
 
 
291
 
sub desc {
292
 
   my ($self,$value) = @_;
293
 
 
294
 
   if( defined $value ) {
295
 
       return $self->primary_seq->desc($value);
296
 
   }
297
 
   return $self->primary_seq->desc();
298
 
}
299
 
 
300
 
 
301
 
 
302
 
 
303
 
=head2 primary_id
304
 
 
305
 
 Title   : primary_id
306
 
 Usage   : $unique_implementation_key = $obj->primary_id;
307
 
 Function: Returns the unique id for this object in this
308
 
           implementation. This allows implementations to manage
309
 
           their own object ids in a way the implementaiton can control
310
 
           clients can expect one id to map to one object.
311
 
 
312
 
           For sequences with no natural id, this method should return
313
 
           a stringified memory location.
314
 
 
315
 
           Also notice that this method is B<not> delegated to the
316
 
           internal PrimarySeq object
317
 
 Returns : A string
318
 
 Args    : None
319
 
 
320
 
 
321
 
=cut
322
 
 
323
 
sub primary_id {
324
 
   my ($obj,$value) = @_;
325
 
 
326
 
   if( defined $value) {
327
 
      $obj->{'primary_id'} = $value;
328
 
    }
329
 
   if( ! exists $obj->{'primary_id'} ) {
330
 
       return "$obj";
331
 
   }
332
 
   return $obj->{'primary_id'};
333
 
}
334
 
 
335
 
=head2 can_call_new
336
 
 
337
 
 Title   : can_call_new
338
 
 Usage   : if( $obj->can_call_new ) {
339
 
             $newobj = $obj->new( %param );
340
 
           }
341
 
 Function: can_call_new returns 1 or 0 depending
342
 
           on whether an implementation allows new
343
 
           constructor to be called. If a new constructor
344
 
           is allowed, then it should take the followed hashed
345
 
           constructor list.
346
 
 
347
 
           $myobject->new( -seq => $sequence_as_string,
348
 
                           -display_id  => $id
349
 
                           -accession_number => $accession
350
 
                           -moltype => 'dna',
351
 
                           );
352
 
 Example :
353
 
 Returns : 1 or 0
354
 
 Args    :
355
 
 
356
 
 
357
 
=cut
358
 
 
359
 
sub can_call_new {
360
 
   my ($self) = @_;
361
 
 
362
 
   return 1;
363
 
}
364
 
 
365
 
=head2 moltype
366
 
 
367
 
 Title   : moltype
368
 
 Usage   : if( $obj->moltype eq 'dna' ) { /Do Something/ }
369
 
 Function: Returns the type of sequence being one of
370
 
           'dna', 'rna' or 'protein'. This is case sensitive.
371
 
 
372
 
           This is not called <type> because this would cause
373
 
           upgrade problems from the 0.5 and earlier Seq objects.
374
 
 
375
 
 Returns : a string either 'dna','rna','protein'. NB - the object must
376
 
           make a call of the type - if there is no type specified it
377
 
           has to guess.
378
 
 Args    : none
379
 
 
380
 
 
381
 
=cut
382
 
 
383
 
sub moltype {
384
 
   my ($self,$value) = @_;
385
 
   if( defined $value ) {
386
 
       return $self->primary_seq->moltype($value);
387
 
   }
388
 
   return $self->primary_seq->moltype();
389
 
}
390
 
 
391
 
=head1 Methods provided in the Bio::PrimarySeqI interface
392
 
 
393
 
These methods are inherited from the PrimarySeq interface
394
 
and work as one expects, building new Bio::Seq objects
395
 
or other information as expected.
396
 
 
397
 
Sequence Features are B<not> transfered to the new objects.
398
 
This is possibly a mistake. Anyone who feels the urge in
399
 
dealing with this is welcome to give it a go.
400
 
 
401
 
=head2 revcom
402
 
 
403
 
 Title   : revcom
404
 
 Usage   : $rev = $seq->revcom()
405
 
 Function: Produces a new Bio::Seq object which
406
 
           is the reversed complement of the sequence. For protein
407
 
           sequences this throws an exception of "Sequence is a protein. Cannot revcom"
408
 
 
409
 
           The id is the same id as the orginal sequence, and the accession number
410
 
           is also indentical. If someone wants to track that this sequence has be
411
 
           reversed, it needs to define its own extensions
412
 
 
413
 
           To do an inplace edit of an object you can go:
414
 
 
415
 
           $seq = $seq->revcom();
416
 
 
417
 
           This of course, causes Perl to handle the garbage collection of the old
418
 
           object, but it is roughly speaking as efficient as an inplace edit.
419
 
 
420
 
 Returns : A new (fresh) Bio::Seq object
421
 
 Args    : none
422
 
 
423
 
 
424
 
=cut
425
 
 
426
 
=head2 trunc
427
 
 
428
 
 Title   : trunc
429
 
 Usage   : $subseq = $myseq->trunc(10,100);
430
 
 Function: Provides a truncation of a sequence,
431
 
 
432
 
 Example :
433
 
 Returns : a fresh Bio::Seq object
434
 
 Args    :
435
 
 
436
 
 
437
 
=cut
438
 
 
439
 
=head2 id
440
 
 
441
 
 Title   : id
442
 
 Usage   : $id = $seq->id()
443
 
 Function: This is mapped on display_id
444
 
 Example :
445
 
 Returns :
446
 
 Args    :
447
 
 
448
 
 
449
 
=cut
450
 
 
451
 
sub  id {
452
 
   my ($self,$value) = @_;
453
 
 
454
 
   if( defined $value ) {
455
 
        return $self->display_id($value);
456
 
   }
457
 
   return $self->display_id();
458
 
}
459
 
 
460
 
 
461
 
=head1 Seq only methods
462
 
 
463
 
These methods are specific to the Bio::Seq object, and not
464
 
found on the Bio::PrimarySeq object
465
 
 
466
 
=head2 primary_seq
467
 
 
468
 
 Title   : primary_seq
469
 
 Usage   : $obj->primary_seq($newval)
470
 
 Function:
471
 
 Example :
472
 
 Returns : value of primary_seq
473
 
 Args    : newvalue (optional)
474
 
 Throws  : Bio::Root::BadParameter if the supplied argument does
475
 
           not derive from Bio::PrimarySeqI.
476
 
 
477
 
=cut
478
 
 
479
 
sub primary_seq {
480
 
   my ($obj,$value) = @_;
481
 
 
482
 
   if( defined $value) {
483
 
       if( ! ref $value || ! $value->isa('Bio::PrimarySeqI') ) {
484
 
           $obj->throw(-class => 'Bio::Root::BadParameter',
485
 
                       -text  => "$value is not a Bio::PrimarySeq compliant object",
486
 
                       -value => $value );
487
 
       }
488
 
 
489
 
      $obj->{'primary_seq'} = $value;
490
 
      # descend down over all seqfeature objects, seeing whether they
491
 
      # want an attached seq.
492
 
 
493
 
      foreach my $sf ( $obj->top_SeqFeatures() ) {
494
 
          if( $sf->can("attach_seq") ) {
495
 
              $sf->attach_seq($value);
496
 
          } else {
497
 
              $obj->warn("In Seq primary_seq, a sequence feature cannot attach seq. Bugger");
498
 
          }
499
 
      }
500
 
 
501
 
    }
502
 
    return $obj->{'primary_seq'};
503
 
 
504
 
}
505
 
 
506
 
=head2 annotation
507
 
 
508
 
 Title   : annotation
509
 
 Usage   : $obj->annotation($seq_obj)
510
 
 Function:
511
 
 Example :
512
 
 Returns : value of annotation
513
 
 Args    : newvalue (optional)
514
 
 
515
 
 
516
 
=cut
517
 
 
518
 
sub annotation {
519
 
   my ($obj,$value) = @_;
520
 
   if( defined $value) {
521
 
      $obj->{'annotation'} = $value;
522
 
    }
523
 
    return $obj->{'annotation'};
524
 
 
525
 
}
526
 
 
527
 
=head2 add_SeqFeature
528
 
 
529
 
 Title   : add_SeqFeature
530
 
 Usage   : $seq->add_SeqFeature($feat);
531
 
           $seq->add_SeqFeature(@feat);
532
 
 Function: Adds the given feature object (or each of an array of feature
533
 
           objects to the feature array of this
534
 
           sequence. The object passed is required to implement the
535
 
           Bio::SeqFeatureI interface.
536
 
 Example :
537
 
 Returns : TRUE on success
538
 
 Args    : A Bio::SeqFeatureI implementing object, or an array of such objects.
539
 
 Throws  : Bio::Root::BadParameter if any of the supplied arguments do
540
 
           not derive from Bio::SeqFeatureI.
541
 
 
542
 
 
543
 
=cut
544
 
 
545
 
sub add_SeqFeature {
546
 
   my ($self,@feat) = @_;
547
 
   my ($fseq,$aseq);
548
 
 
549
 
 
550
 
   foreach my $feat ( @feat ) {
551
 
       if( !$feat->isa("Bio::SeqFeatureI") ) {
552
 
           $self->throw(-class => 'Bio::Root::BadParameter',
553
 
                        -text  =>"$feat is not a SeqFeatureI and that's what we expect...",
554
 
                        -value => $feat);
555
 
       }
556
 
 
557
 
       if( $feat->can("entire_seq") ) {
558
 
           $fseq = $feat->entire_seq;
559
 
           $aseq = $self->primary_seq;
560
 
        
561
 
           if( defined $aseq ) {
562
 
               if( defined $fseq ) {
563
 
                   unless ($aseq == $fseq) {
564
 
                       $self->warn("$feat has an attached sequence which is not in this annseq. I worry about this");
565
 
                   }
566
 
               } else {
567
 
                   if( $feat->can("attach_seq") ) {
568
 
                       # attach it
569
 
                       $feat->attach_seq($aseq);
570
 
                   }
571
 
               }
572
 
           } # end of if aseq
573
 
       } # end of if the feat can entire_seq
574
 
 
575
 
       push(@{$self->{'_as_feat'}},$feat);
576
 
   }
577
 
   return 1;
578
 
}
579
 
 
580
 
=head2 top_SeqFeatures
581
 
 
582
 
 Title   : top_SeqFeatures
583
 
 Usage   : @feat_ary = $seq->top_SeqFeatures();
584
 
 Function: Returns the array of top-level features for this sequence object.
585
 
           Features which are not top-level are subfeatures of one or more
586
 
           of the returned feature objects, which means that you must
587
 
           traverse the subfeature arrays of each top-level feature object
588
 
           in order to traverse all features associated with this sequence.
589
 
 
590
 
           Use all_SeqFeatures() if you want the feature tree flattened into
591
 
           one single array.
592
 
 Example :
593
 
 Returns : An array of Bio::SeqFeatureI implementing objects.
594
 
 Args    :
595
 
 
596
 
 
597
 
=cut
598
 
 
599
 
sub top_SeqFeatures {
600
 
   my ($self) = @_;
601
 
 
602
 
   return @{$self->{'_as_feat'}};
603
 
}
604
 
 
605
 
=head2 all_SeqFeatures
606
 
 
607
 
 Title   : all_SeqFeatures
608
 
 Usage   : @feat_ary = $seq->all_SeqFeatures();
609
 
 Function: Returns the tree of feature objects attached to this sequence
610
 
           object flattened into one single array. Top-level features will
611
 
           still contain their subfeature-arrays, which means that you
612
 
           will encounter subfeatures twice if you traverse the subfeature
613
 
           tree of the returned objects.
614
 
 
615
 
           Use top_SeqFeatures() if you want the array to contain only the
616
 
           top-level features.
617
 
 Example :
618
 
 Returns : An array of Bio::SeqFeatureI implementing objects.
619
 
 Args    :
620
 
 
621
 
 
622
 
=cut
623
 
 
624
 
sub all_SeqFeatures {
625
 
   my ($self) = @_;
626
 
   my (@array);
627
 
   foreach my $feat ( $self->top_SeqFeatures() ){
628
 
       push(@array,$feat);
629
 
       &_retrieve_subSeqFeature(\@array,$feat);
630
 
   }
631
 
 
632
 
   return @array;
633
 
}
634
 
 
635
 
=head2 feature_count
636
 
 
637
 
 Title   : feature_count
638
 
 Usage   : $seq->feature_count()
639
 
 Function: Return the number of SeqFeatures attached to a sequence
640
 
 Example :
641
 
 Returns : number of SeqFeatures
642
 
 Args    : none
643
 
 
644
 
 
645
 
=cut
646
 
 
647
 
sub feature_count {
648
 
    my ($self) = @_;
649
 
 
650
 
    if (defined($self->{'_as_feat'})) {
651
 
        return ($#{$self->{'_as_feat'}} + 1);
652
 
    } else {
653
 
        return 0;
654
 
    }
655
 
}
656
 
 
657
 
sub _retrieve_subSeqFeature {
658
 
    my ($arrayref,$feat) = @_;
659
 
 
660
 
    foreach my $sub ( $feat->sub_SeqFeature() ) {
661
 
        push(@$arrayref,$sub);
662
 
        &_retrieve_subSeqFeature($arrayref,$sub);
663
 
    }
664
 
 
665
 
}
666
 
 
667
 
 
668
 
=head2 species
669
 
 
670
 
 Title   : species
671
 
 Usage   :
672
 
 Function: Gets or sets the species
673
 
 Example : $species = $self->species();
674
 
 Returns : Bio::Species object
675
 
 Args    : Bio::Species object or none;
676
 
 
677
 
 
678
 
=cut
679
 
 
680
 
sub species {
681
 
    my ($self, $species) = @_;
682
 
    if ($species) {
683
 
        $self->{'species'} = $species;
684
 
    } else {
685
 
        return $self->{'species'};
686
 
    }
687
 
}
688
 
 
689
 
# keep AUTOLOAD happy
690
 
sub DESTROY {
691
 
    my ($self) = @_;
692
 
}
693
 
 
694
 
1;