$Tk::Calculator::RPN::HP::VERSION = '1.2';
package Tk::Calculator::RPN::HP;
# OO base class and Exporter module for HP RPN calculators.
use Exporter;
use base qw/Exporter/;
push @EXPORT, qw/
$BLUE $BLUE_DARKER
$GRAY $GRAY_LIGHTER $GRAY_LIGHTEST
$ORANGE $PI $ROLD $ROLU $SILVER $STACKM $SWAP
/;
push @EXPORT, qw/$AC $AS $AT $CO $EX $LG $LN $RP $SI $SQ $TA $TX/;
push @EXPORT, qw/$AD $AN $DD $DM $DV $IO $ML $SB $XR $YX/;
use POSIX;
use Tk::widgets qw /Compound/;
use base qw/Tk::Frame/;
Construct Tk::Widget 'Calculator';
use subs qw/mode/;
use strict;
use constant E => 2.7182818;# e
use constant PI => 3.1415926;# pi
use constant D2R => PI / 180; # degrees per radian
our $ROOT = 'Calculator/RPN/images';
# Exported global constants and mathematical functions.
our $BLUE; # color
our $BLUE_DARKER; # color
our $GRAY; # color
our $GRAY_LIGHTER; # color
our $GRAY_LIGHTEST; # color
our $ORANGE; # color
our $PI; # image of pi
our $ROLD; # roll stack up image
our $ROLU; # roll stack down image
our $SILVER; # color
our $STACKM; # maximum stack length
our $SWAP; # swap X/Y image
our $AC; # arccosine
our $AS; # arcsine
our $AT; # arctangent
our $CO; # cosine
our $EX; # e**x
our $LG; # log10
our $LN; # natural logarithm
our $RP; # reciprocal
our $SI; # sine
our $SQ; # square root
our $TA; # tangent
our $TX; # 10**x
our $AD; # add
our $AN; # AND
our $DD; # double divide
our $DM; # double multiply
our $DV; # divide
our $IO; # inclusive OR
our $ML; # multiply
our $SB; # subtract
our $XR; # exclusive OR
our $YX; # exponentiation
sub ClassInit {
my ($class, $mw) = @_;
# Exported global constants.
$BLUE = 'steelblue1';
$BLUE_DARKER = 'steelblue';
$GRAY = 'gray25';
$GRAY_LIGHTER = 'gray31';
$GRAY_LIGHTEST = 'gray40';
$ORANGE = 'orange';
$SILVER = '#ef5bef5bef5b';
$STACKM = 4 - 1;
# Exported mathematical functions expecting one operand,
# X from the RPN stack.
$AC = sub {acos mode(@_)}; # arccosine
$AS = sub {asin mode(@_)}; # arcsine
$AT = sub {atan mode(@_)}; # arctangent
$CO = sub {sin mode(@_)}; # cosine
$EX = sub {E ** $_[0]}; # e**x
$LG = sub {log10 $_[0]}; # log10
$LN = sub {log $_[0]}; # natural logarithm
$RP = sub {1 / $_[0]}; # reciprocal
$SI = sub {sin mode(@_)}; # sine
$SQ = sub {sqrt $_[0]}; # square root
$TA = sub {tan mode(@_)}; # tangent
$TX = sub {10 ** $_[0]}; # 10**x
# Exported mathematical functions expecting two operands,
# X and Y from the RPN stack.
$AD = sub {$_[1] + $_[0]}; # addition
$AN = sub {$_[1] & $_[0]}; # AND
$DD = sub {$_[1] / $_[0]}; # double divide
$DM = sub {$_[1] * $_[0]}; # double multiply
$DV = sub {$_[1] / $_[0]}; # division
$IO = sub {$_[1] | $_[0]}; # inclusive OR
$ML = sub {$_[1] * $_[0]}; # multiplication
$SB = sub {$_[1] - $_[0]}; # subtraction
$XR = sub {$_[1] ^ $_[0]}; # exclusive OR
$YX = sub {$_[1] ** $_[0]}; # exponentiation
# Exported images.
my (@cargs) = (-foreground => $BLUE, -background => $GRAY_LIGHTER);
$PI = $mw->Bitmap(-file => Tk->findINC("$ROOT/pi.xbm"), @cargs);
$ROLU = $mw->Compound;
$ROLU->Text(-text => 'R', -foreground => $BLUE);
$ROLU->Image(-image => $mw->Bitmap(-file => Tk->findINC("$ROOT/rolu.xbm"), @cargs));
@cargs = (-foreground => 'white', -background => $GRAY);
$ROLD = $mw->Compound;
$ROLD->Text(-text => 'R', -foreground => 'white');
$ROLD->Image(-image => $mw->Bitmap(-file => Tk->findINC("$ROOT/rold.xbm"), @cargs));
$SWAP = $mw->Compound;
$SWAP->Text(-text => 'X', -foreground => 'white');
$SWAP->Image(-image => $mw->Bitmap(-file => Tk->findINC("$ROOT/swap.xbm"), @cargs));
$SWAP->Text(-text => 'Y', -foreground => 'white');
$class->SUPER::ClassInit($mw);
} # end ClassInit
sub Populate {
# Populate() for this base class is rather tricky because it re-blesses
# the incoming object (whether this is good style is another question).
# It does this so that method lookups are dispatched to the new class
# based on the type of calculator. This also means that superclass
# lookups are found here, the HP RPN base class.
#
# This presents one problem - ClassInit() is never called for the new
# subclass. We handle this situation just like a C widget, and invoke
# InitClass on the re-blessed class, which eventually calls ClassInit.
my ($self, $args) = @_;
$self->SUPER::Populate($args);
$self->{TYPE} = delete $args->{-type};
die "HP calculator type not specified." unless $self->{TYPE};
mkdir $^O eq "MSWin32" ? 'C:\.hp' : "$ENV{HOME}/.hp", 0755;
my $calc = 'Tk::Calculator::RPN::HP_' . uc($self->{TYPE});
eval "require $calc";
die "Tk::Calculator::RPN::HP::HP.pm, error loading '$calc': $@" if $@;
bless $self, $calc;
$calc->InitClass($self->MainWindow); # called once/class/MainWindow
# Instance pre-initialization.
$self->{CLRX} = 0; # 1 IFF clear X before inserting next key
$self->{F_PRESSED} = 0; # F-key modifier pressed
$self->{G_PRESSED} = 0; # G-key modifier pressed
$self->{ONOFF} = 0; # 1 IFF calculator on
$self->{PUSHX} = 0; # 1 IFF push X before inserting next key
$self->{MODE} = 0; # 0 = degress, 1 = radians
$self->{PB} = delete $args->{-progressbar}; # possible ProgressBar
$self->{XV} = ' '; # current display (X) value
$self->clr; # clear entire stack
# Build the calculator.
$self->{PB_PERCENT} = 0;
$self->Populate($args);
$self->{PB}->set($self->{PB_PERCENT} = 100) if $self->{PB};
} # end Populate
sub build_help_button {
# Create the ? Button common to all calculator types.
my ($self, $parent, $help) = @_;
my $quest = $parent->Button(
-text => '?',
-font => '6x9',
-relief => 'flat',
-highlightthickness => 0,
-background => $BLUE,
-borderwidth => 0,
-pady => 0,
-command => sub {$help->deiconify},
);
$quest->bind('<2>' => sub {
my (@register) = ('(X)', '(Y)', '(Z)', '(T)');
print "\n";
for (my $i = $STACKM; $i >= 0; $i--) {
print "stack+$i $register[$i] : '", $self->{STACK}[$i], "'\n";
}
});
$self->{PB}->set($self->{PB_PERCENT} += 10) if $self->{PB};
return $quest;
} # end build_help_button
sub build_help_window {
# Called by ClassInit() to build a help window shared by all subclass instances.
my ($class, $mw) = @_;
my $help = $mw->Toplevel;
$help->withdraw;
$help->title('HP 21 Help');
$help->protocol('WM_DELETE_WINDOW' => sub {});
my $frame = $help->Frame->pack;
my ($type) = $class =~ /.*::(.*)/;
$frame->Label(
-image => $mw->Photo(-file => Tk->findINC("$ROOT/" . lc($type) . '-back.gif')),
)->pack;
$frame->Label(
-text => '? <B1> displays this window',
-relief => 'ridge',
)->pack(qw/-expand 1 -fill both/);
$frame->Label(
-text => '? <B2> prints the stack',
-relief => 'ridge',
)->pack(qw/-expand 1 -fill both/);
$frame->Button(
-text => 'Close',
-command => sub {$help->withdraw},
)->pack(qw/-expand 1 -fill both/);
return $help;
} # end build_help_window
sub mode {
# Convert an argument from degees to radians, if required.
my ($f, $mode) = @_;
return $f if $mode; # already in radians
return $f * D2R; # if degrees
} # end mode
sub set_keypad_bindings {
# Now establish key bindings for the digits and common arithmetic
# operations, including keypad keys.
my ($self) = @_;
my $mw = $self->MainWindow;
foreach my $key ( qw/0 1 2 3 4 5 6 7 8 9/ ) {
$mw->bind( "<Key-$key>" => [$self => 'key', $key] );
$mw->bind( "<KP_$key>" => [$self => 'key', $key] );
}
foreach my $key ( qw/period KP_Decimal/ ) {
$mw->bind( "<$key>" => [$self => 'key', '.'] );
}
foreach my $key ( qw/Return KP_Enter/ ) {
$mw->bind( "<$key>" => [$self => 'enter'] );
}
foreach my $key ( qw/plus KP_Add/ ) {
$mw->bind( "<$key>" => [$self => 'math3', $AD, undef, undef] );
}
foreach my $key ( qw/minus KP_Subtract/ ) {
$mw->bind( "<$key>" => [$self => 'math3', $SB, undef, undef] );
}
foreach my $key ( qw/asterisk KP_Multiply/ ) {
$mw->bind( "<$key>" => [$self => 'math3', $ML, undef, undef] );
}
foreach my $key ( qw/slash KP_Divide/ ) {
$mw->bind( "<$key>" => [$self => 'math3', $DV, undef, undef] );
}
} # end set_keypad_bindings
# Function key processors common to all classes.
sub chs { # change sign
my ($self) = @_;
my $s = substr($self->{STACK}[0], 0, 1);
substr($self->{STACK}[0], 0, 1) = ($s eq '-') ? ' ' : '-';
$self->end;
} # end chs
sub clr { # clear stack
my ($self) = @_;
$self->{STACK}[$_] = ' 0.00' foreach (0 .. $STACKM);
$self->end;
} # end clr
sub clx { # clear x
my ($self) = @_;
$self->{STACK}[0] = 0;
$self->{CLRX} = 1;
$self->{PUSHX} = 0;
$self->end;
} # end clx
sub end { # key and display cleanup
my ($self) = @_;
$self->{F_PRESSED} = $self->{G_PRESSED} = 0;
$self->{XV} = $self->{STACK}[0];
} # end end
sub enter { # enter key
my ($self) = @_;
unshift @{$self->{STACK}}, $self->{STACK}[0];
$#{$self->{STACK}} = $STACKM if $#{$self->{STACK}} > $STACKM;
$self->{CLRX} = 1;
$self->{PUSHX} = 0;
$self->end;
} # end enter
sub err { # error
my ($self) = @_;
$self->bell if $self->{ONOFF};
} # end err
sub f { # F key
my ($self) = @_;
$self->{F_PRESSED} = 1;
} # end f
sub g { # G key
my ($self) = @_;
$self->{G_PRESSED} = 1;
} # end g
sub hpshift { # empty HP stack
my ($self) = @_;
$#{$self->{STACK}} = $STACKM if $#{$self->{STACK}} > $STACKM;
my $v = shift @{$self->{STACK}};
$self->{STACK}[$STACKM] = $self->{STACK}[$STACKM - 1] if
$#{$self->{STACK}} == ($STACKM - 1);
$self->end;
return $v;
} # end hpshift
sub key { # process generic key clicks
my ($self) = @_;
shift if ref $_[0]; # toss bind() object
my $key = $_[0];
return unless $self->{ONOFF};
if ($self->{F_PRESSED} or $self->{G_PRESSED}) {
$self->bell;
$self->end;
return;
}
$self->enter if $self->{PUSHX};
$self->{STACK}[0] = ' ' if $self->{CLRX};
$self->{STACK}[0] .= $key;
$self->{CLRX} = $self->{PUSHX} = 0;
$self->end;
} # end key
sub math { # non-G key arithmetic operations
# math() expects one code reference to an anonymous subroutine, which
# expects one argument, X from the RPN stack.
my $self = shift;
$self->{STACK}[0] = &{$_[0]}($self->{STACK}[0]);
$self->{STACK}[0] = ' ' . $self->{STACK}[0] if
substr($self->{STACK}[0], 0, 1) ne '-';
$self->{CLRX} = $self->{PUSHX} = 1;
$self->end;
} # end math
sub math3 { # tri-arithmetic keys
# math3() expects three code references to anonymous subroutines, each
# of which expects two arguments, X and Y from the RPN stack.
#
# $_[0] = normal button press
# $_[1] = "f" qualified button press
# $_[2] = "g" qualified button press
my ($self) = @_;
shift if ref $_[0]; # toss bind() object
my $math = $_[0];
$math = $_[1] if $self->{F_PRESSED};
$math = $_[2] if $self->{G_PRESSED};
if (not defined $math) {
$self->bell;
$self->end;
return;
}
my $x = $self->hpshift;
my $y = $self->{STACK}[0];
$self->{STACK}[0] = &{$math}($x, $y);
$self->{STACK}[0] = ' ' . $self->{STACK}[0]
if substr($self->{STACK}[0], 0, 1) ne '-';
$self->{CLRX} = $self->{PUSHX} = 1;
$self->end;
} # end math3
sub on { # power on/off
my ($self, $val) = @_;
my $rc = $self->{RCFILE};
if ($self->{ONOFF}) {
$self->{ONOFF} = 0;
if (open(RC, ">$rc") or die"open write failed for '$rc': $!") {
foreach (reverse @{$self->{STACK}}) {
print RC "$_\n";
}
close RC;
}
$self->end;
$self->{XV} = '';
} else {
$self->{ONOFF} = 1;
if (open(RC, $rc)) {
$self->{STACK} = [] if -s $rc;
while ($_ = <RC>) {
chomp;
unshift @{$self->{STACK}}, $_;
}
close RC;
}
$self->{CLRX} = $self->{PUSHX} = 1;
$self->end;
}
} # end on
sub pi { # return pi
my ($self) = @_;
$self->enter;
$self->{STACK}[0] = PI;
$self->end;
} # end pi
sub roll_down { # roll stack down
my ($self) = @_;
return unless $self->{ONOFF};
push @{$self->{STACK}}, shift @{$self->{STACK}};
$self->end;
} # end roll_down
sub roll_up { # roll stack up
my ($self) = @_;
return unless $self->{ONOFF};
unshift @{$self->{STACK}}, pop @{$self->{STACK}};
$self->end;
} # end roll_up
sub swapxy { # swap x and y
my ($self) = @_;
return unless $self->{ONOFF};
if ($self->{F_PRESSED} or $self->{G_PRESSED}) {
$self->bell;
$self->end;
return;
}
(@{$self->{STACK}}[0, 1]) = (@{$self->{STACK}}[1, 0]);
$self->end;
} # end swapxy
sub trig_math { # with degree to radian conversion
# trig_math() expects one code reference to an anonymous subroutine, which
# expects one argument, X from the RPN stack. Convert degrees to radians
# as appropriate.
my $self = shift;
$self->{STACK}[0] = &{$_[0]}($self->{STACK}[0], $self->{MODE});
$self->{STACK}[0] = ' ' . $self->{STACK}[0] if
substr($self->{STACK}[0], 0, 1) ne '-';
$self->{CLRX} = $self->{PUSHX} = 1;
$self->end;
} # end trig_math
package Tk::Calculator::RPN::HP::Key3_16C;
# Composite mega-widget Key3 - 3 operators per key.
use Tk::widgets qw/Frame/;
use base qw/Tk::Frame/;
Construct Tk::Calculator::RPN::HP 'Key3_16C';
sub Populate {
my ($self, $args) = @_;
my $topl = delete $args->{-topl};
my $butl = delete $args->{-butl};
my $botl = delete $args->{-botl};
$self->SUPER::Populate($args);
my (@pl) = qw/-side top -expand yes -fill both/;
$self->{topl} = $self->Label(-text => $topl)->pack(@pl);
$self->{topl}->configure( -image => $topl) if ref($topl);
$self->{butl} = $self->Button(
-text => $butl,
-borderwidth => 2,
)->pack(@pl);
$self->{butl}->configure( -image => $butl) if ref($butl);
$self->{botl} = $self->Label(-text => $botl)->pack(@pl);
$self->{botl}->configure( -image => $botl) if ref($botl);
$self->pack(qw/-side left -expand 1 -fill both -padx 3 -pady 3/);
$self->ConfigSpecs(
-background => [qw/METHOD background background yellow/],
-command => [$self->{butl}, qw/command Command/, undef],
-foreground => [qw/METHOD foreground Foreground red/],
-font => [qw/METHOD font Font fixed/],
-width => [qw/METHOD width Width 20/],
-height => [$self->{butl}, qw/height Height 0/],
);
} # end Populate
sub background {
my ($self, $bg) = @_;
$self->{topl}->configure(-background => $GRAY_LIGHTER);
$self->{butl}->configure(-background => $bg);
$self->{botl}->configure(-background => $GRAY_LIGHTER);
}
sub font {
my ($self) = @_;
$self->{topl}->configure(-font => [qw/arial 9 bold/]);
$self->{butl}->configure(-font => [qw/arial 10 bold/]);
$self->{botl}->configure(-font => [qw/arial 9 bold/]);
}
sub foreground {
my ($self) = @_;
$self->{topl}->configure(-foreground => $ORANGE);
my $text = $self->{butl}->cget(-text);
my $fg = ($text =~ /^[fg]{1}$/) ? 'black' : 'white';
$self->{butl}->configure(-foreground => $fg);
$self->{botl}->configure(-foreground => $BLUE);
}
sub width {
my ($self) = @_;
$self->{topl}->configure(-width => 6);
$self->{butl}->configure(-width => 3);
$self->{botl}->configure(-width => 4);
}
package Tk::Calculator::RPN::HP::Key2_21;
# Composite mega-widget Key2 - 2 operators per key.
use Tk::widgets qw/Frame/;
use base qw/Tk::Frame/;
Construct Tk::Calculator::RPN::HP 'Key2_21';
sub Populate {
my ($self, $args) = @_;
my $butl = delete $args->{-butl};
my $botl = delete $args->{-botl};
$self->SUPER::Populate($args);
my (@pl) = qw/-side top -expand yes -fill both/;
$self->{butl} = $self->Button(
-text => $butl,
-borderwidth => 2,
)->pack(@pl);
$self->{butl}->configure( -image => $butl) if ref($butl);
$self->{botl} = $self->Label(-text => $botl)->pack(@pl);
$self->{botl}->configure( -image => $botl) if ref($botl);
$self->pack(qw/-side left -expand 1 -fill both -padx 3 -pady 3/);
$self->ConfigSpecs(
-background => [qw/METHOD background background yellow/],
-command => [$self->{butl}, qw/command Command/, undef],
-foreground => [qw/METHOD foreground Foreground red/],
-font => [qw/METHOD font Font fixed/],
-width => [qw/METHOD width Width 20/],
-height => [$self->{butl}, qw/height Height 0/],
);
} # end Populate
sub background {
my ($self, $bg) = @_;
my $text = $self->{butl}->cget(-text);
$bg = $BLUE if $text eq 'BLUE';
$self->{butl}->configure(-background => $bg);
$self->{botl}->configure(-background => $GRAY_LIGHTER);
}
sub font {
my ($self) = @_;
$self->{butl}->configure(-font => [qw/arial 10 bold/]);
$self->{botl}->configure(-font => [qw/arial 9 bold/]);
}
sub foreground {
my ($self) = @_;
my $text = $self->{butl}->cget(-text);
my $fg = ($text =~ /^[\.\-\+\/x0123456789]$/ or
$text eq 'DSP') ? 'black' : 'white';
$fg = $BLUE if $text eq 'BLUE';
$self->{butl}->configure(-foreground => $fg);
$self->{botl}->configure(-foreground => $BLUE);
}
sub width {
my ($self) = @_;
$self->{butl}->configure(-width => 3);
$self->{botl}->configure(-width => 4);
}
1;
__END__
=head1 NAME
Tk::Calculator::RPN::HP - Hewlett-Packard RPN calculators
=head1 SYNOPSIS
use Tk::Calculator::RPN::HP;
$mw->Calculator(
-type => '21' | '16c'
)->pack;
=head1 DESCRIPTION
Tk::Calculator::RPN::HP is the OO base class and Exporter module for
Perl/Tk Hewlett-Packard Reverse Polish Notation (RPN) calculators. As
a base class it provides methods common to all calculators; for
instance, stack manipulation, function evaluation, and instance
creation activities. As an exporter of data, it provides global
variables and function subroutine definitions.
Tk::Calculator::RPN::HP provides a single constructor, B<Calculator>,
as shown in the B<SYNOPSIS> section.
Tk::Calculator::RPN::HP provides a B<Populate> method implicity used
by all calculator subclasses. The only option that B<Populate> requires
is I<-type>, the type of calculator. Given I<-type>, B<Populate> loads the
appropriate module, performs common instance pre-initialization, and then
calls out to the subclass' B<Populate> method to create the actual
calculator.
Subclasses of Tk::Calculator::RPN::HP have this basic structure:
$Tk::Calculator::RPN::HP_21::VERSION = '1.2';
package Tk::Calculator::RPN::HP_21;
use Tk::widgets qw/SlideSwitch/;
use Tk::Calculator::RPN::HP;
use base qw/Tk::Calculator::RPN::HP/;
use strict;
our $HELP;
sub ClassInit {
my ($class, $mw) = @_;
$HELP = $class->build_help_window($mw);
$class->SUPER::ClassInit($mw);
} # end ClassInit
sub Populate {
my ($self, $args) = @_;
...
$self->build_help_button($frame1, $HELP)->pack(qw/-side left/);
...
} # end Populate
# Function key processors.
sub clxclr {
my ($self) = @_;
return unless $self->{ONOFF};
if ($self->{G_PRESSED}) { # clr
$self->clr;
} else { # clx
$self->clx;
}
} # end clxclr
1;
As you can see, the module is simply a standard Perl/Tk mega-widget.
You are required to invoke two methods, B<build_help_window> and
B<build_help_button>. B<build_help_window> creates a Toplevel that's
exposed when the ? Button is pressed. B<build_help_button> builds the ?
Button proper. Because the Toplevel help window is used by all class
instances, it's typically created in B<ClassInit>. You call
B<build_help_button> when and where you want the ? packed.
Although most calculator functions are provided by the base class,
you may find it necessary to write your own function key processors.
=head1 OPTIONS
The following option/value pairs are supported:
=over 4
=item B<-type>
The type of HP RPN calculator. Currently I<21> and I<16c> are legal
values. There is no default, this option is required.
=item B<-progressbar>
An optional reference to a Tk::ProgressBar::Mac widget. If specified,
you are to update it periodically as the calculator takes shape.
=back
=head1 METHODS
=head2 $HELP = $class->build_help_window($mw);
Build a standard calculator help window and return a reference
to the Toplevel. You must provide an image
I<"images/hp_"> B<concat> I<lc(-type)> B<concat> I<"-back.gif">
(e.g. images/hp_21-back.gif) of
the back of the calculator, since there might be useful data.
B<ClassInit> is a good place to do this.
=head2 $self->build_help_button($parent, $HELP);
Build the ? Button that displays the Toplevel window created by
B<build_help_window>. I<$parent> is the Button's parent widget.
=head1 ADVERTISED WIDGETS
Component subwidgets can be accessed via the B<Subwidget> method.
This mega widget has no advertised subwidgets.
=head1 EXAMPLE
This complete example incorprates a splashscreen with a progressbar.
use Tk;
use Tk::Calculator::RPN::HP;
use Tk::ProgressBar::Mac;
use Tk::Splashscreen;
use subs qw/main/;
use strict;
main;
sub main {
my $type = $OPT{type};
my $mw = MainWindow->new;
$mw->withdraw;
$mw->title('Hewlett-Packard ' . $type . ' Calculator');
$mw->iconname('HP ' . $type);
my $splash = $mw->Splashscreen;
$splash->Label(
-text => 'Building your HP ' . $type . ' ...',
)->pack(qw/-fill both -expand 1/);
my $pb = $splash->ProgressBar(-width => 300);
$pb->pack(qw/-fill both -expand 1/);
$splash->Label(
-image => $mw->Photo(
-file => Tk->findINC('Calculator/RPN/images/hp_' . $type . '-splash.gif')
),
)->pack;
$splash->Splash;
$mw->Calculator(
-type => $type,
-progressbar => $pb,
)->pack;
$splash->Destroy;
$mw->deiconify;
MainLoop;
} # end main
=head1 AUTHOR
sol0@Lehigh.EDU
Copyright (C) 2001 - 2007, Steve Lidie. All rights reserved.
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.
=head1 KEYWORDS
calculator, HP, RPN
=cut