summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/ivymon500
-rwxr-xr-xsrc/ivyreplay768
2 files changed, 786 insertions, 482 deletions
diff --git a/src/ivymon b/src/ivymon
index 848c23c..8e584d1 100755
--- a/src/ivymon
+++ b/src/ivymon
@@ -91,17 +91,11 @@ use strict;
use Getopt::Long;
use Tk::CmdLine;
use vars qw/$VERSION $opt_help $opt_b $opt_bus $opt_history @opt_bind
- @opt_send $opt_size $opt_undersize $opt_out $opt_loadingmode
- $opt_replayrepeat $opt_replaystartregexp
- $opt_replaystopregexp $opt_replaytimegranularity $opt_debug/;
+ @opt_send $opt_size $opt_undersize $opt_out $opt_debug/;
# **** VERSION ****
-$VERSION = '1.17';
+$VERSION = '1.18';
# options initialisation
-$opt_loadingmode = 'replay-pause';
-$opt_replayrepeat = 0;
-$opt_replaystartregexp = '^ClockStart';
-$opt_replaystopregexp = '^ClockStop';
# geometry
my $minW = 1024;
my $minH = 768;
@@ -178,37 +172,6 @@ my @bind_def;
# Effective bindings array
my @effectivebind;
-# replay
-my $replay_current_t0;
-my $replay_current_t;
-my $replay_data_t0;
-my $replay_data_t;
-my $replay_maxgap = 0.2; # sec
-my $replay_regulpct = [50, 20]; # %
-my $replay_factor = 1000; # msec
-my $replay_current_factor = $replay_factor;
-
-my $replay_speed = 1;
-my $replay_runnable = 1;
-my $replay_running = 0;
-my $replay_time_granularity = 1;
-my $replay_time_decimalplaces = 0;
-my $replay_timer;
-my $replay_tpl;
-my $replay_text;
-my $replay_repeat;
-my %replay_msg;
-my $replay_time;
-my $replay_min_time;
-my $replay_max_time;
-my $replay_last_time;
-my $replay_stepbystep;
-my $replay_bg = 'gray75';
-my $replay_fg = 'black';
-my $replay_bg_orig;
-my $replay_fg_orig;
-my $replay_hour;
-
#----------------------------------------------------------------------------------
# command line options management
@@ -218,10 +181,8 @@ Tk::CmdLine::SetArguments(-font => '7x14');
Tk::CmdLine::SetArguments();
if (not GetOptions('-help', '-history=s', '-b=s', '-bus=s', '-bind=s@',
- '-send=s@', '-size=s', '-undersize', '-loadingmode=s',
- '-replayrepeat', '-replaystartregexp=s', '-debug',
- '-replaytimegranularity=s',
- '-replaystopregexp=s', '-out=s') or $opt_help) {
+ '-send=s@', '-size=s', '-undersize', '-debug',
+ '-out=s') or $opt_help) {
print "\n";
print "IvyMon version $VERSION\n";
print "\n";
@@ -229,9 +190,6 @@ if (not GetOptions('-help', '-history=s', '-b=s', '-bus=s', '-bind=s@',
print " [-size size] [-undersize] [-debug]\n";
print " [-bind regexp1] ... [-bind regexpN] \n";
print " [-send message1] ... [-send messageN] \n";
- print " [-loadingmode mode] [-replayrepeat]\n";
- print " [-replaytimegranularity float>0]\n";
- print " [-replaystartregexp regexp] [-replaystopregexp regexp]\n";
print " [-out outputfile] [standard X11 options...]\n";
print " [inputfile]\n";
print "\n";
@@ -244,23 +202,11 @@ if (not GetOptions('-help', '-history=s', '-b=s', '-bus=s', '-bind=s@',
print " -bind <regexp> Ivy binding regular expression\n";
print " ((.*) by default)\n";
print " -send <string> Ivy message to send\n";
- print " -loadingmode <display|replay|replay-pause>\n";
- print " Loading mode of input files\n";
- print " ('replay-pause' by default)\n";
- print " -replaytimegranularity Time granularity (in second) for replaying\n";
- print " messages (1 by default)\n";
- print " NOTE: The following options are usable if at least one input file is\n";
- print " given and if -loadingmode is set to 'replay'\n";
- print " -replayrepeat If set, repeat infinitely the replay sequence\n";
- print " -replaystartregexp <regexp> Regexp to match for starting replay\n";
- print " ('^ClockStart\$'' by default)\n";
- print " -replaystopregexp <regexp> Regexp to match for stopping replay\n";
- print " ('^ClockStop\$'' by default)\n";
+ print " -out <file> output filename\n";
print "\n";
exit ;
}
-$replay_repeat = $opt_replayrepeat;
if ($opt_bus) {
$ivy_port = $opt_bus;
} elsif ($opt_b) {
@@ -281,15 +227,6 @@ if ($ivy_port) {
} else {
$title = "Ivymon v$VERSION (default port) - Ivy $ivy_versionstring";
}
-$replay_time_granularity = $opt_replaytimegranularity if $opt_replaytimegranularity > 0;
-if ($replay_time_granularity >= 1) {
- $replay_time_decimalplaces = 0;
-} else {
- $replay_time_decimalplaces = $replay_time_granularity;
- $replay_time_decimalplaces =~ s/^\+?\d*\.//;
- $replay_time_decimalplaces = length($replay_time_decimalplaces);
-}
-$replay_hour = &replayTime();
push(@effectivebind, @opt_bind);
@effectivebind = ('(.*)') unless @effectivebind > 0;
@@ -299,7 +236,7 @@ push(@send_def, @opt_send);
#===================================
#
# Size options
-
+$opt_size = '' unless defined $opt_size;
if($opt_size eq "UXGA" || $opt_size eq "1600") {
$minW = 1600;
$minH = 1200;
@@ -1029,11 +966,6 @@ for my $bind (@effectivebind) {
# Options and arguments test
#
#=================================================================================
-# loading mode
-$mw->Tk::Error("syntax error : -loadingmode accepts 'replay', 'replay-pause' ".
- "or 'display' value")
- if ($opt_loadingmode ne 'replay' and $opt_loadingmode ne 'replay-pause'
- and $opt_loadingmode ne 'display');
# load input files
if (@ARGV > 0) {
@@ -1042,18 +974,8 @@ if (@ARGV > 0) {
$mw->Tk::Error("Can't open file '$file' ($!)");
} else {
&showProgressbar();
- my ($step, $timefound) = &stepsnumber;
- if ($opt_loadingmode eq 'replay-pause' or $opt_loadingmode eq 'replay') {
- if ($timefound) {
- &loadfileForReplay($step);
- } else {
- $mw->Tk::Error("No time information in file '$file'. ".
- "Can't be replayed.");
- }
- &replayStart() if $opt_loadingmode eq 'replay';
- } elsif ($opt_loadingmode eq 'display') {
- &loadfileForDisplay($step);
- }
+ my $step = &stepsnumber();
+ &loadfileForDisplay($step);
&hideProgressbar();
close(IN);
}
@@ -1317,7 +1239,7 @@ sub showClientBindings {
$t->tagConfigure('1', -background => '#e5e5e5');
my $i = 0;
for my $regexp (sort keys(%{$clientsBindings{$client}})) {
-
+ print "client=$client regexp=$regexp\n";
$t->insert('end', $regexp."\n", $i % 2)
if $clientsBindings{$client}->{$regexp} > 0;
$i++;
@@ -1613,7 +1535,7 @@ sub newBinding {
### extract message to send from regexp ###
# skip expressions between parenthesis
- $msg =~ s/=\(.*?\)/= /g;
+ $msg =~ s/=\(.*?\)/=/g;
$msg =~ s/\s+$//;
# duplicate expressions containing the | character
@@ -2151,19 +2073,9 @@ sub loadfile {
$mw->Tk::Error("$!\n");
return;
}
- my $loadingmode = 'display';
&showProgressbar();
- my ($step, $timefound) = &stepsnumber();
- if ($timefound) {
- $loadingmode = &selectLoadingMode();
- if ($loadingmode eq 'replay') {
- &loadfileForReplay($step);
- } else {
- &loadfileForDisplay($step);
- }
- } else {
- &loadfileForDisplay($step);
- }
+ my $step = &stepsnumber();
+ &loadfileForDisplay($step);
&hideProgressbar();
close(IN);
@@ -2173,28 +2085,19 @@ sub loadfile {
sub stepsnumber {
my $step = 0;
- my $timefound;
my $lc = 0;
- # select loading mode
- # if the 1rst message contains a time field, a dialog window
- # will be displayed in order to select replay mode or simple
- # display mode.
# get lines number and test if exists time field
while(<IN>) {
chomp;
next if (/^applications=/ or /^(marker\d+)$/ or /^(messages_number=)/
or /^\#/);
- my ($sender, $message) = split(/\s+/, $_, 2);
- if ($message =~ /^(\d[\d\.]+\d)\s+.*/) {
- $timefound = 1;
- }
$lc++;
}
$step = int($lc/10);
$progressbar->configure(-to => $step*10);
seek(IN, 0, 0);
- return ($step, $timefound);
+ return $step;
} # end stepsnumber
@@ -2286,208 +2189,7 @@ sub loadfileForDisplay {
} # end loadfileForDisplay
-sub loadfileForReplay {
- my $step = shift;
- my $line = 0;
- %replay_msg = ();
- $replay_time = undef;
- # build replay window
- $replay_tpl->destroy if defined $replay_tpl and Tk::Exists($replay_tpl);
- $replay_tpl = $mw->Toplevel;
- $replay_tpl->iconify if $mw->state eq 'iconic';
- $replay_tpl->title("Replay mode");
- my $ctrl_fm = $replay_tpl->Frame()->pack(-side => 'bottom', -pady => 5);
- $replay_text = $replay_tpl->Scrolled('Text',
- -scrollbars => 'e',
- -spacing1 => 2,
- -spacing2 => 0,
- -spacing3 => 2,
- )->pack(-fill => 'both',
- -expand => 1,
- -side => 'bottom');
- # colors
- $replay_bg_orig = $replay_text->cget(-background);
- $replay_fg_orig = $replay_text->cget(-foreground);
- &wheelmousebindings($replay_text);
- # build speed control buttons
- my $realspeedrate = 1;
- my $ctrl_fm1 = $ctrl_fm->Frame()->pack(-side => 'left', -padx => 10);
- $ctrl_fm1->Radiobutton(-text => "x0.1", -indicatoron => 0,
- -height => 2,
- -width => 4,
- -value => 0.1,
- -variable => \$replay_speed,
- -command => sub { $realspeedrate = 0 },
- -selectcolor => 'white')->pack(-side => 'left');
- $ctrl_fm1->Radiobutton(-text => "x0.5", -indicatoron => 0,
- -height => 2,
- -width => 4,
- -value => 0.5,
- -variable => \$replay_speed,
- -command => sub { $realspeedrate = 0 },
- -selectcolor => 'white')->pack(-side => 'left');
- $ctrl_fm1->Radiobutton(-text => "x1", -indicatoron => 0,
- -height => 2,
- -width => 4,
- -value => 1,
- -variable => \$replay_speed,
- -command => sub {
- return if $realspeedrate == 1;
- $realspeedrate = 1;
- &regulationReset();
- },
- -selectcolor => 'white')->pack(-side => 'left');
- $ctrl_fm1->Radiobutton(-text => "x2", -indicatoron => 0,
- -height => 2,
- -width => 4,
- -value => 2,
- -variable => \$replay_speed,
- -command => sub { $realspeedrate = 0 },
- -selectcolor => 'white')->pack(-side => 'left');
- $ctrl_fm1->Radiobutton(-text => "x5", -indicatoron => 0,
- -height => 2,
- -width => 4,
- -value => 5,
- -variable => \$replay_speed,
- -command => sub { $realspeedrate = 0 },
- -selectcolor => 'white')->pack(-side => 'left');
- $ctrl_fm1->Radiobutton(-text => "x10", -indicatoron => 0,
- -height => 2,
- -width => 4,
- -value => 10,
- -variable => \$replay_speed,
- -command => sub { $realspeedrate = 0 },
- -selectcolor => 'white')->pack(-side => 'left');
- # build hour label
- my $ctrl_fm2 = $ctrl_fm->Frame()->pack(-side => 'left', -padx => 10);
- my $hour_lab = $ctrl_fm2->Label(-borderwidth => 1, -relief => 'ridge',
- -height => 2,
- -width => ($replay_time_decimalplaces > 0) ?
- 10 + $replay_time_decimalplaces : 9,
- -textvariable => \$replay_hour,
- )->pack(-side => 'left');
-
- # build control buttons
- my $ctrl_fm3 = $ctrl_fm->Frame()->pack(-side => 'left', -padx => 10);
- $ctrl_fm3->Radiobutton(-text => "Play", -indicatoron => 0,
- -width => 6,
- -height => 2,
- -value => 0,
- -command => \&replayStart,
- -variable => \$replay_runnable,
- -selectcolor => 'white')->pack(-side => 'left');
- $ctrl_fm3->Radiobutton(-text => "Pause", -indicatoron => 0,
- -width => 6,
- -height => 2,
- -value => 1,
- -command => \&replayStop,
- -variable => \$replay_runnable,
- -selectcolor => 'white')->pack(-side => 'left');
- # build loop and step by step checkbuttons
- my $ctrl_fm4 = $ctrl_fm->Frame(-relief => 'ridge', -borderwidth => 1
- )->pack(-side => 'left', -padx => 10, -fill => 'y',
- -expand => 1);
- $ctrl_fm4->Checkbutton(-text => "Repeat",
- -variable => \$replay_repeat,
- )->pack(-side => 'left');
-
- $ctrl_fm4->Checkbutton(-text => "Step by\nstep",
- -variable => \$replay_stepbystep,
- -command => \&replayStop,
- )->pack(-side => 'left', -padx => 10);
-
- # build close button
- $ctrl_fm->Button(-text => "Close",
- -command => \&replayClose,
- -height => 1)->pack(-side => 'left', -padx => 10, -fill => 'y',
- -expand => 1);
- $replay_tpl->update;
- $replay_tpl->minsize($replay_tpl->width, $replay_tpl->height);
-
-
- # display messsages to replay
- my ($sender, $time, $message);
- while(<IN>) {
- chomp;
- next if /^\#/ or /^applications=/ or /^messages_number=/
- or /^\s*$/ or /^(marker\d+)$/;
- ($sender, $time, $message) = split(/\s+/, $_, 3);
- if ($replay_time_granularity >= 1) {
- $time = int($time);
- } else {
- $time = sprintf("%.".$replay_time_decimalplaces."f", $time);
- }
- if (defined $replay_max_time) {
- $replay_max_time = $time if $time > $replay_max_time;
- } else {
- $replay_max_time = $time;
- }
- if (defined $replay_min_time) {
- $replay_min_time = $time if $time < $replay_min_time;
- } else {
- $replay_min_time = $time;
- }
- $line++;
- $message =~ s/^\"//;
- $message =~ s/\"$//;
- push(@{$replay_msg{$time}}, $message);
- $replay_text->insert('end', &replayTime($time)." ".$message."\n", $time);
- # when user click on a message the begin time changes.
- $replay_text->tagBind($time, '<1>', [sub {
- my $ti = $_[1];
- my $replay_was_running;
- if ($replay_running) {
- $replay_was_running = 1;
- &replayStop;
- }
- $replay_text->tagConfigure($replay_last_time,
- -foreground => $replay_fg_orig,
- -background => $replay_bg_orig)
- if defined $replay_last_time;
- $replay_text->tagConfigure($ti,
- -foreground => $replay_fg,
- -background => $replay_bg);
- $replay_last_time = $ti;
- $replay_hour = &replayTime($ti);
- $replay_time = $ti;
- &regulationReset();
- &replayStart if $replay_was_running;
- }, $time]);
- &setProgressbar($line, $step);
- }
- $replay_tpl->raise;
- $replay_time = $replay_min_time;
- $replay_text->configure(-state => 'disabled');
- # ivy bindings
- $ivy->bindRegexp($opt_replaystartregexp, [\&replayStart]);
- $ivy->bindRegexp($opt_replaystopregexp, [\&replayStop]);
-
- # baloon help
- $balloonhelp->attach($replay_text, -balloonmsg =>
- "Select an item in the list to\n".
- "modify the begin time of replay"
- );
-
-} # end loadfileForReplay
-
-
-sub selectLoadingMode {
-
- my $diag = $mw->Dialog(-text =>
- "The selected file contains time informations. ".
- "Do you want to replay the recorded messages or ".
- "just display them?",
- -default_button => 'Just display',
- -buttons => ['Replay', 'Just display']);
- my $answer = $diag->Show;
- if ($answer eq 'Replay') {
- return 'replay';
- } else {
- return 'display';
- }
-
-} # end selectLoadingMode
sub savefile {
@@ -2637,153 +2339,10 @@ sub setProgressbar {
} # end setProgressbar
-#----------------------------------------------------------------------------------
-# Functions related to replay
-#----------------------------------------------------------------------------------
-sub replayStart {
-
- my $loopflag = ($_[0] == 1) ? 1 : undef;
- $replay_data_t0 = $replay_time unless defined $replay_data_t0;
- $replay_current_t0 = gettimeofday() unless defined $replay_current_t0;
- my $t = $replay_text;
- return if $replay_running and not $loopflag;
- return if $loopflag and not $replay_running;
- $replay_runnable = 0;
- $replay_running = 1;
- if ($replay_time > $replay_max_time) {
- if ($replay_repeat == 1) {
- $replay_time = $replay_min_time;
- } else {
- $t->tagConfigure($replay_last_time,
- -foreground => $replay_fg_orig,
- -background => $replay_bg_orig)
- if defined $replay_last_time;
- $replay_running = 0;
- $replay_runnable = 1;
- return;
- }
- }
- $replay_hour = &replayTime($replay_time);
- my $data_dt = $replay_time - $replay_data_t0;
- if (defined $replay_msg{$replay_time}) {
- for my $msg (@{$replay_msg{$replay_time}}) {
- &sendMsg($msg);
- $t->tagConfigure($replay_last_time,
- -foreground => $replay_fg_orig,
- -background => $replay_bg_orig)
- if defined $replay_last_time;
- $t->tagConfigure($replay_time,
- -foreground => $replay_fg,
- -background => $replay_bg);
- }
- $replay_last_time = $replay_time;
- my $i = $t->tagRanges($replay_time);
- $t->see($i) if defined $i;
- }
- $replay_time += $replay_time_granularity;
- $replay_time = sprintf("%.".$replay_time_decimalplaces."f", $replay_time) if
- $replay_time_decimalplaces > 0;
- # step by step mode
- if ($replay_stepbystep) {
- while (not defined $replay_msg{$replay_time}) {
- $replay_time += $replay_time_granularity;
- $replay_time = sprintf("%.".$replay_time_decimalplaces."f", $replay_time) if
- $replay_time_decimalplaces > 0;
- last if $replay_time > $replay_max_time;
- }
- $replay_running = 0;
- $replay_runnable = 1;
-
- # continuous mode
- } else {
- my $dt = gettimeofday() - $replay_current_t0;
- my $dt2 = sprintf("%.2f", $dt);
- my $d = sprintf("%.3f", $dt-$data_dt);
-
- # if speed rate != 1, time regulation is deactivated
- if ($replay_speed != 1) {
- $replay_current_factor = $replay_factor;
- print "replay_speed=$replay_speed => time regulation deactivated\n"
- if $opt_debug;
-
- # if replay is running behind schedule
- } elsif ($dt > $data_dt + $replay_maxgap and
- $replay_current_factor <= $replay_factor) {
- $replay_current_factor *= (1 - $replay_regulpct->[0]/100);
- print "data_dt=$data_dt dt=$dt2 delay=$d [--] ".
- "replay_factor=$replay_current_factor\n" if $opt_debug;
-
- # if replay is getting ahead of schedule
- } elsif ($dt < $data_dt - $replay_maxgap and
- $replay_current_factor >= $replay_factor) {
- $replay_current_factor *= (1 + $replay_regulpct->[1]/100);
- print "data_dt=$data_dt dt=$dt2 delay=$d [++] ".
- "replay_factor=$replay_current_factor\n" if $opt_debug;
-
- # if replay is on time
- } else {
- print "data_dt=$data_dt dt=$dt2 delay=$d\n" if $opt_debug;
- $replay_current_factor = $replay_factor;
- }
-
- $replay_timer =
- $mw->after($replay_current_factor*$replay_time_granularity/$replay_speed,
- [\&replayStart, 1]);
- }
-
-} # end replayStart
-
-sub replayStop {
-
- $replay_running = 0;
- $replay_runnable = 1;
- $replay_text->afterCancel($replay_timer) if defined $replay_timer;
- &regulationReset();
-
-} # end replayStop
-
-sub replayClose {
-
- $ivy->bindRegexp($opt_replaystartregexp);
- $ivy->bindRegexp($opt_replaystopregexp);
- &replayStop();
- $replay_text->after(400, sub {$replay_tpl->destroy});
- $replay_speed = 1;
- $replay_repeat = $opt_replayrepeat;
- $replay_stepbystep = undef;
- $replay_hour = '--:--:--';
-
-} # end replayClose
-
-sub replayTime {
-
- my $time = shift;
- if (defined $time) {
- my ($s, $m, $h) = localtime($time);
- if ($replay_time_decimalplaces > 0) {
- my $dec =
- substr($time, -$replay_time_decimalplaces, $replay_time_decimalplaces);
- return sprintf("%02d:%02d:%02d.%s", $h, $m, $s, $dec);
- } else {
- return sprintf("%02d:%02d:%02d", $h, $m, $s);
- }
- } elsif ($replay_time_decimalplaces > 0) {
- return "--:--:--."."-" x $replay_time_decimalplaces;
- } else {
- return "--:--:--";
- }
-
-} # end replayTime
#----------------------------------------------------------------------------------
# General functions
#----------------------------------------------------------------------------------
-sub regulationReset {
-
- $replay_data_t0 = undef;
- $replay_current_t0 = undef;
-
-} # end regulationReset
sub enlarge {
@@ -2985,16 +2544,12 @@ B<ivymon> [B<-b> ivybus] [B<-help>] [B<-history> size]
[B<-size> window size] [B<-undersize>]
[B<-bind> regexpB<1>] ... [B<-bind> regexpB<N>]
[B<-send> messageB<1>] ... [B<-send> messageB<N>]
- [B<-loadingmode> mode] [B<-replayrepeat>]
- [B<-replaytimegranularity> float>0]
- [B<-replaystartregexp> regexp]
- [B<-replaystopregexp> regexp]
[B<-out> outputfile] [standard X11 options...]
[INPUT-FILE]
=head1 DESCRIPTION
-IvyMon is dedicated to monitor an Ivy bus. It prints out messages that match regular expressions, lets you send messages on bus, provides a keywords search interface, and can replay recorded messages.
+IvyMon is dedicated to monitor an Ivy bus. It prints out messages that match regular expressions, lets you send messages on bus and provides a keywords search interface.
The main area is the window labeled B<Messages> where are printed messages that forward on bus. Each message is preceded by sender application's name. You can insert a colored marker by double-clicking between two messages.
@@ -3008,8 +2563,6 @@ The B<Search> area provides an interface for searching pattern in messages windo
The B<Control> panel contains some general control buttons. Set or unset balloon help functionality with the I<Balloon help> checkbutton. Stop the messages scrolling with the I<Scroll lock> button. You must do it if you want to insert a marker in the messages window. Restart scrolling with the I<Scroll> button. To access markers sequentially, press the I<Jump> button. With the I<Load> and I<Save> buttons, you can select input and output files. The I<Clear> button removes all displayed messages. At last, the I<Exit> button closes the application.
-You can activate the B<Replay> mode when the selected input file contains time information (file typically created with ivymon release 1.6 or later). In this case, you are asked to choose between replaying messages or just displaying them. If first mode is choosen, messages are loaded in a Replay separate window with control buttons for playing, pausing replay, changing its speed, selecting repetitive and step by step modes. The Replay mode can be also activated using command options and replay sequences can be partially controled by ivy messages.
-
=head1 OPTIONS
@@ -3043,26 +2596,6 @@ Subscribe to ivy messages, by using regular expression. This option may be used
Add an ivy message in the list of potential messages to send. This option may be used several times.
-=item B<-loadingmode> display|replay|replay-pause
-
-Specify how to manage the messages loaded at launching. If set to 'display', they are just displayed in the Messages area for analysis. If set to 'replay-pause' (the default value), they are loaded to a new Replay window and if set to 'replay', the replay is started in addition. This option is ignored unless input file command argument exists.
-
-=item B<-replayrepeat>
-
-If set, the replay sequence will be repetitive.
-
-=item B<-replaytimegranularity> float>0
-
-Specify the time granularity in second for replaying messages. Set to 1 by default.
-
-=item B<-replaystartregexp> regexp
-
-Specify the ivy regular expression to match in order to start the replay sequence. Default is '^ClockStart'. You can do manually the same using the B<Play> button of the Replay window.
-
-=item B<-replaystopregexp> regexp
-
-Specify the ivy regular expression to match in order to stop the replay sequence. Default is '^ClockStop'. You can do manually the same using the B<Pause> button of the Replay window.
-
=item B<-out> output file
Specify the output filename and pass in storage mode : the content of the Messages area will be written to file when you exit the application. You can do manually the same using the B<Save> button. Note that output filename can be set or updated by sending the following message "Ivymon Output=<filename>".
@@ -3074,10 +2607,13 @@ Specify the output filename and pass in storage mode : the content of the Messag
ivymon -b 10.192.36.255:3456 -history 20000 -bind 'PLN:(.*) SectorActivation sector=(.*)' -bind 'CLOCK start' -send 'TRAFFIC RadarEnd' -send 'AIRCRAFT: Activated' -size SVGA -undersize
-ivymon -b 10.192.36.255:3456 -out /tmp/backup.ivy -loadingmode replay -replayrepeat -replaystartregexp '^ReplayOn' -replaystopregexp '^ReplayOff' /my/dir/log.ivy
=head1 HISTORY
+B<V1.18, Jan 2007 :> a new command (ivyreplay) is dedicated to replay. ivymon does not provide this functionality anymore.
+
+B<V1.16, Sep 2006 :> added a time regulation system for replay functionality
+
B<V1.8, Aug 2004 :> replay time granularity can be set.
B<V1.6, Jul 2004 :> a Replay mode is added with new command options to parameter it. Input file can be loaded by command argument. Messages storage can be activated at launching using the -out command option.
diff --git a/src/ivyreplay b/src/ivyreplay
new file mode 100755
index 0000000..8d34b61
--- /dev/null
+++ b/src/ivyreplay
@@ -0,0 +1,768 @@
+#!/usr/bin/perl
+
+
+#=================================================================================
+#
+# M A I N
+#
+#=================================================================================
+
+use Tk;
+use Tk::Font;
+use Tk::ErrorDialog;
+use Tk::Dialog;
+use Tk::ProgressBar;
+use Time::HiRes qw(gettimeofday);
+use Ivy;
+use Carp;
+use strict;
+use Getopt::Long;
+use Tk::CmdLine;
+use vars qw/$opt_help $opt_b $opt_bus
+ $opt_size $opt_undersize $opt_autostart
+ $opt_repeat $opt_startregexp
+ $opt_stopregexp $opt_timegranularity $opt_debug/;
+
+# geometry
+my $minW = 1024;
+my $minH = 768;
+my $smallsized = 0;
+my $coef = 1;
+
+my $ivy_port; # undef:=> default value is treated by ivy-perl
+my $appname = 'IvyReplay';
+$appname =~ s/ /_/g;
+
+
+# replay
+my $replay_current_t0;
+my $replay_current_t;
+my $replay_data_t0;
+my $replay_data_t;
+my $replay_maxgap = 0.2; # sec
+my $replay_regulpct = [50, 20]; # %
+my $replay_factor = 1000; # msec
+my $replay_current_factor = $replay_factor;
+
+my $replay_speed = 1;
+my $replay_runnable = 1;
+my $replay_running = 0;
+my $replay_time_granularity = 1;
+my $replay_time_decimalplaces = 0;
+my $replay_timer;
+my $mw;
+my $replay_text;
+my $replay_repeat;
+my %replay_msg;
+my $replay_time;
+my $replay_min_time;
+my $replay_max_time;
+my $replay_last_time;
+my $replay_stepbystep;
+my $replay_bg = 'gray75';
+my $replay_fg = 'black';
+my $replay_bg_orig;
+my $replay_fg_orig;
+my $replay_hour;
+
+
+#----------------------------------------------------------------------------------
+# command line options management
+#----------------------------------------------------------------------------------
+
+Tk::CmdLine::SetArguments(-font => '7x14');
+Tk::CmdLine::SetArguments();
+
+if (not GetOptions('-help', '-b=s', '-bus=s', '-size=s', '-undersize',
+ '-repeat', '-startregexp=s', '-debug', '-timegranularity=s',
+ '-autostart', '-stopregexp=s') or $opt_help) {
+
+ print "\n";
+ print "Usage: ivyreplay [-b[us] bus] [-help]\n";
+ print " [-size size] [-undersize] [-autostart]\n";
+ print " [-repeat] [-timegranularity float>0]\n";
+ print " [-startregexp regexp] [-stopregexp regexp]\n";
+ print " [standard X11 options...]\n";
+ print " inputfile\n";
+ print "\n";
+ print "Options :\n";
+ print " -b <[addr]:port> Ivy bus (\$IVYBUS by default)\n";
+ print " -size <VGA|SVGA|XGA|SXGA|UXGA> Size of the main window\n";
+ print " -undersize If set, slightly reduces the main window\n";
+ print " -autostart If set, messages are replayed as soon as the\n";
+ print " -repeat If set, repeat infinitely the replay sequence\n";
+ print " -timegranularity Time granularity (in second) for replaying\n";
+ print " messages (1 by default)\n";
+ print " -startregexp <regexp> Regexp to match for starting replay\n";
+ print " ('^ClockStart\$'' by default)\n";
+ print " -stopregexp <regexp> Regexp to match for stopping replay\n";
+ print " ('^ClockStop\$'' by default)\n";
+ print "\n";
+
+ exit ;
+
+}
+
+croak "Error : an input file is expected\n" unless @ARGV > 0;
+
+$replay_repeat = $opt_repeat;
+if ($opt_bus) {
+ $ivy_port = $opt_bus;
+} elsif ($opt_b) {
+ $ivy_port = $opt_b;
+}
+my $title;
+my $ivy_version = $Ivy::VERSION;
+my $ivy_cvsrevision = 0;
+my $ivy_versionstring = "v$ivy_version";
+if ($ivy_version =~ s/Revision: (.*)//) {
+ $ivy_version = $1;
+ $ivy_cvsrevision = 1;
+ $ivy_versionstring = "v$ivy_version (cvs revision)";
+}
+if ($ivy_port) {
+ $title = "Ivyreplay ($ivy_port) - Ivy $ivy_versionstring";
+} else {
+ $title = "Ivyreplay (default port) - Ivy $ivy_versionstring";
+}
+$replay_time_granularity = $opt_timegranularity if $opt_timegranularity > 0;
+if ($replay_time_granularity >= 1) {
+ $replay_time_decimalplaces = 0;
+} else {
+ $replay_time_decimalplaces = $replay_time_granularity;
+ $replay_time_decimalplaces =~ s/^\+?\d*\.//;
+ $replay_time_decimalplaces = length($replay_time_decimalplaces);
+}
+$replay_hour = &replayTime();
+
+
+#===================================
+#
+# Size options
+
+if($opt_size eq "UXGA" || $opt_size eq "1600") {
+ $minW = 1600;
+ $minH = 1200;
+ $smallsized = 0;
+ $coef = 1.2;
+ Tk::CmdLine::SetArguments(-font => '10x20');
+ Tk::CmdLine::SetArguments();
+} elsif ($opt_size eq "SXGA" || $opt_size eq "1280") {
+ $minW = 1280;
+ $minH = 1024;
+ $smallsized = 0;
+ $coef = 1.1;
+ Tk::CmdLine::SetArguments(-font => '8x13');
+ Tk::CmdLine::SetArguments();
+} elsif ($opt_size eq "XGA" || $opt_size eq "1024") {
+ $minW = 1024;
+ $minH = 768;
+ $smallsized = 1;
+ $coef = 1;
+ Tk::CmdLine::SetArguments(-font => '7x14');
+ Tk::CmdLine::SetArguments();
+} elsif ($opt_size eq "SVGA" || $opt_size eq "800") {
+ $minW = 800;
+ $minH = 600;
+ $smallsized = 1;
+ $coef = 0.64;
+ Tk::CmdLine::SetArguments(-font => '6x10');
+ Tk::CmdLine::SetArguments();
+} elsif ($opt_size eq "VGA" || $opt_size eq "640"){
+ $minW = 640;
+ $minH = 480;
+ $smallsized = 1;
+ $coef = 0.48;
+ Tk::CmdLine::SetArguments(-font => '5x7');
+ Tk::CmdLine::SetArguments();
+}
+
+if ($opt_undersize) {
+ $minW -= 10;
+ $minH -= 30;
+}
+
+#=================================================================================
+#
+# H M I
+#
+#=================================================================================
+my $mw = MainWindow->new();
+
+# Set default min size
+$mw->geometry($minW."x".$minH);
+$mw->minsize($minW, $minH);
+$mw->title($title);
+
+# Key-Tab binding is deactivated, because this event will be used by entries
+# for completion functionality
+$mw->bind('<Key-Tab>', sub {Tk->break});
+my $focusedtext;
+$mw->bind("Tk::Text", "<FocusIn>", [sub {
+ &clearSearch() if $_[1] ne $focusedtext;
+ $focusedtext = $_[1];}, Ev('W')]);
+
+
+#----------------------------------------------------------------------------------
+# Progress bar
+#----------------------------------------------------------------------------------
+my $tpl = $mw->Toplevel;
+$tpl->Popup;
+$tpl->raise($mw);
+$tpl->title("");
+$tpl->geometry("300x50");
+my $progressbar =
+ $tpl->ProgressBar(-from => 0,
+ -length => 200,
+ -borderwidth => 2,
+ -colors => [ 0 => 'yellow'],
+ -relief => 'sunken',
+ -resolution => 0,
+ -anchor => 'w',
+ )->pack(-fill => 'both',
+ -expand => 1,
+ );
+$progressbar->value(0);
+$tpl->withdraw;
+
+
+
+#=================================================================================
+#
+# Ivy initialisation and Ivy bindings
+#
+#=================================================================================
+
+# init Ivy bus and start it.
+Ivy->init(-loopMode => 'TK',
+ -appName => $appname,
+ -ivyBus => $ivy_port,
+ -onDieFunc => [\&quit],
+ );
+my $ivy = Ivy->new();
+$ivy->start;
+
+
+#=================================================================================
+#
+# Options and arguments test
+#
+#=================================================================================
+
+&build();
+
+# load input files
+my $file = $ARGV[0];
+
+if (not open(IN, $file)) {
+ $mw->Tk::Error("Can't open file '$file' ($!)");
+} else {
+ &showProgressbar();
+ my ($step, $timefound) = &stepsnumber;
+ if ($timefound) {
+ &loadfileForReplay($step);
+ } else {
+ $mw->Tk::Error("No time information in file '$file'. ".
+ "Can't be replayed.");
+ }
+ &replayStart() if $opt_autostart;
+ &hideProgressbar();
+ close(IN);
+}
+
+MainLoop;
+
+#==================================================================================
+#
+# Functions
+#
+#==================================================================================
+
+
+#----------------------------------------------------------------------------------
+# Functions related to input/output files
+#----------------------------------------------------------------------------------
+
+sub stepsnumber {
+
+ my $step = 0;
+ my $timefound;
+ my $lc = 0;
+
+ # get lines number and test if exists time field
+ while(<IN>) {
+ chomp;
+ next if (/^applications=/ or /^(marker\d+)$/ or /^(messages_number=)/
+ or /^\#/);
+ my ($sender, $message) = split(/\s+/, $_, 2);
+ if ($message =~ /^(\d[\d\.]+\d)\s+.*/) {
+ $timefound = 1;
+ }
+ $lc++;
+ }
+ $step = int($lc/10);
+ $progressbar->configure(-to => $step*10);
+ seek(IN, 0, 0);
+ return ($step, $timefound);
+
+} # end stepsnumber
+
+sub build {
+
+ %replay_msg = ();
+ $replay_time = undef;
+ # build replay window
+ my $ctrl_fm = $mw->Frame()->pack(-side => 'bottom', -pady => 5);
+ $replay_text = $mw->Scrolled('Text',
+ -scrollbars => 'e',
+ -spacing1 => 2,
+ -spacing2 => 0,
+ -spacing3 => 2,
+ )->pack(-fill => 'both',
+ -expand => 1,
+ -side => 'bottom');
+ # colors
+ $replay_bg_orig = $replay_text->cget(-background);
+ $replay_fg_orig = $replay_text->cget(-foreground);
+ &wheelmousebindings($replay_text);
+ # build speed control buttons
+ my $realspeedrate = 1;
+ my $ctrl_fm1 = $ctrl_fm->Frame()->pack(-side => 'left', -padx => 10);
+ $ctrl_fm1->Radiobutton(-text => "x0.1", -indicatoron => 0,
+ -height => 2,
+ -width => 4,
+ -value => 0.1,
+ -variable => \$replay_speed,
+ -command => sub { $realspeedrate = 0 },
+ -selectcolor => 'white')->pack(-side => 'left');
+ $ctrl_fm1->Radiobutton(-text => "x0.5", -indicatoron => 0,
+ -height => 2,
+ -width => 4,
+ -value => 0.5,
+ -variable => \$replay_speed,
+ -command => sub { $realspeedrate = 0 },
+ -selectcolor => 'white')->pack(-side => 'left');
+ $ctrl_fm1->Radiobutton(-text => "x1", -indicatoron => 0,
+ -height => 2,
+ -width => 4,
+ -value => 1,
+ -variable => \$replay_speed,
+ -command => sub {
+ return if $realspeedrate == 1;
+ $realspeedrate = 1;
+ &regulationReset();
+ },
+ -selectcolor => 'white')->pack(-side => 'left');
+ $ctrl_fm1->Radiobutton(-text => "x2", -indicatoron => 0,
+ -height => 2,
+ -width => 4,
+ -value => 2,
+ -variable => \$replay_speed,
+ -command => sub { $realspeedrate = 0 },
+ -selectcolor => 'white')->pack(-side => 'left');
+ $ctrl_fm1->Radiobutton(-text => "x5", -indicatoron => 0,
+ -height => 2,
+ -width => 4,
+ -value => 5,
+ -variable => \$replay_speed,
+ -command => sub { $realspeedrate = 0 },
+ -selectcolor => 'white')->pack(-side => 'left');
+ $ctrl_fm1->Radiobutton(-text => "x10", -indicatoron => 0,
+ -height => 2,
+ -width => 4,
+ -value => 10,
+ -variable => \$replay_speed,
+ -command => sub { $realspeedrate = 0 },
+ -selectcolor => 'white')->pack(-side => 'left');
+ # build hour label
+ my $ctrl_fm2 = $ctrl_fm->Frame()->pack(-side => 'left', -padx => 10);
+ my $hour_lab = $ctrl_fm2->Label(-borderwidth => 1, -relief => 'ridge',
+ -height => 2,
+ -width => ($replay_time_decimalplaces > 0) ?
+ 10 + $replay_time_decimalplaces : 9,
+ -textvariable => \$replay_hour,
+ )->pack(-side => 'left');
+
+ # build control buttons
+ my $ctrl_fm3 = $ctrl_fm->Frame()->pack(-side => 'left', -padx => 10);
+ $ctrl_fm3->Radiobutton(-text => "Play", -indicatoron => 0,
+ -width => 6,
+ -height => 2,
+ -value => 0,
+ -command => \&replayStart,
+ -variable => \$replay_runnable,
+ -selectcolor => 'white')->pack(-side => 'left');
+ $ctrl_fm3->Radiobutton(-text => "Pause", -indicatoron => 0,
+ -width => 6,
+ -height => 2,
+ -value => 1,
+ -command => \&replayStop,
+ -variable => \$replay_runnable,
+ -selectcolor => 'white')->pack(-side => 'left');
+ # build loop and step by step checkbuttons
+ my $ctrl_fm4 =
+ $ctrl_fm->Frame(-relief => 'ridge', -borderwidth => 1
+ )->pack(-side => 'left', -padx => 10, -fill => 'y',
+ -expand => 1);
+ $ctrl_fm4->Checkbutton(-text => "Repeat",
+ -variable => \$replay_repeat,
+ )->pack(-side => 'left');
+
+ $ctrl_fm4->Checkbutton(-text => "Step by\nstep",
+ -variable => \$replay_stepbystep,
+ -command => \&replayStop,
+ )->pack(-side => 'left', -padx => 10);
+
+ # build close button
+ $ctrl_fm->Button(-text => "Close",
+ -command => \&replayClose,
+ -height => 1)->pack(-side => 'left', -padx => 10, -fill => 'y',
+ -expand => 1);
+ $mw->update;
+ $mw->minsize($mw->width, $mw->height);
+
+} # end build
+
+
+sub loadfileForReplay {
+
+ my $step = shift;
+ my $line = 0;
+
+ # display messsages to replay
+ my ($sender, $time, $message);
+ while(<IN>) {
+ chomp;
+ next if /^\#/ or /^applications=/ or /^messages_number=/
+ or /^\s*$/ or /^(marker\d+)$/;
+ ($sender, $time, $message) = split(/\s+/, $_, 3);
+ if ($replay_time_granularity >= 1) {
+ $time = int($time);
+ } else {
+ $time = sprintf("%.".$replay_time_decimalplaces."f", $time);
+ }
+ if (defined $replay_max_time) {
+ $replay_max_time = $time if $time > $replay_max_time;
+ } else {
+ $replay_max_time = $time;
+ }
+ if (defined $replay_min_time) {
+ $replay_min_time = $time if $time < $replay_min_time;
+ } else {
+ $replay_min_time = $time;
+ }
+ $line++;
+ $message =~ s/^\"//;
+ $message =~ s/\"$//;
+ push(@{$replay_msg{$time}}, $message);
+ $replay_text->insert('end', &replayTime($time)." ".$message."\n", $time);
+ # when user click on a message the begin time changes.
+ $replay_text->tagBind($time, '<1>', [sub {
+ my $ti = $_[1];
+ my $replay_was_running;
+ if ($replay_running) {
+ $replay_was_running = 1;
+ &replayStop;
+ }
+ $replay_text->tagConfigure($replay_last_time,
+ -foreground => $replay_fg_orig,
+ -background => $replay_bg_orig)
+ if defined $replay_last_time;
+ $replay_text->tagConfigure($ti,
+ -foreground => $replay_fg,
+ -background => $replay_bg);
+ $replay_last_time = $ti;
+ $replay_hour = &replayTime($ti);
+ $replay_time = $ti;
+ &regulationReset();
+ &replayStart if $replay_was_running;
+ }, $time]);
+ &setProgressbar($line, $step);
+ }
+ $mw->raise;
+ $replay_time = $replay_min_time;
+ $replay_text->configure(-state => 'disabled');
+ # ivy bindings
+ $ivy->bindRegexp($opt_startregexp, [\&replayStart]);
+ $ivy->bindRegexp($opt_stopregexp, [\&replayStop]);
+
+
+} # end loadfileForReplay
+
+
+
+sub showProgressbar {
+
+ $progressbar->value(0);
+ $progressbar->toplevel->deiconify;
+ $progressbar->toplevel->raise($mw);
+
+} # end showProgressbar
+
+
+sub hideProgressbar {
+
+ $progressbar->toplevel->withdraw;
+
+} # end hideProgressbar
+
+
+sub setProgressbar {
+
+ my ($line, $step) = @_;
+ $progressbar->value($line);
+ $progressbar->toplevel->raise($mw);
+ return unless defined $step;
+ $progressbar->update if ($step == 0 or $line % $step == 0);
+
+} # end setProgressbar
+
+
+#----------------------------------------------------------------------------------
+# Functions related to replay
+#----------------------------------------------------------------------------------
+sub replayStart {
+
+ my $loopflag = ($_[0] == 1) ? 1 : undef;
+ $replay_data_t0 = $replay_time unless defined $replay_data_t0;
+ $replay_current_t0 = gettimeofday() unless defined $replay_current_t0;
+ my $t = $replay_text;
+ return if $replay_running and not $loopflag;
+ return if $loopflag and not $replay_running;
+ $replay_runnable = 0;
+ $replay_running = 1;
+ if ($replay_time > $replay_max_time) {
+ if ($replay_repeat == 1) {
+ $replay_time = $replay_min_time;
+ } else {
+ $t->tagConfigure($replay_last_time,
+ -foreground => $replay_fg_orig,
+ -background => $replay_bg_orig)
+ if defined $replay_last_time;
+ $replay_running = 0;
+ $replay_runnable = 1;
+ return;
+ }
+ }
+ $replay_hour = &replayTime($replay_time);
+ my $data_dt = $replay_time - $replay_data_t0;
+ if (defined $replay_msg{$replay_time}) {
+ for my $msg (@{$replay_msg{$replay_time}}) {
+ $ivy->sendMsgs($msg);
+ $t->tagConfigure($replay_last_time,
+ -foreground => $replay_fg_orig,
+ -background => $replay_bg_orig)
+ if defined $replay_last_time;
+ $t->tagConfigure($replay_time,
+ -foreground => $replay_fg,
+ -background => $replay_bg);
+ }
+ $replay_last_time = $replay_time;
+ my $i = $t->tagRanges($replay_time);
+ $t->see($i) if defined $i;
+ }
+ $replay_time += $replay_time_granularity;
+ $replay_time = sprintf("%.".$replay_time_decimalplaces."f", $replay_time) if
+ $replay_time_decimalplaces > 0;
+ # step by step mode
+ if ($replay_stepbystep) {
+ while (not defined $replay_msg{$replay_time}) {
+ $replay_time += $replay_time_granularity;
+ $replay_time = sprintf("%.".$replay_time_decimalplaces."f", $replay_time) if
+ $replay_time_decimalplaces > 0;
+ last if $replay_time > $replay_max_time;
+ }
+ $replay_running = 0;
+ $replay_runnable = 1;
+
+ # continuous mode
+ } else {
+ my $dt = gettimeofday() - $replay_current_t0;
+ my $dt2 = sprintf("%.2f", $dt);
+ my $d = sprintf("%.3f", $dt-$data_dt);
+
+ # if speed rate != 1, time regulation is deactivated
+ if ($replay_speed != 1) {
+ $replay_current_factor = $replay_factor;
+ print "replay_speed=$replay_speed => time regulation deactivated\n"
+ if $opt_debug;
+
+ # if replay is running behind schedule (retard)
+ } elsif ($dt > $data_dt + $replay_maxgap and
+ $replay_current_factor <= $replay_factor) {
+ $replay_current_factor *= (1 - $replay_regulpct->[0]/100);
+ print "data_dt=$data_dt dt=$dt2 delay=$d [--] ".
+ "replay_factor=$replay_current_factor\n" if $opt_debug;
+
+ # if replay is getting ahead of schedule (avance)
+ } elsif ($dt < $data_dt - $replay_maxgap and
+ $replay_current_factor >= $replay_factor) {
+ $replay_current_factor *= (1 + $replay_regulpct->[1]/100);
+ print "data_dt=$data_dt dt=$dt2 delay=$d [++] ".
+ "replay_factor=$replay_current_factor\n" if $opt_debug;
+
+ # if replay is on time
+ } else {
+ print "data_dt=$data_dt dt=$dt2 delay=$d\n" if $opt_debug;
+ $replay_current_factor = $replay_factor;
+ }
+
+ $replay_timer =
+ $mw->after($replay_current_factor*$replay_time_granularity/$replay_speed,
+ [\&replayStart, 1]);
+ }
+
+} # end replayStart
+
+sub replayStop {
+
+ $replay_running = 0;
+ $replay_runnable = 1;
+ $replay_text->afterCancel($replay_timer) if defined $replay_timer;
+ &regulationReset();
+
+} # end replayStop
+
+sub replayClose {
+
+ $ivy->bindRegexp($opt_startregexp);
+ $ivy->bindRegexp($opt_stopregexp);
+ &replayStop();
+ $replay_text->after(400, sub {$mw->destroy});
+ $replay_speed = 1;
+ $replay_repeat = $opt_repeat;
+ $replay_stepbystep = undef;
+ $replay_hour = '--:--:--';
+
+} # end replayClose
+
+sub replayTime {
+
+ my $time = shift;
+ if (defined $time) {
+ my ($s, $m, $h) = localtime($time);
+ if ($replay_time_decimalplaces > 0) {
+ my $dec =
+ substr($time, -$replay_time_decimalplaces, $replay_time_decimalplaces);
+ return sprintf("%02d:%02d:%02d.%s", $h, $m, $s, $dec);
+ } else {
+ return sprintf("%02d:%02d:%02d", $h, $m, $s);
+ }
+ } elsif ($replay_time_decimalplaces > 0) {
+ return "--:--:--."."-" x $replay_time_decimalplaces;
+ } else {
+ return "--:--:--";
+ }
+
+} # end replayTime
+
+#----------------------------------------------------------------------------------
+# General functions
+#----------------------------------------------------------------------------------
+
+sub regulationReset {
+
+ $replay_data_t0 = undef;
+ $replay_current_t0 = undef;
+
+} # end regulationReset
+
+
+sub wheelmousebindings {
+
+ my $w = shift;
+ my $count = shift;
+ my $count = 3 unless $count > 0;
+ $w->bind('<Control-ButtonPress-4>', sub {$w->yview('scroll', -1, 'page')});
+ $w->bind('<Shift-ButtonPress-4>', sub {$w->yview('scroll', -1, 'unit')});
+ $w->bind('<ButtonPress-4>', sub {$w->yview('scroll', -$count, 'unit')});
+
+ $w->bind('<Control-ButtonPress-5>', sub {$w->yview('scroll', 1, 'page')});
+ $w->bind('<Shift-ButtonPress-5>', sub {$w->yview('scroll', 1, 'unit')});
+ $w->bind('<ButtonPress-5>', sub {$w->yview('scroll', $count, 'unit')});
+
+} # end wheelmousebindings
+
+
+sub quit {
+
+ print "Quit\n";
+ exit;
+
+} # end quit
+
+
+__END__
+
+=head1 NAME
+
+ivyreplay - a graphical application for replaying Ivy messages
+
+
+=head1 SYNOPSIS
+
+B<ivyreplay> [B<-b> ivybus] [B<-help>]
+ [B<-size> window size] [B<-undersize>]
+ [B<-autostart>] [B<-repeat>]
+ [B<-timegranularity> float>0]
+ [B<-startregexp> regexp]
+ [B<-stopregexp> regexp]
+ [standard X11 options...]
+ inputfile
+
+=head1 DESCRIPTION
+
+IvyReplay is dedicated to replay Ivy messages. Input file must have been generated with ivymon v1.6 or later (it must contain time information).
+
+
+=head1 OPTIONS
+
+=over
+
+=item B<-b> ip:port
+
+Set the bus domain and port number to be used. Use $IVYBUS variable if defined. Default is 127.255.255.255:2010.
+
+=item B<-help>
+
+Get some help
+
+
+=item B<-size> window size
+
+Set the size of the IvyMon window. Can be VGA or 640, SVGA or 800, XGA or 1024, SXGA or 1280, UXGA or 1600. Default is XGA (1024x768).
+
+=item B<-undersize>
+
+Slightly reduce the IvyMon window to fit it in screen with borders of the window manager. Option not set by default.
+
+
+=item B<-repeat>
+
+If set, the replay sequence will be repetitive.
+
+=item B<-timegranularity> float>0
+
+Specify the time granularity in second for replaying messages. Set to 1 by default.
+
+=item B<-startregexp> regexp
+
+Specify the ivy regular expression to match in order to start the replay sequence. Default is '^ClockStart'. You can do manually the same using the B<Play> button of the Replay window.
+
+=item B<-stopregexp> regexp
+
+Specify the ivy regular expression to match in order to stop the replay sequence. Default is '^ClockStop'. You can do manually the same using the B<Pause> button of the Replay window.
+
+
+=back
+
+
+=head1 EXAMPLE
+
+ivyreplay -b 10.192.36.255:3456 -repeat -startregexp '^ReplayOn' -stopregexp '^ReplayOff' /my/dir/log.ivy
+
+
+=head1 AUTHORS
+
+Daniel Etienne <etienne@cena.fr>
+