File Coverage

blib/lib/App/Sqitch/Target.pm
Criterion Covered Total %
statement 98 99 98.9
branch 48 50 96.0
condition 15 20 75.0
subroutine 14 14 100.0
pod 2 3 66.6
total 177 186 95.1


line stmt bran cond sub pod time code
1              
2             use 5.010;
3 43     43   27188 use Moo;
  43         170  
4 43     43   240 use strict;
  43         84  
  43         295  
5 43     43   13935 use warnings;
  43         125  
  43         991  
6 43     43   250 use App::Sqitch::Types qw(Maybe URIDB Str Dir Engine Sqitch File Plan HashRef);
  43         102  
  43         1932  
7 43     43   268 use App::Sqitch::X qw(hurl);
  43         93  
  43         481  
8 43     43   64405 use Locale::TextDomain qw(App-Sqitch);
  43         98  
  43         380  
9 43     43   11865 use Path::Class qw(dir file);
  43         94  
  43         367  
10 43     43   8295 use URI::db;
  43         89  
  43         2970  
11 43     43   16895 use namespace::autoclean;
  43         519961  
  43         1236  
12 43     43   289  
  43         90  
  43         432  
13             our $VERSION = 'v1.3.1'; # VERSION
14              
15             has name => (
16             is => 'ro',
17             isa => Str,
18             required => 1,
19             );
20              
21 13     13 1 4297 has uri => (
22             is => 'ro',
23             isa => URIDB,
24             required => 1,
25             handles => {
26             engine_key => 'canonical_engine',
27             dsn => 'dbi_dsn',
28             },
29             );
30              
31             has username => (
32             is => 'ro',
33             isa => Maybe[Str],
34             lazy => 1,
35             default => sub {
36             my $self = shift;
37             $ENV{SQITCH_USERNAME} || $self->uri->user
38             },
39             );
40              
41             has password => (
42             is => 'ro',
43             isa => Maybe[Str],
44             lazy => 1,
45             default => sub {
46             $ENV{SQITCH_PASSWORD} || shift->uri->password
47             },
48             );
49              
50             has sqitch => (
51             is => 'ro',
52             isa => Sqitch,
53             required => 1,
54             handles => {
55             _config => 'config',
56             _options => 'options',
57             },
58             );
59              
60             has engine => (
61             is => 'ro',
62             isa => Engine,
63             lazy => 1,
64             default => sub {
65             my $self = shift;
66             require App::Sqitch::Engine;
67             App::Sqitch::Engine->load({
68             sqitch => $self->sqitch,
69             target => $self,
70             });
71             },
72             );
73              
74             my ($self, $key) = @_;
75             my $config = $self->_config;
76             return $config->get( key => "target." . $self->name . ".$key" )
77 1099     1099   2543 || do {
78 1099         15916 my $ekey = $self->engine_key;
79             $ekey ? $config->get( key => "engine.$ekey.$key") : ();
80 1099   100     46319 } || $config->get( key => "core.$key");
81             }
82              
83             has variables => (
84             is => 'rw',
85             isa => HashRef[Str],
86             lazy => 1,
87             default => sub {
88             my $self = shift;
89             my $config = $self->sqitch->config;
90             return {
91             map { %{ $config->get_section( section => "$_.variables" ) || {} } } (
92             'engine.' . $self->engine_key,
93             'target.' . $self->name,
94             )
95             };
96             },
97             );
98              
99             has registry => (
100             is => 'ro',
101             isa => Str,
102             lazy => 1,
103             default => sub {
104             my $self = shift;
105             $self->_fetch('registry') || $self->engine->default_registry;
106             },
107             );
108              
109             has client => (
110             is => 'ro',
111             isa => Str,
112             lazy => 1,
113             default => sub {
114             my $self = shift;
115             $self->_fetch('client') || do {
116             my $client = $self->engine->default_client;
117             return $client unless App::Sqitch::ISWIN;
118             return $client if $client =~ /[.](?:exe|bat)$/;
119             return $client . '.exe';
120             };
121             },
122             );
123              
124             has plan_file => (
125             is => 'ro',
126             isa => File,
127             lazy => 1,
128             default => sub {
129             my $self = shift;
130             if ( my $f = $self->_fetch('plan_file') ) {
131             return file $f;
132             }
133             return $self->top_dir->file('sqitch.plan')->cleanup;
134             },
135             );
136              
137             has plan => (
138             is => 'ro',
139             isa => Plan,
140             lazy => 1,
141             default => sub {
142             my $self = shift;
143             App::Sqitch::Plan->new(
144             sqitch => $self->sqitch,
145             target => $self,
146             );
147             },
148             );
149              
150             has top_dir => (
151             is => 'ro',
152             isa => Dir,
153             lazy => 1,
154             default => sub {
155             my $self = shift;
156             dir $self->_fetch('top_dir') || ();
157             },
158             );
159              
160             has reworked_dir => (
161             is => 'ro',
162             isa => Dir,
163             lazy => 1,
164             default => sub {
165             my $self = shift;
166             if ( my $dir = $self->_fetch('reworked_dir') ) {
167             return dir $dir;
168             }
169             $self->top_dir;
170             },
171             );
172              
173             for my $script (qw(deploy revert verify)) {
174             has "$script\_dir" => (
175             is => 'ro',
176             isa => Dir,
177             lazy => 1,
178             default => sub {
179             my $self = shift;
180             if ( my $dir = $self->_fetch("$script\_dir") ) {
181             return dir $dir;
182             }
183             $self->top_dir->subdir($script)->cleanup;
184             },
185             );
186             has "reworked_$script\_dir" => (
187             is => 'ro',
188             isa => Dir,
189             lazy => 1,
190             default => sub {
191             my $self = shift;
192             if ( my $dir = $self->_fetch("reworked_$script\_dir") ) {
193             return dir $dir;
194             }
195             $self->reworked_dir->subdir($script)->cleanup;
196             },
197             );
198             }
199              
200             has extension => (
201             is => 'ro',
202             isa => Str,
203             lazy => 1,
204             default => sub {
205             shift->_fetch('extension') || 'sql';
206             },
207             );
208              
209             my $class = shift;
210             my $p = @_ == 1 && ref $_[0] ? { %{ +shift } } : { @_ };
211              
212             # Fetch params. URI can come from passed name.
213 603     603 0 794241 my $sqitch = $p->{sqitch} or return $p;
214 603 50 33     3715 my $name = $p->{name} || $ENV{SQITCH_TARGET} || '';
  0         0  
