171
230
$self->{site} = undef; # the site code (4 chars)
172
231
$self->{date_time} = undef; # date/time
173
$self->{modifier} = "AUTO"; # the AUTO/COR modifier (if
232
$self->{modifier} = undef; # the AUTO/COR modifier
175
233
$self->{wind} = undef; # the wind information
234
$self->{vrbwind} = undef; # variable wind information
176
235
$self->{visibility} = undef; # visibility information
177
236
$self->{runway} = undef; # runway visibility
178
237
$self->{weather} = [ ]; # current weather conditions
179
238
$self->{sky} = [ ]; # sky conditions (cloud cover)
180
239
$self->{temp_dew} = undef; # temp and dew pt.
181
$self->{alt} = undef; # altimeter setting
240
$self->{alt} = undef; # altimeter setting (Hg)
241
$self->{alt_hp} = undef; # altimeter setting (hPa)
242
$self->{slp} = undef; # sea level pressure
182
243
$self->{remarks} = [ ]; # remarks
245
$self->{debug} = undef; # enable debug trace
185
247
bless $self, $class;
189
# ----------------------------------------------- #
191
# Autoload for access methods to stuff in %fields hash
195
my $type = ref($self) || croak "$self is not an object";
196
my $name = $AUTOLOAD;
197
$name =~ s/.*:://; # strip fully-qualified portion of name
198
return if ($name eq 'DESTROY');
199
unless (exists $self->{$name}) {
200
croak "You suck. You tried to access something that is not here.";
202
return $self->{$name};
205
# ----------------------------------------------- #
207
# Get current version number.
211
print "version() called.\n" if $debug;
252
## Autoload for access methods to stuff in %fields hash. We should
253
## probably disallow access to the lower-case items as stated above,
254
## but I don't feel like being a Nazi about it. Besides, I haven't
255
## checked to see what that might break.
264
cluck "bad AUTOLOAD for obj [$self]";
267
if ($AUTOLOAD =~ /.*::(.*)/)
272
## Backward compatible temps...
283
$key = $compat{$key};
286
## Check for the items...
288
if (exists $self->{$key})
290
return $self->{$key};
299
warn "strange AUTOLOAD problem!";
305
## Get current version number.
311
print "version() called.\n" if $self->{debug};
212
312
return $self->{VERSION};
215
# ----------------------------------------------- #
316
## Take a METAR, tokenize, and process it.
218
321
my $self = shift;
220
$self->{METAR} = shift;
221
$self->{METAR} =~ s/\n//goi; # nuke any newlines
325
$self->{METAR} = shift;
326
$self->{METAR} =~ s/\n//g; ## nuke any newlines
222
327
_tokenize($self);
225
330
return $self->{METAR};
228
# ----------------------------------------------- #
230
# Break {METAR} into parts. Stuff into @tokens.
334
## Break {METAR} into parts. Stuff into @tokens.
233
339
my $self = shift;
237
343
# Split tokens on whitespace.
238
344
@toks = split(/\s+/, $self->{METAR});
239
345
$self->{tokens} = \@toks;
243
# ----------------------------------------------- #
245
# Process @tokens to populate METAR values.
247
# This is a long and involved subroutine. It basically
248
# copies the @tokens array and treats it as a stack, popping
249
# off items, examining them, and see what they look like.
250
# Based on their "apppearance" it takes care populating the
251
# proper fields internally.
348
## Process @tokens to populate METAR values.
350
## This is a long and involved subroutine. It basically copies the
351
## @tokens array and treats it as a stack, popping off items,
352
## examining them, and see what they look like. Based on their
353
## "apppearance" it takes care populating the proper fields
255
358
my $self = shift;
257
360
my @toks = @{$self->{tokens}}; # copy tokens array...
261
# This is a semi-brute-force way of doing things, but the
262
# amount of data is relatively small, so it shouldn't be
265
# Ideally, I'd have it skip checks for items which have
266
# been found, but that would make this more "linear" and
267
# I'd remove the pretty while loop.
269
while($tok = shift(@toks)) { # as long as there are tokens
271
print "trying to match [$tok]\n" if $debug;
273
# is it a report type?
275
if (($tok =~ /METAR/i) or ($tok =~ /SPECI/i)) {
363
my $in_remarks = 0; # started processing remarks
365
## This is a semi-brute-force way of doing things, but the amount
366
## of data is relatively small, so it shouldn't be a big deal.
368
## Ideally, I'd have it skip checks for items which have been
369
## found, but that would make this more "linear" and I'd remove
370
## the pretty while loop.
372
## Assume standard report by default
374
$self->{type} = "METAR";
375
$self->{TYPE} = "Routine Weather Report";
377
while (defined($tok = shift(@toks))) ## as long as there are tokens
379
print "trying to match [$tok]\n" if $self->{debug};
382
## is it a report type?
385
if (($tok =~ /METAR/i) or ($tok =~ /SPECI/i))
276
387
$self->{type} = $tok;
277
print "[$tok] is a report type.\n" if $debug;
389
if ($self->{type} eq "METAR")
391
$self->{TYPE} = "Routine Weather Report";
393
elsif ($self->{type} eq "SPECI")
395
$self->{TYPE} = "Special Weather Report";
397
print "[$tok] is a report type.\n" if $self->{debug};
281
} elsif ($tok =~ /K[A-Z]{3,3}/) {
405
elsif ($tok =~ /^[A-Z]{4,4}$/ && !$self->{site})
282
407
$self->{site} = $tok;
283
print "[$tok] is a site ID.\n" if $debug;
408
print "[$tok] is a site ID.\n" if $self->{debug};
287
} elsif($tok =~ /\d{6,6}Z/i) {
413
## is it a date/time?
416
elsif ($tok =~ /\d{6,6}Z/i)
288
418
$self->{date_time} = $tok;
289
print "[$tok] is a date/time.\n" if $debug;
419
print "[$tok] is a date/time.\n" if $self->{debug};
292
# is it a report modifier?
293
} elsif(($tok =~ /AUTO/i) or ($tok =~ /COR/i)) {
426
## is it a report modifier?
429
elsif (($tok =~ /AUTO/i) or ($tok =~ /COR/i))
294
431
$self->{modifier} = $tok;
295
print "[$tok] is a report modifier.\n" if $debug;
432
print "[$tok] is a report modifier.\n" if $self->{debug};
298
# is it wind information?
299
} elsif($tok =~ /.*?KT$/i) {
437
## is it wind information?
440
elsif ($tok =~ /.*?KT$/i)
300
442
$self->{wind} = $tok;
301
print "[$tok] is wind information.\n" if $debug;
304
# is it visibility information?
305
} elsif($tok =~ /.*?SM$/i) {
443
print "[$tok] is wind information.\n" if $self->{debug};
448
## is it variable wind information?
451
elsif ($tok =~ /^\d\d\dV\d\d\d$/i)
453
$self->{vrbwind} = $tok;
454
print "[$tok] is variable wind information.\n" if $self->{debug};
459
## is it visibility information?
462
elsif ($tok =~ /.*?SM$/i)
306
464
$self->{visibility} = $tok;
307
print "[$tok] is visibility information.\n" if $debug;
465
print "[$tok] is visibility information.\n" if $self->{debug};
310
# is it visibility information with a leading digit?
311
} elsif($tok =~ /^\d$/) {
470
## does it say CAVOK? (ceiling and visibility ok)
473
elsif ($tok =~ /^CAVOK/i)
475
$self->{visibility} = $tok;
476
print "[$tok] is visibility information, too.\n" if $self->{debug};
481
## is it visibility information with a leading digit?
484
elsif ($tok =~ /^\d$/)
313
486
$tok .= " " . shift(@toks);
314
487
$self->{visibility} = $tok;
315
print "[$tok is multi-part visibility information.\n" if $debug;
488
print "[$tok is multi-part visibility information.\n" if $self->{debug};
318
# is it runway visibility info?
319
} elsif($tok =~ /R.*?FT$/i) {
493
## is it runway visibility info?
496
elsif ($tok =~ /R.*?FT$/i)
320
498
$self->{runway} = $tok;
321
print "[$tok] is runway visual information.\n" if $debug;
499
print "[$tok] is runway visual information.\n" if $self->{debug};
324
# is it current weather info?
325
} elsif($tok =~ /^(-|\+|VC)?(TS|SH|FZ|BL|DR|MI|BC|PR|RA|DZ|SN|SG|GR|GS|PE|IC|UP|BR|FG|FU|VA|DU|SA|HZ|PY|PO|SQ|FC|SS|DS)+$/) {
504
## is it current weather info?
507
elsif ($tok =~ /^(-|\+)?(VC)?($_weather_types_pat)+/i)
517
if ( $qual eq "-" ) {
519
} elsif ( $qual eq "+" ) {
522
$engl = ""; ## moderate
527
$engl = ""; ## moderate
530
while ( $tok =~ /($_weather_types_pat)/gi )
532
$engl .= " " . $_weather_types{$1}; ## figure out weather
537
if (defined $addlqual)
539
if ( $addlqual eq "VC" )
541
$engl .= " in vicinity";
546
$engl =~ s/\s\s/ /gio;
548
push(@{$self->{WEATHER}},$engl);
327
550
push(@{$self->{weather}},$tok);
328
print "[$tok] is current weather.\n" if $debug;
331
# is it sky conditions (clouds)?
332
} elsif(($tok =~ /SKC|CLR/i) or
333
($tok =~ /(FEW|SCT|BKN|OVC)(\d\d\d)(CB|TCU)?$/i)) {
335
push(@{$self->{sky}},$tok);
336
print "[$tok] is a sky condition.\n" if $debug;
339
# is it temperature and dew point info?
340
} elsif($tok =~ /(M?\d\d)\/(M?\d\d)/i) {
551
print "[$tok] is current weather.\n" if $self->{debug};
556
## is it sky conditions (clear)?
559
elsif ( $tok eq "SKC" || $tok eq "CLR" )
561
push(@{$self->{sky}},$tok);
562
push(@{$self->{SKY}}, "Sky Clear");
566
## is it sky conditions (clouds)?
569
elsif ( $tok =~ /^(FEW|SCT|BKN|OVC|SKC|CLR)(\d\d\d)?(CB|TCU)?$/i)
571
push(@{$self->{sky}},$tok);
574
$engl = $_sky_types{$1};
580
$engl .= " Towering Cumulus";
584
$engl .= " Cumulonimbus";
590
my $agl = int($2)*100;
591
$engl .= " at $agl" . "ft";
594
push(@{$self->{SKY}}, $engl);
595
print "[$tok] is a sky condition.\n" if $self->{debug};
600
## is it temperature and dew point info?
603
elsif ($tok =~ /(M?\d\d)\/(M?\d\d)/i)
341
605
next if $self->{temp_dew};
342
606
$self->{temp_dew} = $tok;
343
print "[$tok] is temperature/dew point information.\n" if $debug;
608
$self->{TEMP_C} = $1;
610
$self->{TEMP_C} =~ s/^M/-/;
611
$self->{DEW_C} =~ s/^M/-/;
613
print "[$tok] is temperature/dew point information.\n" if $self->{debug};
346
# is it an altimeter setting?
347
} elsif($tok =~ /A\d{4,4}$/i) {
618
## is it an altimeter setting? (inches in mercury)
621
elsif (!$in_remarks && $tok =~ /^A(\d\d)(\d\d)$/i)
349
623
$self->{alt} = $tok;
350
print "[$tok] is an altimeter setting.\n" if $debug;
354
} elsif($tok =~ /^RMK$/i) {
356
push(@{$self->{remarks}},$tok);
357
print "[$tok] is a remark.\n" if $debug;
360
# unknown. assume remarks
363
push(@{$self->{remarks}},$tok);
364
print "[$tok] is unknown. Assuming remarks.\n" if $debug;
370
# Now that the internal stuff is set, let's do the external
373
if ($self->{type} eq "METAR") {
374
$self->{TYPE} = "Routine Weather Report";
624
$self->{ALT} = "$1.$2";
625
print "[$tok] is an altimeter setting.\n" if $self->{debug};
630
## is it an altimeter setting? (hectopascals)
632
elsif (!$in_remarks && $tok =~ /^Q(\d\d\d\d)$/i)
634
$self->{alt_hp} = $tok;
635
$self->{ALT_HP} = $1;
636
print "[$tok] is an altimeter setting in hectopascals.\n"
642
## automatic station type?
645
elsif ($in_remarks && $tok =~ /^A(O\d)$/i)
647
$self->{autostationtype} = $tok;
648
$self->{AUTO_STATIONTYPE} = $1;
649
print "[$tok] is an automatic station type remark.\n" if $self->{debug};
657
elsif ($tok =~ /^RMK$/i)
659
push(@{$self->{remarks}},$tok);
661
print "[$tok] is a remark.\n" if $self->{debug};
666
## sea level pressure
669
elsif ($tok =~ /^SLP(\d+)/i)
672
$self->{SLP} = "$1 mb";
673
print "[$tok] is a sea level pressure.\n" if $self->{debug};
678
## sea level pressure not available
681
elsif ($tok eq "SLPNO")
683
$self->{slp} = "SLPNO";
684
$self->{SLP} = "not available";
685
print "[$tok] is a sea level pressure.\n" if $self->{debug};
690
## hourly precipitation
693
elsif ($tok =~ /^P(\d\d\d\d)$/i)
695
$self->{hourlyprecip} = $tok;
697
if ( $1 eq "0000" ) {
698
$self->{HOURLY_PRECIP} = "Trace";
700
$self->{HOURLY_PRECIP} = $1;
705
## weather begin/end times
708
elsif ($tok =~ /^($_weather_types_pat)([BE\d]+)$/i)
713
$self->{weatherlog} = $tok;
715
$engl = $_weather_types{$1};
717
while ( $times =~ /(B|E)(\d\d)/g )
720
$engl .= " began :$2";
722
$engl .= " ended :$2";
726
push(@{$self->{WEATHER_LOG}}, $engl);
727
print "[$tok] is a weather log.\n" if $self->{debug};
732
## remarks for significant cloud types
735
elsif ($in_remarks && ($tok eq "CB" || $tok eq "TCU"))
737
push(@{$self->{sigclouds}}, $tok);
739
if ( $tok eq "CB" ) {
740
push(@{$self->{SIGCLOUDS}}, "Cumulonimbus");
741
} elsif ( $tok eq "TCU" ) {
742
push(@{$self->{SIGCLOUDS}}, "Towering Cumulus");
747
## hourly temp/dewpoint
750
elsif ($tok =~ /^T(\d)(\d\d)(\d)(\d)(\d\d)(\d)$/i)
752
$self->{hourlytempdew} = $tok;
754
$self->{HOURLY_TEMP_C} = "-";
756
$self->{HOURLY_TEMP_C} .= "$2.$3";
758
$self->{HOURLY_DEW_C} = "";
760
$self->{HOURLY_DEW_C} = "-";
762
$self->{HOURLY_DEW_C} .= "$5.$6";
764
print "[$tok] is a hourly temp and dewpoint.\n" if $self->{debug};
769
## unknown, not in remarks yet
774
push(@{$self->{unknown}},$tok);
775
push(@{$self->{UNKNOWN}},$tok);
776
print "[$tok] is unknown.\n" if $self->{debug};
781
## unknown. assume remarks
786
push(@{$self->{remarks}},$tok);
787
push(@{$self->{REMARKS}},$tok);
788
print "[$tok] is unknown remark.\n" if $self->{debug};
795
## Now that the internal stuff is set, let's do the external
376
799
$self->{SITE} = $self->{site};
377
800
$self->{DATE} = substr($self->{date_time},0,2);
378
801
$self->{TIME} = substr($self->{date_time},2,4) . " UTC";
379
802
$self->{TIME} =~ s/(\d\d)(\d\d)/$1:$2/o;
380
803
$self->{MOD} = $self->{modifier};
382
# Okay, wind finally gets interesting.
806
## Okay, wind finally gets interesting.
385
810
my $wind = $self->{wind};
436
861
if ($wind =~ /.{5,6}G(\d\d\d?)/o) {
438
863
$mph_gust = $kts_gust * 1.1508;
441
866
$self->{WIND_KTS} = $kts_speed;
442
867
$self->{WIND_MPH} = $mph_speed;
444
$self->{WIND_KTS_GUST} = $kts_gust;
445
$self->{WIND_MPH_GUST} = $mph_gust;
869
$self->{WIND_GUST_KTS} = $kts_gust;
870
$self->{WIND_GUST_MPH} = $mph_gust;
447
872
$self->{WIND_DIR_DEG} = $dir_deg;
448
873
$self->{WIND_DIR_ENG} = $dir_eng;
455
my $vis = $self->{visibility};
456
$vis =~ s/SM$//oi; # nuke the "SM"
457
if ($vis =~ /M(\d\/\d)/o) {
458
$self->{VISIBILITY} = "Less than $1 statute miles";
460
$self->{VISIBILITY} = $vis . " Statute Miles";
463
} # end visibility block
465
# And F/C temperatures.
468
my ($tmp,$dew) = split(/\//, $self->{temp_dew});
470
# check for negative values
474
# convert celcius to farenheit
475
$self->{C_TEMP} = $tmp;
476
$self->{F_TEMP} = (($tmp * (9/5)) + 32);
477
$self->{C_DEW} = $dew;
478
$self->{F_DEW} = (($dew * (9/5)) + 32);
878
## Variable wind information
882
if ($self->{vrbwind}) {
883
my $vrbwind = $self->{vrbwind};
884
my $vrbwind_deg_1 = substr($vrbwind,0,3);
885
my $vrbwind_deg_2 = substr($vrbwind,4,3);
886
my $vrbwind_eng_1 = "";
887
my $vrbwind_eng_2 = "";
889
if ($vrbwind_deg_1 < 15) { $vrbwind_eng_1 = "North"; }
890
elsif ($vrbwind_deg_1 < 30) { $vrbwind_eng_1 = "North/Northeast"; }
891
elsif ($vrbwind_deg_1 < 60) { $vrbwind_eng_1 = "Northeast"; }
892
elsif ($vrbwind_deg_1 < 75) { $vrbwind_eng_1 = "East/Northeast"; }
893
elsif ($vrbwind_deg_1 < 105) { $vrbwind_eng_1 = "East"; }
894
elsif ($vrbwind_deg_1 < 120) { $vrbwind_eng_1 = "East/Southeast"; }
895
elsif ($vrbwind_deg_1 < 150) { $vrbwind_eng_1 = "Southeast"; }
896
elsif ($vrbwind_deg_1 < 165) { $vrbwind_eng_1 = "South/Southeast"; }
897
elsif ($vrbwind_deg_1 < 195) { $vrbwind_eng_1 = "South"; }
898
elsif ($vrbwind_deg_1 < 210) { $vrbwind_eng_1 = "South/Southwest"; }
899
elsif ($vrbwind_deg_1 < 240) { $vrbwind_eng_1 = "Southwest"; }
900
elsif ($vrbwind_deg_1 < 265) { $vrbwind_eng_1 = "West/Southwest"; }
901
elsif ($vrbwind_deg_1 < 285) { $vrbwind_eng_1 = "West"; }
902
elsif ($vrbwind_deg_1 < 300) { $vrbwind_eng_1 = "West/Northwest"; }
903
elsif ($vrbwind_deg_1 < 330) { $vrbwind_eng_1 = "Northwest"; }
904
elsif ($vrbwind_deg_1 < 345) { $vrbwind_eng_1 = "North/Northwest"; }
905
else { $vrbwind_eng_1 = "North"; }
907
if ($vrbwind_deg_2 < 15) { $vrbwind_eng_2 = "North"; }
908
elsif ($vrbwind_deg_2 < 30) { $vrbwind_eng_2 = "North/Northeast"; }
909
elsif ($vrbwind_deg_2 < 60) { $vrbwind_eng_2 = "Northeast"; }
910
elsif ($vrbwind_deg_2 < 75) { $vrbwind_eng_2 = "East/Northeast"; }
911
elsif ($vrbwind_deg_2 < 105) { $vrbwind_eng_2 = "East"; }
912
elsif ($vrbwind_deg_2 < 120) { $vrbwind_eng_2 = "East/Southeast"; }
913
elsif ($vrbwind_deg_2 < 150) { $vrbwind_eng_2 = "Southeast"; }
914
elsif ($vrbwind_deg_2 < 165) { $vrbwind_eng_2 = "South/Southeast"; }
915
elsif ($vrbwind_deg_2 < 195) { $vrbwind_eng_2 = "South"; }
916
elsif ($vrbwind_deg_2 < 210) { $vrbwind_eng_2 = "South/Southwest"; }
917
elsif ($vrbwind_deg_2 < 240) { $vrbwind_eng_2 = "Southwest"; }
918
elsif ($vrbwind_deg_2 < 265) { $vrbwind_eng_2 = "West/Southwest"; }
919
elsif ($vrbwind_deg_2 < 285) { $vrbwind_eng_2 = "West"; }
920
elsif ($vrbwind_deg_2 < 300) { $vrbwind_eng_2 = "West/Northwest"; }
921
elsif ($vrbwind_deg_2 < 330) { $vrbwind_eng_2 = "Northwest"; }
922
elsif ($vrbwind_deg_2 < 345) { $vrbwind_eng_2 = "North/Northwest"; }
923
else { $vrbwind_eng_2 = "North"; }
925
push @{$self->{WIND_VAR_DEG}}, $vrbwind_deg_1;
926
push @{$self->{WIND_VAR_DEG}}, $vrbwind_deg_2;
927
push @{$self->{WIND_VAR_ENG}}, $vrbwind_eng_1;
928
push @{$self->{WIND_VAR_ENG}}, $vrbwind_eng_2;
937
if ($self->{visibility}) {
938
my $vis = $self->{visibility};
939
$vis =~ s/SM$//oi; # nuke the "SM"
940
if ($vis =~ /^CAVOK$/i) {
941
$self->{VISIBILITY} = "Ceiling and visibility OK";
943
elsif ($vis =~ /M(\d\/\d)/o) {
944
$self->{VISIBILITY} = "Less than $1 statute miles";
946
$self->{VISIBILITY} = $vis . " Statute Miles";
952
## Convert ALT to ALT_HP or vice versa
956
if ($self->{ALT} && !$self->{ALT_HP}) {
957
my $alt = $self->{ALT};
958
$alt = $alt * 1.33; # mmHg to hPa
959
$self->{ALT_HP} = $alt;
961
elsif (!$self->{ALT} && $self->{ALT_HP}) {
962
my $alt = $self->{ALT_HP};
963
$alt = $alt * 0.75; # hPa to mmHg
969
## Calculate F temps for all C temps
972
foreach my $key ( keys(%$self) )
974
if ( uc($key) eq $key && $key =~ /^(.*)_C$/ )
976
my $fkey = $1 . "_F";
978
next unless defined $self->{$key};
980
$self->{$fkey} = sprintf("%.1f", (($self->{$key} * (9/5)) + 32));
483
# ----------------------------------------------- #
986
## Print the tokens--usually when debugging.
486
991
my $self = shift;
488
993
foreach $tok (@{$self->{tokens}}) {
521
1029
print "date_time: $self->{date_time}\n";
522
1030
print "modifier: $self->{modifier}\n";
523
1031
print "wind: $self->{wind}\n";
1032
print "variable wind: $self->{vrbwind}\n";
524
1033
print "visibility: $self->{visibility}\n";
525
1034
print "runway: $self->{runway}\n";
526
1035
print "weather: " . join(', ', @{$self->{weather}}) . "\n";
527
1036
print "sky: " . join(', ', @{$self->{sky}}) . "\n";
528
1037
print "temp_dew: $self->{temp_dew}\n";
529
1038
print "alt: $self->{alt}\n";
1039
print "alt_hp: $self->{alt_hp}\n";
1040
print "slp: $self->{slp}\n";
530
1041
print "remarks: " . join (', ', @{$self->{remarks}}) . "\n";
532
print "VERSION: $self->{VERSION}\n";
533
print "METAR: $self->{METAR}\n";
534
print "TYPE: $self->{TYPE}\n";
535
print "SITE: $self->{SITE}\n";
536
print "DATE: $self->{DATE}\n";
537
print "TIME: $self->{TIME}\n";
538
print "MOD: $self->{MOD}\n";
539
print "WIND_DIR_DEG: $self->{WIND_DIR_DEG}\n";
540
print "WIND_DIR_ENG: $self->{WIND_DIR_ENG}\n";
541
print "WIND_KTS: $self->{WIND_KTS}\n";
542
print "WIND_MPH: $self->{WIND_MPH}\n";
543
print "WIND_KTS_GUST: $self->{WIND_KTS_GUST}\n";
544
print "WIND_MPH_GUST: $self->{WIND_MPH_GUST}\n";
545
print "VISIBILITY: $self->{VISIBILITY}\n";
546
print "C_TEMP: $self->{C_TEMP}\n";
547
print "F_TEMP: $self->{F_TEMP}\n";
548
print "C_DEW: $self->{C_DEW}\n";
549
print "F_DEW: $self->{F_DEW}\n";
1044
foreach my $var ( sort(keys(%$self)) )
1046
next if ( uc($var) ne $var );
1048
if ( ref($self->{$var}) eq "ARRAY" )
1050
print "$var: ", join(", ", @{$self->{$var}}), "\n";
1054
print "$var: ", $self->{$var}, "\n";
552
# ----------------------------------------------- #
553
# ----------------------------------------------- #
554
# ----------------------------------------------- #
555
# ----------------------------------------------- #
556
# ----------------------------------------------- #
564
METAR - Process routine aviation weather reports in the METAR format.
1065
Geo::METAR - Process aviation weather reports in the METAR format.