File Coverage

blib/lib/Proc/ProcessTable/Colorizer.pm
Criterion Covered Total %
statement 23 537 4.2
branch 0 232 0.0
condition 0 216 0.0
subroutine 8 37 21.6
pod 26 29 89.6
total 57 1051 5.4


line stmt bran cond sub pod time code
1             package Proc::ProcessTable::Colorizer;
2              
3 1     1   69853 use 5.006;
  1         4  
4 1     1   6 use strict;
  1         2  
  1         21  
5 1     1   5 use warnings;
  1         2  
  1         47  
6 1     1   7 use base 'Error::Helper';
  1         2  
  1         553  
7 1     1   1343 use Proc::ProcessTable;
  1         5251  
  1         46  
8 1     1   750 use Term::ANSIColor;
  1         9021  
  1         67  
9 1     1   634 use Text::Table;
  1         10840  
  1         32  
10 1     1   489 use Term::Size;
  1         568  
  1         5984  
11              
12             =head1 NAME
13              
14             Proc::ProcessTable::Colorizer - Like ps, but with colored columns and enhnaced functions for searching.
15              
16             =head1 VERSION
17              
18             Version 0.3.0
19              
20             =cut
21              
22             our $VERSION = '0.3.0';
23              
24              
25             =head1 SYNOPSIS
26              
27             use Proc::ProcessTable::Colorizer;
28              
29             my $cps = Proc::ProcessTable::Colorizer->new;
30             print $cps->colorize;
31              
32             This module uses L for error reporting.
33              
34             As of right now this module is not really user friend and will likely be going through lots of changes as it grows.
35              
36             =head1 METHODS
37              
38             =head2 new
39              
40             Creates a new object. This method will never error.
41              
42             my $cps=Proc::ProcessTable::Colorizer->new;
43              
44             =cut
45              
46             sub new {
47 0     0 1   my $self={
48             perror=>undef,
49             error=>undef,
50             errorString=>'',
51             errorExtra=>{
52             1=>'badTimeString',
53             2=>'badPctcpuString',
54             },
55             colors=>[
56             'BRIGHT_YELLOW',
57             'BRIGHT_CYAN',
58             'BRIGHT_MAGENTA',
59             'BRIGHT_BLUE'
60             ],
61             timeColors=>[
62             'GREEN',
63             'BRIGHT_GREEN',
64             'RED',
65             'BRIGHT_RED'
66             ],
67             processColor=>'WHITE',
68             fields=>[
69             'pid',
70             'uid',
71             'pctcpu',
72             'pctmem',
73             'size',
74             'rss',
75             'info',
76             'nice',
77             'start',
78             'time',
79             'proc',
80             ],
81             header=>1,
82             search=>undef,
83             resolveUser=>1,
84             nextColor=>0,
85             showIdle=>0,
86             proc_search=>undef,
87             user_search=>[],
88             wait_search=>[],
89             self_ignore=>2,
90             zombie_search=>0,
91             swapped_out_search=>0,
92             time_search=>[],
93             pctcpu_search=>[],
94             };
95 0           bless $self;
96              
97 0 0         if ($^O =~ /bsd/){
98 0           $self->{physmem}=`/sbin/sysctl -a hw.physmem`;
99 0           chomp($self->{physmem});
100 0           $self->{physmem}=~s/^.*\: //;
101             }
102              
103 0           return $self;
104             }
105              
106             =head2 colorize
107              
108             This colorizes it and returns a setup Text::Table object with everything already setup.
109              
110             use Proc::ProcessTable::Colorizer;
111             my $cps = Proc::ProcessTable::Colorizer->new;
112             print $cps->colorize;
113              
114             =cut
115              
116             sub colorize{
117 0     0 1   my $self=$_[0];
118 0           $self->errorblank;
119              
120             #the feilds to use
121 0           my $fields=$self->fieldsGet;
122              
123             #array of colored items
124 0           my @colored;
125              
126             #
127 0           my $fieldInt=0;
128 0           my $header;
129 0 0         if ( $self->{header} ){
130 0           my @header;
131 0           while ( defined( $fields->[$fieldInt] ) ){
132 0           my $field=color('underline white');
133              
134 0 0         if ( $fields->[$fieldInt] eq 'pid' ){
    0          
    0          
    0          
    0          
    0          
    0          
135 0           $field=$field.'PID';
136             }elsif( $fields->[$fieldInt] eq 'uid' ){
137 0           $field=$field.'User';
138             }elsif( $fields->[$fieldInt] eq 'pctcpu' ){
139 0           $field=$field.'CPU%';
140             }elsif( $fields->[$fieldInt] eq 'pctmem' ){
141 0           $field=$field.'Mem%';
142             }elsif( $fields->[$fieldInt] eq 'size' ){
143 0           $field=$field.'VM Size';
144             }elsif( $fields->[$fieldInt] eq 'rss' ){
145 0           $field=$field.'RSS';
146             }elsif( $fields->[$fieldInt] eq 'proc' ){
147 0           $field=$field.'Command';
148             }else{
149 0           $field=$field.ucfirst($fields->[$fieldInt]);
150             }
151            
152 0           push( @header, $field.color('reset') );
153              
154 0           $fieldInt++;
155             }
156              
157 0           push( @colored, \@header );
158             }
159              
160             #get the process table
161 0           my $pt=Proc::ProcessTable->new;
162              
163             #an array of procs
164 0           my @procs;
165            
166             #goes through it all and gathers the information
167 0           foreach my $proc ( @{$pt->table} ){
  0            
168            
169             #process the requested fields
170 0           $fieldInt=0;
171 0           my %values;
172 0           while ( defined( $fields->[$fieldInt] ) ){
173 0           my $field=$fields->[$fieldInt];
174            
175 0 0 0       if (
    0 0        
    0          
    0          
176             ($^O =~ /bsd/) &&
177             ( $field =~ /pctmem/ )
178             ){
179 0           my $rss=$proc->{rssize};
180 0 0         if ( defined( $rss ) ){
181 0           $rss=$rss*1024*4;
182 0           $values{pctmem}=($rss / $self->{physmem})*100;
183             }else{
184 0           $values{pctmem}=0;
185             }
186             }elsif(
187             ($^O =~ /bsd/) &&
188             ( $field =~ /rss/ )
189             ){
190 0           $values{rss}=$proc->{rssize};
191 0 0         if (!defined $values{rss} ){
192 0           $values{rss}=0;
193             }else{
194             #not sure why this needs done :/
195 0           $values{rss}=$values{rss}*4;
196             }
197             }elsif(
198             $field eq 'proc'
199             ){
200 0           my $fname=$proc->fname;
201 0           my $cmndline=$proc->cmndline;
202              
203             #save it for possible future use
204 0           $values{fname}=$fname;
205 0           $values{cmndline}=$cmndline;
206              
207             #set the proc value
208 0 0         if ( $cmndline =~ /^$/ ){
209 0           my $kernel_proc=1; #just assuming yet, unless it is otherwise
210              
211             #may possible be a zombie, run checks for on FreeBSD
212 0 0 0       if (
213             ($^O =~ /bsd/) &&
214             ( hex($proc->flags) & 0x00200000 )
215             ){
216 0           $kernel_proc=1;
217             }
218              
219             #need to find something similar as above for Linux
220              
221             #
222 0 0         if ( $kernel_proc ){
223 0           $values{'proc'}='['.$fname.']';
224 0 0         if ( $fname eq 'idle' ){
225 0           $values{'idle'}=1;
226             }
227             }else{
228             #most likely a zombie
229 0           $values{'proc'}=$fname;
230             }
231             }else{
232 0 0         if ( $cmndline =~ /^su *$/ ){
233 0           $values{'proc'}=$cmndline.'('.$fname.')';
234             }else{
235 0           $values{'proc'}=$cmndline;
236             }
237             }
238             }elsif(
239             $field eq 'info'
240             ){
241 0           $values{wchan}=$proc->wchan;
242 0           $values{state}=$proc->state;
243              
244 0 0         if ($^O =~ /bsd/){
245 0           $values{is_session_leader}=0;
246 0           $values{is_being_forked}=0;
247 0           $values{working_on_exiting}=0;
248 0           $values{has_controlling_terminal}=0;
249 0           $values{is_locked}=0;
250 0           $values{traced_by_debugger}=0;
251             #$values{is_stopped}=0;
252 0           $values{posix_advisory_lock}=0;
253              
254 0 0         if ( hex($proc->flags) & 0x00002 ){ $values{controlling_tty_active}=1; }
  0            
255 0 0         if ( hex($proc->flags) & 0x00000002 ){$values{is_session_leader}=1; }
  0            
256             #if ( hex($proc->flags) & ){$values{is_being_forked}=1; }
257 0 0         if ( hex($proc->flags) & 0x02000 ){$values{working_on_exiting}=1; }
  0            
258 0 0         if ( hex($proc->flags) & 0x00002 ){$values{has_controlling_terminal}=1; }
  0            
259 0 0         if ( hex($proc->flags) & 0x00000004 ){$values{is_locked}=1; }
  0            
260 0 0         if ( hex($proc->flags) & 0x00800 ){$values{traced_by_debugger}=1; }
  0            
261 0 0         if ( hex($proc->flags) & 0x00001 ){$values{posix_advisory_lock}=1; }
  0            
262             }
263            
264             }else{
265 0           $values{$field}=$proc->$field;
266             }
267              
268            
269 0           $fieldInt++;
270             }
271              
272 0 0         if ( ! defined( $values{pctmem} ) ){
273 0           $values{pctmem} = 0;
274             }
275 0 0         if ( ! defined( $values{pctcpu} ) ){
276 0           $values{pctcpu} = 0;
277             }
278              
279 0 0         if ( ! defined( $values{size} ) ){
280 0           $values{size} = 0;
281             }
282            
283 0           $values{pctmem}=sprintf('%.2f', $values{pctmem});
284 0           $values{pctcpu}=sprintf('%.2f', $values{pctcpu});
285              
286 0           $values{size}=$values{size}/1024;
287              
288 0           push( @procs, \%values );
289              
290             }
291              
292             #sort by CPU percent and then RAM
293             @procs=sort {
294 0           $a->{pctcpu} <=> $b->{pctcpu} or
295             $a->{pctmem} <=> $b->{pctmem} or
296             $a->{rss} <=> $b->{rss} or
297             $a->{size} <=> $b->{size} or
298             $a->{time} <=> $b->{time}
299 0 0 0       } @procs;
      0        
      0        
300 0           @procs=reverse(@procs);
301              
302             #put together the colored colums, minus the proc column which will be done later
303 0           my @proc_column;
304 0           foreach my $proc (@procs){
305 0           my @line;
306 0           $self->nextColorReset;
307              
308 0           my $show=0;
309              
310             #checks if it is the idle proc and if it should show it
311 0 0 0       if (
312             defined ( $proc->{idle} ) &&
313             ( ! $self->{showIdle} )
314             ){
315 0           $show = 0;
316             }else{
317 0           my $required_hits=0; #number of hits required to print it
318 0           my $hits=0; #default to zero so we print it unless we increment this for a search item
319              
320             #checks if we need to do a proc search
321 0           my $proc_search=$self->{proc_search};
322 0 0         if ( defined( $proc_search ) ){
323 0           $required_hits++;
324             #cehck if the cmndline or fname matches
325 0 0         if ( $proc->{proc} =~ /$proc_search/ ){
326 0           $hits++;
327             }
328             }
329              
330             #check to see if it needs to search for users
331 0           my $user_search_array=$self->userSearchGet;
332 0 0         if ( defined( $user_search_array->[0] ) ){
333 0           my $user=getpwuid($proc->{uid});
334 0           $required_hits++;
335 0           my $user_search_int=0;
336 0           my $matched=0;
337             #search while we have a user defined and it has not already been matched
338 0   0       while(
339             defined( $user_search_array->[ $user_search_int ] ) &&
340             ( $matched == 0 )
341             ){
342 0           my $to_match=$user_search_array->[ $user_search_int ];
343 0           my $to_invert=0;
344 0 0         if ( $to_match=~ /^\!/ ){
345 0           $to_invert=1;
346 0           $to_match=~s/^\!//;
347             }
348              
349             #check if it matches
350 0 0         if ( $to_invert ){
351 0 0         if ( $to_match ne $user ){
352 0           $hits++;
353 0           $matched=1;
354             }
355             }else{
356 0 0         if ( $to_match eq $user ){
357 0           $hits++;
358 0           $matched=1;
359             }
360             }
361            
362 0           $user_search_int++;
363             }
364            
365             }
366              
367             #check to see if it needs to search for wait channels
368 0           my $wait_search_array=$self->waitSearchGet;
369 0 0         if ( defined( $wait_search_array->[0] ) ){
370 0           $required_hits++;
371 0           my $wait_search_int=0;
372 0           my $matched=0;
373             #search while we have a wait channel defined and it has not already been matched
374 0   0       while(
375             defined( $wait_search_array->[ $wait_search_int ] ) &&
376             ( $matched == 0 )
377             ){
378 0           my $to_match=$wait_search_array->[ $wait_search_int ];
379 0           my $to_invert=0;
380 0 0         if ( $to_match=~ /^\!/ ){
381 0           $to_invert=1;
382 0           $to_match=~s/^\!//;
383             }
384              
385             #check if it matches
386 0 0         if ( $to_invert ){
387 0 0         if ( $to_match ne $proc->{wchan} ){
388 0           $hits++;
389 0           $matched=1;
390             }
391             }else{
392 0 0         if ( $to_match eq $proc->{wchan} ){
393 0           $hits++;
394 0           $matched=1;
395             }
396             }
397            
398 0           $wait_search_int++;
399             }
400            
401             }
402              
403             #check to see if it needs to search for CPU time usage
404 0           my $time_search_array=$self->timeSearchGet;
405 0 0         if ( defined( $time_search_array->[0] ) ){
406 0           $required_hits++;
407 0           my $time_search_int=0;
408 0           my $matched=0;
409             #search while we have a CPU time defined and it has not already been matched
410 0   0       while(
411             defined( $time_search_array->[ $time_search_int ] ) &&
412             ( $matched == 0 )
413             ){
414 0           my $checked=0;
415 0           my $to_match=$time_search_array->[ $time_search_int ];
416 0           my $time=$proc->{time};
417             #checks for less than or equal
418 0 0 0       if (
419             ( $to_match =~ /^\<\=/ ) &&
420             ( $checked == 0 )
421             ){
422 0           $checked++;
423 0           $to_match =~ s/^\<\=//;
424 0 0         if ( $time <= $to_match ){
425 0           $hits++;
426 0           $matched++;
427             }
428             }
429              
430             #checks for less than
431 0 0 0       if (
432             ( $to_match =~ /^\
433             ( $checked == 0 )
434             ){
435 0           $checked++;
436 0           $to_match =~ s/^\
437 0 0         if ( $time < $to_match ){
438 0           $hits++;
439 0           $matched++;
440             }
441             }
442              
443             #checks for greater than or equal
444 0 0 0       if (
445             ( $to_match =~ /^\>=/ ) &&
446             ( $checked == 0 )
447             ){
448 0           $checked++;
449 0           $to_match =~ s/^\>\=//;
450 0 0         if ( $time >= $to_match ){
451 0           $hits++;
452 0           $matched++;
453             }
454             }
455              
456             #checks for greater than
457 0 0 0       if (
458             ( $to_match =~ /^\>/ ) &&
459             ( $checked == 0 )
460             ){
461 0           $checked++;
462 0           $to_match =~ s/^\>//;
463 0 0         if ( $time > $to_match ){
464 0           $hits++;
465 0           $matched++;
466             }
467             }
468            
469 0           $time_search_int++;
470             }
471            
472             }
473              
474             #check to see if it needs to search for CPU percent
475 0           my $pctcpu_search_array=$self->pctcpuSearchGet;
476 0 0         if ( defined( $pctcpu_search_array->[0] ) ){
477 0           $required_hits++;
478 0           my $pctcpu_search_int=0;
479 0           my $matched=0;
480             #search while we have a CPU usage defined and it has not already been matched
481 0   0       while(
482             defined( $pctcpu_search_array->[ $pctcpu_search_int ] ) &&
483             ( $matched == 0 )
484             ){
485 0           my $checked=0;
486 0           my $to_match=$pctcpu_search_array->[ $pctcpu_search_int ];
487 0           my $time=$proc->{pctcpu};
488             #checks for less than or equal
489 0 0 0       if (
490             ( $to_match =~ /^\<\=/ ) &&
491             ( $checked == 0 )
492             ){
493 0           $checked++;
494 0           $to_match =~ s/^\<\=//;
495 0 0         if ( $time <= $to_match ){
496 0           $hits++;
497 0           $matched++;
498             }
499             }
500              
501             #checks for less than
502 0 0 0       if (
503             ( $to_match =~ /^\
504             ( $checked == 0 )
505             ){
506 0           $checked++;
507 0           $to_match =~ s/^\
508 0 0         if ( $time < $to_match ){
509 0           $hits++;
510 0           $matched++;
511             }
512             }
513              
514             #checks for greater than or equal
515 0 0 0       if (
516             ( $to_match =~ /^\>=/ ) &&
517             ( $checked == 0 )
518             ){
519 0           $checked++;
520 0           $to_match =~ s/^\>\=//;
521 0 0         if ( $time >= $to_match ){
522 0           $hits++;
523 0           $matched++;
524             }
525             }
526              
527             #checks for greater than
528 0 0 0       if (
529             ( $to_match =~ /^\>/ ) &&
530             ( $checked == 0 )
531             ){
532 0           $checked++;
533 0           $to_match =~ s/^\>//;
534 0 0         if ( $time > $to_match ){
535 0           $hits++;
536 0           $matched++;
537             }
538             }
539            
540 0           $pctcpu_search_int++;
541             }
542             }
543              
544             #check to see if it needs to search for memory percent
545 0           my $pctmem_search_array=$self->pctmemSearchGet;
546 0 0         if ( defined( $pctmem_search_array->[0] ) ){
547 0           $required_hits++;
548 0           my $pctmem_search_int=0;
549 0           my $matched=0;
550             #search while we have a memory usage defined and it has not already been matched
551 0   0       while(
552             defined( $pctmem_search_array->[ $pctmem_search_int ] ) &&
553             ( $matched == 0 )
554             ){
555 0           my $checked=0;
556 0           my $to_match=$pctmem_search_array->[ $pctmem_search_int ];
557 0           my $pctmem=$proc->{pctmem};
558             #checks for less than or equal
559 0 0 0       if (
560             ( $to_match =~ /^\<\=/ ) &&
561             ( $checked == 0 )
562             ){
563 0           $checked++;
564 0           $to_match =~ s/^\<\=//;
565 0 0         if ( $pctmem <= $to_match ){
566 0           $hits++;
567 0           $matched++;
568             }
569             }
570              
571             #checks for less than
572 0 0 0       if (
573             ( $to_match =~ /^\
574             ( $checked == 0 )
575             ){
576 0           $checked++;
577 0           $to_match =~ s/^\
578 0 0         if ( $pctmem < $to_match ){
579 0           $hits++;
580 0           $matched++;
581             }
582             }
583              
584             #checks for greater than or equal
585 0 0 0       if (
586             ( $to_match =~ /^\>=/ ) &&
587             ( $checked == 0 )
588             ){
589 0           $checked++;
590 0           $to_match =~ s/^\>\=//;
591 0 0         if ( $pctmem >= $to_match ){
592 0           $hits++;
593 0           $matched++;
594             }
595             }
596              
597             #checks for greater than
598 0 0 0       if (
599             ( $to_match =~ /^\>/ ) &&
600             ( $checked == 0 )
601             ){
602 0           $checked++;
603 0           $to_match =~ s/^\>//;
604 0 0         if ( $pctmem > $to_match ){
605 0           $hits++;
606 0           $matched++;
607             }
608             }
609            
610 0           $pctmem_search_int++;
611             }
612             }
613            
614             #show zombie procs
615 0 0         if ( $self->{zombie_search} ){
616 0           $required_hits++;
617 0 0         if ( $proc->{state} eq 'zombie' ){
618 0           $hits++;
619             }
620             }
621              
622             #show swapped out procs
623 0 0         if ( $self->{swapped_out_search} ){
624 0           $required_hits++;
625 0 0 0       if (
626             ( $proc->{state} ne 'zombie' ) &&
627             ( $proc->{rss} == '0' )
628             ){
629 0           $hits++;
630             }
631             }
632              
633             #checks to see if it should ignore its self
634 0           my $self_ignore=$self->{self_ignore};
635 0 0 0       if (
    0 0        
      0        
636             #if it is set to 1
637             ( $self_ignore == 1 ) &&
638             ( $proc->{pid} == $$ )
639             ){
640 0           $required_hits++;
641             }elsif(
642             #if it is set to 2... we only care if we are doing a search...
643             #meaning required hits are greater than zero
644             ( $required_hits > 0 ) &&
645             ( $self_ignore == 2 ) &&
646             ( $proc->{pid} == $$ )
647             ){
648             #increment this so it will always be off by one for this proc, meaning it is ignored
649 0           $required_hits++;
650             }
651            
652 0 0         if ( $required_hits == $hits ){
653 0           $show=1;
654             }
655             }
656              
657 0 0         if (
658             ( $show )
659             ){
660            
661 0           foreach my $field ( @{$fields} ){
  0            
662 0           my $item='';
663 0 0         if ( defined( $proc->{$field} ) ){
664 0           $item=$proc->{$field};
665             }
666             #we will add proc later once we know the size of the table
667 0 0         if ($field ne 'proc'){
668 0 0         if ( $field eq 'start' ){
669 0           $item=$self->startString($item);
670             }
671            
672 0 0 0       if (
673             ( $field eq 'uid' ) &&
674             $self->{resolveUser}
675             ){
676 0           $item=getpwuid($item);
677             }
678            
679             #colorizes it
680 0 0         if ( $field eq 'time' ){
    0          
    0          
681 0           $item=$self->timeString($item);
682             }elsif( $field eq 'proc' ){
683 0           $item=color($self->processColorGet).$item;
684             }elsif( $field eq 'info'){
685 0           my $left=$proc->{state};
686 0 0         if (
    0          
    0          
    0          
687             $left eq 'sleep'
688             ){
689 0           $left='S';
690             }elsif(
691             $left eq 'zombie'
692             ){
693 0           $left='Z';
694             }elsif(
695             $left eq 'wait'
696             ){
697 0           $left='W';
698             }elsif(
699             $left eq 'run'
700             ){
701 0           $left='R';
702             }
703            
704             #checks if it is swapped out
705 0 0 0       if (
706             ( $proc->{state} ne 'zombie' ) &&
707             ( $proc->{rss} == '0' )
708             ){
709 0           $left=$left.'O';
710             }
711            
712             #waiting to exit
713 0 0 0       if (
714             ( defined( $proc->{working_on_exiting} ) ) &&
715             $proc->{working_on_exiting}
716             ){
717 0           $left=$left.'E';
718             }
719            
720             #session leader
721 0 0 0       if (
722             ( defined( $proc->{is_session_leader} ) ) &&
723             $proc->{is_session_leader}
724             ){
725 0           $left=$left.'s';
726             }
727            
728             #checks to see if any sort of locks are present
729 0 0 0       if (
      0        
      0        
730             ( defined( $proc->{is_locked} ) || defined( $proc->{posix_advisory_lock} ) )&&
731             ( $proc->{is_locked} || $proc->{posix_advisory_lock} )
732             ){
733 0           $left=$left.'L';
734             }
735            
736             #checks to see if has a controlling terminal
737 0 0 0       if (
738             ( defined( $proc->{has_controlling_terminal} ) ) &&
739             $proc->{has_controlling_terminal}
740             ){
741 0           $left=$left.'+';
742             }
743              
744             #if it is being forked
745 0 0 0       if (
746             ( defined( $proc->{is_being_forked} ) ) &&
747             $proc->{is_being_forked}
748             ){
749 0           $left=$left.'F';
750             }
751            
752             #checks if it knows it is being traced
753 0 0 0       if (
754             ( defined( $proc->{traced_by_debugger} ) ) &&
755             $proc->{traced_by_debugger}
756             ){
757 0           $left=$left.'X';
758             }
759            
760 0           $item=color($self->nextColor).$left.' '.color($self->nextColor).$proc->{wchan};
761            
762             }else{
763 0           $item=color($self->nextColor).$item;
764             }
765              
766 0           push( @line, $item.color('reset') );
767             }else{
768 0           push( @proc_column, $item );
769             }
770             }
771            
772 0           push( @colored, \@line );
773             }
774             }
775              
776             #get table width info
777 0           my $tb = Text::Table->new;
778 0           $tb->load( @colored );
779 0           my $width=$tb->width;
780 0           my ($columns, $rows) = Term::Size::chars *STDOUT{IO};
781 0           $tb->clear;
782              
783             #add 120 as Text::Table appears to be off by that much
784 0           $columns=$columns+128;
785              
786             #this is
787 0           my $procwidth=$columns-$width;
788              
789             #process each colored item and shove the proc info in
790 0           my $colored_int=1;
791 0           my $proc_column_int=0;
792 0           while ( defined( $colored[$colored_int] ) ){
793 0           my $item=$proc_column[$proc_column_int];
794             #remove all the newlines
795 0           $item=~s/\n//g;
796              
797 0           $item=substr( $item, 0, $procwidth);
798              
799 0           push( @{$colored[$colored_int]}, $item );
  0            
800              
801 0           $proc_column_int++;
802 0           $colored_int++;
803             }
804            
805 0           return $tb->load( @colored );
806             }
807              
808             =head2 fields
809              
810             Gets a hash of possible fields from Proc::ProcessTable as an hash.
811              
812             This is really meant as a internal function.
813              
814             =cut
815              
816             sub fields{
817 0     0 1   my $self=$_[0];
818 0           $self->errorblank;
819              
820 0           my $p=Proc::ProcessTable->new;
821 0           my @fields=$p->fields;
822              
823 0           my $int=0;
824 0           my %toReturn;
825 0           while( defined($fields[$int]) ){
826 0           $toReturn{$fields[$int]}=1;
827            
828 0           $int++;
829             }
830              
831 0           return %toReturn;
832             }
833              
834             =head2 fieldsGet
835              
836             Gets the currently set fields.
837              
838             Returns a array ref of current fields to be printed.
839              
840             my $fields=$cps->fieldsGet;
841              
842             =cut
843              
844             sub fieldsGet{
845 0     0 1   my $self=$_[0];
846 0           $self->errorblank;
847              
848 0           return $self->{fields};
849             }
850              
851             =head2 nextColor
852              
853             Returns the next color.
854              
855             my $nextColor=$cps->nextColor;
856              
857             =cut
858              
859             sub nextColor{
860 0     0 1   my $self=$_[0];
861 0           $self->errorblank;
862              
863 0           my $color;
864            
865 0 0         if( defined( $self->{colors}[ $self->{nextColor} ] ) ){
866 0           $color=$self->{colors}[ $self->{nextColor} ];
867 0           $self->{nextColor}++;
868             }else{
869 0           $self->{nextColor}=0;
870 0           $color=$self->{colors}[ $self->{nextColor} ];
871 0           $self->{nextColor}++;
872             }
873              
874 0           return $color;
875             }
876              
877             =head2 nextColor
878              
879             Resets the next color to the first one.
880              
881             my $nextColor=$cps->nextColor;
882              
883             =cut
884              
885             sub nextColorReset{
886 0     0 0   my $self=$_[0];
887 0           $self->errorblank;
888              
889 0           $self->{nextColor}=0;
890              
891 0           return 1;
892             }
893              
894             =head2 fieldsSet
895              
896             Gets the currently set fields.
897              
898             Returns a list of current fields to be printed.
899              
900             my @fields=$cps->fieldsGet;
901              
902             =cut
903              
904             sub fieldsSet{
905 0     0 1   my $self=$_[0];
906 0           $self->errorblank;
907              
908              
909             }
910              
911             =head2 pctcpuSearchGet
912              
913             Returns the current value for the PCT CPU search.
914              
915             The return is a array ref.
916              
917             my $pctcpu_search=$cps->pctcpuSearchGet;
918              
919             =cut
920              
921             sub pctcpuSearchGet{
922 0     0 1   my $self=$_[0];
923 0           $self->errorblank;
924              
925 0           return $self->{pctcpu_search};
926             }
927              
928             =head2 pctcpuSearchSetString
929              
930             Search for procs based on the CPU usage.
931              
932             The following equalities are understood.
933              
934             <=
935             <
936             >
937             >=
938              
939             The string may contain multiple values seperated by a comma. Checking will stop after the first hit.
940              
941             If the string is undef, all procs will be shown.
942              
943             #search for procs with less than 60% of CPU usage
944             $cps->pctcpuSearchSetString('<60');
945             #shows procs with greater than 60% of CPU usage
946             $cps->pctcpuSearchSetString('>60');
947              
948             =cut
949              
950             sub pctcpuSearchSetString{
951 0     0 1   my $self=$_[0];
952 0           my $pctcpu_search_string=$_[1];
953 0           $self->errorblank;
954              
955 0           my @pctcpu_search_array;
956 0 0         if ( ! defined( $pctcpu_search_string ) ){
957 0           $self->{pctcpu_search}=\@pctcpu_search_array;
958             }else{
959 0           @pctcpu_search_array=split(/\,/, $pctcpu_search_string);
960              
961 0           foreach my $item ( @pctcpu_search_array ){
962 0 0 0       if (
      0        
      0        
      0        
      0        
      0        
      0        
      0        
      0        
      0        
      0        
963             ( $item !~ /^\>[0123456789]*$/ ) &&
964             ( $item !~ /^\>[0123456789]*\.[0123456789]*$/ ) &&
965             ( $item !~ /^\>\.[0123456789]*$/ ) &&
966             ( $item !~ /^\>\=[0123456789]*$/ ) &&
967             ( $item !~ /^\>\=[0123456789]*\.[0123456789]*$/ ) &&
968             ( $item !~ /^\>\=\.[0123456789]*$/ ) &&
969             ( $item !~ /^\<[0123456789]*$/ ) &&
970             ( $item !~ /^\<[0123456789]*\.[0123456789]*$/ ) &&
971             ( $item !~ /^\<\.[0123456789]*$/ ) &&
972             ( $item !~ /^\<\=[0123456789]*$/ ) &&
973             ( $item !~ /^\<\=[0123456789]*\.[0123456789]*$/ ) &&
974             ( $item !~ /^\<\=\.[0123456789]*$/ )
975             ){
976 0           $self->{error}=2;
977 0           $self->{errorString}='"'.$item.'"" is not a valid value for use in a PCT CPU search';
978 0           $self->warn;
979 0           return undef;
980             }
981            
982             }
983            
984 0           $self->{pctcpu_search}=\@pctcpu_search_array;
985             }
986              
987 0           return 1;
988             }
989              
990             =head2 pctmemSearchGet
991              
992             Returns the current value for the PCT MEM search.
993              
994             The return is a array ref.
995              
996             my $pctmem_search=$cps->pctmemSearchGet;
997              
998             =cut
999              
1000             sub pctmemSearchGet{
1001 0     0 1   my $self=$_[0];
1002 0           $self->errorblank;
1003              
1004 0           return $self->{pctmem_search};
1005             }
1006              
1007             =head2 pctmemSearchSetString
1008              
1009             Search for procs based on the memory usage.
1010              
1011             The following equalities are understood.
1012              
1013             <=
1014             <
1015             >
1016             >=
1017              
1018             The string may contain multiple values seperated by a comma. Checking will stop after the first hit.
1019              
1020             If the string is undef, all procs will be shown.
1021              
1022             #search for procs with less than 60% of the memory
1023             $cps->pctmemSearchSetString('<60');
1024             #shows procs with greater than 60% of the memory
1025             $cps->pctmemSearchSetString('>60');
1026              
1027             =cut
1028              
1029             sub pctmemSearchSetString{
1030 0     0 1   my $self=$_[0];
1031 0           my $pctmem_search_string=$_[1];
1032 0           $self->errorblank;
1033              
1034 0           my @pctmem_search_array;
1035 0 0         if ( ! defined( $pctmem_search_string ) ){
1036 0           $self->{pctmem_search}=\@pctmem_search_array;
1037             }else{
1038 0           @pctmem_search_array=split(/\,/, $pctmem_search_string);
1039              
1040 0           foreach my $item ( @pctmem_search_array ){
1041 0 0 0       if (
      0        
      0        
      0        
      0        
      0        
      0        
      0        
      0        
      0        
      0        
1042             ( $item !~ /^\>[0123456789]*$/ ) &&
1043             ( $item !~ /^\>[0123456789]*\.[0123456789]*$/ ) &&
1044             ( $item !~ /^\>\.[0123456789]*$/ ) &&
1045             ( $item !~ /^\>\=[0123456789]*$/ ) &&
1046             ( $item !~ /^\>\=[0123456789]*\.[0123456789]*$/ ) &&
1047             ( $item !~ /^\>\=\.[0123456789]*$/ ) &&
1048             ( $item !~ /^\<[0123456789]*$/ ) &&
1049             ( $item !~ /^\<[0123456789]*\.[0123456789]*$/ ) &&
1050             ( $item !~ /^\<\.[0123456789]*$/ ) &&
1051             ( $item !~ /^\<=[0123456789]*$/ ) &&
1052             ( $item !~ /^\<\=[0123456789]*\.[0123456789]*$/ ) &&
1053             ( $item !~ /^\<\=\.[0123456789]*$/ )
1054             ){
1055 0           $self->{error}=3;
1056 0           $self->{errorString}='"'.$item.'"" is not a valid value for use in a PCT MEM search';
1057 0           $self->warn;
1058 0           return undef;
1059             }
1060            
1061             }
1062            
1063 0           $self->{pctmem_search}=\@pctmem_search_array;
1064             }
1065              
1066 0           return 1;
1067             }
1068              
1069             =head2 processColorGet
1070              
1071             my $timeColors=$cps->processColorGet;
1072              
1073             =cut
1074              
1075             sub processColorGet{
1076 0     0 1   my $self=$_[0];
1077 0           $self->errorblank;
1078              
1079 0           return $self->{processColor};
1080             }
1081              
1082             =head2 procSearchGet
1083              
1084             This returns the search string value that will be used
1085             for matching the proc column.
1086              
1087             The return is undefined if one is not set.
1088              
1089             my $search_regex=$cps->procSearchGet;
1090             if ( defined( $search_regex ) ){
1091             print "search regex: ".$search_regex."\n";
1092             }else{
1093             print "No search regex.\n";
1094             }
1095              
1096             =cut
1097              
1098             sub procSearchGet{
1099 0     0 1   my $self=$_[0];
1100 0           $self->errorblank;
1101              
1102 0           return $self->{proc_search};
1103             }
1104              
1105             =head2 procSearchSet
1106              
1107             This sets the proc column search regex to use.
1108              
1109             If set to undef(the default), then it will show all procs.
1110              
1111             #shows everything
1112             $cps->procSearchSet( undef );
1113              
1114             #search for only those matching musicpd
1115             $cps->procSeearchSet( 'musicpd' );
1116              
1117             #search for those that match /[Zz]whatever/
1118             $cps->procSearchSet( '[Zz]whatever' );
1119              
1120             =cut
1121              
1122             sub procSearchSet{
1123 0     0 1   my $self=$_[0];
1124 0           my $proc_search=$_[1];
1125 0           $self->errorblank;
1126              
1127 0           $self->{proc_search}=$proc_search;
1128            
1129 0           return 1;
1130             }
1131              
1132             =head2 selfIgnoreGet
1133              
1134             =cut
1135              
1136             sub selfIgnoreGet{
1137 0     0 1   my $self=$_[0];
1138 0           $self->errorblank;
1139              
1140 0           return $self->{self_ignore};
1141             }
1142              
1143             =head2 selfIgnoreSet
1144              
1145             Wether or not to show the PID of this processes in the list.
1146              
1147             =head3 undef
1148              
1149             Resets it to the default, 2.
1150              
1151             =head3 0
1152              
1153             Always show self PID in the list.
1154              
1155             =head3 1
1156              
1157             Never show self PID in the list.
1158              
1159             =head3 2
1160              
1161             Don't show self PID if it is a search.
1162              
1163             This is the default.
1164              
1165             =cut
1166              
1167             sub selfIgnoreSet{
1168 0     0 1   my $self=$_[0];
1169 0           my $self_ignore=$_[1];
1170 0           $self->errorblank;
1171              
1172 0 0         if ( ! defined( $self_ignore ) ){
1173 0           $self_ignore='2';
1174             }
1175            
1176 0           $self->{self_ignore}=$self_ignore;
1177            
1178 0           return 1;
1179             }
1180              
1181             =head2 startString
1182              
1183             Generates a short time string based on the supplied unix time.
1184              
1185             =cut
1186              
1187             sub startString{
1188 0     0 1   my $self=$_[0];
1189 0           my $startTime=$_[1];
1190 0           $self->errorblank;
1191              
1192 0           my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($startTime);
1193 0           my ($csec,$cmin,$chour,$cmday,$cmon,$cyear,$cwday,$cyday,$cisdst) = localtime(time);
1194              
1195             #add the required stuff to make this sane
1196 0           $year += 1900;
1197 0           $cyear += 1900;
1198 0           $mon += 1;
1199 0           $cmon += 1;
1200            
1201             #find the most common one and return it
1202 0 0         if ( $year ne $cyear ){
1203 0           return $year.sprintf('%02d', $mon).sprintf('%02d', $mday).'-'.sprintf('%02d', $hour).':'.sprintf('%02d', $min);
1204             }
1205 0 0         if ( $mon ne $cmon ){
1206 0           return sprintf('%02d', $mon).sprintf('%02d', $mday).'-'.sprintf('%02d', $hour).':'.sprintf('%02d', $min);
1207             }
1208 0 0         if ( $mday ne $cmday ){
1209 0           return sprintf('%02d', $mday).'-'.sprintf('%02d', $hour).':'.sprintf('%02d', $min);
1210             }
1211              
1212             #just return this for anything less
1213 0           return sprintf('%02d', $hour).':'.sprintf('%02d', $min);
1214             }
1215              
1216             =head2 swappedOutSearchGet
1217              
1218             Returns the current value for the swapped out search.
1219              
1220             The return is a Perl boolean.
1221              
1222             my $swappedOut_search=$cps->swappedOutSearchGet;
1223             if ( $swappedOut_search ){
1224             print "only swapped out procs will be shown";
1225             }
1226              
1227             =cut
1228              
1229             sub swappedOutSearchGet{
1230 0     0 1   my $self=$_[0];
1231 0           $self->errorblank;
1232              
1233 0           return $self->{swapped_out_search};
1234             }
1235              
1236             =head2 swappedOutSearchSet
1237              
1238             Sets the swapped out search value.
1239              
1240             The value taken is a Perl boolean.
1241              
1242             $cps->swappedOutSearchSet( 1 );
1243              
1244             =cut
1245              
1246             sub swappedOutSearchSet{
1247 0     0 1   my $self=$_[0];
1248 0           my $swapped_out_search=$_[1];
1249 0           $self->errorblank;
1250              
1251 0           $self->{swapped_out_search}=$swapped_out_search;
1252              
1253 0           return 1;
1254             }
1255              
1256             =head2 timeColorsGet
1257              
1258             my $timeColors=$cps->timeColorsGet;
1259              
1260             =cut
1261              
1262             sub timeColorsGet{
1263 0     0 1   my $self=$_[0];
1264 0           $self->errorblank;
1265              
1266 0           return $self->{timeColors};
1267             }
1268              
1269             =head2 timeSearchGet
1270              
1271             Returns the current value for the time search.
1272              
1273             The return is a array ref.
1274              
1275             my $time_search=$cps->waitSearchGet;
1276              
1277             =cut
1278              
1279             sub timeSearchGet{
1280 0     0 1   my $self=$_[0];
1281 0           $self->errorblank;
1282              
1283 0           return $self->{time_search};
1284             }
1285              
1286             =head2 timeSearchSetString
1287              
1288             Search for procs based on the CPU time value.
1289              
1290             The following equalities are understood.
1291              
1292             <=
1293             <
1294             >
1295             >=
1296              
1297             The string may contain multiple values seperated by a comma. Checking will stop after the first hit.
1298              
1299             If the string is undef, all wait channels will be shown.
1300              
1301             #search for procs with less than 60 seconds of CPU time
1302             $cps->waitSearchSetString('<69');
1303             #shows procs with less than 60 seconds and greater 120 seconds
1304             $cps->waitSearchSetString('<60,>120');
1305              
1306             =cut
1307              
1308             sub timeSearchSetString{
1309 0     0 1   my $self=$_[0];
1310 0           my $time_search_string=$_[1];
1311 0           $self->errorblank;
1312              
1313 0           my @time_search_array;
1314 0 0         if ( ! defined( $time_search_string ) ){
1315 0           $self->{time_search}=\@time_search_array;
1316             }else{
1317 0           @time_search_array=split(/\,/, $time_search_string);
1318              
1319 0           foreach my $item ( @time_search_array ){
1320 0 0 0       if (
      0        
      0        
      0        
      0        
      0        
      0        
      0        
      0        
      0        
      0        
1321             ( $item !~ /^\>[0123456789]*$/ ) &&
1322             ( $item !~ /^\>[0123456789]*\.[0123456789]*$/ ) &&
1323             ( $item !~ /^\>\.[0123456789]*$/ ) &&
1324             ( $item !~ /^\>=[0123456789]*$/ ) &&
1325             ( $item !~ /^\>\=[0123456789]*\.[0123456789]*$/ ) &&
1326             ( $item !~ /^\>\=\.[0123456789]*$/ ) &&
1327             ( $item !~ /^\<[0123456789]*$/ ) &&
1328             ( $item !~ /^\<[0123456789]*\.[0123456789]*$/ ) &&
1329             ( $item !~ /^\<\.[0123456789]*$/ ) &&
1330             ( $item !~ /^\<=[0123456789]*$/ ) &&
1331             ( $item !~ /^\<\=[0123456789]*\.[0123456789]*$/ ) &&
1332             ( $item !~ /^\<\=\.[0123456789]*$/ )
1333             ){
1334 0           $self->{error}=1;
1335 0           $self->{errorString}='"'.$item.'"" is not a valid value for use in a time search';
1336 0           $self->warn;
1337 0           return undef;
1338             }
1339            
1340             }
1341            
1342 0           $self->{time_search}=\@time_search_array;
1343             }
1344              
1345 0           return 1;
1346             }
1347              
1348             =head2 timeString
1349              
1350             Turns the raw run string into something usable.
1351              
1352             This returns a colorized item.
1353              
1354             my $time=$cps->timeString( $seconds );
1355              
1356             =cut
1357              
1358             sub timeString{
1359 0     0 1   my $self=$_[0];
1360 0           my $time=$_[1];
1361 0           $self->errorblank;
1362              
1363 0           my $colors=$self->timeColorsGet;
1364              
1365 0           my $hours=0;
1366 0 0         if ( $time >= 3600 ){
1367 0           $hours = $time / 3600;
1368             }
1369 0           my $loSeconds = $time % 3600;
1370 0           my $minutes=0;
1371 0 0         if ( $time >= 60 ){
1372 0           $minutes = $loSeconds / 60;
1373             }
1374 0           my $seconds = $loSeconds % 60;
1375              
1376             #nicely format it
1377 0           $hours=~s/\..*//;
1378 0           $minutes=~s/\..*//;
1379 0           $seconds=sprintf('%.f',$seconds);
1380            
1381             #this will be returned
1382 0           my $toReturn='';
1383              
1384             #process the hours bit
1385 0 0         if ( $hours == 0 ){
    0          
1386             #don't do anything if time is 0
1387             }elsif(
1388             $hours >= 10
1389             ){
1390 0           $toReturn=color($colors->[3]).$hours.':';
1391             }else{
1392 0           $toReturn=color($colors->[2]).$hours.':';
1393             }
1394              
1395             #process the minutes bit
1396 0 0 0       if (
1397             ( $hours > 0 ) ||
1398             ( $minutes > 0 )
1399             ){
1400 0           $toReturn=$toReturn.color( $colors->[1] ). $minutes.':';
1401             }
1402              
1403 0           $toReturn=$toReturn.color( $colors->[0] ).$seconds;
1404            
1405 0           return $toReturn;
1406             }
1407              
1408             =head1 userSearchGet
1409              
1410             This gets the user to be searched for and if it should be inverted or not.
1411              
1412             This returns an array reference of users to search for.
1413              
1414             An selection can be inverted via !.
1415              
1416             my $user_search=$cps->userSearchGet;
1417              
1418             =cut
1419              
1420             sub userSearchGet{
1421 0     0 0   my $self=$_[0];
1422 0           $self->errorblank;
1423              
1424 0           return $self->{user_search};
1425             }
1426              
1427             =head1 userSearchSetString
1428              
1429             This takes a string to set the user search for.
1430              
1431             An selection can be inverted via !.
1432              
1433             The string may contain multiple users seperated by a comma.
1434              
1435             If the string is undef, all users will be shown.
1436              
1437             #search for user foo and bar
1438             $cps->userSearchSetString('foo,bar');
1439             #show users not matching foo
1440             $cps->userSearchSetString('!foo');
1441             #show all users, clearing any previous settings
1442             $cps->userSearchSetString;
1443              
1444             =cut
1445              
1446             sub userSearchSetString{
1447 0     0 0   my $self=$_[0];
1448 0           my $user_search_string=$_[1];
1449 0           $self->errorblank;
1450              
1451 0           my @user_search_array;
1452 0 0         if ( ! defined( $user_search_string ) ){
1453 0           $self->{user_search}=\@user_search_array;
1454             }else{
1455 0           @user_search_array=split(/\,/, $user_search_string);
1456 0           $self->{user_search}=\@user_search_array;
1457             }
1458              
1459 0           return 1;
1460             }
1461              
1462             =head2 waitSearchGet
1463              
1464             Returns the current value for the wait search.
1465              
1466             The return is a array ref.
1467              
1468             my $wait_search=$cps->waitSearchGet;
1469              
1470             =cut
1471              
1472             sub waitSearchGet{
1473 0     0 1   my $self=$_[0];
1474 0           $self->errorblank;
1475              
1476 0           return $self->{wait_search};
1477             }
1478              
1479             =head2 waitSearchSetString
1480              
1481             This takes a string to set the wait channel search for.
1482              
1483             An selection can be inverted via !.
1484              
1485             The string may contain multiple users seperated by a comma.
1486              
1487             If the string is undef, all wait channels will be shown.
1488              
1489             #search for wait channel wait and sleep
1490             $cps->waitSearchSetString('wait,sleep');
1491             #shows wait channels not matching sbwait
1492             $cps->waitSearchSetString('!sbwait');
1493             #show all users, clearing any previous settings
1494             $cps->waitSearchSetString;
1495              
1496             =cut
1497              
1498             sub waitSearchSetString{
1499 0     0 1   my $self=$_[0];
1500 0           my $wait_search_string=$_[1];
1501 0           $self->errorblank;
1502              
1503 0           my @wait_search_array;
1504 0 0         if ( ! defined( $wait_search_string ) ){
1505 0           $self->{wait_search}=\@wait_search_array;
1506             }else{
1507 0           @wait_search_array=split(/\,/, $wait_search_string);
1508 0           $self->{wait_search}=\@wait_search_array;
1509             }
1510              
1511 0           return 1;
1512             }
1513              
1514             =head2 zombieSearchGet
1515              
1516             Returns the current value for the zombie search.
1517              
1518             The return is a Perl boolean.
1519              
1520             my $zombie_search=$cps->zombieSearchGet;
1521             if ( $zombie_search ){
1522             print "only zombie procs will be shown";
1523             }
1524              
1525             =cut
1526              
1527             sub zombieSearchGet{
1528 0     0 1   my $self=$_[0];
1529 0           $self->errorblank;
1530              
1531 0           return $self->{zombie_search};
1532             }
1533              
1534             =head2 zombieSearchSet
1535              
1536             Sets the zombie search value.
1537              
1538             The value taken is a Perl boolean.
1539              
1540             $cps->zombieSearchSet( 1 );
1541              
1542             =cut
1543              
1544             sub zombieSearchSet{
1545 0     0 1   my $self=$_[0];
1546 0           my $zombie_search=$_[1];
1547 0           $self->errorblank;
1548              
1549 0           $self->{zombie_search}=$zombie_search;
1550              
1551 0           return 1;
1552             }
1553              
1554             =head1 COLORS
1555              
1556             These corresponds to L colors.
1557              
1558             =head2 Time
1559              
1560             The color column is not a single color, but multiple depending on the amount of time.
1561              
1562             The default is as below.
1563              
1564             'GREEN', seconds
1565             'BRIGHT_GREEN', minutes
1566             'RED', hours
1567             'BRIGHT_RED', 10+ hours
1568              
1569             =head2 Columns
1570              
1571             The non-proc/time columns are colored in a rotating color sequence.
1572              
1573             The default is as below.
1574              
1575             BRIGHT_YELLOW
1576             BRIGHT_CYAN
1577             BRIGHT_MAGENTA
1578             BRIGHT_BLUE
1579              
1580             =head1 ERROR CODES/FLAGS
1581              
1582             =head2 1 / badTimeString
1583              
1584             The time search string contains errors.
1585              
1586             =head2 2 / badPctcpuString
1587              
1588             The PCT CPU search string contains errors.
1589              
1590             =head2 3 / badPctmemString
1591              
1592             The PCT MEM search string contains errors.
1593              
1594             =head1 AUTHOR
1595              
1596             Zane C. Bowers-Hadley, C<< >>
1597              
1598             =head1 BUGS
1599              
1600             Please report any bugs or feature requests to C, or through
1601             the web interface at L. I will be notified, and then you'll
1602             automatically be notified of progress on your bug as I make changes.
1603              
1604              
1605              
1606              
1607             =head1 SUPPORT
1608              
1609             You can find documentation for this module with the perldoc command.
1610              
1611             perldoc Proc::ProcessTable::Colorizer
1612              
1613              
1614             You can also look for information at:
1615              
1616             =over 4
1617              
1618             =item * RT: CPAN's request tracker (report bugs here)
1619              
1620             L
1621              
1622             =item * AnnoCPAN: Annotated CPAN documentation
1623              
1624             L
1625              
1626             =item * CPAN Ratings
1627              
1628             L
1629              
1630             =item * Search CPAN
1631              
1632             L
1633              
1634             =back
1635              
1636              
1637             =head1 ACKNOWLEDGEMENTS
1638              
1639              
1640             =head1 LICENSE AND COPYRIGHT
1641              
1642             Copyright 2017 Zane C. Bowers-Hadley.
1643              
1644             This program is distributed under the (Simplified) BSD License:
1645             L
1646              
1647             Redistribution and use in source and binary forms, with or without
1648             modification, are permitted provided that the following conditions
1649             are met:
1650              
1651             * Redistributions of source code must retain the above copyright
1652             notice, this list of conditions and the following disclaimer.
1653              
1654             * Redistributions in binary form must reproduce the above copyright
1655             notice, this list of conditions and the following disclaimer in the
1656             documentation and/or other materials provided with the distribution.
1657              
1658             THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1659             "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1660             LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1661             A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
1662             OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
1663             SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
1664             LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
1665             DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
1666             THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1667             (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
1668             OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1669              
1670              
1671             =cut
1672              
1673             1; # End of Proc::ProcessTable::Colorizer