"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 }