commit-before-the-branch
[gitmo/Class-MOP.git] / lib / Class / MOP.pm
CommitLineData
94b19069 1
2package Class::MOP;
3
4use strict;
5use warnings;
6
727919c5 7use Carp 'confess';
be7677c7 8use Scalar::Util 'weaken';
8b978dd5 9
2eb717d5 10use Class::MOP::Class;
11use Class::MOP::Attribute;
12use Class::MOP::Method;
13
857f87a7 14use Class::MOP::Class::Immutable;
15
c4260b45 16our $VERSION = '0.34';
f0480c45 17our $AUTHORITY = 'cpan:STEVAN';
94b19069 18
be7677c7 19{
20 # Metaclasses are singletons, so we cache them here.
21 # there is no need to worry about destruction though
22 # because they should die only when the program dies.
23 # After all, do package definitions even get reaped?
24 my %METAS;
25
26 # means of accessing all the metaclasses that have
27 # been initialized thus far (for mugwumps obj browser)
28 sub get_all_metaclasses { %METAS }
29 sub get_all_metaclass_instances { values %METAS }
30 sub get_all_metaclass_names { keys %METAS }
31 sub get_metaclass_by_name { $METAS{$_[0]} }
32 sub store_metaclass_by_name { $METAS{$_[0]} = $_[1] }
33 sub weaken_metaclass { weaken($METAS{$_[0]}) }
34 sub does_metaclass_exist { exists $METAS{$_[0]} && defined $METAS{$_[0]} }
35 sub remove_metaclass_by_name { $METAS{$_[0]} = undef }
36
37 # NOTE:
38 # We only cache metaclasses, meaning instances of
39 # Class::MOP::Class. We do not cache instance of
40 # Class::MOP::Package or Class::MOP::Module. Mostly
41 # because I don't yet see a good reason to do so.
42}
43
aa448b16 44## ----------------------------------------------------------------------------
45## Setting up our environment ...
46## ----------------------------------------------------------------------------
47## Class::MOP needs to have a few things in the global perl environment so
48## that it can operate effectively. Those things are done here.
49## ----------------------------------------------------------------------------
50
3bf7644b 51# ... nothing yet actually ;)
8b978dd5 52
b51af7f9 53## ----------------------------------------------------------------------------
54## Bootstrapping
55## ----------------------------------------------------------------------------
56## The code below here is to bootstrap our MOP with itself. This is also
57## sometimes called "tying the knot". By doing this, we make it much easier
58## to extend the MOP through subclassing and such since now you can use the
59## MOP itself to extend itself.
60##
61## Yes, I know, thats weird and insane, but it's a good thing, trust me :)
62## ----------------------------------------------------------------------------
727919c5 63
64# We need to add in the meta-attributes here so that
65# any subclass of Class::MOP::* will be able to
66# inherit them using &construct_instance
67
f0480c45 68## --------------------------------------------------------
6d5355c3 69## Class::MOP::Package
727919c5 70
6d5355c3 71Class::MOP::Package->meta->add_attribute(
351bd7d4 72 Class::MOP::Attribute->new('$:package' => (
b880e0de 73 reader => {
74 # NOTE: we need to do this in order
75 # for the instance meta-object to
76 # not fall into meta-circular death
77 'name' => sub { (shift)->{'$:package'} }
78 },
7b31baf4 79 init_arg => ':package',
727919c5 80 ))
81);
82
a5e51f0b 83Class::MOP::Package->meta->add_attribute(
84 Class::MOP::Attribute->new('%:namespace' => (
85 reader => {
56dcfc1a 86 # NOTE:
87 # because of issues with the Perl API
88 # to the typeglob in some versions, we
89 # need to just always grab a new
90 # reference to the hash here. Ideally
91 # we could just store a ref and it would
92 # Just Work, but oh well :\
93 'namespace' => sub {
94 no strict 'refs';
95 \%{$_[0]->name . '::'}
96 }
a5e51f0b 97 },
98 # NOTE:
99 # protect this from silliness
a2ee6c61 100 init_arg => '!............( DO NOT DO THIS )............!',
c4260b45 101 default => sub { \undef }
a5e51f0b 102 ))
103);
104
9d6dce77 105# NOTE:
106# use the metaclass to construct the meta-package
107# which is a superclass of the metaclass itself :P
108Class::MOP::Package->meta->add_method('initialize' => sub {
109 my $class = shift;
110 my $package_name = shift;
111 $class->meta->new_object(':package' => $package_name, @_);
112});
113
f0480c45 114## --------------------------------------------------------
115## Class::MOP::Module
116
117# NOTE:
118# yeah this is kind of stretching things a bit,
119# but truthfully the version should be an attribute
120# of the Module, the weirdness comes from having to
121# stick to Perl 5 convention and store it in the
122# $VERSION package variable. Basically if you just
123# squint at it, it will look how you want it to look.
124# Either as a package variable, or as a attribute of
125# the metaclass, isn't abstraction great :)
126
127Class::MOP::Module->meta->add_attribute(
128 Class::MOP::Attribute->new('$:version' => (
129 reader => {
130 'version' => sub {
131 my $self = shift;
132 ${$self->get_package_symbol('$VERSION')};
133 }
134 },
135 # NOTE:
136 # protect this from silliness
137 init_arg => '!............( DO NOT DO THIS )............!',
c4260b45 138 default => sub { \undef }
f0480c45 139 ))
140);
141
142# NOTE:
143# By following the same conventions as version here,
144# we are opening up the possibility that people can
145# use the $AUTHORITY in non-Class::MOP modules as
146# well.
147
148Class::MOP::Module->meta->add_attribute(
149 Class::MOP::Attribute->new('$:authority' => (
150 reader => {
151 'authority' => sub {
152 my $self = shift;
153 ${$self->get_package_symbol('$AUTHORITY')};
154 }
155 },
156 # NOTE:
157 # protect this from silliness
158 init_arg => '!............( DO NOT DO THIS )............!',
c4260b45 159 default => sub { \undef }
f0480c45 160 ))
161);
162
163## --------------------------------------------------------
6d5355c3 164## Class::MOP::Class
165
727919c5 166Class::MOP::Class->meta->add_attribute(
351bd7d4 167 Class::MOP::Attribute->new('%:attributes' => (
f7259199 168 reader => {
169 # NOTE: we need to do this in order
170 # for the instance meta-object to
171 # not fall into meta-circular death
172 'get_attribute_map' => sub { (shift)->{'%:attributes'} }
173 },
351bd7d4 174 init_arg => ':attributes',
727919c5 175 default => sub { {} }
176 ))
177);
178
351bd7d4 179Class::MOP::Class->meta->add_attribute(
c4260b45 180 Class::MOP::Attribute->new('%:methods' => (
181 reader => {
182 # NOTE:
183 # as with the $VERSION and $AUTHORITY above
184 # sometimes we don't/can't store directly
185 # inside the instance, so we need the accessor
186 # to just DWIM
187 'get_method_map' => sub {
188 my $self = shift;
189 # FIXME:
190 # there is a faster/better way
191 # to do this, I am sure :)
192 return +{
193 map {
194 $_ => $self->get_method($_)
195 } grep {
196 $self->has_method($_)
197 } $self->list_all_package_symbols
198 };
199 }
200 },
201 init_arg => '!............( DO NOT DO THIS )............!',
202 default => sub { \undef }
203 ))
204);
205
206Class::MOP::Class->meta->add_attribute(
351bd7d4 207 Class::MOP::Attribute->new('$:attribute_metaclass' => (
7b31baf4 208 reader => 'attribute_metaclass',
351bd7d4 209 init_arg => ':attribute_metaclass',
210 default => 'Class::MOP::Attribute',
211 ))
212);
213
214Class::MOP::Class->meta->add_attribute(
215 Class::MOP::Attribute->new('$:method_metaclass' => (
7b31baf4 216 reader => 'method_metaclass',
351bd7d4 217 init_arg => ':method_metaclass',
218 default => 'Class::MOP::Method',
219 ))
220);
221
2bab2be6 222Class::MOP::Class->meta->add_attribute(
223 Class::MOP::Attribute->new('$:instance_metaclass' => (
b880e0de 224 reader => {
225 # NOTE: we need to do this in order
226 # for the instance meta-object to
227 # not fall into meta-circular death
228 'instance_metaclass' => sub { (shift)->{'$:instance_metaclass'} }
229 },
2bab2be6 230 init_arg => ':instance_metaclass',
231 default => 'Class::MOP::Instance',
232 ))
233);
234
9d6dce77 235# NOTE:
236# we don't actually need to tie the knot with
237# Class::MOP::Class here, it is actually handled
238# within Class::MOP::Class itself in the
239# construct_class_instance method.
240
f0480c45 241## --------------------------------------------------------
727919c5 242## Class::MOP::Attribute
243
7b31baf4 244Class::MOP::Attribute->meta->add_attribute(
245 Class::MOP::Attribute->new('name' => (
b880e0de 246 reader => {
247 # NOTE: we need to do this in order
248 # for the instance meta-object to
249 # not fall into meta-circular death
250 'name' => sub { (shift)->{name} }
251 }
7b31baf4 252 ))
253);
254
255Class::MOP::Attribute->meta->add_attribute(
256 Class::MOP::Attribute->new('associated_class' => (
b880e0de 257 reader => {
258 # NOTE: we need to do this in order
259 # for the instance meta-object to
260 # not fall into meta-circular death
261 'associated_class' => sub { (shift)->{associated_class} }
262 }
7b31baf4 263 ))
264);
265
266Class::MOP::Attribute->meta->add_attribute(
267 Class::MOP::Attribute->new('accessor' => (
268 reader => 'accessor',
269 predicate => 'has_accessor',
270 ))
271);
272
273Class::MOP::Attribute->meta->add_attribute(
274 Class::MOP::Attribute->new('reader' => (
275 reader => 'reader',
276 predicate => 'has_reader',
277 ))
278);
279
280Class::MOP::Attribute->meta->add_attribute(
281 Class::MOP::Attribute->new('writer' => (
282 reader => 'writer',
283 predicate => 'has_writer',
284 ))
285);
286
287Class::MOP::Attribute->meta->add_attribute(
288 Class::MOP::Attribute->new('predicate' => (
289 reader => 'predicate',
290 predicate => 'has_predicate',
291 ))
292);
293
294Class::MOP::Attribute->meta->add_attribute(
7d28758b 295 Class::MOP::Attribute->new('clearer' => (
296 reader => 'clearer',
297 predicate => 'has_clearer',
298 ))
299);
300
301Class::MOP::Attribute->meta->add_attribute(
7b31baf4 302 Class::MOP::Attribute->new('init_arg' => (
303 reader => 'init_arg',
304 predicate => 'has_init_arg',
305 ))
306);
307
308Class::MOP::Attribute->meta->add_attribute(
309 Class::MOP::Attribute->new('default' => (
310 # default has a custom 'reader' method ...
311 predicate => 'has_default',
312 ))
313);
314
727919c5 315
316# NOTE: (meta-circularity)
317# This should be one of the last things done
318# it will "tie the knot" with Class::MOP::Attribute
319# so that it uses the attributes meta-objects
320# to construct itself.
321Class::MOP::Attribute->meta->add_method('new' => sub {
322 my $class = shift;
323 my $name = shift;
324 my %options = @_;
325
326 (defined $name && $name)
327 || confess "You must provide a name for the attribute";
5659d76e 328 $options{init_arg} = $name
329 if not exists $options{init_arg};
148b4697 330
331 (Class::MOP::Attribute::is_default_a_coderef(\%options))
332 || confess("References are not allowed as default values, you must ".
333 "wrap then in a CODE reference (ex: sub { [] } and not [])")
334 if exists $options{default} && ref $options{default};
651955fb 335
5659d76e 336 # return the new object
337 $class->meta->new_object(name => $name, %options);
338});
339
340Class::MOP::Attribute->meta->add_method('clone' => sub {
a740253a 341 my $self = shift;
a27ae83f 342 $self->meta->clone_object($self, @_);
727919c5 343});
344
f0480c45 345## --------------------------------------------------------
346## Now close all the Class::MOP::* classes
4d47b77f 347
348Class::MOP::Package ->meta->make_immutable(inline_constructor => 0);
349Class::MOP::Module ->meta->make_immutable(inline_constructor => 0);
350Class::MOP::Class ->meta->make_immutable(inline_constructor => 0);
351Class::MOP::Attribute->meta->make_immutable(inline_constructor => 0);
352Class::MOP::Method ->meta->make_immutable(inline_constructor => 0);
353Class::MOP::Instance ->meta->make_immutable(inline_constructor => 0);
6e57504d 354Class::MOP::Object ->meta->make_immutable(inline_constructor => 0);
4d47b77f 355
94b19069 3561;
357
358__END__
359
360=pod
361
362=head1 NAME
363
364Class::MOP - A Meta Object Protocol for Perl 5
365
366=head1 SYNOPSIS
367
a2e85e6c 368 # ... This will come later, for now see
369 # the other SYNOPSIS for more information
94b19069 370
371=head1 DESCRIPTON
372
373This module is an attempt to create a meta object protocol for the
374Perl 5 object system. It makes no attempt to change the behavior or
375characteristics of the Perl 5 object system, only to create a
27e31eaf 376protocol for its manipulation and introspection.
94b19069 377
378That said, it does attempt to create the tools for building a rich
379set of extensions to the Perl 5 object system. Every attempt has been
380made for these tools to keep to the spirit of the Perl 5 object
381system that we all know and love.
382
40483095 383This documentation is admittedly sparse on details, as time permits
384I will try to improve them. For now, I suggest looking at the items
385listed in the L<SEE ALSO> section for more information. In particular
386the book "The Art of the Meta Object Protocol" was very influential
387in the development of this system.
388
bfe4d0fc 389=head2 What is a Meta Object Protocol?
390
391A meta object protocol is an API to an object system.
392
393To be more specific, it is a set of abstractions of the components of
394an object system (typically things like; classes, object, methods,
395object attributes, etc.). These abstractions can then be used to both
396inspect and manipulate the object system which they describe.
397
398It can be said that there are two MOPs for any object system; the
399implicit MOP, and the explicit MOP. The implicit MOP handles things
400like method dispatch or inheritance, which happen automatically as
401part of how the object system works. The explicit MOP typically
402handles the introspection/reflection features of the object system.
403All object systems have implicit MOPs, without one, they would not
404work. Explict MOPs however as less common, and depending on the
405language can vary from restrictive (Reflection in Java or C#) to
406wide open (CLOS is a perfect example).
407
e16da3e6 408=head2 Yet Another Class Builder!! Why?
409
410This is B<not> a class builder so much as it is a I<class builder
411B<builder>>. My intent is that an end user does not use this module
412directly, but instead this module is used by module authors to
413build extensions and features onto the Perl 5 object system.
414
94b19069 415=head2 Who is this module for?
416
417This module is specifically for anyone who has ever created or
418wanted to create a module for the Class:: namespace. The tools which
419this module will provide will hopefully make it easier to do more
420complex things with Perl 5 classes by removing such barriers as
421the need to hack the symbol tables, or understand the fine details
422of method dispatch.
423
bfe4d0fc 424=head2 What changes do I have to make to use this module?
425
2eb717d5 426This module was designed to be as unintrusive as possible. Many of
343203ee 427its features are accessible without B<any> change to your existsing
bfe4d0fc 428code at all. It is meant to be a compliment to your existing code and
2eb717d5 429not an intrusion on your code base. Unlike many other B<Class::>
a2e85e6c 430modules, this module B<does not> require you subclass it, or even that
431you C<use> it in within your module's package.
bfe4d0fc 432
2eb717d5 433The only features which requires additions to your code are the
434attribute handling and instance construction features, and these are
a2e85e6c 435both completely optional features. The only reason for this is because
2eb717d5 436Perl 5's object system does not actually have these features built
437in. More information about this feature can be found below.
bfe4d0fc 438
439=head2 A Note about Performance?
440
441It is a common misconception that explict MOPs are performance drains.
442But this is not a universal truth at all, it is an side-effect of
443specific implementations. For instance, using Java reflection is much
444slower because the JVM cannot take advantage of any compiler
445optimizations, and the JVM has to deal with much more runtime type
446information as well. Reflection in C# is marginally better as it was
447designed into the language and runtime (the CLR). In contrast, CLOS
448(the Common Lisp Object System) was built to support an explicit MOP,
449and so performance is tuned for it.
450
451This library in particular does it's absolute best to avoid putting
2eb717d5 452B<any> drain at all upon your code's performance. In fact, by itself
453it does nothing to affect your existing code. So you only pay for
454what you actually use.
bfe4d0fc 455
550d56db 456=head2 About Metaclass compatibility
457
458This module makes sure that all metaclasses created are both upwards
459and downwards compatible. The topic of metaclass compatibility is
460highly esoteric and is something only encountered when doing deep and
461involved metaclass hacking. There are two basic kinds of metaclass
462incompatibility; upwards and downwards.
463
464Upwards metaclass compatibility means that the metaclass of a
465given class is either the same as (or a subclass of) all of the
466class's ancestors.
467
468Downward metaclass compatibility means that the metaclasses of a
469given class's anscestors are all either the same as (or a subclass
470of) that metaclass.
471
472Here is a diagram showing a set of two classes (C<A> and C<B>) and
473two metaclasses (C<Meta::A> and C<Meta::B>) which have correct
474metaclass compatibility both upwards and downwards.
475
476 +---------+ +---------+
477 | Meta::A |<----| Meta::B | <....... (instance of )
478 +---------+ +---------+ <------- (inherits from)
479 ^ ^
480 : :
481 +---------+ +---------+
482 | A |<----| B |
483 +---------+ +---------+
484
485As I said this is a highly esoteric topic and one you will only run
486into if you do a lot of subclassing of B<Class::MOP::Class>. If you
487are interested in why this is an issue see the paper
488I<Uniform and safe metaclass composition> linked to in the
489L<SEE ALSO> section of this document.
490
aa448b16 491=head2 Using custom metaclasses
492
493Always use the metaclass pragma when using a custom metaclass, this
494will ensure the proper initialization order and not accidentely
495create an incorrect type of metaclass for you. This is a very rare
496problem, and one which can only occur if you are doing deep metaclass
497programming. So in other words, don't worry about it.
498
94b19069 499=head1 PROTOCOLS
500
501The protocol is divided into 3 main sub-protocols:
502
503=over 4
504
505=item The Class protocol
506
507This provides a means of manipulating and introspecting a Perl 5
508class. It handles all of symbol table hacking for you, and provides
509a rich set of methods that go beyond simple package introspection.
510
552e3d24 511See L<Class::MOP::Class> for more details.
512
94b19069 513=item The Attribute protocol
514
515This provides a consistent represenation for an attribute of a
516Perl 5 class. Since there are so many ways to create and handle
517atttributes in Perl 5 OO, this attempts to provide as much of a
518unified approach as possible, while giving the freedom and
519flexibility to subclass for specialization.
520
552e3d24 521See L<Class::MOP::Attribute> for more details.
522
94b19069 523=item The Method protocol
524
525This provides a means of manipulating and introspecting methods in
526the Perl 5 object system. As with attributes, there are many ways to
527approach this topic, so we try to keep it pretty basic, while still
528making it possible to extend the system in many ways.
529
552e3d24 530See L<Class::MOP::Method> for more details.
94b19069 531
532=back
533
be7677c7 534=head1 FUNCTIONS
535
536Class::MOP holds a cache of metaclasses, the following are functions
537(B<not methods>) which can be used to access that cache. It is not
538recommended that you mess with this, bad things could happen. But if
539you are brave and willing to risk it, go for it.
540
541=over 4
542
543=item B<get_all_metaclasses>
544
b9d9fc0b 545This will return an hash of all the metaclass instances that have
546been cached by B<Class::MOP::Class> keyed by the package name.
547
be7677c7 548=item B<get_all_metaclass_instances>
549
b9d9fc0b 550This will return an array of all the metaclass instances that have
551been cached by B<Class::MOP::Class>.
552
be7677c7 553=item B<get_all_metaclass_names>
554
b9d9fc0b 555This will return an array of all the metaclass names that have
556been cached by B<Class::MOP::Class>.
557
be7677c7 558=item B<get_metaclass_by_name ($name)>
559
560=item B<store_metaclass_by_name ($name, $meta)>
561
562=item B<weaken_metaclass ($name)>
563
564=item B<does_metaclass_exist ($name)>
565
566=item B<remove_metaclass_by_name ($name)>
567
568=back
569
552e3d24 570=head1 SEE ALSO
8b978dd5 571
552e3d24 572=head2 Books
8b978dd5 573
a2e85e6c 574There are very few books out on Meta Object Protocols and Metaclasses
575because it is such an esoteric topic. The following books are really
576the only ones I have found. If you know of any more, B<I<please>>
577email me and let me know, I would love to hear about them.
578
8b978dd5 579=over 4
580
552e3d24 581=item "The Art of the Meta Object Protocol"
8b978dd5 582
552e3d24 583=item "Advances in Object-Oriented Metalevel Architecture and Reflection"
8b978dd5 584
b51af7f9 585=item "Putting MetaClasses to Work"
586
a2e85e6c 587=item "Smalltalk: The Language"
588
94b19069 589=back
590
550d56db 591=head2 Papers
592
593=over 4
594
595=item Uniform and safe metaclass composition
596
597An excellent paper by the people who brought us the original Traits paper.
598This paper is on how Traits can be used to do safe metaclass composition,
599and offers an excellent introduction section which delves into the topic of
600metaclass compatibility.
601
602L<http://www.iam.unibe.ch/~scg/Archive/Papers/Duca05ySafeMetaclassTrait.pdf>
603
604=item Safe Metaclass Programming
605
606This paper seems to precede the above paper, and propose a mix-in based
607approach as opposed to the Traits based approach. Both papers have similar
608information on the metaclass compatibility problem space.
609
610L<http://citeseer.ist.psu.edu/37617.html>
611
612=back
613
552e3d24 614=head2 Prior Art
8b978dd5 615
616=over 4
617
7184ca14 618=item The Perl 6 MetaModel work in the Pugs project
8b978dd5 619
620=over 4
621
552e3d24 622=item L<http://svn.openfoundry.org/pugs/perl5/Perl6-MetaModel>
8b978dd5 623
552e3d24 624=item L<http://svn.openfoundry.org/pugs/perl5/Perl6-ObjectSpace>
8b978dd5 625
626=back
627
94b19069 628=back
629
a2e85e6c 630=head1 SIMILAR MODULES
631
632As I have said above, this module is a class-builder-builder, so it is
633not the same thing as modules like L<Class::Accessor> and
634L<Class::MethodMaker>. That being said there are very few modules on CPAN
635with similar goals to this module. The one I have found which is most
550d56db 636like this module is L<Class::Meta>, although it's philosophy and the MOP it
637creates are very different from this modules.
94b19069 638
a2e85e6c 639=head1 BUGS
640
641All complex software has bugs lurking in it, and this module is no
642exception. If you find a bug please either email me, or add the bug
643to cpan-RT.
644
22286063 645=head1 CODE COVERAGE
646
647I use L<Devel::Cover> to test the code coverage of my tests, below is the
648L<Devel::Cover> report on this module's test suite.
649
650 ---------------------------- ------ ------ ------ ------ ------ ------ ------
651 File stmt bran cond sub pod time total
652 ---------------------------- ------ ------ ------ ------ ------ ------ ------
b9d9fc0b 653 Class/MOP.pm 78.0 87.5 55.6 71.4 100.0 12.4 76.8
654 Class/MOP/Attribute.pm 83.4 75.6 86.7 94.4 100.0 8.9 85.2
655 Class/MOP/Class.pm 96.9 75.8 43.2 98.0 100.0 55.3 83.6
656 Class/MOP/Class/Immutable.pm 88.5 53.8 n/a 95.8 100.0 1.1 84.7
657 Class/MOP/Instance.pm 87.9 75.0 33.3 89.7 100.0 10.1 89.1
658 Class/MOP/Method.pm 97.6 60.0 57.9 76.9 100.0 1.5 82.8
659 Class/MOP/Module.pm 87.5 n/a 11.1 83.3 100.0 0.3 66.7
660 Class/MOP/Object.pm 100.0 n/a 33.3 100.0 100.0 0.1 89.5
661 Class/MOP/Package.pm 95.1 69.0 33.3 100.0 100.0 9.9 85.5
662 metaclass.pm 100.0 100.0 83.3 100.0 n/a 0.5 97.7
22286063 663 ---------------------------- ------ ------ ------ ------ ------ ------ ------
b9d9fc0b 664 Total 91.5 72.1 48.8 90.7 100.0 100.0 84.2
22286063 665 ---------------------------- ------ ------ ------ ------ ------ ------ ------
666
a2e85e6c 667=head1 ACKNOWLEDGEMENTS
668
669=over 4
670
b9d9fc0b 671=item Rob Kinyon
a2e85e6c 672
673Thanks to Rob for actually getting the development of this module kick-started.
674
675=back
676
1a09d9cc 677=head1 AUTHORS
94b19069 678
a2e85e6c 679Stevan Little E<lt>stevan@iinteractive.comE<gt>
552e3d24 680
1a09d9cc 681Yuval Kogman E<lt>nothingmuch@woobling.comE<gt>
682
94b19069 683=head1 COPYRIGHT AND LICENSE
684
685Copyright 2006 by Infinity Interactive, Inc.
686
687L<http://www.iinteractive.com>
688
689This library is free software; you can redistribute it and/or modify
690it under the same terms as Perl itself.
691
692=cut