215             my $uri = $p->{uri};
216              
217 603 100       2423 # If we have a URI up-front, it's all good.
218 602   100     3779 if ($uri) {
219 602         1182 unless ($name) {
220             # Set the URI as the name, sans password.
221             if ($uri->password) {
222 602 100       2669 $uri = $uri->clone;
223 139 100       5038 $uri->password(undef);
224             }
225 98 100       660 $p->{name} = $uri->as_string;
226 8         498 }
227 8         163 return $p;
228             }
229 98         5284  
230             my $ekey;
231 139         3161 my $config = $sqitch->config;
232              
233             # If no name, try to find one.
234 463         721 if (!$name) {
235 463         7404 # There are a couple of places to look for a name.
236             NAME: {
237             # Look for core target.
238 463 100       3985 if ( $uri = $config->get( key => 'core.target' ) ) {
239             # We got core.target.
240             $p->{name} = $name = $uri;
241             last NAME;
242 265 100       470 }
  265         1280  
243              
244 3         401 # No core target, look for an engine key.
245 3         7 $ekey = $config->get( key => 'core.engine' ) or do {
246             hurl target => __(
247             'No engine specified; specify via target or core.engine'
248             ) if $config->initialized;
249 262 100       29490 hurl target => __(
250 5 100       481 'No project configuration found. Run the "init" command to initialize a project'
251             );
252             };
253 4         29 $ekey =~ s/\s+$//;
254              
255             # Find the name in the engine config, or fall back on a simple URI.
256             $uri = $config->get( key => "engine.$ekey.target" ) || "db:$ekey:";
257 257         33516 $p->{name} = $name = $uri;
258             }
259             }
260 257   66     1113  
261 257         29052 # Now we should have a name. What is it?
262             if ($name =~ /:/) {
263             # The name is a URI.
264             $uri = $name;
265             $name = $p->{name} = undef;
266 458 100       1825 } else {
267             $p->{name} = $name;
268 375         679 # Well then, there had better be a config with a URI.
269 375         772 $uri = $config->get( key => "target.$name.uri" ) or do {
270             # Die on no section or no URI.
271 83         217 hurl target => __x(
272             'Cannot find target "{target}"',
273 83 100       427 target => $name
274             ) unless %{ $config->get_section(
275             section => "target.$name"
276             ) };
277             hurl target => __x(
278 3 100       343 'No URI associated with target "{target}"',
  3         14  
279             target => $name,
280             );
281 1         8 };
282             }
283              
284             # Instantiate the URI.
285             $uri = $p->{uri} = URI::db->new( $uri );
286             $ekey ||= $uri->canonical_engine or hurl target => __x(
287             'No engine specified by URI {uri}; URI must start with "db:$engine:"',
288             uri => $uri->as_string,
289 455         14429 );
290 455 100 100     94660  
291             # Override with optional parameters.
292             for my $attr (qw(user host port dbname)) {
293             $uri->$attr(delete $p->{$attr}) if exists $p->{$attr};
294             }
295              
296 453         4401 unless ($name) {
297 1812 100       3859 # Set the name.
298             if ($uri->password) {
299             # Remove the password from the name.
300 453 100       1716 my $tmp = $uri->clone;
301             $tmp->password(undef);
302 373 100       1971 $p->{name} = $tmp->as_string;
303             } else {
304 11         688 $p->{name} = $uri->as_string;
305 11         217 }
306 11         1233 }
307              
308 362         17587 return $p;
309             }
310              
311             my ($class, %p) = @_;
312 453         13930 my $sqitch = $p{sqitch} or hurl 'Missing required argument: sqitch';
313             my $config = delete $p{config} || $sqitch->config;
314             my (@targets, %seen);
315             my %dump = $config->dump;
316 39     39 1 19628  
317 39 50       236 # First, load the default target.
318 39   33     1259 my $core = $dump{'core.target'} || do {
319 39         473 if ( my $engine = $dump{'core.engine'} ) {
320 39         337 $engine =~ s/\s+$//;
321             $dump{"engine.$engine.target"} || "db:$engine:";
322             }
323 39   100     1743 };
324             push @targets => $seen{$core} = $class->new(%p, name => $core)
325             if $core;
326              
327             # Next, load named targets.
328             for my $key (keys %dump) {
329 39 100       863 next if $key !~ /^target[.]([^.]+)[.]uri$/;
330             push @targets => $seen{$1} = $class->new(%p, name => $1)
331             unless $seen{$1};
332             }
333 39         3562  
334 196 100       996 # Now, load the engine targets.
335             while ( my ($key, $val) = each %dump ) {
336 13 100       287 next if $key !~ /^engine[.]([^.]+)[.]target$/;
337             push @targets => $seen{$val} = $class->new(%p, name => $val)
338             unless $seen{$val};
339             $seen{$1} = $seen{$val};
340 39         364 }
341 196 100       688  
342             # Finally, load any engines for which no target name was specified.
343 16 100       144 while ( my ($key, $val) = each %dump ) {
344 16         416 my ($engine) = $key =~ /^engine[.]([^.]+)/ or next;
345             $engine =~ s/\s+$//;
346             next if $seen{$engine}++;
347             my $uri = URI->new("db:$engine:");
348 39         197 push @targets => $seen{$uri} = $class->new(%p, uri => $uri)
349 196 100       3763 unless $seen{$uri};
350 107         262 }
351 107 100       377  
352 66         264 # Return all the targets.
353             return @targets;
354 66 100       13262 }
355              
356             1;
357              
358 39         1232  
359             =head1 Name
360              
361             App::Sqitch::Target - Sqitch deployment target
362              
363             =head1 Synopsis
364              
365             my $plan = App::Sqitch::Target->new(
366             sqitch => $sqitch,
367             name => 'development',
368             );
369             $target->engine->deploy;
370              
371             =head1 Description
372              
373             App::Sqitch::Target provides collects, in one place, the
374             L<engine|App::Sqitch::Engine>, L<plan|App::Sqitch::Engine>, and file locations
375             required to carry out Sqitch commands. All commands should instantiate a
376             target to work with the plan or database.
377              
378             =head1 Interface
379              
380             =head2 Constructors
381              
382             =head3 C<new>
383              
384             my $target = App::Sqitch::Target->new( sqitch => $sqitch );
385              
386             Instantiates and returns an App::Sqitch::Target object. The most important
387             parameters are C<sqitch>, C<name>, and C<uri>. The constructor tries really
388             hard to figure out the proper name and URI during construction. If the C<uri>
389             parameter is passed, this is straight-forward: if no C<name> is passed,
390             C<name> will be set to the stringified format of the URI (minus the password,
391             if present).
392              
393             Otherwise, when no URI is passed, the name and URI are determined by taking
394             the following steps:
395              
396             =over
397              
398             =item *
399              
400             If there is no name, get the engine key from or the C<core.engine>
401             +configuration option. If no key can be determined, an exception will be
402             thrown.
403              
404             =item *
405              
406             Use the key to look up the target name in the C<engine.$engine.target>
407             configuration option. If none is found, use C<db:$key:>.
408              
409             =item *
410              
411             If the name contains a colon (C<:>), assume it is also the value for the URI.
412              
413             =item *
414              
415             Otherwise, it should be the name of a configured target, so look for a URI in
416             the C<target.$name.uri> configuration option.
417              
418             =back
419              
420             As a general rule, then, pass either a target name or URI string in the
421             C<name> parameter, and Sqitch will do its best to find all the relevant target
422             information. And if there is no name or URI, it will try to construct a
423             reasonable default from the command-line options or engine configuration.
424              
425             All Target attributes may be passed as parameters to C<new()>. In addition,
426             C<new()> accepts a few non-attribute parameters that may be used to override
427             parts of the connection URI. They are:
428              
429             =over
430              
431             =item * C<user>
432              
433             =item * C<host>
434              
435             =item * C<port>
436              
437             =item * C<dbname>
438              
439             =back
440              
441             For example, if the the named target had its URI configured as
442             C<db:pg://fred@example.com/work>, The C<uri> would be set as such by:
443              
444             my $target = App::Sqitch::Target->new(sqitch => $sqitch, name => 'work');
445             say $target->uri;
446              
447             However, passing the URI parameters like this:
448              
449             my $target = App::Sqitch::Target->new(
450             sqitch => $sqitch,
451             name => 'work',
452             user => 'bill',
453             port => 1212,
454             );
455             say $target->uri;
456              
457             Sets the URI to C<db:pg://bill@example.com:1212/work>.
458              
459             =head3 C<all_targets>
460              
461             Returns a list of all the targets defined by the local Sqitch configuration
462             file. Done by examining the configuration object to find all defined targets
463             and engines, as well as the default "core" target. Duplicates are removed and
464             the list returned. This method takes the same parameters as C<new>; only
465             C<sqitch> is required. All other parameters will be set on all of the returned
466             targets.
467              
468             =head2 Accessors
469              
470             =head3 C<sqitch>
471              
472             my $sqitch = $target->sqitch;
473              
474             Returns the L<App::Sqitch> object that instantiated the target.
475              
476             =head3 C<name>
477              
478             =head3 C<target>
479              
480             my $name = $target->name;
481             $name = $target->target;
482              
483             The name of the target. If there was no name specified, the URI will be used
484             (minus the password, if there is one).
485              
486             =head3 C<uri>
487              
488             my $uri = $target->uri;
489              
490             The L<URI::db> object encapsulating the database connection information.
491              
492             =head3 C<username>
493              
494             my $username = $target->username;
495              
496             Returns the target username, if any. The username is looked up from the URI.
497              
498             =head3 C<password>
499              
500             my $password = $target->password;
501              
502             Returns the target password, if any. The password is looked up from the URI
503             or the C<$SQITCH_PASSWORD> environment variable.
504              
505             =head3 C<engine>
506              
507             my $engine = $target->engine;
508              
509             A L<App::Sqitch::Engine> object to use for database interactions with the
510             target.
511              
512             =head3 C<registry>
513              
514             my $registry = $target->registry;
515              
516             The name of the registry used by the database. The value comes from one of
517             these options, searched in this order:
518              
519             =over
520              
521             =item * C<--registry>
522              
523             =item * C<target.$name.registry>
524              
525             =item * C<engine.$engine.registry>
526              
527             =item * C<core.registry>
528              
529             =item * Engine-specific default
530              
531             =back
532              
533             =head3 C<client>
534              
535             my $client = $target->client;
536              
537             Path to the engine command-line client. The value comes from one of these
538             options, searched in this order:
539              
540             =over
541              
542             =item * C<--client>
543              
544             =item * C<target.$name.client>
545              
546             =item * C<engine.$engine.client>
547              
548             =item * C<core.client>
549              
550             =item * Engine-and-OS-specific default
551              
552             =back
553              
554             =head3 C<top_dir>
555              
556             my $top_dir = $target->top_dir;
557              
558             The path to the top directory of the project. This directory generally
559             contains the plan file and subdirectories for deploy, revert, and verify
560             scripts. The value comes from one of these options, searched in this order:
561              
562             =over
563              
564             =item * C<--top-dir>
565              
566             =item * C<target.$name.top_dir>
567              
568             =item * C<engine.$engine.top_dir>
569              
570             =item * C<core.top_dir>
571              
572             =item * F<.>
573              
574             =back
575              
576             =head3 C<plan_file>
577              
578             my $plan_file = $target->plan_file;
579              
580             The path to the plan file. The value comes from one of these options, searched
581             in this order:
582              
583             =over
584              
585             =item * C<--plan-file>
586              
587             =item * C<target.$name.plan_file>
588              
589             =item * C<engine.$engine.plan_file>
590              
591             =item * C<core.plan_file>
592              
593             =item * F<C<$top_dir>/sqitch.plan>
594              
595             =back
596              
597             =head3 C<deploy_dir>
598              
599             my $deploy_dir = $target->deploy_dir;
600              
601             The path to the deploy directory of the project. This directory contains all
602             of the deploy scripts referenced by changes in the C<plan_file>. The value
603             comes from one of these options, searched in this order:
604              
605             =over
606              
607             =item * C<--dir deploy_dir=$deploy_dir>
608              
609             =item * C<target.$name.deploy_dir>
610              
611             =item * C<engine.$engine.deploy_dir>
612              
613             =item * C<core.deploy_dir>
614              
615             =item * F<C<$top_dir/deploy>>
616              
617             =back
618              
619             =head3 C<revert_dir>
620              
621             my $revert_dir = $target->revert_dir;
622              
623             The path to the revert directory of the project. This directory contains all
624             of the revert scripts referenced by changes the C<plan_file>. The value comes
625             from one of these options, searched in this order:
626              
627             =over
628              
629             =item * C<--dir revert_dir=$revert_dir>
630              
631             =item * C<target.$name.revert_dir>
632              
633             =item * C<engine.$engine.revert_dir>
634              
635             =item * C<core.revert_dir>
636              
637             =item * F<C<$top_dir/revert>>
638              
639             =back
640              
641             =head3 C<verify_dir>
642              
643             my $verify_dir = $target->verify_dir;
644              
645             The path to the verify directory of the project. This directory contains all
646             of the verify scripts referenced by changes in the C<plan_file>. The value
647             comes from one of these options, searched in this order:
648              
649             =over
650              
651             =item * C<--dir verify_dir=$verify_dir>
652              
653             =item * C<target.$name.verify_dir>
654              
655             =item * C<engine.$engine.verify_dir>
656              
657             =item * C<core.verify_dir>
658              
659             =item * F<C<$top_dir/verify>>
660              
661             =back
662              
663             =head3 C<reworked_dir>
664              
665             my $reworked_dir = $target->reworked_dir;
666              
667             The path to the reworked directory of the project. This directory contains
668             subdirectories for reworked deploy, revert, and verify scripts. The value
669             comes from one of these options, searched in this order:
670              
671             =over
672              
673             =item * C<--dir reworked_dir=$reworked_dir>
674              
675             =item * C<target.$name.reworked_dir>
676              
677             =item * C<engine.$engine.reworked_dir>
678              
679             =item * C<core.reworked_dir>
680              
681             =item * C<$top_dir>
682              
683             =back
684              
685             =head3 C<reworked_deploy_dir>
686              
687             my $reworked_deploy_dir = $target->reworked_deploy_dir;
688              
689             The path to the reworked deploy directory of the project. This directory
690             contains all of the reworked deploy scripts referenced by changes in the
691             C<plan_file>. The value comes from one of these options, searched in this
692             order:
693              
694             =over
695              
696             =item * C<--dir reworked_deploy_dir=$reworked_deploy_dir>
697              
698             =item * C<target.$name.reworked_deploy_dir>
699              
700             =item * C<engine.$engine.reworked_deploy_dir>
701              
702             =item * C<core.reworked_deploy_dir>
703              
704             =item * F<C<$reworked_dir/reworked_deploy>>
705              
706             =back
707              
708             =head3 C<reworked_revert_dir>
709              
710             my $reworked_revert_dir = $target->reworked_revert_dir;
711              
712             The path to the reworked revert directory of the project. This directory
713             contains all of the reworked revert scripts referenced by changes the
714             C<plan_file>. The value comes from one of these options, searched in this
715             order:
716              
717             =over
718              
719             =item * C<--dir reworked_revert_dir=$reworked_revert_dir>
720              
721             =item * C<target.$name.reworked_revert_dir>
722              
723             =item * C<engine.$engine.reworked_revert_dir>
724              
725             =item * C<core.reworked_revert_dir>
726              
727             =item * F<C<$reworked_dir/reworked_revert>>
728              
729             =back
730              
731             =head3 C<reworked_verify_dir>
732              
733             my $reworked_verify_dir = $target->reworked_verify_dir;
734              
735             The path to the reworked verify directory of the project. This directory
736             contains all of the reworked verify scripts referenced by changes in the
737             C<plan_file>. The value comes from one of these options, searched in this
738             order:
739              
740             =over
741              
742             =item * C<--dir reworked_verify_dir=$reworked_verify_dir>
743              
744             =item * C<target.$name.reworked_verify_dir>
745              
746             =item * C<engine.$engine.reworked_verify_dir>
747              
748             =item * C<core.reworked_verify_dir>
749              
750             =item * F<C<$reworked_dir/reworked_verify>>
751              
752             =back
753              
754             =head3 C<extension>
755              
756             my $extension = $target->extension;
757              
758             The file name extension to append to change names to create script file names.
759             The value comes from one of these options, searched in this order:
760              
761             =over
762              
763             =item * C<--extension>
764              
765             =item * C<target.$name.extension>
766              
767             =item * C<engine.$engine.extension>
768              
769             =item * C<core.extension>
770              
771             =item * C<"sql">
772              
773             =back
774              
775             =head3 C<variables>
776              
777             my $variables = $target->variables;
778              
779             The database variables to use in change scripts. The value are merged from
780             these options, in this order:
781              
782             =over
783              
784             =item * C<target.$name.variables>
785              
786             =item * C<engine.$engine.variables>
787              
788             =back
789              
790             The C<core.variables> configuration is not read, because command-specific
791             configurations, such as C<deploy.variables> and C<revert.variables> take
792             priority. The command themselves therefore pass them to the engine in the
793             proper priority order.
794              
795             =head3 C<engine_key>
796              
797             my $key = $target->engine_key;
798              
799             The key defining which engine to use. This value defines the class loaded by
800             C<engine>. Convenience method for C<< $target->uri->canonical_engine >>.
801              
802             =head3 C<dsn>
803              
804             my $dsn = $target->dsn;
805              
806             The DSN to use when connecting to the target via the DBI. Convenience method
807             for C<< $target->uri->dbi_dsn >>.
808              
809             =head3 C<username>
810              
811             my $username = $target->username;
812              
813             The username to use when connecting to the target via the DBI. Convenience
814             method for C<< $target->uri->user >>.
815              
816             =head3 C<password>
817              
818             my $password = $target->password;
819              
820             The password to use when connecting to the target via the DBI. Convenience
821             method for C<< $target->uri->password >>.
822              
823             =head1 See Also
824              
825             =over
826              
827             =item L<sqitch>
828              
829             The Sqitch command-line client.
830              
831             =back
832              
833             =head1 Author
834              
835             David E. Wheeler <david@justatheory.com>
836              
837             =head1 License
838              
839             Copyright (c) 2012-2022 iovation Inc., David E. Wheeler
840              
841             Permission is hereby granted, free of charge, to any person obtaining a copy
842             of this software and associated documentation files (the "Software"), to deal
843             in the Software without restriction, including without limitation the rights
844             to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
845             copies of the Software, and to permit persons to whom the Software is
846             furnished to do so, subject to the following conditions:
847              
848             The above copyright notice and this permission notice shall be included in all
849             copies or substantial portions of the Software.
850              
851             THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
852             IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
853             FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
854             AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
855             LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
856             OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
857             SOFTWARE.
858              
859             =cut