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