| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package Lirc::Client; | 
| 2 |  |  |  |  |  |  |  | 
| 3 |  |  |  |  |  |  | # ABSTRACT: A client library for the Linux Infrared Remote Control | 
| 4 |  |  |  |  |  |  |  | 
| 5 | 7 |  |  | 7 |  | 178126 | use strict; | 
|  | 7 |  |  |  |  | 17 |  | 
|  | 7 |  |  |  |  | 234 |  | 
| 6 | 7 |  |  | 7 |  | 37 | use warnings; | 
|  | 7 |  |  |  |  | 12 |  | 
|  | 7 |  |  |  |  | 181 |  | 
| 7 | 7 |  |  | 7 |  | 6358 | use Moo; | 
|  | 7 |  |  |  |  | 155485 |  | 
|  | 7 |  |  |  |  | 46 |  | 
| 8 | 7 |  |  | 7 |  | 13067 | use Carp; | 
|  | 7 |  |  |  |  | 14 |  | 
|  | 7 |  |  |  |  | 551 |  | 
| 9 | 7 |  |  | 7 |  | 6297 | use IO::Socket; | 
|  | 7 |  |  |  |  | 214228 |  | 
|  | 7 |  |  |  |  | 109 |  | 
| 10 | 7 |  |  | 7 |  | 10995 | use File::Path::Expand; | 
|  | 7 |  |  |  |  | 98824 |  | 
|  | 7 |  |  |  |  | 26348 |  | 
| 11 |  |  |  |  |  |  |  | 
| 12 |  |  |  |  |  |  | our $VERSION = '2.02'; | 
| 13 |  |  |  |  |  |  |  | 
| 14 |  |  |  |  |  |  | has prog => ( is => 'ro', required => 1 );   # the program name from lircrc file | 
| 15 |  |  |  |  |  |  | has rcfile => ( is => 'ro', default => sub { "$ENV{HOME}/.lircrc" } ); | 
| 16 |  |  |  |  |  |  | has dev => ( is => 'ro', default => sub { '/dev/lircd' } );    # lircd device | 
| 17 |  |  |  |  |  |  | has debug => ( is => 'ro', default => sub { 0 } );    # instance debug flag | 
| 18 |  |  |  |  |  |  | has fake  => ( is => 'ro', default => sub { 0 } );    # fake the lirc connection | 
| 19 |  |  |  |  |  |  | has sock          => ( is => 'rw' );                          # the lircd socket | 
| 20 |  |  |  |  |  |  | has mode          => ( is => 'rw', default => sub { '' } ); | 
| 21 |  |  |  |  |  |  | has _in_block     => ( is => 'rw', default => sub { 0 } ); | 
| 22 |  |  |  |  |  |  | has _commands     => ( is => 'rw', default => sub { {} } ); | 
| 23 |  |  |  |  |  |  | has _startup_mode => ( is => 'rw' ); | 
| 24 |  |  |  |  |  |  | has _buf          => ( is => 'rw', default => sub { '' } ); | 
| 25 |  |  |  |  |  |  |  | 
| 26 |  |  |  |  |  |  | sub BUILD { | 
| 27 | 6 |  |  | 6 | 0 | 78 | my $self = shift; | 
| 28 |  |  |  |  |  |  |  | 
| 29 | 6 | 50 |  |  |  | 44 | if ( $self->fake ) { | 
| 30 | 6 |  |  |  |  | 58 | $self->sock( \*STDIN ); | 
| 31 |  |  |  |  |  |  | } else { | 
| 32 | 0 | 0 |  |  |  | 0 | $self->sock( | 
| 33 |  |  |  |  |  |  | IO::Socket->new( | 
| 34 |  |  |  |  |  |  | Domain => &AF_UNIX, | 
| 35 |  |  |  |  |  |  | Type   => SOCK_STREAM, | 
| 36 |  |  |  |  |  |  | Peer   => $self->dev, | 
| 37 |  |  |  |  |  |  | ) ) or croak "couldn't connect to $self->dev: $!"; | 
| 38 |  |  |  |  |  |  | } | 
| 39 |  |  |  |  |  |  |  | 
| 40 | 6 |  |  |  |  | 37 | $self->_parse_lircrc( $self->rcfile ); | 
| 41 | 6 | 100 |  |  |  | 43 | $self->mode( $self->_startup_mode ) if defined $self->_startup_mode; | 
| 42 | 6 |  |  |  |  | 153 | return 1; | 
| 43 |  |  |  |  |  |  | } | 
| 44 |  |  |  |  |  |  |  | 
| 45 |  |  |  |  |  |  | sub BUILDARGS { | 
| 46 | 6 |  |  | 6 | 0 | 29716 | my ( $class, @args ) = @_; | 
| 47 |  |  |  |  |  |  |  | 
| 48 | 6 |  |  |  |  | 17 | my $cfg       = {}; | 
| 49 | 6 |  |  |  |  | 29 | my @arg_names = qw{prog rcfile dev debug fake};    # get any passed by order | 
| 50 |  |  |  |  |  |  |  | 
| 51 | 6 | 100 | 66 |  |  | 671 | carp | 
| 52 |  |  |  |  |  |  | "positional parameters for constructor is depreciated and will be removed from a future version" | 
| 53 |  |  |  |  |  |  | if @args and ref $args[0] ne 'HASH'; | 
| 54 |  |  |  |  |  |  |  | 
| 55 | 6 |  | 100 |  |  | 162 | while ( @args and ref $args[0] ne 'HASH' ) { | 
| 56 | 6 |  |  |  |  | 7 | my $arg_name = shift @arg_names; | 
| 57 | 6 |  |  |  |  | 6 | my $arg_val  = shift @args; | 
| 58 | 6 | 100 |  |  |  | 30 | $cfg->{$arg_name} = $arg_val if defined $arg_val; | 
| 59 |  |  |  |  |  |  | } | 
| 60 |  |  |  |  |  |  |  | 
| 61 | 6 | 100 |  |  |  | 30 | if ( ref $args[0] eq 'HASH' ) { | 
| 62 | 5 |  |  |  |  | 14 | $cfg = { %$cfg, %{ shift @args } };    # Merge the two hashes | 
|  | 5 |  |  |  |  | 26 |  | 
| 63 |  |  |  |  |  |  | } | 
| 64 |  |  |  |  |  |  |  | 
| 65 | 6 | 50 |  |  |  | 24 | croak "new expects list of args or hash ref of named args" if @args; | 
| 66 | 6 |  |  |  |  | 143 | return $cfg; | 
| 67 |  |  |  |  |  |  | } | 
| 68 |  |  |  |  |  |  |  | 
| 69 |  |  |  |  |  |  | sub clean_up { | 
| 70 | 6 |  |  | 6 | 1 | 12 | my $self = shift; | 
| 71 |  |  |  |  |  |  |  | 
| 72 | 6 | 50 |  |  |  | 35 | if ( defined $self->sock ) { | 
| 73 | 6 | 50 |  |  |  | 30 | close $self->sock unless $self->fake; | 
| 74 |  |  |  |  |  |  | } | 
| 75 |  |  |  |  |  |  |  | 
| 76 | 6 |  |  |  |  | 14 | return; | 
| 77 |  |  |  |  |  |  | } | 
| 78 |  |  |  |  |  |  |  | 
| 79 |  |  |  |  |  |  | sub _parse_lircrc {    ## no critic | 
| 80 | 9 |  |  | 9 |  | 26 | my ( $self, $rcfilename ) = @_; | 
| 81 |  |  |  |  |  |  |  | 
| 82 | 9 | 50 |  |  |  | 369 | open( my $rcfile, '<', $rcfilename ) | 
| 83 |  |  |  |  |  |  | or croak "couldn't open lircrc file ($rcfilename): $!"; | 
| 84 |  |  |  |  |  |  |  | 
| 85 | 9 |  |  |  |  | 15 | my $in_block = 0; | 
| 86 | 9 |  |  |  |  | 19 | my $cur_mode = ''; | 
| 87 | 9 |  |  |  |  | 19 | my $ops      = {}; | 
| 88 |  |  |  |  |  |  |  | 
| 89 | 9 |  |  |  |  | 275 | while (<$rcfile>) { | 
| 90 | 238 |  |  |  |  | 424 | s/^\s*#.*$//g;    # remove commented lines | 
| 91 | 238 |  |  |  |  | 254 | chomp; | 
| 92 | 238 | 100 |  |  |  | 10944 | print "> ($rcfilename) ($cur_mode) $_\n" if $self->debug; | 
| 93 |  |  |  |  |  |  |  | 
| 94 |  |  |  |  |  |  | ## begin block | 
| 95 | 238 | 100 |  |  |  | 854 | /^\s*begin\s*$/i && do { | 
| 96 | 36 | 50 |  |  |  | 68 | $in_block && croak "Found begin inside a block in line: $_\n"; | 
| 97 | 36 |  |  |  |  | 40 | $in_block = 1; | 
| 98 | 36 |  |  |  |  | 127 | next; | 
| 99 |  |  |  |  |  |  | }; | 
| 100 |  |  |  |  |  |  |  | 
| 101 |  |  |  |  |  |  | ## end block | 
| 102 | 202 | 100 |  |  |  | 490 | /^\s*end\s*$/i && do { | 
| 103 | 36 | 50 |  |  |  | 163 | croak "found end outside of a block in line: $_\n" unless $in_block; | 
| 104 |  |  |  |  |  |  |  | 
| 105 | 36 | 100 | 100 |  |  | 113 | if ( defined $ops->{flags} && $ops->{flags} =~ /\bstartup_mode\b/ ) | 
| 106 |  |  |  |  |  |  | { | 
| 107 | 1 | 50 |  |  |  | 3 | croak "startup_mode flag given without a mode line" | 
| 108 |  |  |  |  |  |  | unless defined $ops->{mode}; | 
| 109 | 1 |  |  |  |  | 6 | $self->_startup_mode( $ops->{mode} ); | 
| 110 | 1 |  |  |  |  | 3 | next; | 
| 111 |  |  |  |  |  |  | } | 
| 112 |  |  |  |  |  |  |  | 
| 113 | 35 | 50 |  |  |  | 67 | croak "end of block found without a prog code at line: $_\n" | 
| 114 |  |  |  |  |  |  | unless defined $ops->{prog}; | 
| 115 | 35 |  | 100 |  |  | 87 | $ops->{remote} ||= '*'; | 
| 116 | 35 |  |  |  |  | 92 | my $key = join '-', $ops->{remote}, $ops->{button}, $cur_mode; | 
| 117 | 35 |  |  |  |  | 36 | my $val = $ops; | 
| 118 |  |  |  |  |  |  |  | 
| 119 | 35 |  |  |  |  | 44 | $in_block = 0; | 
| 120 | 35 |  |  |  |  | 50 | $ops      = {}; | 
| 121 |  |  |  |  |  |  |  | 
| 122 | 35 | 50 |  |  |  | 108 | next unless $val->{prog} eq $self->prog; | 
| 123 |  |  |  |  |  |  |  | 
| 124 | 35 |  |  |  |  | 102 | $self->_commands->{$key} = $val; | 
| 125 |  |  |  |  |  |  |  | 
| 126 | 35 |  |  |  |  | 117 | next; | 
| 127 |  |  |  |  |  |  | }; | 
| 128 |  |  |  |  |  |  |  | 
| 129 |  |  |  |  |  |  | ## token = arg | 
| 130 | 166 | 100 |  |  |  | 753 | /^\s*([\w-]+)\s*=\s*(.*?)\s*$/ && do { | 
| 131 | 138 |  |  |  |  | 347 | my ( $tok, $act ) = ( $1, $2 ); | 
| 132 | 138 | 50 |  |  |  | 538 | croak "unknown token found in rc file: $_\n" | 
| 133 |  |  |  |  |  |  | unless $tok =~ /^(prog|remote|button|repeat|config|mode|flags)$/i; | 
| 134 | 138 |  |  |  |  | 282 | $ops->{$tok} = $act; | 
| 135 |  |  |  |  |  |  |  | 
| 136 | 138 |  |  |  |  | 409 | next; | 
| 137 |  |  |  |  |  |  | }; | 
| 138 |  |  |  |  |  |  |  | 
| 139 |  |  |  |  |  |  | ## begin mode | 
| 140 | 28 | 100 |  |  |  | 70 | /^\s*begin\s*([\w-]+)\s*$/i && do { | 
| 141 | 4 | 50 | 33 |  |  | 30 | croak "found embedded mode line: $_\n" if $1 && $cur_mode; | 
| 142 | 4 | 100 |  |  |  | 25 | $self->_startup_mode($1) if $1 eq $self->prog; | 
| 143 | 4 |  |  |  |  | 7 | $cur_mode = $1; | 
| 144 | 4 |  |  |  |  | 12 | next; | 
| 145 |  |  |  |  |  |  | }; | 
| 146 |  |  |  |  |  |  |  | 
| 147 |  |  |  |  |  |  | ## end mode | 
| 148 | 24 | 100 |  |  |  | 53 | /^\s*end\s*([\w-]+)\s*$/i && do { | 
| 149 | 4 | 50 |  |  |  | 12 | croak "end $1: found inside a begin/end block" if $in_block; | 
| 150 | 4 | 50 |  |  |  | 15 | croak "end $1: found without associated begin mode" | 
| 151 |  |  |  |  |  |  | unless $cur_mode eq $1; | 
| 152 |  |  |  |  |  |  |  | 
| 153 | 4 |  |  |  |  | 6 | $cur_mode = ''; | 
| 154 | 4 |  |  |  |  | 13 | next; | 
| 155 |  |  |  |  |  |  | }; | 
| 156 |  |  |  |  |  |  |  | 
| 157 |  |  |  |  |  |  | ## include file | 
| 158 | 20 | 100 |  |  |  | 43 | /^include\s+(.*)\s*$/ && do { | 
| 159 | 3 |  |  |  |  | 9 | my $file = $1; | 
| 160 | 3 |  |  |  |  | 54 | $file =~ s/^["<]|[">]$//g; | 
| 161 | 3 |  |  |  |  | 7 | $file = eval { expand_filename($file) }; | 
|  | 3 |  |  |  |  | 19 |  | 
| 162 | 3 | 50 |  |  |  | 37 | croak "error parsing include statement: $_\n" if $@; | 
| 163 | 3 | 50 |  |  |  | 63 | croak "could not find file ($file) in include: $_\n" | 
| 164 |  |  |  |  |  |  | unless -r $file; | 
| 165 | 3 |  |  |  |  | 39 | $self->_parse_lircrc($file); | 
| 166 | 3 |  |  |  |  | 9 | next; | 
| 167 |  |  |  |  |  |  | }; | 
| 168 |  |  |  |  |  |  |  | 
| 169 |  |  |  |  |  |  | ## blank lines | 
| 170 | 17 | 50 |  |  |  | 127 | /^\s*$/ && next; | 
| 171 |  |  |  |  |  |  |  | 
| 172 |  |  |  |  |  |  | ## unrecognized | 
| 173 | 0 |  |  |  |  | 0 | croak sprintf "Couldn't parse lircrc file (%s) error in line: %s\n", | 
| 174 |  |  |  |  |  |  | $self->rcfile, $_; | 
| 175 |  |  |  |  |  |  | } | 
| 176 | 9 |  |  |  |  | 98 | close $rcfile; | 
| 177 |  |  |  |  |  |  |  | 
| 178 | 9 |  |  |  |  | 41 | return; | 
| 179 |  |  |  |  |  |  | } | 
| 180 |  |  |  |  |  |  |  | 
| 181 |  |  |  |  |  |  | sub recognized_commands { | 
| 182 | 2 |  |  | 2 | 1 | 1588 | my $self = shift; | 
| 183 |  |  |  |  |  |  |  | 
| 184 | 2 |  |  |  |  | 19 | return $self->_commands; | 
| 185 |  |  |  |  |  |  | } | 
| 186 |  |  |  |  |  |  |  | 
| 187 |  |  |  |  |  |  | sub _get_lines { | 
| 188 | 1 |  |  | 1 |  | 2 | my $self = shift; | 
| 189 |  |  |  |  |  |  |  | 
| 190 |  |  |  |  |  |  | # what is in the buffer now? | 
| 191 | 1 | 50 |  |  |  | 5 | printf "buffer1=%s\n", $self->_buf if $self->debug; | 
| 192 |  |  |  |  |  |  |  | 
| 193 |  |  |  |  |  |  | # read anything in the pipe | 
| 194 | 1 |  |  |  |  | 1 | my $buf; | 
| 195 | 1 |  |  |  |  | 14 | my $status = sysread( $self->sock, $buf, 512 ); | 
| 196 | 1 | 50 | 0 |  |  | 4 | ( carp "bad status from read" and return ) unless defined $status; | 
| 197 |  |  |  |  |  |  |  | 
| 198 |  |  |  |  |  |  | # what is in the buffer after the read? | 
| 199 | 1 |  |  |  |  | 3 | $self->{_buf} .= $buf; | 
| 200 | 1 | 50 |  |  |  | 4 | print "buffer2=%s\n", $self->_buf if $self->debug; | 
| 201 |  |  |  |  |  |  |  | 
| 202 |  |  |  |  |  |  | # separate the lines, leaving partial lines on _buf | 
| 203 | 1 |  |  |  |  | 2 | my @lines; | 
| 204 | 1 |  |  |  |  | 16 | push @lines, $1 while ( $self->{_buf} =~ s/^(.+)\n// );    ## no critic | 
| 205 |  |  |  |  |  |  | # while() tests that s/// matched | 
| 206 |  |  |  |  |  |  |  | 
| 207 | 1 |  |  |  |  | 3 | return @lines; | 
| 208 |  |  |  |  |  |  | } | 
| 209 |  |  |  |  |  |  |  | 
| 210 |  |  |  |  |  |  | sub nextcodes { | 
| 211 | 0 |  |  | 0 | 1 | 0 | return shift->next_codes(); | 
| 212 |  |  |  |  |  |  | } | 
| 213 |  |  |  |  |  |  |  | 
| 214 |  |  |  |  |  |  | sub next_codes { | 
| 215 | 1 |  |  | 1 | 1 | 989 | my $self = shift; | 
| 216 |  |  |  |  |  |  |  | 
| 217 | 1 |  |  |  |  | 5 | my @lines = $self->_get_lines; | 
| 218 | 1 | 0 |  |  |  | 5 | print "==", join( ", ", map { defined $_ ? $_ : "undef" } @lines ), "\n" | 
|  | 0 | 50 |  |  |  | 0 |  | 
| 219 |  |  |  |  |  |  | if $self->debug; | 
| 220 | 1 | 50 |  |  |  | 4 | return () unless scalar @lines; | 
| 221 | 1 |  |  |  |  | 1 | my @commands = (); | 
| 222 | 1 |  |  |  |  | 3 | for my $line (@lines) { | 
| 223 | 2 |  |  |  |  | 3 | chomp $line; | 
| 224 | 2 | 50 |  |  |  | 7 | print "Line: $line\n" if $self->debug; | 
| 225 | 2 |  |  |  |  | 6 | my $command = $self->parse_line($line); | 
| 226 | 2 | 0 |  |  |  | 10 | print "Command: ", ( defined $command ? $command : "undef" ), "\n" | 
|  |  | 50 |  |  |  |  |  | 
| 227 |  |  |  |  |  |  | if $self->debug; | 
| 228 | 2 | 50 |  |  |  | 7 | push @commands, $command if defined $command; | 
| 229 |  |  |  |  |  |  | } | 
| 230 | 1 |  |  |  |  | 5 | return @commands; | 
| 231 |  |  |  |  |  |  | } | 
| 232 |  |  |  |  |  |  |  | 
| 233 |  |  |  |  |  |  | sub nextcode { | 
| 234 | 0 |  |  | 0 | 1 | 0 | return shift->next_code(); | 
| 235 |  |  |  |  |  |  | } | 
| 236 |  |  |  |  |  |  |  | 
| 237 |  |  |  |  |  |  | sub next_code { | 
| 238 | 9 |  |  | 9 | 1 | 15559 | my $self = shift; | 
| 239 |  |  |  |  |  |  |  | 
| 240 | 9 |  |  |  |  | 26 | my $fh = $self->sock; | 
| 241 | 9 |  |  |  |  | 43 | while ( defined( my $line = <$fh> ) ) { | 
| 242 | 12 |  |  |  |  | 17 | chomp $line; | 
| 243 | 12 | 50 |  |  |  | 56 | print "Line: $line\n" if $self->debug; | 
| 244 | 12 |  |  |  |  | 27 | my $command = $self->parse_line($line); | 
| 245 | 12 | 0 |  |  |  | 30 | print "Command: ", ( defined $command ? $command : "undef" ), "\n" | 
|  |  | 50 |  |  |  |  |  | 
| 246 |  |  |  |  |  |  | if $self->debug; | 
| 247 | 12 | 100 |  |  |  | 242 | return $command if defined $command; | 
| 248 |  |  |  |  |  |  | } | 
| 249 | 0 |  |  |  |  | 0 | return;    # no command found and lirc exited? | 
| 250 |  |  |  |  |  |  | } | 
| 251 |  |  |  |  |  |  |  | 
| 252 |  |  |  |  |  |  | sub parse_line {    ## parse a line read from lircd | 
| 253 | 14 |  |  | 14 | 1 | 18 | my $self = shift; | 
| 254 | 14 |  |  |  |  | 24 | $_ = shift; | 
| 255 |  |  |  |  |  |  |  | 
| 256 | 14 | 50 |  |  |  | 43 | printf "> (%s) %s\n", $self->_in_block, $_ if $self->debug; | 
| 257 |  |  |  |  |  |  |  | 
| 258 |  |  |  |  |  |  | # Take care of response blocks | 
| 259 |  |  |  |  |  |  | ## Right Lirc::Client doesn't support LIST or VERSION, so we can ignore | 
| 260 |  |  |  |  |  |  | ## Responses that come inside a block | 
| 261 | 14 | 50 |  |  |  | 39 | if (/^\s*BEGIN\s*$/) { | 
| 262 | 0 | 0 |  |  |  | 0 | croak "got BEGIN inside a block from lircd: $_" if $self->_in_block; | 
| 263 | 0 |  |  |  |  | 0 | $self->_in_block(1); | 
| 264 | 0 |  |  |  |  | 0 | return; | 
| 265 |  |  |  |  |  |  | } | 
| 266 | 14 | 50 |  |  |  | 32 | if (/^\s*END\s*$/) { | 
| 267 | 0 | 0 |  |  |  | 0 | croak "got END outside a block from lircd: $_" if !$self->_in_block; | 
| 268 | 0 |  |  |  |  | 0 | $self->_in_block(0); | 
| 269 | 0 |  |  |  |  | 0 | return; | 
| 270 |  |  |  |  |  |  | } | 
| 271 | 14 | 50 |  |  |  | 35 | return if $self->_in_block; | 
| 272 |  |  |  |  |  |  |  | 
| 273 |  |  |  |  |  |  | # Decipher IR Command | 
| 274 |  |  |  |  |  |  | # http://www.lirc.org/html/technical.html#applications | 
| 275 |  |  |  |  |  |  | # | 
| 276 | 14 |  |  |  |  | 50 | my ( $hex, $repeat, $button, $remote ) = split /\s+/; | 
| 277 | 14 | 50 | 33 |  |  | 76 | defined $button and length $button or do { | 
| 278 | 0 |  |  |  |  | 0 | carp "Unable to decode.\n"; | 
| 279 | 0 |  |  |  |  | 0 | return; | 
| 280 |  |  |  |  |  |  | }; | 
| 281 |  |  |  |  |  |  |  | 
| 282 | 14 |  |  |  |  | 27 | my $commands = $self->_commands; | 
| 283 | 14 |  |  |  |  | 28 | my $cur_mode = $self->mode; | 
| 284 | 14 |  | 66 |  |  | 75 | my $command = | 
| 285 |  |  |  |  |  |  | $commands->{"$remote-$button-$cur_mode"} | 
| 286 |  |  |  |  |  |  | || $commands->{"*-$button-$cur_mode"} | 
| 287 |  |  |  |  |  |  | || $commands->{"$remote-*-$cur_mode"}; | 
| 288 | 14 | 50 |  |  |  | 27 | defined $command or return; | 
| 289 |  |  |  |  |  |  |  | 
| 290 | 14 |  |  |  |  | 25 | my $rep_count = | 
| 291 |  |  |  |  |  |  | $command->{repeat};    # default repeat count is 0 (ignore repeated keys) | 
| 292 | 14 | 50 |  |  |  | 57 | return if $rep_count ? hex($repeat) % $rep_count : hex $repeat; | 
|  |  | 50 |  |  |  |  |  | 
| 293 |  |  |  |  |  |  |  | 
| 294 | 14 | 100 | 66 |  |  | 59 | if ( defined $command->{flags} && $command->{flags} =~ /\bmode\b/ ) { | 
| 295 | 2 |  |  |  |  | 7 | $self->mode(''); | 
| 296 |  |  |  |  |  |  | } | 
| 297 | 14 | 100 |  |  |  | 27 | if ( defined $command->{mode} ) { $self->mode( $command->{mode} ); } | 
|  | 1 |  |  |  |  | 5 |  | 
| 298 |  |  |  |  |  |  |  | 
| 299 | 14 | 100 |  |  |  | 36 | return unless defined $command->{config}; | 
| 300 | 11 | 50 |  |  |  | 45 | printf ">> %s accepted --> %s\n", $button, $command->{config} | 
| 301 |  |  |  |  |  |  | if $self->debug; | 
| 302 | 11 |  |  |  |  | 32 | return $command->{config}; | 
| 303 |  |  |  |  |  |  | } | 
| 304 |  |  |  |  |  |  |  | 
| 305 |  |  |  |  |  |  | sub DEMOLISH { | 
| 306 | 6 |  |  | 6 | 0 | 11263 | my $self = shift; | 
| 307 | 6 | 100 |  |  |  | 300 | print __PACKAGE__, ": DEMOLISH\n" if $self->debug; | 
| 308 |  |  |  |  |  |  |  | 
| 309 | 6 |  |  |  |  | 28 | $self->clean_up; | 
| 310 | 6 |  |  |  |  | 132 | return; | 
| 311 |  |  |  |  |  |  | } | 
| 312 |  |  |  |  |  |  |  | 
| 313 |  |  |  |  |  |  | 1; | 
| 314 |  |  |  |  |  |  |  | 
| 315 |  |  |  |  |  |  | __END__ |