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