"Programming with Perl: Looking for an Old Job"
by Randal L. Schwartz
Web Techniques, May 1999

Web Techniques grants permission to use these listings (and code) for 
private or commercial use provided that credit to Web Techniques and 
the author is maintained within the comments of the source. For 
questions, contact editors@web-techniques.com. 



NOTE: Remove line numbers!



[LISTING ONE]


1    #!/usr/bin/perl -w
2    use strict;
3    $|++;
4
5    use GIFgraph::lines;
6    use Date::Calc qw(Today Days_in_Month Compress Add_Delta_YMD Month_to_Text);
7
8    ## begin configuration
9
10    my @LANGS = sort qw(java perl|perl5 html cgi cobol fortran python tcl);
11
12    my (@LOWER) = (1995,3,1);       # beginning of useful data
13    my (@UPPER) = Add_Delta_YMD(Today,0,-1,0); # last month
14
15    use constant GIFOUT => "/home/merlyn/Html/x.gif";
16    use constant MEMORY => "/home/merlyn/.dejajobscache";
17
18    ## end configuration
19
20    my @plotdata = ();
21
22    my (@from) = @LOWER;
23    {
24     my $days = Days_in_Month(@from[0,1]);
25     my (@to) = (@from[0,1],$days);
26     last if Compress(@to) >= Compress(@UPPER);
27     my $fromdate = to_dejadate(@from);
28     my $todate = to_dejadate(@to);
29     push @{$plotdata[0]}, sprintf("%04d %02d", @from);
30     my $id = 0;
31     for my $lang (@LANGS) {
32       my $hits = count_hits($lang, $fromdate, $todate);
33       if (defined $hits) {
34         print "$fromdate $todate $lang $hits\n";
35         $hits /= $days;
36       }
37       push @{$plotdata[++$id]}, $hits;
38     }
39     @from = Add_Delta_YMD(@from, 0, 1, 0);
40     redo;
41    }
42
43    my $graph = GIFgraph::lines->new(640,480);
44    $graph->set(
45               x_labels_vertical => 1,
46               title => 'Keyword hits per day in misc.jobs.offered from Dejanews',
47               dclrs => [qw(
48                           lred lorange lyellow lgreen lblue lpurple
49                           dred  orange dyellow dgreen dblue dpurple
50                           )],
51              );
52    $graph->set_legend(@LANGS);
53    $graph->plot_to_gif(GIFOUT, \@plotdata);
54
55    ## subroutines
56
57    sub to_dejadate {
58     my($y,$m,$d) = @_;
59     join " ", Month_to_Text($m), $d, $y;
60    }
61
62    BEGIN {
63     my %HIT_CACHE;
64     my $SEPARATOR = "\001";
65
66     dbmopen(%HIT_CACHE, MEMORY, 0666);
67
68     sub count_hits {
69       my $tag = join $SEPARATOR, @_;
70       my $response;
71
72       if ($response = $HIT_CACHE{$tag}) {
73         (split $SEPARATOR, $response)[0];
74       } elsif (defined ($response = count_hits_from_deja(@_))) {
75         $HIT_CACHE{$tag} = join $SEPARATOR, $response, time;
76         $response;
77       } else {
78         undef;
79       }
80     }
81    }
82
83    BEGIN {
84     my $ua;
85     my $uri;
86
87     sub count_hits_from_deja {
88       my ($query,$fromdate,$todate) = @_;
89       
90       unless ($ua) {
91         require LWP::UserAgent;
92         require URI;
93
94         $ua = LWP::UserAgent->new;
95         $uri = URI->new('http://www.dejanews.com/[ST_rn=ps]/dnquery.xp');
96       }
97       $uri->query_form(
98                        ST => "PS",        # hidden
99                        QRY => $query,
100                       "groups" => "misc.jobs.offered",
101                       "fromdate" => $fromdate,
102                       "todate" => $todate,
103                      );
104
105      require HTTP::Request;
106      my $req = HTTP::Request->new('GET',$uri);
107      
108      for ($ua->request($req)->as_string) {
109        if (/Messages.*of exactly.*?(\d+)/) {
110          return "$1";
111        } elsif (/did not match any/) {
112          return 0;
113        } else {
114          return undef;
115        }
116      }
117    }
118   }