1 package NonameTV
::Exporter
::Lysis
;
8 The exporter for Lysis from Nagravision (www.nagravision.com) CMS system.
18 use Encode qw
/encode decode/;
22 use Lingua
::Translate
;
24 use NonameTV
::Exporter
;
25 use NonameTV
::Language qw
/LoadLanguage/;
26 use NonameTV qw
/norm/;
27 use DVB qw
/DVBCategory/;
29 use NonameTV
::Log qw
/progress error d p w StartLogSection EndLogSection SetVerbosity/;
31 use base
'NonameTV::Exporter';
35 Export data in Lysis format.
40 Show which datafiles are created.
42 --epgserver <servername>
43 Export data only for the epg server specified.
46 Show only fatal errors.
49 Print a list of all network information in xml-format.
52 Remove any old xml files from the output directory.
55 Recreate all output files, not only the ones where data has
58 --exportedlist <filename>
59 Write the list of files that have been updated to this file.
65 my $class = ref($proto) || $proto;
66 my $self = $class->SUPER::new
( @_ );
67 bless ($self, $class);
69 defined( $self->{Encoding
} ) or die "You must specify Encoding.";
70 #defined( $self->{DtdFile} ) or die "You must specify DtdFile.";
71 defined( $self->{Root
} ) or die "You must specify Root";
72 defined( $self->{Language
} ) or die "You must specify Language";
74 $self->{MaxDays
} = 365 unless defined $self->{MaxDays
};
75 $self->{MinDays
} = $self->{MaxDays
} unless defined $self->{MinDays
};
77 $self->{LastRequiredDate
} =
78 DateTime
->today->add( days
=> $self->{MinDays
}-1 )->ymd("-");
80 $self->{OptionSpec
} = [ qw
/export
-networks remove
-old force
-export
81 epgserver
=s exportedlist
=s
82 verbose quiet help
/ ];
84 $self->{OptionDefaults
} = {
85 'export-networks' => 0,
95 #LoadDtd( $self->{DtdFile} );
97 my $ds = $self->{datastore
};
99 # Load language strings
100 $self->{lngstr
} = LoadLanguage
( $self->{Language
},
101 "exporter-lysis", $ds );
108 my( $self, $p ) = @_;
110 my $epgserver = $p->{'epgserver'};
112 my $ds = $self->{datastore
};
117 Export data
in xml
-format with one file per day
and channel
.
122 Generate an xml
-file listing all network information
.
124 --epgserver
<servername
>
125 Export data only
for the epg server specified
.
128 Remove all data
-files
for dates that have already passed
.
131 Export all data
. Default is to only export data
for batches that
132 have changed since the
last export
.
139 SetVerbosity
( $p->{verbose
}, $p->{quiet
} );
141 StartLogSection
( "Lysis", 0 );
143 if( $p->{'export-networks'} )
145 $self->ExportNetworks( $epgserver );
149 if( $p->{'remove-old'} )
155 my $exportedlist = $p->{'exportedlist'};
157 $self->{exportedlist
} = $exportedlist;
158 progress
("Lysis: The list of exported files will be available in '$exportedlist'");
162 my $update_started = time();
163 my $last_update = $self->ReadState();
165 if( $p->{'force-export'} ) {
166 $self->FindAll( $todo );
169 $self->FindUpdated( $todo, $last_update );
170 $self->FindUnexportedDays( $todo, $last_update );
173 my $equery = "SELECT * from epgservers WHERE `active`=1 AND `type`='Lysis'";
174 $equery .= " AND name='$epgserver'" if $epgserver;
176 my( $eres, $esth ) = $ds->sa->Sql( $equery );
178 while( my $edata = $esth->fetchrow_hashref() )
180 progress
("Lysis: Exporting schedules for services on epg server '$edata->{name}'");
182 my $nquery = "SELECT * from networks WHERE epgserver=$edata->{id} AND active=1";
183 my( $nres, $nsth ) = $ds->sa->Sql( $nquery );
184 while( my $ndata = $nsth->fetchrow_hashref() )
186 my $squery = "SELECT * from services WHERE network=$ndata->{id} AND active=1";
187 my( $sres, $ssth ) = $ds->sa->Sql( $squery );
188 while( my $sdata = $ssth->fetchrow_hashref() )
190 progress
("Lysis: Exporting service $ndata->{id}/$sdata->{serviceid} - $sdata->{servicename}");
191 $self->ExportData( $edata, $ndata, $sdata, $todo );
199 $self->WriteState( $update_started );
201 EndLogSection
( "Lysis" );
205 # Find all dates for each channel
210 my $ds = $self->{datastore
};
212 my ( $res, $channels ) = $ds->sa->Sql(
213 "select id from channels where export=1");
215 my $last_date = DateTime
->today->add( days
=> $self->{MaxDays
} -1 );
216 my $first_date = DateTime
->today;
218 while( my $data = $channels->fetchrow_hashref() ) {
219 add_dates
( $todo, $data->{id
},
220 '1970-01-01 00:00:00', '2100-12-31 23:59:59',
221 $first_date, $last_date );
227 # Find all dates that may have new data for each channel.
230 my( $todo, $last_update ) = @_;
232 my $ds = $self->{datastore
};
234 my ( $res, $update_batches ) = $ds->sa->Sql( << 'EOSQL'
235 select channel_id
, batch_id
,
236 min
(start_time
)as min_start
, max
(start_time
) as max_start
239 select id from batches where last_update
> ?
241 group by channel_id
, batch_id
246 my $last_date = DateTime
->today->add( days
=> $self->{MaxDays
} -1 );
247 my $first_date = DateTime
->today;
249 while( my $data = $update_batches->fetchrow_hashref() ) {
250 add_dates
( $todo, $data->{channel_id
},
251 $data->{min_start
}, $data->{max_start
},
252 $first_date, $last_date );
255 $update_batches->finish();
258 # Find all dates that should be exported but haven't been exported
260 sub FindUnexportedDays
{
262 my( $todo, $last_update ) = @_;
264 my $ds = $self->{datastore
};
266 my $days = int( time()/(24*60*60) ) - int( $last_update/(24*60*60) );
267 $days = $self->{MaxDays
} if $days > $self->{MaxDays
};
270 # The previous export was done $days ago.
272 my $last_date = DateTime
->today->add( days
=> $self->{MaxDays
} -1 );
273 my $first_date = $last_date->clone->subtract( days
=> $days-1 );
275 my ( $res, $channels ) = $ds->sa->Sql(
276 "select id from channels where export=1");
278 while( my $data = $channels->fetchrow_hashref() ) {
279 add_dates
( $todo, $data->{id
},
280 '1970-01-01 00:00:00', '2100-12-31 23:59:59',
281 $first_date, $last_date );
290 my( $edata, $ndata, $sdata, $todo ) = @_;
292 my $ds = $self->{datastore
};
294 foreach my $channel (keys %{$todo}) {
296 # only export files for the channel
297 # which is used as the source for this service
298 next if ( $sdata->{dbchid
} ne $channel );
300 my $chd = $ds->sa->Lookup( "channels", { id
=> $channel } );
302 foreach my $date (sort keys %{$todo->{$channel}}) {
303 $self->ExportFile( $edata, $ndata, $sdata, $chd, $date );
311 my $ds = $self->{datastore
};
313 my $last_update = $ds->sa->Lookup( 'state', { name
=> "lysis_last_update" },
316 if( not defined( $last_update ) )
318 $ds->sa->Add( 'state', { name
=> "lysis_last_update", value
=> 0 } );
327 my( $update_started ) = @_;
329 my $ds = $self->{datastore
};
331 $ds->sa->Update( 'state', { name
=> "lysis_last_update" },
332 { value
=> $update_started } );
335 sub ReadLastEventId
{
339 my $ds = $self->{datastore
};
341 my $lastno = $ds->sa->Lookup( 'services', { id
=> $sid }, 'lasteventid' );
343 if( not defined( $lastno ) )
346 $self->WriteLastEventId( $sid, $lastno );
352 sub WriteLastEventId
{
354 my( $sid, $lastno ) = @_;
356 my $ds = $self->{datastore
};
358 $ds->sa->Update( 'services', { id
=> $sid }, { lasteventid
=> $lastno } );
362 my( $start, $end ) = @_;
364 my( $year1, $month1, $day1, $hour1, $min1, $sec1 ) = ( $start =~ /^(\d+)-(\d+)-(\d+)\s+(\d+):(\d+):(\d+)$/ );
365 my( $year2, $month2, $day2, $hour2, $min2, $sec2 ) = ( $end =~ /^(\d+)-(\d+)-(\d+)\s+(\d+):(\d+):(\d+)$/ );
367 my $dt1 = DateTime
->new(
374 time_zone
=> "Europe/Zagreb"
377 my $dt2 = DateTime
->new(
384 time_zone
=> "Europe/Zagreb"
387 my $duration = $dt2 - $dt1;
389 return $duration->in_units( 'minutes' ) * 60;
392 #######################################################
397 my( $h, $chid, $from, $to, $first, $last ) = @_;
399 my $from_dt = create_dt
( $from, 'UTC' )->truncate( to
=> 'day' );
400 my $to_dt = create_dt
( $to, 'UTC' )->truncate( to
=> 'day' );
402 $to_dt = $last->clone() if $last < $to_dt;
403 $from_dt = $first->clone() if $first > $from_dt;
405 my $first_dt = $from_dt->clone()->subtract( days
=> 1 );
407 for( my $dt = $first_dt->clone();
408 $dt <= $to_dt; $dt->add( days
=> 1 ) ) {
409 $h->{$chid}->{$dt->ymd('-')} = 1;
415 my( $str, $tz ) = @_;
417 my( $year, $month, $day, $hour, $minute, $second ) =
418 ( $str =~ /^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})$/ );
420 if( defined( $second ) ) {
421 return DateTime
->new(
431 ( $year, $month, $day ) =
432 ( $str =~ /^(\d{4})-(\d{2})-(\d{2})$/ );
434 die( "Lysis: Unknown time format $str" )
437 return DateTime
->new(
444 #######################################################
446 # Lysis-specific methods.
451 my( $edata, $ndata, $sdata, $chd, $date ) = @_;
453 my $startdate = $date;
454 my $enddate = create_dt
( $date, 'UTC' )->add( days
=> 1 )->ymd('-');
456 my( $res, $sth ) = $self->{datastore
}->sa->Sql( "
457 SELECT * from programs
458 WHERE (channel_id = ?)
459 and (start_time >= ?)
461 ORDER BY start_time",
462 [$chd->{id
}, "$startdate 00:00:00", "$enddate 23:59:59"] );
464 my ( $odoc, $root ) = $self->CreateWriter( $edata, $ndata, $sdata, $chd, $date );
466 my $dp = $odoc->createElement( 'DownloadPeriod' );
467 $dp->setAttribute( 'action' , "override" );
468 $dp->setAttribute( 'serviceRef' , $sdata->{serviceid
} );
469 $dp->setAttribute( 'type' , "turnaround" );
470 $root->appendChild( $dp );
472 my $per = $odoc->createElement( 'Period' );
473 $per->setAttribute( 'start' , $startdate . "T00:00:00Z" );
474 $per->setAttribute( 'end' , $startdate . "T23:59:59Z" );
475 $dp->appendChild( $per );
479 my $d1 = $sth->fetchrow_hashref();
481 if( (not defined $d1) or ($d1->{start_time
} gt "$startdate 23:59:59") ) {
482 $self->CloseWriter( $odoc );
487 my $lasteventid = $self->ReadLastEventId( $sdata->{id
} );
489 while( my $d2 = $sth->fetchrow_hashref() )
491 if( (not defined( $d1->{end_time
})) or
492 ($d1->{end_time
} eq "0000-00-00 00:00:00") )
494 # Fill in missing end_time on the previous entry with the start-time
495 # of the current entry
496 $d1->{end_time
} = $d2->{start_time
}
498 elsif( $d1->{end_time
} gt $d2->{start_time
} )
500 # The previous programme ends after the current programme starts.
501 # Adjust the end_time of the previous programme.
502 error
( "Lysis: Adjusted endtime for $chd->{xmltvid}: " .
503 "$d1->{end_time} => $d2->{start_time}" );
505 $d1->{end_time
} = $d2->{start_time
}
509 $self->WriteEntry( $odoc, $dp, $d1, $chd, $lasteventid )
510 unless $d1->{title
} eq "end-of-transmission";
512 if( $d2->{start_time
} gt "$startdate 23:59:59" ) {
523 # The loop exited because we ran out of data. This means that
524 # there is no data for the day after the day that we
525 # wanted to export. Make sure that we write out the last entry
526 # if we know the end-time for it.
527 if( (defined( $d1->{end_time
})) and
528 ($d1->{end_time
} ne "0000-00-00 00:00:00") )
530 $self->WriteEntry( $odoc, $dp, $d1, $chd, $lasteventid )
531 unless $d1->{title
} eq "end-of-transmission";
537 error
( "Lysis: Missing end-time for last entry for " .
538 "$chd->{xmltvid}_$date" )
539 unless $date gt $self->{LastRequiredDate
};
543 $self->WriteLastEventId( $sdata->{id
}, $lasteventid );
545 $self->CloseWriter( $odoc );
552 my( $edata, $ndata, $sdata, $chd, $date ) = @_;
554 my $xmltvid = $chd->{xmltvid
};
556 my $path = $self->{Root
} . "/" . $edata->{name
};
557 my $filename = sprintf( "EPG%d_NET%d_SID%d_%s.xml", $edata->{id
}, $ndata->{nid
}, $sdata->{serviceid
}, $date );
559 #progress( "Lysis: $filename" );
561 $self->{writer_path
} = $path;
562 $self->{writer_filename
} = $filename;
563 $self->{writer_entries
} = 0;
565 # Make sure that writer_entries is always true if we don't require data
567 $self->{writer_entries
} = "0 but true"
568 if( ($date gt $self->{LastRequiredDate
}) or $chd->{empty_ok
} );
570 my $odoc = XML
::LibXML
::Document
->new( "1.0", $ndata->{charset
} );
571 $self->{networkcharset
} = $ndata->{charset
};
573 my $c1 = $odoc->createComment( " Created by Gonix (www.gonix.net) at " . DateTime
->now . " " );
574 $odoc->appendChild( $c1 );
576 my $c2 = $odoc->createComment( " Schedule for '" . $sdata->{servicename
} . "' service at EPG server '" . $edata->{name
}. "' ");
577 $odoc->appendChild( $c2 );
579 #my $dtd = $odoc->createInternalSubset( "event-information", undef, "event-information.dtd" );
581 my $root = $odoc->createElement('ScheduleProvider');
582 $root->setAttribute( 'id' => "1" );
583 $root->setAttribute( 'name' => "Gonix" );
584 $root->setAttribute( 'scheduleDate' => DateTime
->now . "Z" );
585 $root->setAttribute( 'xmlns:xsi' => "http://www.w3.org/2001/XMLSchema-instance" );
586 $odoc->setDocumentElement($root);
588 return($odoc, $root);
596 my $path = $self->{writer_path
};
597 my $filename = $self->{writer_filename
};
598 delete $self->{writer_filename
};
599 my $networkcharset = $self->{networkcharset
};
601 my $docstring = $w->toString( 1 );
603 open( my $fh, '>', $path . "/" . $filename . ".new" );
605 print $fh $docstring;
608 #progress("Lysis: Service schedule exported to $filename");
610 if( -f
"$path/$filename" )
612 system("diff $path/$filename.new $path/$filename > /dev/null");
615 move
( "$path/$filename.new", "$path/$filename" );
616 progress
( "Lysis: Exported $filename" );
617 if( not $self->{writer_entries
} )
619 error
( "Lysis: $filename is empty" );
621 elsif( $self->{writer_entries
} > 0 )
627 unlink( "$path/$filename.new" );
632 move
( "$path/$filename.new", "$path/$filename" );
633 progress
( "Lysis: Exported $filename" );
634 if( not $self->{writer_entries
} )
636 error
( "Lysis: $filename is empty" );
638 elsif( $self->{writer_entries
} > 0 )
643 if( $self->{exportedlist
} ){
644 $self->ExportFileNameToList( "$path/$filename" );
651 my( $odoc, $parent, $data, $chd, $evno ) = @_;
653 my $ds = $self->{datastore
};
655 Lingua
::Translate
::config
657 back_end
=> 'Google',
659 referer
=> 'http://www.gonix.net/',
662 my $xl8r = Lingua
::Translate
->new( src
=> $chd->{sched_lang
}, dest
=> 'en' );
664 $self->{writer_entries
}++;
666 my $networkcharset = $self->{networkcharset
};
668 my $start_time = create_dt
( $data->{start_time
}, "UTC" );
669 $start_time->set_time_zone( "Europe/Zagreb" );
671 my $end_time = create_dt
( $data->{end_time
}, "UTC" );
672 $end_time->set_time_zone( "Europe/Zagreb" );
674 my $duration = EventDuration
( $data->{start_time
}, $data->{end_time
} );
676 my $programme = $odoc->createElement( 'Programme' );
677 $programme->setAttribute( 'isCatchUp' => "false" );
678 $programme->setAttribute( 'id' => $data->{schedule_id
} || $evno );
679 $programme->setAttribute( 'title' => $data->{title
} );
680 $parent->appendChild( $programme );
682 my $per = $odoc->createElement( 'Period' );
683 $per->setAttribute( 'start' , $start_time . "Z" );
684 $per->setAttribute( 'duration' , $duration );
685 $programme->appendChild( $per );
689 $epgdesc = $odoc->createElement( 'EpgDescription' );
690 $programme->appendChild( $epgdesc );
694 $epgel = $odoc->createElement( 'EpgElement' );
695 $epgel->setAttribute( 'key' , "SeriesId" );
696 $epgel->appendText( $data->{title_id
} || 0 );
697 $epgdesc->appendChild( $epgel );
699 $epgel = $odoc->createElement( 'EpgElement' );
700 $epgel->setAttribute( 'key' , "Episode_Number_Display" );
701 if( $data->{episode
} ){
702 my( $epno ) = ( $data->{episode
} =~ /^.*\.\s+(\d+)\s+\..*$/ );
703 $epgel->appendText( $epno );
705 $epgel->appendText( 0 );
707 $epgdesc->appendChild( $epgel );
709 $epgel = $odoc->createElement( 'EpgElement' );
710 $epgel->setAttribute( 'key' , "Rating" );
711 $epgel->appendText( $data->{rating
} || 0 );
712 $epgdesc->appendChild( $epgel );
714 my $dvbcategory = DVBCategory
( $ds, $data->{category
}, $data->{program_type
} );
715 $epgel = $odoc->createElement( 'EpgElement' );
716 $epgel->setAttribute( 'key' , "DVB_Content" );
717 $epgel->appendText( $dvbcategory );
718 $epgdesc->appendChild( $epgel );
720 # local Epg title and description
721 $epgdesc = $odoc->createElement( 'EpgDescription' );
722 $epgdesc->setAttribute( 'locale' , $chd->{sched_lang
} . "_" . uc( $chd->{sched_lang
} ) || "en_GB" );
723 $programme->appendChild( $epgdesc );
725 $epgel = $odoc->createElement( 'EpgElement' );
726 $epgel->setAttribute( 'key' , "Title" );
727 $epgel->appendText( $data->{title
} );
728 $epgdesc->appendChild( $epgel );
730 $epgel = $odoc->createElement( 'EpgElement' );
731 $epgel->setAttribute( 'key' , "Description" );
732 $epgel->appendText( $data->{description
} || "" );
733 $epgdesc->appendChild( $epgel );
735 # # English Epg title and description
736 # $epgdesc = $odoc->createElement( 'EpgDescription' );
737 # $epgdesc->setAttribute( 'locale' , "en_GB" );
738 # $programme->appendChild( $epgdesc );
740 # $epgel = $odoc->createElement( 'EpgElement' );
741 # $epgel->setAttribute( 'key' , "Title" );
742 # $epgel->appendText( $xl8r->translate( $data->{title} ) );
743 # $epgdesc->appendChild( $epgel );
745 # $epgel = $odoc->createElement( 'EpgElement' );
746 # $epgel->setAttribute( 'key' , "Description" );
747 # $epgel->appendText( $xl8r->translate( "Bok Pero" ) );
748 # $epgdesc->appendChild( $epgel );
752 # $enctitle = myEncode( $networkcharset, $data->{title} );
753 # $epgel->appendText( $enctitle );
757 sub ExportFileNameToList
760 my( $filename ) = @_;
762 open( ELF
, '>>' . $self->{exportedlist
} );
763 print ELF
"$filename\n";
768 # Write description of all networks to networks.xml
773 my( $epgserver ) = @_;
775 my $ds = $self->{datastore
};
777 my $now = my $keep_date = DateTime
->now;
779 my $odoc = XML
::LibXML
::Document
->new( "1.0", $self->{Encoding
} );
781 my $c1 = $odoc->createComment( " Created by Gonix (www.gonix.net) at " . DateTime
->now . " " );
782 $odoc->appendChild( $c1 );
784 my $dtd = $odoc->createInternalSubset( "network-information", undef, "network-information.dtd" );
786 my $root = $odoc->createElement('network-information');
787 $odoc->setDocumentElement($root);
789 my $equery = "SELECT * from epgservers WHERE active=1";
790 $equery .= " AND name='$epgserver'" if $epgserver;
792 my( $eres, $esth ) = $ds->sa->Sql( $equery );
794 while( my $edata = $esth->fetchrow_hashref() )
796 progress
("Lysis: Exporting network information for epg server '$edata->{name}'");
798 my $nquery = "SELECT * from networks WHERE epgserver=$edata->{id} AND active=1";
799 my( $nres, $nsth ) = $ds->sa->Sql( $nquery );
800 while( my $ndata = $nsth->fetchrow_hashref() )
802 progress
("Lysis: Exporting network $ndata->{id} ($ndata->{name})");
804 my $net = $odoc->createElement( 'network' );
805 $net->setAttribute( 'network-id' => $ndata->{id
} );
806 $net->setAttribute( 'operator' => $ndata->{operator
} );
807 $net->setAttribute( 'description' => $ndata->{description
} );
808 $net->setAttribute( 'character-set' => $ndata->{charset
} );
809 $root->appendChild( $net );
811 my $lt = $odoc->createElement( 'local-time' );
812 $lt->setAttribute( 'country-code' => '900' );
813 $lt->setAttribute( 'country-region-id' => '0' );
814 $lt->setAttribute( 'local-time-offset-polarity' => 'NEGATIVE' );
815 $lt->setAttribute( 'local-time-offset' => '60' );
816 $lt->setAttribute( 'time-of-change' => $now->ymd('-') . " " . $now->hms(':') );
817 $lt->setAttribute( 'next-time-offset' => '120' );
818 $net->appendChild( $lt );
820 my $squery = "SELECT * from services WHERE network=$ndata->{id} AND active=1";
821 my( $sres, $ssth ) = $ds->sa->Sql( $squery );
822 while( my $sdata = $ssth->fetchrow_hashref() )
824 progress
("Lysis: Adding service $sdata->{id} ($sdata->{servicename}) to network $ndata->{id}");
826 my $srv = $odoc->createElement( 'service' );
827 $srv->setAttribute( 'service-name' => $sdata->{servicename
} );
828 $srv->setAttribute( 'logical-channel-number' => $sdata->{logicalchannelnumber
} );
829 $srv->setAttribute( 'service-id' => $sdata->{serviceid
} );
830 $srv->setAttribute( 'description' => $sdata->{description
} );
831 $srv->setAttribute( 'nvod' => $sdata->{nvod
} );
832 $srv->setAttribute( 'service-type-id' => $sdata->{servicetypeid
} );
833 $net->appendChild( $srv );
837 my $outfile = "$self->{Root}/$edata->{name}/network-information.xml";
838 open( my $fh, '>:encoding(' . $self->{Encoding
} . ')', $outfile )
839 or die( "Lysis: cannot write to $outfile" );
841 $odoc->toFH( $fh, 1 );
844 progress
("Lysis: Network information exported to $outfile");
849 # Remove old xml-files and xml files.
856 my $ds = $self->{datastore
};
858 # Keep files for the last week.
859 my $keep_date = DateTime
->today->subtract( days
=> 8 )->ymd("-");
861 my $f = File
::Util
->new();
863 my @dirs = $f->list_dir( $self->{Root
}, '--no-fsdots' );
864 foreach my $dir( @dirs ){
866 my $ftype = join(',', File
::Util
->file_type( $self->{Root
} . "/" . $dir ) );
867 if( $ftype =~ /DIRECTORY/ )
869 progress
( "Lysis: Removing old files in directory $dir" );
871 my @files = glob( $self->{Root
} . "/$dir/" . "*" );
872 foreach my $file (@files)
874 my($date) = ($file =~ /(\d\d\d\d-\d\d-\d\d)\.xml/);
876 if( defined( $date ) )
878 # Compare date-strings.
879 if( $date lt $keep_date )
889 progress
( "Lysis: Removed $removed files" ) if( $removed > 0 );
894 my( $encoding, $str ) = @_;
895 #print "\n----------------------------------------------------------\n$str\n";
899 my $encstr = encode
( $encoding, $str );
909 foreach my $data (unpack("a16"x
(length($_[0])/16)."a*",$_[0])) {
910 my($len)=length($data);
912 @array = unpack('N4', $data);
913 $format="0x%08x (%05d) %08x %08x %08x %08x %s\n";
915 @array = unpack('C*', $data);
916 $_ = sprintf "%2.2x", $_ for @array;
917 push(@array, ' ') while $len++ < 16;
918 $format="0x%08x (%05d)" .
919 " %s%s%s%s %s%s%s%s %s%s%s%s %s%s%s%s %s\n";
921 $data =~ tr/\0-\37\177-\377/./;
922 printf $format,$offset,$offset,@array,$data;
929 ### Setup coding system