File Coverage

blib/lib/File/List/Object.pm
Criterion Covered Total %
statement 4 6 66.6
branch n/a
condition n/a
subroutine 2 2 100.0
pod n/a
total 6 8 75.0


line stmt bran cond sub pod time code
1             package File::List::Object;
2              
3             =pod
4              
5             =begin readme text
6              
7             File::List::Object version 0.202
8              
9             =end readme
10              
11             =for readme stop
12              
13             =head1 NAME
14              
15             File::List::Object - Object containing a list of files (filelist, packlist).
16              
17             =head1 VERSION
18              
19             This document describes File::List::Object version 0.200.
20              
21             =for readme continue
22              
23             =head1 DESCRIPTION
24              
25             This package provides for creating a list of files (from different sources)
26             and performing arithmetic and other applicable operations on said lists.
27              
28             =begin readme
29              
30             =head1 INSTALLATION
31              
32             To install this module, run the following commands:
33              
34             perl Makefile.PL
35             make
36             make test
37             make install
38              
39             This method of installation will install a current version of Module::Build
40             if it is not already installed.
41            
42             Alternatively, to install with Module::Build, you can use the following commands:
43              
44             perl Build.PL
45             ./Build
46             ./Build test
47             ./Build install
48              
49             =end readme
50              
51             =for readme stop
52              
53             =head1 SYNOPSIS
54              
55             # Since this module is object-oriented, it does not matter if you
56             # use or require the module, because there are no imports.
57             require File::List::Object;
58              
59             # Cheate a File::List::Object
60             my $filelist = File::List::Object->new();
61              
62             # Clones the filelist passed in;
63             $filelist3 = File::List::Object->clone($filelist);
64              
65             # Add an individual file to a filelist.
66             $filelist->add_file('/usr/bin/perl5');
67              
68             # Load a filelist from an array of files.
69             $filelist2 = File::List::Object->new();
70             $filelist2->load_array(@files);
71              
72             # Adds the files in $filelist2 to $filelist
73             $filelist->add($filelist2);
74              
75             # Subtracts the files in $filelist2 from $filelist
76             $filelist->subtract($filelist2);
77              
78             # Filters out the files with these strings at the
79             # beginnning of their name.
80             $filelist->filter(['/excluded', '/bad']);
81              
82             # Filters out the files on drive D.
83             $filelist->filter(['D:\']);
84              
85             # Gets the number of files in the list.
86             $filelist->count();
87              
88             # Moves a file within the filelist.
89             $filelist->move('file.txt', 'file2.txt');
90              
91             # Moves a directory within the filelist.
92             $filelist->move_dir('\test1', '\test2');
93              
94             # Loads the filelist from a file with filenames in it.
95             $filelist->load_file($packlist_file);
96              
97             # Returns the list of files, sorted.
98             # Useful for debugging purposes.
99             $filelist->as_string();
100              
101             # Most operations return the original object, so they can be chained.
102             # count and as_string stop a chain, new and clone can only start one.
103             $filelist->load_file($packlist_file)->add_file($file)->as_string();
104              
105             =head1 DESCRIPTION
106              
107             This module provides an object-oriented interface to manipulate a list of files.
108              
109             It was made to manipulate Perl .packlist files in memory, but the filelist does not
110             have to be loaded from disk.
111              
112             =head1 INTERFACE
113              
114             =cut
115              
116             #<<<
117 1     1   23604 use 5.008001;
  1         4  
  1         41  
118 1     1   454 use Moose 0.90;
  0            
  0            
119             use File::Spec::Functions
120             qw( catdir catfile splitpath splitdir curdir updir );
121             use English qw(-no_match_vars);
122             use Params::Util 0.35 qw( _INSTANCE _STRING _NONNEGINT );
123             use IO::Dir qw();
124             use IO::File qw();
125             use Exception::Class 1.29 (
126             'File::List::Object::Exception' => {
127             'description' => 'File::List::Object error',
128             },
129             'File::List::Object::Exception::Parameter' => {
130             'description' =>
131             'File::List::Object error: Parameter missing or invalid',
132             'isa' => 'File::List::Object::Exception',
133             'fields' => [ 'parameter', 'where' ],
134             },
135             );
136              
137             our $VERSION = '0.202';
138             $VERSION =~ s/_//ms;
139              
140             #
141              
142             my %sortcache; # Defined at this level so that the cache does not
143             # get reset each time _sorter is called.
144             #>>>
145              
146             # The only attribute of this object.
147              
148             has '_files' => (
149             traits => ['Hash'],
150             is => 'bare',
151             isa => 'HashRef',
152             handles => {
153             '_add_file' => 'set',
154             '_clear' => 'clear',
155             'count' => 'count',
156             '_get_file' => 'get',
157             '_is_file' => 'exists',
158             '_delete_files' => 'delete',
159             '_get_files_array' => 'keys',
160             },
161             reader => '_get_files_hashref',
162             writer => '_set_files_hashref',
163             init_arg => undef,
164             default => sub { return {}; },
165             );
166              
167             #####################################################################
168             # Construction Methods
169              
170             =head2 new
171              
172             $filelist = File::List::Object->new();
173              
174             Creates an empty object. To load the object with files, call add_file,
175             load_array, or load_packlist.
176              
177             =head2 clone
178              
179             $filelist2 = File::List::Object->clone($filelist);
180              
181             Creates a new object that is a copy of the one passed to it. It performs
182             a deep copy, so that the original object is not modified when the new one
183             is.
184              
185             =cut
186              
187             # Moose provides ->new(), so I don't need to.
188              
189             sub clone {
190             my $self = shift->new();
191             my $source = shift;
192              
193             # Check parameters
194             if ( not _INSTANCE( $source, 'File::List::Object' ) ) {
195             File::List::Object::Exception::Parameter->throw(
196             parameter => 'source',
197             where => '->clone'
198             );
199             }
200              
201             # Add filelist passed in.
202             ## no critic(ProhibitVoidMap)
203             $self->_set_files_hashref(
204             { map { $_ => 1 } $source->_get_files_array() } );
205              
206             return $self;
207             } ## end sub clone
208              
209             #####################################################################
210             # Sorting filelists.
211              
212             sub _splitdir {
213             my $dirs = shift;
214              
215             my @dirs = splitdir($dirs);
216              
217             @dirs = grep { defined $_ and $_ ne q{} } @dirs;
218              
219             return \@dirs;
220             }
221              
222             sub _splitpath {
223             my $path = shift;
224              
225             my @answer = splitpath( $path, 0 );
226              
227             return \@answer;
228             }
229              
230             sub _sorter {
231              
232             # Takes advantage of $a and $b, using the Orcish Manoevure to cache
233             # calls to File::Spec::Functions::splitpath and splitdir
234              
235             # Short-circuit.
236             return 0 if ( $a eq $b );
237              
238             # Get directoryspec and file
239             my ( undef, $dirspec_1, $file_1 ) =
240             @{ ( $sortcache{$a} ||= _splitpath($a) ) };
241             my ( undef, $dirspec_2, $file_2 ) =
242             @{ ( $sortcache{$b} ||= _splitpath($b) ) };
243              
244             # Deal with equal directories by comparing their files.
245             return ( $file_1 cmp $file_2 ) if ( $dirspec_1 eq $dirspec_2 );
246              
247             # Get list of directories.
248             my @dirs_1 = @{ ( $sortcache{$dirspec_1} ||= _splitdir($dirspec_1) ) };
249             my @dirs_2 = @{ ( $sortcache{$dirspec_2} ||= _splitdir($dirspec_2) ) };
250              
251             # Find first directory that is not equal.
252             my ( $dir_1, $dir_2 ) = ( q{}, q{} );
253             while ( $dir_1 eq $dir_2 ) {
254             $dir_1 = shift @dirs_1 || q{};
255             $dir_2 = shift @dirs_2 || q{};
256             }
257              
258             # Compare directories/
259             return 1 if $dir_1 eq q{};
260             return -1 if $dir_2 eq q{};
261             return $dir_1 cmp $dir_2;
262             } ## end sub _sorter
263              
264             #####################################################################
265             # Exception output methods.
266              
267             sub File::List::Object::Exception::full_message {
268             my $self = shift;
269              
270             my $string =
271             $self->description() . ': '
272             . $self->message() . "\n"
273             . 'Time error caught: '
274             . localtime() . "\n";
275              
276             $string .= "\n" . $self->trace() . "\n";
277              
278             return $string;
279             } ## end sub File::List::Object::Exception::full_message
280              
281             sub File::List::Object::Exception::Parameter::full_message {
282             my $self = shift;
283              
284             my $string =
285             $self->description() . ': '
286             . $self->parameter()
287             . ' in File::List::Object'
288             . $self->where() . "\n"
289             . 'Time error caught: '
290             . localtime() . "\n";
291              
292             # Add trace to it. (We automatically dump trace for parameter errors.)
293             $string .= "\n" . $self->trace() . "\n";
294              
295             return $string;
296             } ## end sub File::List::Object::Exception::Parameter::full_message
297              
298              
299             =head2 debug
300              
301             $filelist->debug();
302              
303             Sets the "debug state" of the object (currently only used in load_file).
304              
305             =cut
306              
307             has debug => (
308             is => 'bare',
309             isa => 'Bool',
310             reader => '_debug',
311             writer => 'debug',
312             init_arg => undef,
313             default => 0,
314             );
315              
316             #####################################################################
317             # Main Methods
318              
319             =head2 count
320              
321             $number = $filelist->count();
322              
323             Returns the number of files in the list.
324              
325             =head2 clear
326              
327             $filelist = $filelist->clear();
328              
329             Empties an object.
330              
331             =cut
332              
333             # This routine exists because the 'clear' that MooseX::AttributeHelpers
334             # provides does not return the object, and we'd like it to.
335              
336             sub clear {
337             my $self = shift;
338              
339             $self->_clear();
340             return $self;
341             }
342              
343             =head2 files
344              
345             @filelist = $filelist->files();
346              
347             Returns a sorted list of the files in this object.
348              
349             =cut
350              
351             sub files {
352             my $self = shift;
353              
354             my @answer = sort {_sorter} $self->_get_files_array();
355             return \@answer;
356             }
357              
358             =head2 readdir
359              
360             $filelist = $filelist->readdir('C:\');
361              
362             Adds the files in the directory passed in to the filelist.
363              
364             This includes all files within subdirectories of this directory.
365              
366             =cut
367              
368             sub readdir { ## no critic 'ProhibitBuiltinHomonyms'
369             my ( $self, $dir ) = @_;
370              
371             # Check parameters.
372             if ( not _STRING($dir) ) {
373             File::List::Object::Exception::Parameter->throw(
374             parameter => 'dir',
375             where => '->readdir'
376             );
377             }
378             if ( not -d $dir ) {
379             File::List::Object::Exception::Parameter->throw(
380             parameter => "dir: $dir is not a directory",
381             where => '->readdir'
382             );
383             }
384              
385             # Open directory.
386             my $dir_object = IO::Dir->new($dir);
387             if ( !defined $dir_object ) {
388             File::List::Object::Exception->throw(
389             "Error reading directory $dir: $OS_ERROR");
390             }
391              
392             # Read a file from the directory.
393             my $file = $dir_object->read();
394              
395             while ( defined $file ) {
396              
397             # Check to make sure it isn't . or ..
398             if ( ( $file ne curdir() ) and ( $file ne updir() ) ) {
399              
400             # Check for another directory.
401             my $filespec = catfile( $dir, $file );
402             if ( -d $filespec ) {
403              
404             # Read this directory.
405             $self->readdir($filespec);
406             } else {
407              
408             # Add the file!
409             $self->_add_file( $filespec, 1 );
410             }
411             } ## end if ( ( $file ne curdir...))
412              
413             # Next one, please?
414             $file = $dir_object->read();
415             } ## end while ( defined $file )
416              
417             return $self;
418             } ## end sub readdir
419              
420             =head2 load_file
421              
422             $filelist = $filelist->load_file('C:\perl\.packlist');
423              
424             Adds the files listed in the file passed in to the filelist.
425              
426             This includes files that do not exist.
427              
428             =cut
429              
430             sub load_file {
431             my ( $self, $packlist ) = @_;
432              
433             # Check parameters.
434             if ( not _STRING($packlist) ) {
435             File::List::Object::Exception::Parameter->throw(
436             parameter => 'packlist',
437             where => '->load_file'
438             );
439             }
440             if ( not -r $packlist ) {
441             File::List::Object::Exception::Parameter->throw(
442             parameter => "packlist: $packlist cannot be read",
443             where => '->load_file'
444             );
445             }
446              
447             # Read .packlist file.
448             my $fh = IO::File->new( $packlist, 'r' );
449             if ( not defined $fh ) {
450             File::List::Object::Exception->throw(
451             "Error reading packlist file $packlist: $OS_ERROR");
452             }
453             my @files_list = <$fh>;
454             $fh->close;
455             my $file;
456             my $short_file;
457              
458             # Insert list of files read into this object. Chomp on the way.
459             my @files_intermediate = map { ## no critic 'ProhibitComplexMappings'
460             $short_file = undef;
461             $file = $_;
462             chomp $file;
463             print "Packlist file formatting: $file\n" if $self->_debug();
464             ($short_file) = $file =~ m/\A (.*?) (?:\s+ \w+ = .*?)* \z/msx;
465             print "filtered to: $short_file\n" if $self->_debug();
466             $short_file || $file;
467             } @files_list;
468              
469             my @files;
470             if ($OSNAME eq 'MSWin32') {
471             @files = map { ## no critic 'ProhibitComplexMappings'
472             $file = $_;
473             $file =~ s{/}{\\}gmsx;
474             $file;
475             } @files_intermediate;
476             } else {
477             @files = @files_intermediate;
478             }
479              
480             foreach my $file_to_add (@files) {
481             $self->_add_file( $file_to_add, 1 );
482             }
483              
484             return $self;
485             } ## end sub load_file
486              
487             =head2 load_array
488              
489             =head2 add_files
490              
491             $filelist = $filelist->load_array(@files_list);
492             $filelist = $filelist->add_files(@files_list);
493              
494             Adds the files listed in the array passed in to the filelist.
495              
496             C<add_files> is an alias for C<load_array>.
497              
498             =cut
499              
500             sub load_array {
501             my ( $self, @files_list ) = @_;
502              
503             # Add each file in the array - if it is a file.
504             FILE:
505             foreach my $file (@files_list) {
506             next FILE if not -f $file;
507             $self->_add_file( $file, 1 );
508             }
509              
510             return $self;
511             } ## end sub load_array
512              
513             sub add_files {
514             goto &load_array;
515             }
516              
517             =head2 add_file
518              
519             $filelist = $filelist->add_file('C:\readme.txt');
520              
521             Adds the file passed in to the filelist.
522              
523             The file being added must exist.
524              
525             =cut
526              
527             sub add_file {
528             my ( $self, $file ) = @_;
529              
530             # Check parameters.
531             if ( not _STRING($file) ) {
532             File::List::Object::Exception::Parameter->throw(
533             parameter => 'file',
534             where => 'add_file'
535             );
536             }
537              
538             if ( not -f $file ) {
539             File::List::Object::Exception::Parameter->throw(
540             parameter => "file: $file is not a file",
541             where => 'add_file'
542             );
543             }
544              
545             $self->_add_file( $file, 1 );
546              
547             return $self;
548             } ## end sub add_file
549              
550             =head2 remove_files
551              
552             =head2 remove_file
553              
554             $filelist = $filelist->remove_file('C:\readme.txt');
555             $filelist = $filelist->remove_files('C:\readme.txt', 'C:\LICENSE');
556             $filelist = $filelist->remove_files(@files);
557              
558             Removes the file(s) passed in to the filelist.
559              
560             C<remove_file> is an alias for C<remove_files>.
561              
562             =cut
563              
564             sub remove_files { ## no critic(RequireArgUnpacking)
565             my $self = shift;
566             my @files = @_;
567              
568             $self->_delete_files(@files);
569              
570             return $self;
571             }
572              
573             sub remove_file {
574             goto &remove_files;
575             }
576              
577             =head2 subtract
578              
579             $filelist = $filelist->subtract($filelist2);
580              
581             Removes the files listed in the filelist object passed in.
582              
583             =cut
584              
585             sub subtract {
586             my ( $self, $subtrahend ) = @_;
587              
588             # Check parameters
589             if ( not _INSTANCE( $subtrahend, 'File::List::Object' ) ) {
590             File::List::Object::Exception::Parameter->throw(
591             parameter => 'subtrahend',
592             where => '->subtract'
593             );
594             }
595              
596             my @files_to_remove = $subtrahend->_get_files_array();
597             $self->_delete_files(@files_to_remove);
598              
599             return $self;
600             } ## end sub subtract
601              
602             =head2 add
603              
604             $filelist = $filelist->add($filelist2);
605              
606             Adds the files listed in the filelist object passed in.
607              
608             =cut
609              
610             sub add {
611             my ( $self, $term ) = @_;
612              
613             # Check parameters
614             if ( not _INSTANCE( $term, 'File::List::Object' ) ) {
615             File::List::Object::Exception::Parameter->throw(
616             parameter => 'term',
617             where => '->add'
618             );
619             }
620              
621             # Add the two hashes together.
622             my %files =
623             ( %{ $self->_get_files_hashref() },
624             %{ $term->_get_files_hashref() } );
625             $self->_set_files_hashref( \%files );
626              
627             return $self;
628             } ## end sub add
629              
630             =head2 move
631              
632             $filelist = $filelist->move($file1, $file2);
633              
634             Removes the first file passed in, and adds the second one to the filelist.
635              
636             The second file need not exist yet.
637              
638             =cut
639              
640             sub move {
641             my ( $self, $from, $to ) = @_;
642              
643             # Check parameters.
644             if ( not _STRING($from) ) {
645             File::List::Object::Exception::Parameter->throw(
646             parameter => 'from',
647             where => '::Filelist->move'
648             );
649             }
650             if ( not _STRING($to) ) {
651             File::List::Object::Exception::Parameter->throw(
652             parameter => 'to',
653             where => '::Filelist->move'
654             );
655             }
656              
657             # Move the file if it exists.
658             if ( $self->_is_file($from) ) {
659             $self->_delete_files($from);
660             $self->_add_file( $to, 1 );
661             }
662              
663             return $self;
664             } ## end sub move
665              
666             =head2 move_dir
667              
668             $filelist = $filelist->move_dir($dir1, $dir2);
669              
670             Moves the files that would be in the first directory passed in into the
671             second directory within the filelist.
672              
673             This does not modify the files on disk, and the second directory and the files
674             in it need not exist yet.
675              
676             =cut
677              
678             sub _move_dir_grep {
679             my $in = catfile( shift, q{} );
680             my $from = catfile( shift, q{} );
681              
682             return ( $in =~ m{\A\Q$from\E}msx ) ? 1 : 0;
683             }
684              
685             sub move_dir {
686             my ( $self, $from, $to ) = @_;
687              
688             # Check parameters.
689             if ( not _STRING($from) ) {
690             File::List::Object::Exception::Parameter->throw(
691             parameter => 'from',
692             where => '->move_dir'
693             );
694             }
695             if ( not _STRING($to) ) {
696             File::List::Object::Exception::Parameter->throw(
697             parameter => 'to',
698             where => '->move_dir'
699             );
700             }
701              
702             # Find which files need moved.
703             my @files_to_move =
704             grep { _move_dir_grep( $_, $from ) } $self->_get_files_array();
705             my $to_file;
706             foreach my $file_to_move (@files_to_move) {
707              
708             # Get the correct name.
709             $to_file = $file_to_move;
710             $to_file =~ s{\A\Q$from\E}{$to}msx;
711              
712             # "move" the file.
713             $self->_delete_files($file_to_move);
714             $self->_add_file( $to_file, 1 );
715             }
716              
717             return $self;
718             } ## end sub move_dir
719              
720             =head2 filter
721              
722             $filelist = $filelist->filter([$string1, $string2, ...]);
723              
724             Removes the files from the list whose names begin with the strings listed.
725              
726             =cut
727              
728             sub filter {
729             my ( $self, $re_list ) = @_;
730              
731             # Define variables to use.
732             my @files_list = $self->_get_files_array();
733              
734             my @files_to_remove;
735              
736             # Filtering out values that match the regular expressions.
737             foreach my $re ( @{$re_list} ) {
738             push @files_to_remove, grep {m/\A\Q$re\E/msx} @files_list;
739             }
740             $self->_delete_files(@files_to_remove);
741              
742             return $self;
743             } ## end sub filter
744              
745             =head2 as_string
746              
747             $string = $filelist->as_string();
748             print $filelist2->as_string();
749            
750             Prints out the files contained in the list, sorted, one per line.
751              
752             =cut
753              
754             sub as_string {
755             my $self = shift;
756              
757             my @files_list = sort {_sorter} $self->_get_files_array();
758              
759             return join "\n", @files_list;
760             }
761              
762             1; # Magic true value required at end of module
763             __END__
764            
765             =head1 DIAGNOSTICS
766              
767             All diagnostics are returned as L<Exception::Class::Base|Exception::Class::Base>
768             subclasses in the C<< File::List::Object::Exception >> subtree.
769              
770             =over
771              
772             =item C<< File::List::Object error: Parameter missing or invalid: %s >>
773              
774             An invalid parameter was passed in. More information about why it was
775             invalid may be returned.
776              
777             (Returned as a C<< File::List::Object::Exception::Parameter >> object)
778              
779             =item Error reading directory %s: %s
780              
781             For some reason, the directory exists, but it could not be read.
782              
783             =back
784              
785             =head1 CONFIGURATION AND ENVIRONMENT
786              
787             File::List::Object requires no configuration files or environment variables.
788              
789             =for readme continue
790              
791             =head1 DEPENDENCIES
792              
793             Dependencies of this module that are non-core in perl 5.8.1 (which is the
794             minimum version of Perl required) include
795             L<Moose|Moose> version 0.90, L<Exception::Class|Exception::Class> version
796             1.29, and L<Params::Util|Params::Util> version 0.35.
797              
798             =for readme stop
799              
800             =head1 INCOMPATIBILITIES
801              
802             None reported.
803              
804             =head1 BUGS AND LIMITATIONS (SUPPORT)
805              
806             The L<clone()|/clone> routine did not work in versions previous to 0.189.
807              
808             Bugs should be reported via:
809              
810             1) The CPAN bug tracker at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=File-List-Object>
811             if you have an account there.
812              
813             2) Email to E<lt>bug-File-List-Object@rt.cpan.orgE<gt> if you do not.
814              
815             For other issues, contact the topmost author.
816              
817             =head1 AUTHOR
818              
819             Curtis Jewell, C<< <csjewell@cpan.org> >>
820              
821             =head1 SEE ALSO
822              
823             L<http://csjewell.comyr.com/perl/>
824              
825             =for readme continue
826              
827             =head1 LICENSE AND COPYRIGHT
828              
829             Copyright (c) 2009, Curtis Jewell C<< <csjewell@cpan.org> >>.
830              
831             This module is free software; you can redistribute it and/or
832             modify it under the same terms as Perl itself, either version
833             5.8.1 or any later version. See L<perlartistic> and L<perlgpl>.
834              
835             The full text of the license can be found in the
836             LICENSE file included with this module.
837              
838             =for readme stop
839              
840             =head1 DISCLAIMER OF WARRANTY
841              
842             BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
843             FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
844             OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
845             PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
846             EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
847             WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
848             ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH
849             YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
850             NECESSARY SERVICING, REPAIR, OR CORRECTION.
851              
852             IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
853             WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
854             REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE
855             LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL,
856             OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
857             THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
858             RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
859             FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
860             SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
861             SUCH DAMAGES.