cycle tests and a weaken call
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Schema.pm
CommitLineData
a02675cd 1package DBIx::Class::Schema;
2
3use strict;
4use warnings;
aa562407 5
701da8c4 6use Carp::Clan qw/^DBIx::Class/;
a917fb06 7use Scalar::Util qw/weaken/;
a02675cd 8
41a6f8c0 9use base qw/DBIx::Class/;
a02675cd 10
0dc79249 11__PACKAGE__->mk_classdata('class_mappings' => {});
12__PACKAGE__->mk_classdata('source_registrations' => {});
1e10a11d 13__PACKAGE__->mk_classdata('storage_type' => '::DBI');
d7156e50 14__PACKAGE__->mk_classdata('storage');
a02675cd 15
c2da098a 16=head1 NAME
17
18DBIx::Class::Schema - composable schemas
19
20=head1 SYNOPSIS
21
24d67825 22 package Library::Schema;
c2da098a 23 use base qw/DBIx::Class::Schema/;
a3d93194 24
24d67825 25 # load Library::Schema::CD, Library::Schema::Book, Library::Schema::DVD
26 __PACKAGE__->load_classes(qw/CD Book DVD/);
c2da098a 27
24d67825 28 package Library::Schema::CD;
03312470 29 use base qw/DBIx::Class/;
77254782 30 __PACKAGE__->load_components(qw/PK::Auto Core/); # for example
24d67825 31 __PACKAGE__->table('cd');
c2da098a 32
5d9076f2 33 # Elsewhere in your code:
24d67825 34 my $schema1 = Library::Schema->connect(
a3d93194 35 $dsn,
36 $user,
37 $password,
24d67825 38 { AutoCommit => 0 },
a3d93194 39 );
90ec6cad 40
24d67825 41 my $schema2 = Library::Schema->connect($coderef_returning_dbh);
c2da098a 42
24d67825 43 # fetch objects using Library::Schema::DVD
44 my $resultset = $schema1->resultset('DVD')->search( ... );
45 my @dvd_objects = $schema2->resultset('DVD')->search( ... );
c2da098a 46
47=head1 DESCRIPTION
48
a3d93194 49Creates database classes based on a schema. This is the recommended way to
50use L<DBIx::Class> and allows you to use more than one concurrent connection
51with your classes.
429bd4f1 52
03312470 53NB: If you're used to L<Class::DBI> it's worth reading the L</SYNOPSIS>
2053ab2a 54carefully, as DBIx::Class does things a little differently. Note in
03312470 55particular which module inherits off which.
56
c2da098a 57=head1 METHODS
58
87c4e602 59=head2 register_class
60
27f01d1f 61=over 4
62
ebc77b53 63=item Arguments: $moniker, $component_class
27f01d1f 64
65=back
076652e8 66
71f9df37 67Registers a class which isa DBIx::Class::ResultSourceProxy. Equivalent to
2053ab2a 68calling:
66d9ef6b 69
181a28f4 70 $schema->register_source($moniker, $component_class->result_source_instance);
076652e8 71
c2da098a 72=cut
73
a02675cd 74sub register_class {
0dc79249 75 my ($self, $moniker, $to_register) = @_;
76 $self->register_source($moniker => $to_register->result_source_instance);
74b92d9a 77}
78
87c4e602 79=head2 register_source
80
27f01d1f 81=over 4
82
ebc77b53 83=item Arguments: $moniker, $result_source
27f01d1f 84
85=back
076652e8 86
82b01c38 87Registers the L<DBIx::Class::ResultSource> in the schema with the given
88moniker.
076652e8 89
90=cut
91
0dc79249 92sub register_source {
93 my ($self, $moniker, $source) = @_;
94 my %reg = %{$self->source_registrations};
95 $reg{$moniker} = $source;
96 $self->source_registrations(\%reg);
97 $source->schema($self);
a917fb06 98 weaken($source->{schema}) if ref($self);
0dc79249 99 if ($source->result_class) {
100 my %map = %{$self->class_mappings};
101 $map{$source->result_class} = $moniker;
102 $self->class_mappings(\%map);
103 }
75d07914 104}
a02675cd 105
bfb2bd4f 106=head2 class
107
27f01d1f 108=over 4
82b01c38 109
ebc77b53 110=item Arguments: $moniker
27f01d1f 111
d601dc88 112=item Return Value: $classname
27f01d1f 113
114=back
82b01c38 115
2053ab2a 116Retrieves the result class name for the given moniker. For example:
82b01c38 117
118 my $class = $schema->class('CD');
bfb2bd4f 119
120=cut
121
122sub class {
0dc79249 123 my ($self, $moniker) = @_;
124 return $self->source($moniker)->result_class;
bfb2bd4f 125}
126
ea20d0fd 127=head2 source
128
27f01d1f 129=over 4
130
ebc77b53 131=item Arguments: $moniker
27f01d1f 132
d601dc88 133=item Return Value: $result_source
82b01c38 134
27f01d1f 135=back
82b01c38 136
24d67825 137 my $source = $schema->source('Book');
ea20d0fd 138
82b01c38 139Returns the L<DBIx::Class::ResultSource> object for the registered moniker.
ea20d0fd 140
141=cut
142
143sub source {
0dc79249 144 my ($self, $moniker) = @_;
145 my $sreg = $self->source_registrations;
146 return $sreg->{$moniker} if exists $sreg->{$moniker};
147
148 # if we got here, they probably passed a full class name
149 my $mapped = $self->class_mappings->{$moniker};
701da8c4 150 $self->throw_exception("Can't find source for ${moniker}")
0dc79249 151 unless $mapped && exists $sreg->{$mapped};
152 return $sreg->{$mapped};
ea20d0fd 153}
154
0dc79249 155=head2 sources
156
27f01d1f 157=over 4
158
d601dc88 159=item Return Value: @source_monikers
27f01d1f 160
161=back
82b01c38 162
163Returns the source monikers of all source registrations on this schema.
2053ab2a 164For example:
82b01c38 165
166 my @source_monikers = $schema->sources;
0dc79249 167
168=cut
169
170sub sources { return keys %{shift->source_registrations}; }
171
ea20d0fd 172=head2 resultset
173
27f01d1f 174=over 4
175
ebc77b53 176=item Arguments: $moniker
27f01d1f 177
d601dc88 178=item Return Value: $result_set
82b01c38 179
27f01d1f 180=back
82b01c38 181
24d67825 182 my $rs = $schema->resultset('DVD');
ea20d0fd 183
82b01c38 184Returns the L<DBIx::Class::ResultSet> object for the registered moniker.
ea20d0fd 185
186=cut
187
188sub resultset {
0dc79249 189 my ($self, $moniker) = @_;
190 return $self->source($moniker)->resultset;
ea20d0fd 191}
192
87c4e602 193=head2 load_classes
194
27f01d1f 195=over 4
196
197=item Arguments: @classes?, { $namespace => [ @classes ] }+
198
199=back
076652e8 200
82b01c38 201With no arguments, this method uses L<Module::Find> to find all classes under
202the schema's namespace. Otherwise, this method loads the classes you specify
203(using L<use>), and registers them (using L</"register_class">).
076652e8 204
2053ab2a 205It is possible to comment out classes with a leading C<#>, but note that perl
206will think it's a mistake (trying to use a comment in a qw list), so you'll
207need to add C<no warnings 'qw';> before your load_classes call.
5ce32fc1 208
2053ab2a 209Example:
82b01c38 210
211 My::Schema->load_classes(); # loads My::Schema::CD, My::Schema::Artist,
75d07914 212 # etc. (anything under the My::Schema namespace)
82b01c38 213
214 # loads My::Schema::CD, My::Schema::Artist, Other::Namespace::Producer but
215 # not Other::Namespace::LinerNotes nor My::Schema::Track
216 My::Schema->load_classes(qw/ CD Artist #Track /, {
217 Other::Namespace => [qw/ Producer #LinerNotes /],
218 });
219
076652e8 220=cut
221
a02675cd 222sub load_classes {
5ce32fc1 223 my ($class, @params) = @_;
224
225 my %comps_for;
226
227 if (@params) {
228 foreach my $param (@params) {
229 if (ref $param eq 'ARRAY') {
230 # filter out commented entries
231 my @modules = grep { $_ !~ /^#/ } @$param;
232
233 push (@{$comps_for{$class}}, @modules);
234 }
235 elsif (ref $param eq 'HASH') {
236 # more than one namespace possible
237 for my $comp ( keys %$param ) {
238 # filter out commented entries
239 my @modules = grep { $_ !~ /^#/ } @{$param->{$comp}};
240
241 push (@{$comps_for{$comp}}, @modules);
242 }
243 }
244 else {
245 # filter out commented entries
246 push (@{$comps_for{$class}}, $param) if $param !~ /^#/;
247 }
248 }
249 } else {
41a6f8c0 250 eval "require Module::Find;";
bc0c9800 251 $class->throw_exception(
252 "No arguments to load_classes and couldn't load Module::Find ($@)"
253 ) if $@;
254 my @comp = map { substr $_, length "${class}::" }
255 Module::Find::findallmod($class);
5ce32fc1 256 $comps_for{$class} = \@comp;
41a6f8c0 257 }
5ce32fc1 258
e6efde04 259 my @to_register;
260 {
261 no warnings qw/redefine/;
262 local *Class::C3::reinitialize = sub { };
263 foreach my $prefix (keys %comps_for) {
264 foreach my $comp (@{$comps_for{$prefix}||[]}) {
265 my $comp_class = "${prefix}::${comp}";
266 eval "use $comp_class"; # If it fails, assume the user fixed it
267 if ($@) {
75d07914 268 $comp_class =~ s/::/\//g;
3b24f6ea 269 die $@ unless $@ =~ /Can't locate.+$comp_class\.pm\sin\s\@INC/;
75d07914 270 warn $@ if $@;
e6efde04 271 }
272 push(@to_register, [ $comp, $comp_class ]);
bfb2bd4f 273 }
5ce32fc1 274 }
a02675cd 275 }
e6efde04 276 Class::C3->reinitialize;
277
278 foreach my $to (@to_register) {
279 $class->register_class(@$to);
280 # if $class->can('result_source_instance');
281 }
a02675cd 282}
283
87c4e602 284=head2 compose_connection
285
27f01d1f 286=over 4
287
ebc77b53 288=item Arguments: $target_namespace, @db_info
429bd4f1 289
d601dc88 290=item Return Value: $new_schema
27f01d1f 291
292=back
076652e8 293
2053ab2a 294Calls L<DBIx::Class::Schema/"compose_namespace"> to the target namespace,
295calls L<DBIx::Class::Schema/connection> with @db_info on the new schema,
296then injects the L<DBix::Class::ResultSetProxy> component and a
297resultset_instance classdata entry on all the new classes, in order to support
82b01c38 298$target_namespaces::$class->search(...) method calls.
299
300This is primarily useful when you have a specific need for class method access
301to a connection. In normal usage it is preferred to call
302L<DBIx::Class::Schema/connect> and use the resulting schema object to operate
303on L<DBIx::Class::ResultSet> objects with L<DBIx::Class::Schema/resultset> for
304more information.
54540863 305
076652e8 306=cut
307
a02675cd 308sub compose_connection {
ea20d0fd 309 my ($self, $target, @info) = @_;
80c90f5d 310 my $base = 'DBIx::Class::ResultSetProxy';
8ef144ff 311 eval "require ${base};";
bc0c9800 312 $self->throw_exception
313 ("No arguments to load_classes and couldn't load ${base} ($@)")
314 if $@;
be381829 315
316 if ($self eq $target) {
317 # Pathological case, largely caused by the docs on early C::M::DBIC::Plain
318 foreach my $moniker ($self->sources) {
319 my $source = $self->source($moniker);
320 my $class = $source->result_class;
321 $self->inject_base($class, $base);
322 $class->mk_classdata(resultset_instance => $source->resultset);
323 $class->mk_classdata(class_resolver => $self);
324 }
50041f3c 325 $self->connection(@info);
be381829 326 return $self;
327 }
328
66d9ef6b 329 my $schema = $self->compose_namespace($target, $base);
ecceadff 330 {
331 no strict 'refs';
332 *{"${target}::schema"} = sub { $schema };
333 }
334
66d9ef6b 335 $schema->connection(@info);
0dc79249 336 foreach my $moniker ($schema->sources) {
337 my $source = $schema->source($moniker);
338 my $class = $source->result_class;
339 #warn "$moniker $class $source ".$source->storage;
8c49f629 340 $class->mk_classdata(result_source_instance => $source);
ea20d0fd 341 $class->mk_classdata(resultset_instance => $source->resultset);
66d9ef6b 342 $class->mk_classdata(class_resolver => $schema);
bfb2bd4f 343 }
344 return $schema;
e678398e 345}
346
77254782 347=head2 compose_namespace
348
27f01d1f 349=over 4
350
351=item Arguments: $target_namespace, $additional_base_class?
82b01c38 352
d601dc88 353=item Return Value: $new_schema
27f01d1f 354
355=back
13765dad 356
82b01c38 357For each L<DBIx::Class::ResultSource> in the schema, this method creates a
358class in the target namespace (e.g. $target_namespace::CD,
359$target_namespace::Artist) that inherits from the corresponding classes
360attached to the current schema.
77254782 361
82b01c38 362It also attaches a corresponding L<DBIx::Class::ResultSource> object to the
363new $schema object. If C<$additional_base_class> is given, the new composed
364classes will inherit from first the corresponding classe from the current
365schema then the base class.
366
2053ab2a 367For example, for a schema with My::Schema::CD and My::Schema::Artist classes,
82b01c38 368
369 $schema->compose_namespace('My::DB', 'Base::Class');
370 print join (', ', @My::DB::CD::ISA) . "\n";
371 print join (', ', @My::DB::Artist::ISA) ."\n";
372
2053ab2a 373will produce the output
82b01c38 374
375 My::Schema::CD, Base::Class
376 My::Schema::Artist, Base::Class
77254782 377
378=cut
379
e678398e 380sub compose_namespace {
66d9ef6b 381 my ($self, $target, $base) = @_;
382 my %reg = %{ $self->source_registrations };
11b78bd6 383 my %target;
384 my %map;
66d9ef6b 385 my $schema = $self->clone;
e9100ff7 386 {
387 no warnings qw/redefine/;
388 local *Class::C3::reinitialize = sub { };
389 foreach my $moniker ($schema->sources) {
390 my $source = $schema->source($moniker);
391 my $target_class = "${target}::${moniker}";
392 $self->inject_base(
393 $target_class => $source->result_class, ($base ? $base : ())
394 );
395 $source->result_class($target_class);
396 }
b7951443 397 }
e9100ff7 398 Class::C3->reinitialize();
11b78bd6 399 {
400 no strict 'refs';
1edaf6fe 401 foreach my $meth (qw/class source resultset/) {
402 *{"${target}::${meth}"} =
403 sub { shift->schema->$meth(@_) };
404 }
11b78bd6 405 }
bfb2bd4f 406 return $schema;
b7951443 407}
408
87c4e602 409=head2 setup_connection_class
410
27f01d1f 411=over 4
412
ebc77b53 413=item Arguments: $target, @info
27f01d1f 414
415=back
076652e8 416
82b01c38 417Sets up a database connection class to inject between the schema and the
418subclasses that the schema creates.
429bd4f1 419
076652e8 420=cut
421
b7951443 422sub setup_connection_class {
423 my ($class, $target, @info) = @_;
63e9583a 424 $class->inject_base($target => 'DBIx::Class::DB');
425 #$target->load_components('DB');
b7951443 426 $target->connection(@info);
427}
428
87c4e602 429=head2 connection
430
27f01d1f 431=over 4
432
ebc77b53 433=item Arguments: @args
66d9ef6b 434
d601dc88 435=item Return Value: $new_schema
27f01d1f 436
437=back
82b01c38 438
439Instantiates a new Storage object of type
440L<DBIx::Class::Schema/"storage_type"> and passes the arguments to
441$storage->connect_info. Sets the connection in-place on the schema. See
442L<DBIx::Class::Storage::DBI/"connect_info"> for more information.
66d9ef6b 443
444=cut
445
446sub connection {
447 my ($self, @info) = @_;
e59d3e5b 448 return $self if !@info && $self->storage;
1e10a11d 449 my $storage_class = $self->storage_type;
450 $storage_class = 'DBIx::Class::Storage'.$storage_class
451 if $storage_class =~ m/^::/;
8ef144ff 452 eval "require ${storage_class};";
bc0c9800 453 $self->throw_exception(
454 "No arguments to load_classes and couldn't load ${storage_class} ($@)"
455 ) if $@;
66d9ef6b 456 my $storage = $storage_class->new;
457 $storage->connect_info(\@info);
458 $self->storage($storage);
459 return $self;
460}
461
87c4e602 462=head2 connect
463
27f01d1f 464=over 4
465
ebc77b53 466=item Arguments: @info
66d9ef6b 467
d601dc88 468=item Return Value: $new_schema
27f01d1f 469
470=back
82b01c38 471
472This is a convenience method. It is equivalent to calling
473$schema->clone->connection(@info). See L</connection> and L</clone> for more
474information.
66d9ef6b 475
476=cut
477
08b515f1 478sub connect { shift->clone->connection(@_) }
479
480=head2 txn_begin
481
82b01c38 482Begins a transaction (does nothing if AutoCommit is off). Equivalent to
483calling $schema->storage->txn_begin. See
484L<DBIx::Class::Storage::DBI/"txn_begin"> for more information.
08b515f1 485
486=cut
487
488sub txn_begin { shift->storage->txn_begin }
489
490=head2 txn_commit
491
82b01c38 492Commits the current transaction. Equivalent to calling
493$schema->storage->txn_commit. See L<DBIx::Class::Storage::DBI/"txn_commit">
494for more information.
08b515f1 495
496=cut
497
498sub txn_commit { shift->storage->txn_commit }
499
500=head2 txn_rollback
501
82b01c38 502Rolls back the current transaction. Equivalent to calling
503$schema->storage->txn_rollback. See
504L<DBIx::Class::Storage::DBI/"txn_rollback"> for more information.
08b515f1 505
506=cut
507
508sub txn_rollback { shift->storage->txn_rollback }
66d9ef6b 509
a62cf8d4 510=head2 txn_do
511
27f01d1f 512=over 4
513
ebc77b53 514=item Arguments: C<$coderef>, @coderef_args?
82b01c38 515
d601dc88 516=item Return Value: The return value of $coderef
27f01d1f 517
518=back
a62cf8d4 519
82b01c38 520Executes C<$coderef> with (optional) arguments C<@coderef_args> atomically,
521returning its result (if any). If an exception is caught, a rollback is issued
522and the exception is rethrown. If the rollback fails, (i.e. throws an
523exception) an exception is thrown that includes a "Rollback failed" message.
a62cf8d4 524
525For example,
526
24d67825 527 my $author_rs = $schema->resultset('Author')->find(1);
a62cf8d4 528
529 my $coderef = sub {
24d67825 530 my ($author, @titles) = @_;
a62cf8d4 531
532 # If any one of these fails, the entire transaction fails
24d67825 533 $author->create_related('books', {
534 title => $_
535 }) foreach (@titles);
a62cf8d4 536
24d67825 537 return $author->books;
a62cf8d4 538 };
539
540 my $rs;
541 eval {
24d67825 542 $rs = $schema->txn_do($coderef, $author_rs, qw/Night Day It/);
a62cf8d4 543 };
544
545 if ($@) {
546 my $error = $@;
547 if ($error =~ /Rollback failed/) {
548 die "something terrible has happened!";
549 } else {
550 deal_with_failed_transaction();
a62cf8d4 551 }
552 }
553
82b01c38 554In a nested transaction (calling txn_do() from within a txn_do() coderef) only
555the outermost transaction will issue a L<DBIx::Class::Schema/"txn_commit"> on
556the Schema's storage, and txn_do() can be called in void, scalar and list
557context and it will behave as expected.
a62cf8d4 558
559=cut
560
561sub txn_do {
562 my ($self, $coderef, @args) = @_;
563
171dadd7 564 ref $self or $self->throw_exception
565 ('Cannot execute txn_do as a class method');
566 ref $coderef eq 'CODE' or $self->throw_exception
567 ('$coderef must be a CODE reference');
a62cf8d4 568
569 my (@return_values, $return_value);
570
571 $self->txn_begin; # If this throws an exception, no rollback is needed
572
e7f2b7d5 573 my $wantarray = wantarray; # Need to save this since the context
75d07914 574 # inside the eval{} block is independent
575 # of the context that called txn_do()
a62cf8d4 576 eval {
82b01c38 577
24d67825 578 # Need to differentiate between scalar/list context to allow for
579 # returning a list in scalar context to get the size of the list
a62cf8d4 580 if ($wantarray) {
eeb34228 581 # list context
a62cf8d4 582 @return_values = $coderef->(@args);
eeb34228 583 } elsif (defined $wantarray) {
584 # scalar context
a62cf8d4 585 $return_value = $coderef->(@args);
eeb34228 586 } else {
587 # void context
588 $coderef->(@args);
a62cf8d4 589 }
590 $self->txn_commit;
591 };
592
593 if ($@) {
594 my $error = $@;
595
596 eval {
597 $self->txn_rollback;
598 };
599
600 if ($@) {
601 my $rollback_error = $@;
602 my $exception_class = "DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION";
603 $self->throw_exception($error) # propagate nested rollback
75d07914 604 if $rollback_error =~ /$exception_class/;
a62cf8d4 605
bc0c9800 606 $self->throw_exception(
607 "Transaction aborted: $error. Rollback failed: ${rollback_error}"
608 );
a62cf8d4 609 } else {
610 $self->throw_exception($error); # txn failed but rollback succeeded
611 }
612 }
613
614 return $wantarray ? @return_values : $return_value;
615}
616
66d9ef6b 617=head2 clone
618
27f01d1f 619=over 4
620
d601dc88 621=item Return Value: $new_schema
27f01d1f 622
623=back
82b01c38 624
66d9ef6b 625Clones the schema and its associated result_source objects and returns the
626copy.
627
628=cut
629
630sub clone {
631 my ($self) = @_;
632 my $clone = bless({ (ref $self ? %$self : ()) }, ref $self || $self);
633 foreach my $moniker ($self->sources) {
634 my $source = $self->source($moniker);
635 my $new = $source->new($source);
636 $clone->register_source($moniker => $new);
637 }
638 return $clone;
639}
640
87c4e602 641=head2 populate
642
27f01d1f 643=over 4
644
ebc77b53 645=item Arguments: $moniker, \@data;
27f01d1f 646
647=back
a37a4697 648
649Populates the source registered with the given moniker with the supplied data.
82b01c38 650@data should be a list of listrefs -- the first containing column names, the
651second matching values.
652
653i.e.,
a37a4697 654
24d67825 655 $schema->populate('Artist', [
656 [ qw/artistid name/ ],
657 [ 1, 'Popular Band' ],
658 [ 2, 'Indie Band' ],
a62cf8d4 659 ...
660 ]);
a37a4697 661
662=cut
663
664sub populate {
665 my ($self, $name, $data) = @_;
666 my $rs = $self->resultset($name);
667 my @names = @{shift(@$data)};
84e3c114 668 my @created;
a37a4697 669 foreach my $item (@$data) {
670 my %create;
671 @create{@names} = @$item;
84e3c114 672 push(@created, $rs->create(\%create));
a37a4697 673 }
84e3c114 674 return @created;
a37a4697 675}
676
5160b401 677=head2 throw_exception
701da8c4 678
75d07914 679=over 4
82b01c38 680
ebc77b53 681=item Arguments: $message
82b01c38 682
683=back
684
685Throws an exception. Defaults to using L<Carp::Clan> to report errors from
686user's perspective.
701da8c4 687
688=cut
689
690sub throw_exception {
691 my ($self) = shift;
692 croak @_;
693}
694
ec6704d4 695=head2 deploy (EXPERIMENTAL)
1c339d71 696
82b01c38 697=over 4
698
ebc77b53 699=item Arguments: $sqlt_args
82b01c38 700
701=back
702
703Attempts to deploy the schema to the current storage using L<SQL::Translator>.
ec6704d4 704
705Note that this feature is currently EXPERIMENTAL and may not work correctly
706across all databases, or fully handle complex relationships.
1c339d71 707
708=cut
709
710sub deploy {
cb561d1a 711 my ($self, $sqltargs) = @_;
1c339d71 712 $self->throw_exception("Can't deploy without storage") unless $self->storage;
cb561d1a 713 $self->storage->deploy($self, undef, $sqltargs);
1c339d71 714}
715
a02675cd 7161;
c2da098a 717
c2da098a 718=head1 AUTHORS
719
daec44b8 720Matt S. Trout <mst@shadowcatsystems.co.uk>
c2da098a 721
722=head1 LICENSE
723
724You may distribute this code under the same terms as Perl itself.
725
726=cut
727