File Coverage

blib/lib/Geo/WeatherNOAA.pm
Criterion Covered Total %
statement 232 282 82.2
branch 64 116 55.1
condition 25 57 43.8
subroutine 18 20 90.0
pod 7 13 53.8
total 346 488 70.9


line stmt bran cond sub pod time code
1              
2             # $Id: WeatherNOAA.pm,v 4.38 2006/12/10 21:58:11 msolomon Exp $
3              
4              
5             package Geo::WeatherNOAA;
6              
7 1     1   1422 use strict;
  1         2  
  1         151  
8 1     1   8 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
  1         3  
  1         196  
9 1     1   1358 use LWP::Simple;
  1         143067  
  1         8  
10 1     1   472 use LWP::UserAgent;
  1         2  
  1         65  
11 1     1   2599 use Tie::IxHash;
  1         6433  
  1         123  
12 1     1   1719 use Text::Wrap;
  1         3365  
  1         124  
13              
14             require Exporter;
15              
16             @ISA = qw(Exporter);
17             # Items to export into callers namespace by default. Note: do not export
18             # names by default without a very good reason. Use EXPORT_OK instead.
19             # Do not simply export all your public functions/methods/constants.
20             @EXPORT = qw(
21             make_noaa_table
22              
23             print_forecast
24             print_current
25              
26             get_city_zone
27             process_city_zone
28              
29             get_city_hourly
30             process_city_hourly
31             );
32              
33             $VERSION = do { my @r = (q$Revision: 4.38 $ =~ /\d+/g); sprintf "%d."."%02d" x $#r, @r };
34             # my $URL_BASE = 'http://iwin.nws.noaa.gov/iwin/';
35             my $URL_BASE = 'http://www.weather.gov/view/prodsByState.php?';
36             # state=ia&prodtype=zone
37              
38 1     1   9 use vars '$proxy_from_env';
  1         1  
  1         3973  
39             $proxy_from_env = 0;
40              
41             # Preloaded methods go here.
42              
43             sub print_forecast {
44 0     0 1 0 my ($city, $state, $filename, $fileopt, $UA) = @_;
45 0         0 my $in = get_city_zone($city,$state,$filename,$fileopt,$UA);
46              
47 0         0 my $out;
48              
49 0         0 $out = "Geo::WeatherNOAA.pm v.$Geo::WeatherNOAA::VERSION\n";
50              
51 0         0 my ($date,$warnings,$forecast) =
52             process_city_zone($city,$state,$filename,$fileopt);
53              
54 0         0 $out .= "As of $date:\n";
55 0         0 foreach my $warning (@$warnings) {
56 0         0 $out .= wrap('WARNING: ',' ',"$warning\n");
57             }
58 0         0 foreach my $key (keys %$forecast) {
59 0         0 $out .= wrap('',' ',"$key: $forecast->{$key}\n");
60             }
61 0         0 return $out
62             }
63              
64              
65             #########################################################################
66             #########################################################################
67             #
68             # Zone file processing
69             #
70             #########################################################################
71             #########################################################################
72             sub process_city_zone {
73 2     2 1 87 my ($city, $state, $filename, $fileopt, $UA) = @_;
74 2         10 my $in = get_city_zone($city,$state,$filename,$fileopt,$UA);
75              
76             # Return error if problem getting URL
77 2 50       62 if ($in =~ /Error/) {
78 0         0 my %error;
79             my @null;
80 0         0 $error{'Error'} = 'Error';
81 0         0 $error{'Network Error'} = $in;
82 0         0 return ('',\@null,\%error);
83             }
84             #print STDERR $in;exit;
85              
86             # Split coverage, date, and forecast
87             #
88 2         32 my ($coverage, $date, $forecast) = ($in =~ /(^.*?)\012 # Coverage
89             (\d.*?)\012 # Date
90             (.*)/sx); # Entire Forecast
91            
92             # Format Coverage
93             #
94 2         7 $coverage =~ s/corrected//gi; # Remove stat word
95 2         23 $coverage =~ s/(\/|-|\.\.\.)/, /g; # Turn weird punct to commas
96 2         8 $coverage =~ s/,\s*$//; # Remove last comma
97 2         8 $coverage = ucfirst_words($coverage); # Make caps correct
98            
99             # Format date (easy)
100             #
101 2         9 $date = format_date($date);
102              
103             # Vars for forecast
104             #
105 2         4 my %forecast;
106 2         25 tie %forecast, "Tie::IxHash";
107 2         33 my @warnings;
108              
109             # Iterate through forecast and assign warnings to list or pairs to hash
110             #
111             my $forecast_item; # Used as place holder for line breaks of $value
112 2         4 my $warnings_done = 0; # Flag for warnings (Always at top of forcast)
113              
114 2         19 foreach my $line (split "\012",$forecast) {
115             # Be-gone if we've got temp data (will include parse for that later)
116 40 50       477 last if $line =~ /^\.
117              
118 40         39 my ($key,$value);
119 40         130 ($key,$value) = ($line =~ /(.*?)\.\.\.(.*)/);
120              
121 40 100       75 if (! $value) {
122             # If there's no value, this must be either a warning or
123             # a continutation of value-data
124 20         29 $key = $line;
125             }
126 40 50       75 next if ($key =~ /EXTENDED/);
127              
128              
129 40 100 66     146 $warnings_done = 1 if ( ($key) and ($value) );
130             #print "WARN_DONE: $warnings_done\n";
131              
132 40 50       63 if ($warnings_done) {
    0          
133 40 100 66     206 if ( ($key =~ s/^\.//) and ($value) and ($key) ) {
    50 66        
134             # Add VALUE to KEY (new key)
135 20         25 $key =~ s/^\.//;
136 20         35 $key = ucfirst_words($key);
137 20         35 $forecast_item = $key;
138 20         78 $forecast{$forecast_item} .= $value;
139             }
140             elsif ( $forecast_item ) {
141             # Add KEY (with data) to OLD KEY (FORECAST_ITEM)
142 20         78 $forecast{$forecast_item} .= ' ' . $key;
143 20 50       308 $forecast{$forecast_item} .= ', ' . $value if $value;
144             }
145             else {
146             # print "LINE IGNORED\n";
147             }
148             }
149             elsif (! $warnings_done ) {
150 0 0 0     0 if ( (!$key) and ($value) ) {
    0 0        
151 0         0 $value = ucfirst lc $value;
152 0         0 push @warnings, $value;
153             }
154             elsif ( ($key) and (!$value) ) {
155 0         0 $key = ucfirst lc $key;
156 0         0 push @warnings, $key;
157             }
158             }
159             else {
160             # line ignored
161             }
162             }
163              
164 2         16 foreach my $key ( keys %forecast ) {
165 20         297 $forecast{$key} =~ tr/\012//d; # Remove newlines
166             #$forecast{$key} = lc($forecast{$key}); # No all CAPS
167 20         293 $forecast{$key} =~ s/\s+/ /g; # Rid of multi-spaces
168 20         507 $forecast{$key} = sent_caps($forecast{$key}); # Proper sentance caps
169             }
170              
171 2         37 return ($date,\@warnings,\%forecast,$coverage);
172              
173             } # process_city_zone()
174              
175              
176             sub get_city_zone {
177 2     2 1 5 my ($city, $state, $filename, $fileopt, $UA) = @_;
178              
179             # my $URL = $URL_BASE . lc $state . '/zone.html';
180 2         8 my $URL = $URL_BASE . 'state=' . lc($state) . '&prodtype=zone';
181            
182              
183             # City and States must be capital
184             #
185 2         6 $state = uc($state);
186 2         6 $city = uc($city);
187              
188             # Declare some working vars
189             #
190 2         2 my ($rawData, $coverage);
191              
192             # Get data from filehandle object
193             #
194 2         10 $rawData = get_data($URL,$filename,$fileopt,$UA);
195            
196             # clean raw data to remove leading whitespace (I hope this works) 2006-12-10
197             #$rawData =~ s#\n\s*\.#\n.#gm;
198              
199             #my $t1 = $rawData;
200             #$rawData =~ s#\r\n#\n#sg;
201 2         3594 $rawData =~ s#\n\s+#\n#sg;
202              
203 2         1160 $rawData =~ s#\$\$#ENDOFSECTION#sg;
204              
205             # print STDERR $rawData;
206 2         2406 foreach my $line ($rawData =~ /\n(\w\wZ.*?)\012/sg) {
207 2         5 $line =~ s/\r//g;
208 2         7 $line =~ s/\n//g;
209             # print STDERR "HERE: " . $line . "\n";
210 2         7 my $pattern = "$line\\n(.*?)\\n(?:ENDOFSECTION|NNN)";
211             #print STDERR "PATTERN=" . $pattern . "<--\n";
212 2         347 my $section = ($rawData =~ /$pattern/sg)[0];
213 2 50       10 if ($section) {
214             #print "\n\n$section\n";
215             #print " SIZE OF DATA: " . length($section) . "\n";
216             # Iterate though section and get coverage
217 2         4 my $coverage_ended = 0;
218 2         22 foreach my $line (split /\012/, $section) {
219 46         57 $line =~ tr/\015//d; # \r
220 46 100       81 $coverage .= $line . "\n" if (! $coverage_ended);
221 46 100       113 if ($line !~ /^\w/) {
222 20         46 $coverage_ended = 1;
223             }
224             }
225 2 50 33     48 return $section if ( ($coverage =~ /$city/i) && ($section =~ /\d{4}/));
226             }
227             }
228 0         0 return "$city not found";
229              
230             # Return error if there's an error
231 0 0       0 if ($rawData =~ /Error/) {
232 0         0 return $rawData;
233             }
234              
235             # Find our city's data from all raw data
236             #
237             #foreach my $section ($rawData =~ /\012${state}Z.*? # StateZone
238 0         0 foreach my $section ($rawData =~ /\013\w\wZ.*? # StateZone
239             \012\013(.*?) # Data sect
240             \012\013(?:\$\$|NNN)/xsg) {
241             # print STDERR "\n\nSECTION:\n$section\n";
242             # Iterate though section and get coverage
243 0         0 my $coverage_ended = 0;
244 0         0 foreach my $line (split /\012/, $section) {
245 0         0 $line =~ tr/\015//d; # \r
246 0 0       0 $coverage .= $line . "\n" if (! $coverage_ended);
247 0 0       0 if ($line !~ /^\w/) {
248 0         0 $coverage_ended = 1;
249             }
250             }
251 0 0 0     0 return $section if ( ($coverage =~ /$city/i) && ($section =~ /\d{4}/));
252             }
253 0         0 return "$city not found";
254             }
255              
256             ##############################################################################
257             ##############################################################################
258             ##
259             ## Html for Mark's Site
260             ##
261             ##############################################################################
262             ##############################################################################
263              
264             sub font {
265 15     15 0 27 my $in = shift;
266 15   100     74 my $size = shift || 2;
267 15   50     52 my $font_face = $main::font_face || 'FACE="Helvetica, Lucida, Ariel"';
268 15         72 return qq|$in|;
269             }
270              
271             sub make_noaa_table {
272 1     1 1 55 my ($city, $state, $filename, $fileopt, $UA, $max_items) = @_;
273              
274 1   50     4 $fileopt ||= 'get';
275 1 50       3 $max_items && $max_items--;
276 1   50     6 $max_items ||= 4;
277            
278 1   50     7 my $med_bg = $main::med_bg || '#ddddff';
279 1   50     5 my $light_bg = $main::light_bg || '#eeeeff';
280 1   50     5 my $font_face = $main::font_face || 'FACE="Helvetica, Lucida, Ariel"';
281              
282 1         2 my $locfilename;
283 1         2 $locfilename = $filename . "_hourly";
284 1         6 my $current = process_city_hourly( $city,$state,$locfilename,$fileopt,$UA );
285            
286 1         4 $locfilename = $filename . "_zone";
287 1         8 my ($date,$warnings,$forecast,$coverage) = process_city_zone( $city,$state,$locfilename,$fileopt,$UA);
288 1         5 my $cols = (keys %$forecast);
289 1 50       47 $cols = $max_items if $cols > $max_items;
290 1         3 my $out;
291 1         2 $out .= qq|\n|; \n"; \n"; \n|; \n|; \n|; \n|; \n"; \n"; \n" . $bottom . "\n"; \n|; \n|; \n|; \n|; \n|; \n";
292 1         3 $out .= qq|\n|;
293 1         4 $out .= qq|
\n|;
294 1         3 $out .= font('Current') . "\n
295 1         4 $out .= qq||;
296 1         3 $out .= font($current) . "\n
297              
298             # Add one to make cols real width of table
299             #
300 1         4 $cols++;
301              
302             # Add warnings, if needed
303             #
304 1 50       5 if (@$warnings) {
305 0         0 $out .= qq|\n|;
306 0         0 foreach my $warning (@$warnings) {
307 0         0 $out .= qq|
308 0         0 $out .= qq|\t|;
309 0         0 $out .= qq|\n|;
310 0         0 $out .= qq|\t$warning\n
311             }
312             }
313              
314             # Iterate over the first $max_items items in forecast
315             #
316 1         3 my $bottom; # add this after the iteration;
317 1         3 $out .= qq|
318 1         3 $bottom .= qq|
319 1         7 foreach my $key ( (keys %$forecast)[0..($cols - 1)] ) {
320             #print STDERR "DEBUG: $key\n";
321 5         56 $out .= "\t" . font($key) . "
322 5         18 $bottom .= "\t" . font($forecast->{$key}) . "
323             }
324 1         10 $out .= "
325            
326             # Add coverage area
327 1         5 $out .= qq|
328 1         3 $out .= qq| | . font('Area') . qq|
329 1         5 $out .= qq| | . font($coverage,1) . qq|
330 1         4 $out .= qq|
331              
332             # Add credits
333             #
334 1         6 my $wx_cred = 'NOAA forecast made ' .
335             "$date by " .
336             "" .
337             "Geo::WeatherNOAA V.$Geo::WeatherNOAA::VERSION";
338 1         3 $out .= qq|
339 1         5 $out .= qq|| . font($wx_cred) . "
340 1         15 $out .= qq|
\n|;
341              
342              
343              
344             }
345              
346             ##############################################################################
347             ##############################################################################
348             ##
349             ## Misc funcs
350             ##
351             ##############################################################################
352             ##############################################################################
353              
354             sub get_url {
355 3     3 0 6 my ($URL, $UA) = @_;
356              
357 3 50       8 $URL or die "No URL to get!";
358              
359             # Create the useragent and get the data
360             #
361 3 50       8 if (! $UA) {
362 3         37 $UA = new LWP::UserAgent;
363 3 50 33     753 if ( $ENV{'HTTP_PROXY'} or $ENV{'http_proxy'} ) {
364 0         0 $UA->env_proxy;
365             }
366             }
367 3         15 $UA->agent("WeatherNOAA/$VERSION");
368            
369             # Create a request
370 3         155 my $req = new HTTP::Request GET => $URL;
371 3         9952 my $res = $UA->request($req);
372 3 50       305997 if ($res->is_success) {
373 3         49 return $res->content;
374             }
375             else {
376 0         0 return;
377             }
378             } # getURL()
379              
380             sub get_data {
381 3     3 0 6 my ($URL,$filename,$fileopt,$UA) = @_;
382              
383 3   50     10 $fileopt ||= 'get';
384              
385 3         4 my $data; # Data
386              
387 3 50 66     19 if ( ($fileopt eq 'get') || ($fileopt eq 'save') ) {
388 3 50       7 print STDERR "Retrieving $URL\n" if $main::opt_v;
389 3   50     11 $data = get_url($URL,$UA) ||
390             return "Error getting data from $URL";
391 3 100       1609 if ( $fileopt eq 'save' ) {
392 2 50       9 print STDERR "Writing $URL to $filename\n" if $main::opt_v;
393 2 50       316 open(OUT,">$filename") or die "Cannot create $filename";
394 2         2676 print OUT $data;
395 2         158 close OUT;
396 2         8 $fileopt = 'usefile';
397             }
398             }
399 3 100       15 if ( $fileopt eq 'usefile' ) {
400 2 50       8 print STDERR "Reading data from $filename\n" if $main::opt_v;
401 2 50       82 open(FILE,$filename) or die "Cannot read $filename";
402 2         96 while () { $data .= $_; }
  13925         30343  
403             }
404 3         1623 return $data;
405             } # get_fh
406              
407             sub format_date {
408 3     3 0 8 my $in = shift;
409 3         68 $in =~ s/^(\d+)(\d\d)\s(AM|PM)\s(\w+)\s(\w+)\s(\w+)\s0*(\d+)/$1:$2\L$3\E ($4) \u\L$5\E\E \u\L$6 $7,/;
410 3         7 $in =~ tr/\015//d; # \r
411 3         10 return $in;
412             }
413             sub sent_caps {
414 20     20 0 45 my $in = shift;
415 20         124 $in = ucfirst(lc($in));
416 20         244 $in =~ s/(\.\W+)(\w)/$1\U$2/g; # Proper sentance caps
417 20         89 return $in;
418             }
419              
420             sub ucfirst_words {
421 23     23 0 35 my ($in) = @_;
422 23         125 return join " ", map ucfirst(lc($_)),(split /\s+/, $in);
423             }
424              
425             #########################################################################
426             #########################################################################
427             ##
428             ## Hourly city data
429             ##
430             #########################################################################
431             #########################################################################
432              
433             sub get_city_hourly {
434 1     1 1 3 my ($city,$state,$filename,$fileopt,$UA) = @_;
435            
436             # City and state in all caps please
437             #
438 1         2 $city = uc $city;
439 1         2 $state = uc $state;
440              
441             # work var
442 1         2 my ($fields,$line,$date,$time);
443            
444             # Get data
445             #
446             #my $URL = $URL_BASE . lc $state . '/hourly.html';
447 1         4 my $URL = $URL_BASE . 'state=' . lc($state) . '&prodtype=hourly';
448             #print STDERR "Getting data from $URL\n";
449 1         5 my $data = get_data($URL,$filename,$fileopt,$UA);
450 1         4 my $datalength = length($data);
451             #print STDERR "Got data ($datalength)\n";
452              
453             # Return error if there's an error
454 1 50       646 if ($data =~ /Error/) {
455 0         0 my %retHash;
456 0         0 $retHash{ERROR} = $data;
457 0         0 return \%retHash;
458             }
459              
460 1         2841 $data =~ s/\015//g; # \r
461              
462             #print STDERR "LOOKING FOR: " . $city . "\n";
463              
464             # Get line for our city from Data
465             #
466 1         8303 foreach (split /\012/, $data) {
467 73         93 chomp;
468 73         211 s/^\s*//;
469 73 100       189 $date = $_ if /^\s*(\d+)(\d\d)\s+(AM|PM)\s+(\w+)/;
470 73 50 66     207 $time = "$1:$2 $3" if (($1) && ($2) && ($3));
      33        
471 73 100       141 $fields = $_ if /^CITY/;
472 73 100       226 $line = $_ if /^$city\s/;
473              
474             #print STDERR "LINE: $line\n" if $line;
475            
476             # Newest data seems to be at the top of the file
477 73 100       170 last if $line;
478             }
479 1         1446 $date = format_date($date);
480              
481             # Set pack strings
482             #
483 1         5 my $fields_pack_str;
484             my $values_pack_str;
485 1 50 33     16 if ( ($fields =~ /TMP/) and ($fields =~ /\sDP\s/) ) {
486             #print STDERR "NEW FORMAT!\n";
487 1         4 $fields_pack_str =
488             '@0 A15 @15 A9 @25 A3 @29 A2 @33 A2 @36 A8 @47 A5 @54 A7';
489 1         2 $values_pack_str =
490             '@0 A15 @15 A8 @24 A4 @28 A4 @32 A3 @36 A8 @46 A7 @53 A8';
491             }
492             else {
493             #print STDERR "OLD FORMAT!\n";
494 0         0 $fields_pack_str =
495             '@0 A15 @15 A9 @24 A5 @29 A5 @35 A4 @39 A8 @47 A8 @55 A8';
496 0         0 $values_pack_str =
497             '@0 A15 @15 A9 @24 A5 @29 A5 @34 A4 @39 A8 @47 A8 @55 A8';
498             }
499              
500             # unpack gives error of the string is smaller than the unpack string
501 1 50       8 $line .= ' ' x (64 - length($line)) if length($line) < 64;
502            
503 1 50 33     9 return { } unless ( ($line) && ($fields) ); # Return ref to empty hash
504              
505 1         3 my @fields;
506 1 50       15 push @fields, 'DATE', 'TIME', unpack $fields_pack_str, $fields if $fields;
507             #'@0 A15 @15 A9 @24 A5 @29 A5 @35 A4 @39 A8 @47 A8 @55 A8', $fields if $fields;
508 1         3 my @values;
509 1         8 push @values, $date, $time, unpack $values_pack_str, $line;
510             #print STDERR "$line\n";
511             #'@0 A15 @15 A9 @24 A5 @29 A5 @34 A4 @39 A8 @47 A8 @55 A8', $line;
512              
513            
514              
515 1 50       6 return { } if $values[3] eq 'NOT AVBL'; # Return ref to empty hash
516              
517 1         1 my %retValue;
518 1         4 foreach my $i (0..$#fields) {
519             # Convert odd fieldnames to standard
520 10 100       21 $fields[$i] = 'DEWPT' if $fields[$i] eq 'DP';
521 10 100       21 $fields[$i] = 'TEMP' if $fields[$i] eq 'TMP';
522              
523             # Assign value
524 10         23 $retValue{$fields[$i]} = $values[$i];
525             }
526              
527 1         8 return \%retValue;
528              
529             } # get_city_hourly()
530              
531             sub print_current {
532 0     0 1 0 my ($city,$state,$filename,$fileopt,$UA) = @_;
533 0         0 my $in = process_city_hourly($city, $state, $filename, $fileopt,$UA);
534 0         0 return wrap('',' ',$in)
535             }
536              
537            
538             sub process_city_hourly {
539 1     1 1 3 my ($city,$state,$filename,$fileopt,$UA) = @_;
540 1         5 my $in = get_city_hourly($city, $state, $filename, $fileopt,$UA);
541              
542 1         4 $state = uc($state);
543              
544 1 50       5 return $in->{ERROR} if $in->{ERROR};
545 1 50       4 $in->{CITY} or return "No data available";
546 1         6 $in->{CITY} = ucfirst_words($in->{CITY});
547            
548 1         22 my %sky = (
549             'SUNNY' => 'sunny skies',
550             'MOSUNNY' => 'mostly sunny skies',
551             'PTSUNNY' => 'partly sunny skies',
552             'CLEAR' => 'clear weather',
553             'DRIZZLE' => 'a drizzle',
554             'CLOUDY' => 'cloudy skies',
555             'MOCLDY' => 'mostly cloudy skies',
556             'PTCLDY' => 'partly cloudy skies',
557             'LGT RAIN' => 'light rain',
558             'FRZ DRZL' => 'freezing drizzle',
559             'FLURRIES' => 'flurries',
560             'LGT SNOW' => 'light snow',
561             'SNOW' => 'snow',
562             'N/A' => 'N/A',
563             'NOT AVBL' => '*not available*',
564             'FAIR' => 'fair weather');
565              
566             # Format the wind direction and speed
567             #
568 1         6 my %compass = qw/N north S south E east W west/;
569             # my $direction = join '',map $compass{$_},split(/(\w)\d/g, $in->{WIND});
570 1         4 my $direction;
571             {
572 1         2 $direction = $in->{WIND};
  1         3  
573 1         3 $direction =~ s/(.*?)G.*/$1/; # Remove gusts
574 1         7 $direction =~ s/\d//g; # Remove digits
575 1 50       5 if ( $direction ) {
576 1         3 $direction = $compass{$direction};
577             }
578             }
579 1         5 my ($speed) = ($in->{WIND} =~ /(\d+)/);
580 1         5 my ($gusts) = ($in->{WIND} =~ /G(\d+)/);
581              
582 1 50       4 if ($in->{WIND} eq 'CALM') {
583 0         0 $in->{WIND} = 'calm';
584             }
585             else {
586 1         4 $in->{WIND} = "$direction at ${speed} mph";
587 1 50       583 $in->{WIND} .= ", gusts up to ${gusts} mph" if $gusts;
588             }
589              
590             # Format relative humidity and ibarometric pressure
591             #
592 1         3 my $rh_pres;
593 1 50       4 if ($in->{RH}) {
594 1         5 $rh_pres = " The relative humidity was $in->{RH}\%";
595             }
596 1 50       5 if ($in->{PRES}) {
597 1         5 my %rise_fall = qw/R rising S steady F falling/;
598             # my $direction = join '',map $rise_fall{$_},split(/\d(\w)/g, $in->{PRES});
599 1         20 my $direction;
600             {
601 1         4 $direction = $in->{PRES};
  1         4  
602 1         6 $direction = ( $direction =~ /.*(\w)$/ )[0];
603 1 50       4 if ( $direction ) {
604 1         38 $direction = $rise_fall{$direction};
605             }
606             }
607 1         3 $in->{PRES} =~ tr/RSF//d;
608 1 50       6 if ($rh_pres) {
609 1         2 $rh_pres .= ", and b";
610             }
611             else {
612 0         0 $rh_pres .= " B";
613             }
614 1         5 $rh_pres .= "arometric pressure was $direction from $in->{PRES} in";
615             }
616 1 50       5 $rh_pres .= '.' if $rh_pres;
617              
618             # Format output sentence
619             #
620 1         2 my $out;
621 1         4 $out = "At $in->{TIME}, $in->{CITY}, $state conditions were ";
622 1         4 $out .= $sky{$in->{'SKY/WX'}} . " ";
623 1         6 $out .= "at $in->{TEMP}°F, wind was $in->{WIND}. $rh_pres\n";
624 1         11 return $out;
625              
626             } # process_city_hourly()
627              
628             # Autoload methods go after =cut, and are processed by the autosplit program.
629              
630             1;
631             __END__