some changes
[gitmo/Moose.git] / lib / Moose / Meta / Attribute.pm
1
2 package Moose::Meta::Attribute;
3
4 use strict;
5 use warnings;
6
7 use Scalar::Util 'blessed', 'weaken', 'reftype';
8 use Carp         'confess';
9 use Sub::Name    'subname';
10 use overload     ();
11
12 our $VERSION   = '0.22';
13 our $AUTHORITY = 'cpan:STEVAN';
14
15 use Moose::Meta::Method::Accessor;
16 use Moose::Util::TypeConstraints ();
17
18 use base 'Class::MOP::Attribute';
19
20 # options which are not directly used
21 # but we store them for metadata purposes
22 __PACKAGE__->meta->add_attribute('isa'  => (reader    => '_isa_metadata'));
23 __PACKAGE__->meta->add_attribute('does' => (reader    => '_does_metadata'));
24 __PACKAGE__->meta->add_attribute('is'   => (reader    => '_is_metadata'));
25
26 # these are actual options for the attrs
27 __PACKAGE__->meta->add_attribute('required'   => (reader => 'is_required'      ));
28 __PACKAGE__->meta->add_attribute('lazy'       => (reader => 'is_lazy'          ));
29 __PACKAGE__->meta->add_attribute('lazy_build' => (reader => 'is_lazy_build'    ));
30 __PACKAGE__->meta->add_attribute('coerce'     => (reader => 'should_coerce'    ));
31 __PACKAGE__->meta->add_attribute('weak_ref'   => (reader => 'is_weak_ref'      ));
32 __PACKAGE__->meta->add_attribute('auto_deref' => (reader => 'should_auto_deref'));
33 __PACKAGE__->meta->add_attribute('type_constraint' => (
34     reader    => 'type_constraint',
35     predicate => 'has_type_constraint',
36 ));
37 __PACKAGE__->meta->add_attribute('trigger' => (
38     reader    => 'trigger',
39     predicate => 'has_trigger',
40 ));
41 __PACKAGE__->meta->add_attribute('handles' => (
42     reader    => 'handles',
43     predicate => 'has_handles',
44 ));
45 __PACKAGE__->meta->add_attribute('documentation' => (
46     reader    => 'documentation',
47     predicate => 'has_documentation',
48 ));
49
50 # NOTE:
51 # we need to have a ->does method in here to 
52 # more easily support traits, and the introspection 
53 # of those traits. So in order to do this we 
54 # just alias Moose::Object's version of it.
55 # - SL
56 *does = \&Moose::Object::does;
57
58 sub new {
59     my ($class, $name, %options) = @_;
60     $class->_process_options($name, \%options);
61     return $class->SUPER::new($name, %options);
62 }
63
64 sub clone_and_inherit_options {
65     my ($self, %options) = @_;
66     # you can change default, required, coerce, documentation and lazy
67     my %actual_options;
68     foreach my $legal_option (qw(default coerce required documentation lazy)) {
69         if (exists $options{$legal_option}) {
70             $actual_options{$legal_option} = $options{$legal_option};
71             delete $options{$legal_option};
72         }
73     }
74
75     # handles can only be added, not changed
76     if ($options{handles}) {
77         confess "You can only add the 'handles' option, you cannot change it"
78             if $self->has_handles;
79         $actual_options{handles} = $options{handles};
80         delete $options{handles};
81     }
82     
83     # handles can only be added, not changed
84     if ($options{builder}) {
85         confess "You can only add the 'builder' option, you cannot change it"
86             if $self->has_builder;
87         $actual_options{builder} = $options{builder};
88         delete $options{builder};
89     }    
90
91     # isa can be changed, but only if the
92     # new type is a subtype
93     if ($options{isa}) {
94         my $type_constraint;
95         if (blessed($options{isa}) && $options{isa}->isa('Moose::Meta::TypeConstraint')) {
96             $type_constraint = $options{isa};
97         }
98         else {
99             $type_constraint = Moose::Util::TypeConstraints::find_or_create_type_constraint(
100                 $options{isa}
101             );
102             (defined $type_constraint)
103                 || confess "Could not find the type constraint '" . $options{isa} . "'";
104         }
105         # NOTE:
106         # check here to see if the new type
107         # is a subtype of the old one
108         ($type_constraint->is_subtype_of($self->type_constraint->name))
109             || confess "New type constraint setting must be a subtype of inherited one"
110                 # iff we have a type constraint that is ...
111                 if $self->has_type_constraint;
112         # then we use it :)
113         $actual_options{type_constraint} = $type_constraint;
114         delete $options{isa};
115     }
116     (scalar keys %options == 0)
117         || confess "Illegal inherited options => (" . (join ', ' => keys %options) . ")";
118     $self->clone(%actual_options);
119 }
120
121 sub _process_options {
122     my ($class, $name, $options) = @_;
123
124     if (exists $options->{is}) {
125         if ($options->{is} eq 'ro') {
126             $options->{reader} ||= $name;
127             (!exists $options->{trigger})
128                 || confess "Cannot have a trigger on a read-only attribute";
129         }
130         elsif ($options->{is} eq 'rw') {
131             $options->{accessor} = $name;
132             ((reftype($options->{trigger}) || '') eq 'CODE')
133                 || confess "Trigger must be a CODE ref"
134                     if exists $options->{trigger};
135         }
136         else {
137             confess "I do not understand this option (is => " . $options->{is} . ")"
138         }
139     }
140
141     if (exists $options->{isa}) {
142         if (exists $options->{does}) {
143             if (eval { $options->{isa}->can('does') }) {
144                 ($options->{isa}->does($options->{does}))
145                     || confess "Cannot have an isa option and a does option if the isa does not do the does";
146             }
147             else {
148                 confess "Cannot have an isa option which cannot ->does()";
149             }
150         }
151
152         # allow for anon-subtypes here ...
153         if (blessed($options->{isa}) && $options->{isa}->isa('Moose::Meta::TypeConstraint')) {
154             $options->{type_constraint} = $options->{isa};
155         }
156         else {
157             $options->{type_constraint} = Moose::Util::TypeConstraints::find_or_create_type_constraint(
158                 $options->{isa} => {
159                     parent     => Moose::Util::TypeConstraints::find_type_constraint('Object'),
160                     constraint => sub { $_[0]->isa($options->{isa}) }
161                 }
162             );
163         }
164     }
165     elsif (exists $options->{does}) {
166         # allow for anon-subtypes here ...
167         if (blessed($options->{does}) && $options->{does}->isa('Moose::Meta::TypeConstraint')) {
168                 $options->{type_constraint} = $options->{does};
169         }
170         else {
171             $options->{type_constraint} = Moose::Util::TypeConstraints::find_or_create_type_constraint(
172                 $options->{does} => {
173                     parent     => Moose::Util::TypeConstraints::find_type_constraint('Role'),
174                     constraint => sub { 
175                         Moose::Util::does_role($_[0], $options->{does})
176                     }
177                 }
178             );
179         }
180     }
181
182     if (exists $options->{coerce} && $options->{coerce}) {
183         (exists $options->{type_constraint})
184             || confess "You cannot have coercion without specifying a type constraint";
185         confess "You cannot have a weak reference to a coerced value"
186             if $options->{weak_ref};
187     }
188
189     if (exists $options->{auto_deref} && $options->{auto_deref}) {
190         (exists $options->{type_constraint})
191             || confess "You cannot auto-dereference without specifying a type constraint";
192         ($options->{type_constraint}->is_a_type_of('ArrayRef') ||
193          $options->{type_constraint}->is_a_type_of('HashRef'))
194             || confess "You cannot auto-dereference anything other than a ArrayRef or HashRef";
195     }
196
197     if (exists $options->{lazy_build} && $options->{lazy_build} == 1) {
198         confess("You can not use lazy_build and default for the same attribute")
199             if exists $options->{default};
200         $options->{lazy}      = 1;
201         $options->{required}  = 1;
202         $options->{builder} ||= "_build_${name}";
203         if ($name =~ /^_/) {
204             $options->{clearer}   ||= "_clear${name}";
205             $options->{predicate} ||= "_has${name}";
206         } 
207         else {
208             $options->{clearer}   ||= "clear_${name}";
209             $options->{predicate} ||= "has_${name}";
210         }
211     }
212
213     if (exists $options->{lazy} && $options->{lazy}) {
214         (exists $options->{default} || defined $options->{builder} )
215             || confess "You cannot have lazy attribute without specifying a default value for it";
216     }
217
218     if ( $options->{required} && !( ( !exists $options->{init_arg} || defined $options->{init_arg} ) || exists $options->{default} || defined $options->{builder} ) ) {
219         confess "You cannot have a required attribute without a default, builder, or an init_arg";
220     }
221
222 }
223
224 sub initialize_instance_slot {
225     my ($self, $meta_instance, $instance, $params) = @_;
226     my $init_arg = $self->init_arg();
227     # try to fetch the init arg from the %params ...
228
229     my $val;
230     my $value_is_set;
231     if ( defined($init_arg) and exists $params->{$init_arg}) {
232         $val = $params->{$init_arg};
233         $value_is_set = 1;    
234     }
235     else {
236         # skip it if it's lazy
237         return if $self->is_lazy;
238         # and die if it's required and doesn't have a default value
239         confess "Attribute (" . $self->name . ") is required"
240             if $self->is_required && !$self->has_default && !$self->has_builder;
241
242         # if nothing was in the %params, we can use the
243         # attribute's default value (if it has one)
244         if ($self->has_default) {
245             $val = $self->default($instance);
246             $value_is_set = 1;
247         } 
248         elsif ($self->has_builder) {
249             if (my $builder = $instance->can($self->builder)){
250                 $val = $instance->$builder;
251                 $value_is_set = 1;
252             } 
253             else {
254                 confess(blessed($instance)." does not support builder method '".$self->builder."' for attribute '" . $self->name . "'");
255             }
256         }
257     }
258
259     return unless $value_is_set;
260
261     if ($self->has_type_constraint) {
262         my $type_constraint = $self->type_constraint;
263         if ($self->should_coerce && $type_constraint->has_coercion) {
264             $val = $type_constraint->coerce($val);
265         }
266         $type_constraint->check($val)
267             || confess "Attribute (" 
268                      . $self->name 
269                      . ") does not pass the type constraint because: " 
270                      . $type_constraint->get_message($val);
271     }
272
273     $self->set_initial_value($instance, $val);
274     $meta_instance->weaken_slot_value($instance, $self->name)
275         if ref $val && $self->is_weak_ref;
276 }
277
278 ## Slot management
279
280 # FIXME:
281 # this duplicates too much code from 
282 # Class::MOP::Attribute, we need to 
283 # refactor these bits eventually.
284 # - SL
285 sub _set_initial_slot_value {
286     my ($self, $meta_instance, $instance, $value) = @_;
287
288     my $slot_name = $self->name;
289
290     return $meta_instance->set_slot_value($instance, $slot_name, $value)
291         unless $self->has_initializer;
292
293     my ($type_constraint, $can_coerce);
294     if ($self->has_type_constraint) {
295         $type_constraint = $self->type_constraint;
296         $can_coerce      = ($self->should_coerce && $type_constraint->has_coercion);
297     }
298
299     my $callback = sub {
300         my $val = shift;
301         if ($type_constraint) {
302             $val = $type_constraint->coerce($val)
303                 if $can_coerce;
304             $type_constraint->check($val)
305                 || confess "Attribute (" 
306                          . $slot_name 
307                          . ") does not pass the type constraint because: " 
308                          . $type_constraint->get_message($val);            
309         }
310         $meta_instance->set_slot_value($instance, $slot_name, $val);
311     };
312     
313     my $initializer = $self->initializer;
314
315     # most things will just want to set a value, so make it first arg
316     $instance->$initializer($value, $callback, $self);
317 }
318
319 sub set_value {
320     my ($self, $instance, $value) = @_;
321
322     my $attr_name = $self->name;
323
324     if ($self->is_required) {
325         defined($value)
326             || confess "Attribute ($attr_name) is required, so cannot be set to undef";
327     }
328
329     if ($self->has_type_constraint) {
330
331         my $type_constraint = $self->type_constraint;
332
333         if ($self->should_coerce) {
334             $value = $type_constraint->coerce($value);
335         }        
336         $type_constraint->_compiled_type_constraint->($value)
337             || confess "Attribute (" 
338                      . $self->name 
339                      . ") does not pass the type constraint because " 
340                      . $type_constraint->get_message($value);
341     }
342
343     my $meta_instance = Class::MOP::Class->initialize(blessed($instance))
344                                          ->get_meta_instance;
345
346     $meta_instance->set_slot_value($instance, $attr_name, $value);
347
348     if (ref $value && $self->is_weak_ref) {
349         $meta_instance->weaken_slot_value($instance, $attr_name);
350     }
351
352     if ($self->has_trigger) {
353         $self->trigger->($instance, $value, $self);
354     }
355 }
356
357 sub get_value {
358     my ($self, $instance) = @_;
359
360     if ($self->is_lazy) {
361         unless ($self->has_value($instance)) {
362             if ($self->has_default) {
363                 my $default = $self->default($instance);
364                 $self->set_initial_value($instance, $default);
365             }
366             if ( $self->has_builder ){
367                 if (my $builder = $instance->can($self->builder)){
368                     $self->set_initial_value($instance, $instance->$builder);
369                 } 
370                 else {
371                     confess(blessed($instance) 
372                           . " does not support builder method '"
373                           . $self->builder 
374                           . "' for attribute '" 
375                           . $self->name 
376                           . "'");
377                 }
378             } 
379             else {
380                 $self->set_initial_value($instance, undef);
381             }
382         }
383     }
384
385     if ($self->should_auto_deref) {
386
387         my $type_constraint = $self->type_constraint;
388
389         if ($type_constraint->is_a_type_of('ArrayRef')) {
390             my $rv = $self->SUPER::get_value($instance);
391             return unless defined $rv;
392             return wantarray ? @{ $rv } : $rv;
393         }
394         elsif ($type_constraint->is_a_type_of('HashRef')) {
395             my $rv = $self->SUPER::get_value($instance);
396             return unless defined $rv;
397             return wantarray ? %{ $rv } : $rv;
398         }
399         else {
400             confess "Can not auto de-reference the type constraint '" . $type_constraint->name . "'";
401         }
402
403     }
404     else {
405
406         return $self->SUPER::get_value($instance);
407     }
408 }
409
410 ## installing accessors
411
412 sub accessor_metaclass { 'Moose::Meta::Method::Accessor' }
413
414 sub install_accessors {
415     my $self = shift;
416     $self->SUPER::install_accessors(@_);
417
418     if ($self->has_handles) {
419
420         # NOTE:
421         # Here we canonicalize the 'handles' option
422         # this will sort out any details and always
423         # return an hash of methods which we want
424         # to delagate to, see that method for details
425         my %handles = $self->_canonicalize_handles();
426
427         # find the accessor method for this attribute
428         my $accessor = $self->get_read_method_ref;
429         # then unpack it if we need too ...
430         $accessor = $accessor->body if blessed $accessor;
431
432         # install the delegation ...
433         my $associated_class = $self->associated_class;
434         foreach my $handle (keys %handles) {
435             my $method_to_call = $handles{$handle};
436             my $class_name = $associated_class->name;
437             my $name = "${class_name}::${handle}";
438
439             (!$associated_class->has_method($handle))
440                 || confess "You cannot overwrite a locally defined method ($handle) with a delegation";
441
442             # NOTE:
443             # handles is not allowed to delegate
444             # any of these methods, as they will
445             # override the ones in your class, which
446             # is almost certainly not what you want.
447
448             # FIXME warn when $handle was explicitly specified, but not if the source is a regex or something
449             #cluck("Not delegating method '$handle' because it is a core method") and
450             next if $class_name->isa("Moose::Object") and $handle =~ /^BUILD|DEMOLISH$/ || Moose::Object->can($handle);
451
452             if ((reftype($method_to_call) || '') eq 'CODE') {
453                 $associated_class->add_method($handle => subname $name, $method_to_call);
454             }
455             else {
456                 # NOTE:
457                 # we used to do a goto here, but the
458                 # goto didn't handle failure correctly
459                 # (it just returned nothing), so I took 
460                 # that out. However, the more I thought
461                 # about it, the less I liked it doing 
462                 # the goto, and I prefered the act of 
463                 # delegation being actually represented
464                 # in the stack trace. 
465                 # - SL
466                 $associated_class->add_method($handle => subname $name, sub {
467                     my $proxy = (shift)->$accessor();
468                     (defined $proxy) 
469                         || confess "Cannot delegate $handle to $method_to_call because " . 
470                                    "the value of " . $self->name . " is not defined";
471                     $proxy->$method_to_call(@_);
472                 });
473             }
474         }
475     }
476
477     return;
478 }
479
480 # private methods to help delegation ...
481
482 sub _canonicalize_handles {
483     my $self    = shift;
484     my $handles = $self->handles;
485     if (my $handle_type = ref($handles)) {
486         if ($handle_type eq 'HASH') {
487             return %{$handles};
488         }
489         elsif ($handle_type eq 'ARRAY') {
490             return map { $_ => $_ } @{$handles};
491         }
492         elsif ($handle_type eq 'Regexp') {
493             ($self->has_type_constraint)
494                 || confess "Cannot delegate methods based on a RegExpr without a type constraint (isa)";
495             return map  { ($_ => $_) }
496                    grep { /$handles/ } $self->_get_delegate_method_list;
497         }
498         elsif ($handle_type eq 'CODE') {
499             return $handles->($self, $self->_find_delegate_metaclass);
500         }
501         else {
502             confess "Unable to canonicalize the 'handles' option with $handles";
503         }
504     }
505     else {
506         my $role_meta = eval { $handles->meta };
507         if ($@) {
508             confess "Unable to canonicalize the 'handles' option with $handles because : $@";
509         }
510
511         (blessed $role_meta && $role_meta->isa('Moose::Meta::Role'))
512             || confess "Unable to canonicalize the 'handles' option with $handles because ->meta is not a Moose::Meta::Role";
513
514         return map { $_ => $_ } (
515             $role_meta->get_method_list,
516             $role_meta->get_required_method_list
517         );
518     }
519 }
520
521 sub _find_delegate_metaclass {
522     my $self = shift;
523     if (my $class = $self->_isa_metadata) {
524         # if the class does have
525         # a meta method, use it
526         return $class->meta if $class->can('meta');
527         # otherwise we might be
528         # dealing with a non-Moose
529         # class, and need to make
530         # our own metaclass
531         return Moose::Meta::Class->initialize($class);
532     }
533     elsif (my $role = $self->_does_metadata) {
534         # our role will always have
535         # a meta method
536         return $role->meta;
537     }
538     else {
539         confess "Cannot find delegate metaclass for attribute " . $self->name;
540     }
541 }
542
543 sub _get_delegate_method_list {
544     my $self = shift;
545     my $meta = $self->_find_delegate_metaclass;
546     if ($meta->isa('Class::MOP::Class')) {
547         return map  { $_->{name}                     }  # NOTE: !never! delegate &meta
548                grep { $_->{class} ne 'Moose::Object' && $_->{name} ne 'meta' }
549                     $meta->compute_all_applicable_methods;
550     }
551     elsif ($meta->isa('Moose::Meta::Role')) {
552         return $meta->get_method_list;
553     }
554     else {
555         confess "Unable to recognize the delegate metaclass '$meta'";
556     }
557 }
558
559 1;
560
561 __END__
562
563 =pod
564
565 =head1 NAME
566
567 Moose::Meta::Attribute - The Moose attribute metaclass
568
569 =head1 DESCRIPTION
570
571 This is a subclass of L<Class::MOP::Attribute> with Moose specific
572 extensions.
573
574 For the most part, the only time you will ever encounter an
575 instance of this class is if you are doing some serious deep
576 introspection. To really understand this class, you need to refer
577 to the L<Class::MOP::Attribute> documentation.
578
579 =head1 METHODS
580
581 =head2 Overridden methods
582
583 These methods override methods in L<Class::MOP::Attribute> and add
584 Moose specific features. You can safely assume though that they
585 will behave just as L<Class::MOP::Attribute> does.
586
587 =over 4
588
589 =item B<new>
590
591 =item B<initialize_instance_slot>
592
593 =item B<install_accessors>
594
595 =item B<accessor_metaclass>
596
597 =item B<get_value>
598
599 =item B<set_value>
600
601   eval { $point->meta->get_attribute('x')->set_value($point, 'fourty-two') };
602   if($@) {
603     print "Oops: $@\n";
604   }
605
606 I<Attribute (x) does not pass the type constraint (Int) with 'fourty-two'>
607
608 Before setting the value, a check is made on the type constraint of
609 the attribute, if it has one, to see if the value passes it. If the
610 value fails to pass, the set operation dies with a L<Carp/confess>.
611
612 Any coercion to convert values is done before checking the type constraint.
613
614 To check a value against a type constraint before setting it, fetch the
615 attribute instance using L<Class::MOP::Class/find_attribute_by_name>,
616 fetch the type_constraint from the attribute using L<Moose::Meta::Attribute/type_constraint>
617 and call L<Moose::Meta::TypeConstraint/check>. See L<Moose::Cookbook::RecipeX>
618 for an example.
619
620 =back
621
622 =head2 Additional Moose features
623
624 Moose attributes support type-constraint checking, weak reference
625 creation and type coercion.
626
627 =over 4
628
629 =item B<clone_and_inherit_options>
630
631 This is to support the C<has '+foo'> feature, it clones an attribute
632 from a superclass and allows a very specific set of changes to be made
633 to the attribute.
634
635 =item B<has_type_constraint>
636
637 Returns true if this meta-attribute has a type constraint.
638
639 =item B<type_constraint>
640
641 A read-only accessor for this meta-attribute's type constraint. For
642 more information on what you can do with this, see the documentation
643 for L<Moose::Meta::TypeConstraint>.
644
645 =item B<has_handles>
646
647 Returns true if this meta-attribute performs delegation.
648
649 =item B<handles>
650
651 This returns the value which was passed into the handles option.
652
653 =item B<is_weak_ref>
654
655 Returns true if this meta-attribute produces a weak reference.
656
657 =item B<is_required>
658
659 Returns true if this meta-attribute is required to have a value.
660
661 =item B<is_lazy>
662
663 Returns true if this meta-attribute should be initialized lazily.
664
665 NOTE: lazy attributes, B<must> have a C<default> or C<builder> field set.
666
667 =item B<is_lazy_build>
668
669 Returns true if this meta-attribute should be initialized lazily through
670 the builder generated by lazy_build. Using C<lazy_build =E<gt> 1> will
671 make your attribute required and lazy. In addition it will set the builder, clearer
672 and predicate options for you using the following convention.
673
674    #If your attribute name starts with an underscore:
675    has '_foo' => (lazy_build => 1);
676    #is the same as
677    has '_foo' => (lazy => 1, required => 1, predicate => '_has_foo', clearer => '_clear_foo', builder => '_build__foo);
678    # or
679    has '_foo' => (lazy => 1, required => 1, predicate => '_has_foo', clearer => '_clear_foo', default => sub{shift->_build__foo});
680
681    #If your attribute name does not start with an underscore:
682    has 'foo' => (lazy_build => 1);
683    #is the same as
684    has 'foo' => (lazy => 1, required => 1, predicate => 'has_foo', clearer => 'clear_foo', builder => '_build_foo);
685    # or
686    has 'foo' => (lazy => 1, required => 1, predicate => 'has_foo', clearer => 'clear_foo', default => sub{shift->_build_foo});
687
688 The reason for the different naming of the C<builder> is that the C<builder>
689 method is a private method while the C<clearer> and C<predicate> methods
690 are public methods.
691
692 NOTE: This means your class should provide a method whose name matches the value
693 of the builder part, in this case _build__foo or _build_foo.
694
695 =item B<should_coerce>
696
697 Returns true if this meta-attribute should perform type coercion.
698
699 =item B<should_auto_deref>
700
701 Returns true if this meta-attribute should perform automatic
702 auto-dereferencing.
703
704 NOTE: This can only be done for attributes whose type constraint is
705 either I<ArrayRef> or I<HashRef>.
706
707 =item B<has_trigger>
708
709 Returns true if this meta-attribute has a trigger set.
710
711 =item B<trigger>
712
713 This is a CODE reference which will be executed every time the
714 value of an attribute is assigned. The CODE ref will get two values,
715 the invocant and the new value. This can be used to handle I<basic>
716 bi-directional relations.
717
718 =item B<documentation>
719
720 This is a string which contains the documentation for this attribute.
721 It serves no direct purpose right now, but it might in the future
722 in some kind of automated documentation system perhaps.
723
724 =item B<has_documentation>
725
726 Returns true if this meta-attribute has any documentation.
727
728 =back
729
730 =head1 BUGS
731
732 All complex software has bugs lurking in it, and this module is no
733 exception. If you find a bug please either email me, or add the bug
734 to cpan-RT.
735
736 =head1 AUTHOR
737
738 Stevan Little E<lt>stevan@iinteractive.comE<gt>
739
740 Yuval Kogman E<lt>nothingmuch@woobling.comE<gt>
741
742 =head1 COPYRIGHT AND LICENSE
743
744 Copyright 2006-2008 by Infinity Interactive, Inc.
745
746 L<http://www.iinteractive.com>
747
748 This library is free software; you can redistribute it and/or modify
749 it under the same terms as Perl itself.
750
751 =cut