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