geturl.pl to HTML.

index -|- end

Generated: Tue Feb 2 17:54:40 2010 from geturl.pl 2008/01/26 51.3 KB.

#!/perl -w
# NAME: geturl.pl
# AIM: Get the text from a URL page ...
# 22/01/2008 - geoff mclane
# references
# see from : http://aviationweather.gov/static/help/taf-decode.php - see html/taf-decode.htm
# from : http://mbev.net/wikka/METARSandTAFS
# KJAX 020256Z 02003KT 10SM TSRA OVC01OCB SCT100 BKN130 18/17 A2996 
# METAR's will always be published in the same order: see: html/METARSandTAFS.htm
# see from : http://www.nws.noaa.gov/oso/oso1/oso12/document/guide.shtml
# also from : http://www.faa.gov/about/office_org/field_offices/fsdo/orl/local_more/media/ppt/metar.ppt
# from : http://www.srh.noaa.gov/srh/cwwd/msd/note6.html
# from : http://www.wunderground.com/metarFAQ.asp
# from : http://www.nws.noaa.gov/oso/oso1/oso12/overview.htm
# from : http://www.flyingineurope.be/metar_taf_decode.htm
# from : http://www.alaska.faa.gov/fai/afss/metar%20taf/metcont.htm
# from : http://www.geocities.com/CapeCanaveral/Lab/6799/metarpg.htm
# from : http://www.alaska.faa.gov/fai/afss/metar%20taf/sametar1.htm
# from : http://weather.cod.edu/notes/metar.html
use strict;
use warnings;
use Socket;
use LWP::Simple;
require 'logfile.pl' or die "Unable to load logfile.pl ...\n";
# log file stuff
my ($LF);
my $pgmname = $0;
if ($pgmname =~ /\w{1}:\\.*/) {
   my @tmpsp = split(/\\/,$pgmname);
   $pgmname = $tmpsp[-1];
}
my $outfile = "temp.$pgmname.txt";
open_log($outfile);
prt( "$0 ... Hello, World ...\n" );
my $minkey = 16;
# apt.dat.gz CODES - see http://x-plane.org/home/robinp/Apt810.htm for DETAILS
my $aln =     '1';   # airport line
my $rln =    '10';   # runways/taxiways line
my $sealn =  '16'; # Seaplane base header data.
my $heliln = '17'; # Heliport header data.  
my $twrln =  '14'; # Tower view location. 
my $rampln = '15'; # Ramp startup position(s) 
my $bcnln =  '18'; # Airport light beacons  
my $wsln =   '19'; # windsock
my $minatc = '50';
my $twrfrq = '54';   # like 12210 TWR
my $appfrq = '55';  # like 11970 ROTTERDAM APP
my $maxatc = '56';
my $lastln = '99'; # end of file
my @aptlist = ();
my $aptcnt  = 0;
my @taflist = ();
# This NEEDS to be adjusted to YOUR particular default location of these files.
my $FGROOT = (exists $ENV{FG_ROOT}) ? $ENV{FG_ROOT} : "C:/FGCVS/FlightGear/data";
my $APTFILE      = "$FGROOT/Airports/apt.dat.gz";   # the airports data file
my $NAVFILE      = "$FGROOT/Navaids/nav.dat.gz";   # the NAV, NDB, etc. data file
my $testurl = 'http://weather.noaa.gov/pub/data/forecasts/taf/stations/LFPO.TXT';
my $testurl2 = 'http://weather.noaa.gov/pub/data/forecasts/taf/stations/XS50.TXT';
my $testtaf = 'KSFO 231456Z 03009KT 10SM FEW009 OVC020 06/04 A2999 RMK AO2 RAB25E33 SLP156 P0000 60003 T00610039 55000';
my $testtaf2 = '2008/01/09 04:09 NZWD TAF 090303 15022G32KT 0400 -SN BLSN OVC007 650079 520005 QNH2910INS GRID32022G32KT BECMG 1214 16017KT 1600 -SN BLSN BKN008 OVC012 620089 QNH2908INS GRID33017KT BECMG 1719 16015KT 3200 -SN SCT010 BKN010 OVC025 610159 QNH2912INS GRID33015KT BECMG 2301 16020KT 1200 -SN BLSN BKN008 OVC010 620089 510005 QNH2915INS GRID33020KT';
my $acttaf = '';
my @warnings = ();
my $cannedtaf = 'taf200825.txt';
##load_airport_file($APTFILE);
$aptcnt = scalar @aptlist;
prt( "Got $aptcnt airports loaded ...\n" );
for (my $i = 1; $i <= $aptcnt; $i++) {
   show_airport($i);
}
###fetch_url( $testurl );
if (open TF, "<$cannedtaf") {
   @taflist = <TF>;
   close TF;
} else {
   push(@taflist, $testtaf2);
}
foreach my $taf (@taflist) {
   chomp $taf;
   show_taf($taf);
}
foreach my $warn (@warnings) {
   prt( "$warn\n" );
}
close_log($outfile,1);
exit(0);
sub fetch_url {
   my ($url) = shift;
   prt( "Fetching: $url\n" );
   my $txt = get($url);
   if ($txt && length($txt)) {
      prt( "$txt\n" );
      # the TEXT - something like
      # 2008/01/22 11:00
      # TAF LFPO 221100Z 221818 20006KT 9999 SCT025 SCT040 
      #      BECMG 1820 6000 SCT004 
      #      TEMPO 2002 2000 BR BKN003 
      #      TEMPO 0408 -RADZ BKN006 
      #      BECMG 0810 BKN012 
      #      BECMG 1214 BKN018
      my $taftxt = $txt;
      $taftxt =~ s/\n/ /gm;
      $taftxt = trim_all($taftxt);
      prt( "$taftxt\n" );
      # 2008/01/22 11:00 TAF LFPO 221100Z 221818 20006KT 9999 SCT025 SCT040 BECMG 1820 6000 SCT004 TEMPO 2002 2000 BR BKN003 TEMPO 0408 -RADZ BKN006 BECMG 0810 BKN012 BECMG 1214 BKN018
      # 2008/01/22 17:00 TAF LFPO 221700Z 230024 20005KT 9999 SCT040 BECMG 0002 4000 BR BKN040 TEMPO 0205 2500 BR SCT006 BECMG 0810 19012KT BECMG 1416 BKN025
      push(@taflist,$taftxt);
   } else {
      prt( "FAILED to get URL $url ...\n" );
   }
}
sub show_taf {
   my ($taftxt) = shift;
   prt( "\nDECODE: $taftxt\n" );
   my %metar = decode_metar($taftxt);
   my $msg = '';
   foreach my $key (keys %metar) {
      my $hash = $metar{$key};
      #if (($key eq 'wind')||($key eq 'visibility')) { # ||($key eq 'clouds')) {
      $msg = "$key ";
      $msg .= '.' while (length($msg) < $minkey);
      $msg .= ': ';
      if (ref($hash) eq "HASH") {
         my $mg = '';
         foreach my $k (keys %{$hash}) {
            my $v = ${%{$hash}}{$k};
            $mg .= ', ' if length($mg);
            $mg .= "$k=$v";
         }
         $msg .= $mg;
      } else {
         $msg .= $metar{$key};
      }
      prt( "$msg\n" );
   }
}
sub number_format {
   my ($num, $len) = @_;
   my $rnum = $num;
   if ($len == 0) {
      $rnum = int($num);
   } else {
      my $val = 10;
      my $n = $len - 1;
      while ($n) {
         $val = $val * 10;
         $n--;
      }
      $rnum =  (int($num * $val)) / $val;
   }
   return $rnum;
}
sub get_descriptor {
   my ($desc) = shift;
   # '(MI|PR|BC|DR|BL|SH|TS|FZ)?' = Descriptor
   if ($desc eq 'MI') {
      return 'MI (Shallow)';
   } elsif ($desc eq 'BC') {
      return 'BC (Patches)';
   } elsif ($desc eq 'PR') {
      return 'PR (Partial)';
   } elsif ($desc eq 'TS') {
      return 'TS (Thunderstorm)';
   } elsif ($desc eq 'BL') {
      return 'BL (Blowing)';
   } elsif ($desc eq 'SH') {
      return 'SH (Showers)';
   } elsif ($desc eq 'DR') {
      return 'DR (Drifting)';
   } elsif ($desc eq 'FZ') {
      return 'FZ (Freezing)';
   }
   return "$desc (CHECKME)";
}
sub get_obscuration {
   my ($obs) = shift;
   if ($obs eq 'BR') {
      return 'BR (Mist >= 5/8SM)';
   } elsif ($obs eq 'FG') {
      return 'FG (Fog < 5/8SM)';
   } elsif ($obs eq 'FU') {
      return 'FU (Smoke)';
   } elsif ($obs eq 'VA') {
      return 'VA (Volcanic Ash)';
   } elsif ($obs eq 'SA') {
      return 'SA (Sand)';
   } elsif ($obs eq 'HZ') {
      return 'HZ (Haze)';
   } elsif ($obs eq 'PY') {
      return 'PY (Spray)';
   } elsif ($obs eq 'DU') {
      return 'DU (Widespread dust)';
   }
   ###return "$obs (CHECKME)";
   return get_precipitation($obs);
}
sub get_precipitation {
   my ($prc) = shift;
   if ($prc eq 'DZ') {
      return 'DZ (Drizzle)';
   } elsif ($prc eq 'RA') {
      return 'RA (Rain)';
   } elsif ($prc eq 'SN') {
      return 'SN (Snow)';
   } elsif ($prc eq 'SG') {
      return 'SG (Snow grains)';
   } elsif ($prc eq 'IC') {
      return 'IC (Ice crystals)';
   } elsif ($prc eq 'PL') {
      return 'PL (Ice pellets)';
   } elsif ($prc eq 'GR') {
      return 'GR (Hail)';
   } elsif ($prc eq 'GS') {
      return 'GS (Small hail/snow pellets)';
   } elsif ($prc eq 'UP') {
      return 'UP (Unknown precipitation in automated observations)';
   }
   return "$prc (CHECKME)";
}
sub get_other {
   my ($oth) = shift;
   if ($oth eq 'SQ') {
      return 'SQ (Squall)';
   } elsif ($oth eq 'SS') {
      return 'SS (Sandstorm)';
   } elsif ($oth eq 'DS') {
      return 'DS (Duststorm)';
   } elsif ($oth eq 'PO') {
      return 'PO (Well developed)';
   } elsif ($oth eq 'FC') {
      return 'FC (Funnel cloud)';
   } elsif ($oth eq '+FC') {
      return '+FC (tornado/waterspout)';
   }
   ### ??? dust/sand whirls
   return "$oth (CHECKME)";
}
sub prtw {
   my ($mg, $tf) = @_;
   if ($tf ne $acttaf) {
      $acttaf = $tf;
      push(@warnings,$tf);
   }
   prt($mg);
   chomp $mg;
   push(@warnings,$mg);
}
sub decode_metar {
   my ($tt) = shift;
   my ($part, $ppart, $had_dc, $msg);
   my ($v1,$v2,$v3,$v4,$v5,$v6, $tr, $tmpn, $tmptr);
   my @parts = split(/\s/, $tt);
   my $num_parts = scalar @parts;
   my %decoded_metar = ();
    $decoded_metar{'remarks'} = '';
   $part = '';
   $had_dc = 0;
   $msg = '';
   for (my $i = 0; $i < $num_parts; $i++) {
      $ppart = $part;
      $part = $parts[$i];
      $had_dc = 0;   # no DECODE yet
      # if (ereg('RMK|AFT|TEMPO|BECMG|INTER', $part))
      #if ($part =~ /(RMK|AFT|TEMPO|BECMG|INTER)/) {
      if (($part =~ /(RMK|AFT|TEMPO|BECMG|INTER)/)||($part eq 'BEC')||($part =~ /^BEC([0-9]{2,4})/) ) {
         $msg = "$part - The rest of the METAR is either a remark or temporary information. We keep the remark.";
          $decoded_metar{'remarks'} = $part;
         $i++;
         for ( ; $i < $num_parts; $i++) {
            $part = $parts[$i];
             $decoded_metar{'remarks'} .= ' '.$part;
         }
          $decoded_metar{'remarks'} = trim_all($decoded_metar{'remarks'});
         $had_dc = 1;
         last;
      } elsif (($part eq 'METAR')||($part eq 'SPECI')||($part eq 'TAF')) {
         $msg = "$part - Type of Report: METAR, SPECI, TAF";
         $decoded_metar{'type'} = $part;
         $had_dc = 1;
      ###} elsif ($part eq 'AMD') {
      } elsif ($part =~ /^AMD(.*)$/) {
         $msg = "$part - Qualifier of report.";
         $v1 = $1;
         $tr = 'qualifier';
         $tmptr = $tr;
         $tmpn = 0;
         while (defined $decoded_metar{$tmptr}) {
            $tmpn++;
            $tmptr = $tr.$tmpn;
         }
         if ($v1 && length($v1)) {
            $decoded_metar{$tmptr} = "Amendment $v1";   # $tr = 'qualifier';
         } else {
            $decoded_metar{$tmptr} = 'Amended';
         }
         $had_dc = 1;
      } elsif ($part =~ /^CAVOK(=)?/) {
         $msg = "$part - indicates Ceiling And Visibility OKay";
         # (no cloud below 5000 feet, a visibility of 6 Statute Miles or more and
         # no precipitation, thunderstorms, shallow fog, or low drifting snow) 
         # = indicates the end of the METAR report 
         $v1 = $1;
         if ($v1 && length($v1)) {
            $decoded_metar{'end-report'} = $part.' (Clear, no cloud 5000 feet, vis 6 miles+, no rain ...)';
            last;
         } else {
            $decoded_metar{'indication'} = $part.' (Clear, no cloud 5000 feet, vis 6 miles+, no rain ...)';
         }
         $had_dc = 1;
      } elsif ($part =~ /^[A-Z]{4,5}$/) {
         $msg = "$part - Station Identifier.";
         # $decoded_metar{'icao'}  = $part;
         $v1 = $part;
         $tr = 'icao';
         $tmptr = $tr;
         $tmpn = 0;
         while (defined $decoded_metar{$tmptr}) {
            $tmpn++;
            $tmptr = $tr.$tmpn;
         }
         $decoded_metar{$tmptr} = $v1;
         $had_dc = 1;
      } elsif ($part =~ /([0-9]{2})([0-9]{2})([0-9]{2})Z/) {
         $msg = "$part - DATE, HOUR, MINUTES Z.";
         $decoded_metar{'time'}{'day'} = $1;
         $decoded_metar{'time'}{'hour'} = $2;
         $decoded_metar{'time'}{'mins'} = $3;
         if (($i + 1) < $num_parts) {
            $part = $parts[$i+1];
            if ($part =~ /([0-9]{2})([0-9]{2})([0-9]{2})/) {
               $decoded_metar{'time2'}{'day'} = $1;
               ##$decoded_metar{'time2'}{'hour'} = $2;
               ##$decoded_metar{'time2'}{'mins'} = $3;
               $decoded_metar{'time2'}{'begin-hour'} = $2;
               $decoded_metar{'time2'}{'end-hour'} = $3;
               $i++;
            }
         }
         $had_dc = 1;
      } elsif ($part =~ /([0-9]{4})\/([0-9]{2})\/([0-9]{2})/) {
         $msg = "$part - got a DATE YYYY/MM/DD";
         $decoded_metar{'record_date'}{'year'} = $1;
         $decoded_metar{'record_date'}{'month'} = $2;
         $decoded_metar{'record_date'}{'day'} = $3;
         if (($i + 1) < $num_parts) {
            $part = $parts[$i+1];
            if ($part =~ /([0-9]{2}):([0-9]{2})/) {
               $decoded_metar{'record_date'}{'hour'} = $1;
               $decoded_metar{'record_date'}{'minutes'} = $2;
               $i++;
               $msg .= ", plus $part - HOUR, MINUTES";
            }
         }
         $had_dc = 1;
      } elsif ($part =~ /(AUTO|COR|RTD|CC[A-Z]|RR[A-Z])/ ) {
         $msg = "$part - Report Modifier: AUTO, COR, CCx or RRx";
         $v1 = $1;
         $decoded_metar{'report_mod'} = $v1;
         $had_dc = 1;
      } elsif ($part =~ /([0-9]{3}|VRB)([0-9]{2,3})G?([0-9]{2,3})?(KT|MPS|KMH)/) {
         $msg = "$part - Wind Group";
         # Wind Group = 20006KT
         # Examples:
         #   18010KT - Wind one eight zero at one zero knots 
         # 35012G20KT - Wind three five zero at one two gust two zero knots 
         # 00000KT - Wind calm 
         # VRB16G28KT - Wind variable at one six gust two eight knots  
         $v1 = $1;   # direction, or VRB = variable
         $v2 = $2;   # wind speed
         $v3 = $3;   # gusts, if any
         $v4 = $4;   # units
         $tr = 'wind';
         $tmptr = $tr;
         $tmpn = 0;
         while (defined $decoded_metar{$tmptr}) {
            $tmpn++;
            $tmptr = $tr.$tmpn;
         }
         $decoded_metar{$tmptr}{'deg'} = $v1; # $tmptr = 'wind'.[nn]
         if ($v2 == 0) {
            $decoded_metar{$tmptr}{'knots'} = 0;
            $decoded_metar{$tmptr}{'meters_per_second'} = 0;
            $decoded_metar{$tmptr}{'miles_per_hour'} = 0;
         } else {
            if ($v4 eq 'KT') {
               $decoded_metar{$tmptr}{'knots'} = $v2;
               # The windspeed measured in meters per second, rounded to one decimal place
               # $meterspersec = number_format($value * 0.5144, 1);
               $decoded_metar{$tmptr}{'meters_per_second'} = number_format( ($v2 * 0.5144), 1 );
               # The windspeed measured in miles per hour, rounded to one decimal place
               $decoded_metar{$tmptr}{'miles_per_hour'} = number_format( ($v2 * 1.1508), 1 );
            } elsif ($v4 eq 'MPS') {
               # The windspeed measured in meters per second */
               $decoded_metar{$tmptr}{'meters_per_second'} = number_format( $v2, 1 );
               # The windspeed measured in knots, rounded to one decimal place
               $decoded_metar{$tmptr}{'knots'} = number_format($v2 / 0.5144, 1);
               # The windspeed measured in miles per hour, rounded to one decimal place
               $decoded_metar{$tmptr}{'miles_per_hour'} = number_format($v2 / 0.5144 * 1.1508, 1);
            } elsif ($v4 eq 'KMH') {
               # The windspeed measured in kilometers per hour
               $decoded_metar{$tmptr}{'meters_per_second'} = number_format($v2 * 1000 / 3600, 1);
               $decoded_metar{$tmptr}{'knots'} = number_format($v2 * 1000 / 3600 / 0.5144, 1);
               # The windspeed measured in miles per hour, rounded to one decimal place
               $decoded_metar{$tmptr}{'miles_per_hour'} = number_format($decoded_metar{'wind'}{'knots'} * 1.1508, 1);
            } else {
               $decoded_metar{$tmptr}{'knots'} = "$v2 (KTS assumed!)";
            }
         }
         $had_dc = 1;
      } elsif ($part =~ /^([0-9]{3})V([0-9]{3})$/) { # !empty($decoded_metar['wind'])) {
         $msg = "$part - Variable wind-direction";
         $decoded_metar{'wind'}{'var_beg'} = $1;
         $decoded_metar{'wind'}{'var_end'} = $2;
         $had_dc = 1;
      } elsif ($part =~ /^([0-9]{4})([NS]?[EW]?)$/) {
         $msg = "$part - Visibility in meters (4 digits only).";
         $v1 = $1;
         if ($v1 eq '0000') {
            $decoded_metar{'visibility'}{'prefix'} = -1;
            $decoded_metar{'visibility'}{'meter'}  = 50;
            $decoded_metar{'visibility'}{'km'}     = 0.05;
            $decoded_metar{'visibility'}{'ft'}     = 164;
            $decoded_metar{'visibility'}{'mile'}   = 0.031;
         } elsif ($v1 eq '9999') {
            # elseif ($regs[1] == '9999')
            # Special high value
            $decoded_metar{'visibility'}{'prefix'} = 1;
            $decoded_metar{'visibility'}{'meter'}  = 10000;
            $decoded_metar{'visibility'}{'km'}     = 10;
            $decoded_metar{'visibility'}{'ft'}     = 32800;
            $decoded_metar{'visibility'}{'mile'}   = 6.2;
         } else {
            # Normal visibility, returned in both small and large units.
            $decoded_metar{'visibility'}{'prefix'} = 0;
            $decoded_metar{'visibility'}{'km'}     = number_format($v1 / 1000, 1);
            $decoded_metar{'visibility'}{'meter'}  = number_format($v1, 1);
            $decoded_metar{'visibility'}{'ft'}     = number_format($v1 * 3.28084, 1);
            $decoded_metar{'visibility'}{'mile'}   = number_format($v1 / 1609.344, 1);
         }
         $had_dc = 1;
      } elsif ($part =~ /^(VC)?(-|\+)?(MI|PR|BC|DR|BL|SH|TS|FZ)?((DZ|RA|SN|SG|IC|PL|GR|GS|UP)+)?(BR|FG|FU|VA|DU|SA|HZ|PY)?(PO|SQ|FC|SS)?$/ ) {
         # } elseif (ereg('^(VC)?' .                /* Proximity */
         #     '(-|\+)?' .                          /* Intensity */
         #     '(MI|PR|BC|DR|BL|SH|TS|FZ)?' .       /* Descriptor */
         #     '((DZ|RA|SN|SG|IC|PL|GR|GS|UP)+)?' . /* Precipitation */
         #     '(BR|FG|FU|VA|DU|SA|HZ|PY)?' .       /* Obscuration */
         #     '(PO|SQ|FC|SS)?$',                   /* Other */
         $msg = "$part - Weather.";
         $v1 = $1;
         $v2 = $2;
         $v3 = $3;
         $v4 = $4;
         $v5 = $5;
         $v6 = $6;
         $tr = 'weather';
         $tmptr = $tr;
         $tmpn = 0;
         while (defined $decoded_metar{$tmptr}) {
            $tmpn++;
            $tmptr = $tr.$tmpn;
         }
         # $decoded_metar{'weather'}{'proximity'}     = $v1 if ($v1 && length($v1));
         if ($v1 && length($v1)) {
            if ($v1 eq 'VC') {
               $decoded_metar{$tmptr}{'proximity'}     = 'outside aerodrome (5-10km)'; # 'weather'.[nn]
            } else {
               $decoded_metar{$tmptr}{'proximity'}     = 'outside aerodrome (5-10km) $v1 CHECKME';
            }
         } else {
            $decoded_metar{$tmptr}{'proximity'}     = 'at aerodrome';
         }
         ###$decoded_metar{'weather'}{'intensity'}     = $v2 if ($v2 && length($v2));
         if ($v2 && length($v2)) {
            if ($v2 eq '-') {
               $decoded_metar{$tmptr}{'intensity'} = 'light (-)';
            } elsif ($v2 eq '+') {
               $decoded_metar{$tmptr}{'intensity'} = 'heavy (+)';
            } else {
               $decoded_metar{$tmptr}{'intensity'} = 'unknown ($v2) CHECKME';
            }
         } else {
            # no sign
            $decoded_metar{$tmptr}{'intensity'} = 'moderate (no sign)';
         }
         $decoded_metar{$tmptr}{'decriptor'}     = get_descriptor($v3) if ($v3 && length($v3));
         $decoded_metar{$tmptr}{'precipitation'} = get_precipitation($v4) if ($v4 && length($v4));
         $decoded_metar{$tmptr}{'obscuration'}   = get_obscuration($v5) if ($v5 && length($v5));
         $decoded_metar{$tmptr}{'other'}         = get_other($v6) if ($v6 && length($v6));
         $had_dc = 1;
         # ================================================================================
      } elsif (($part eq 'SKC') || ($part eq 'CLR') || ($part eq 'NSC')) {
         $msg = "$part - Cloud-group.";
         #$decoded_metar{'clouds'}{'condition'} = $part;
         $decoded_metar{'conditions'} = $part.' (Clear)';
         $had_dc = 1;
      ###} elsif ($part =~ /^(VV|FEW|SCT|BKN|OVC)([0-9]{3}|\/\/\/)(CB|TCU)?$/ ) {
      } elsif ($part =~ /^(VV|FEW|SCT|BKN|OVC)([0-9]{2,3}|\/\/\/)(CB|TCU)?$/ ) {
         $msg = "$part - We have found (another) a cloud-layer-group.";
         $v1 = $1;
         $v2  = $2;
         $v3  = $3;
         $tr = 'clouds';
         $tmptr = $tr;
         $tmpn = 0;
         while (defined $decoded_metar{$tmptr}) {
            $tmpn++;
            $tmptr = $tr.$tmpn;
         }
         if ($v2 eq '000') {
            # if ($regs[2] == '000')
            # '000' is a special height.
            $decoded_metar{$tmptr}{'ft'}     = 100; # $tr = 'clouds'.[nn]
            $decoded_metar{$tmptr}{'meter'}  = 30;
            $decoded_metar{$tmptr}{'prefix'} = -1; #/* Less than */
         } elsif ($v2 eq '///') {
            # '///' means height nil
            $decoded_metar{$tmptr}{'ft'}     = 'nil';
            $decoded_metar{$tmptr}{'meter'}  = 'nil';
         } else {
            $decoded_metar{$tmptr}{'ft'}     = $v2 * 100;
            $decoded_metar{$tmptr}{'meter'}  = int($v2 * 30.48);
         }
         $decoded_metar{$tmptr}{'cond'}   = $v3 if ($v3 && length($v3));
         $had_dc = 1;
         ################################################################
      } elsif ($part =~ /^(M?[0-9]{2})\/(M?[0-9]{2}|\/\/)?$/) {
         $msg = "$part - Temperature/Dew Point Group.";
         # eg 12/08-Temperature and Dewpoint
         # 12 represents the temperature in Celcius 
         # 08 represents the dewpoint in Celcius 
         # If the temperature or dewpoint falls below 0 
         # there will be an "M" before it (i.e. 03/M02). "M" means minus. 
         $v1 = $1;
         $v2 = $2;
         $v3 = '';
         if ($v1 && length($v1) && (substr($v1,0,1) eq 'M')) {
            $v3 = '-';
         }
         $decoded_metar{'temperature'}{'temp_c'} = $v3.int($v1);
         $decoded_metar{'temperature'}{'temp_f'} = $v3.int( ($v1 * (9/5)) + 32 );
         # The dewpoint could be missing, this is indicated by the
         # second group being empty at most places, but in the UK they
         # use '//' instead of the missing temperature... */
         $v3 = '';
         if ($v2 && length($v2) && (substr($v2,0,1) eq 'M')) {
            $v3 = '-';
         }
         if (length($v2) && ($v2 ne '//')) {
            $decoded_metar{'temperature'}{'dew_c'} = $v3.int($v2);
            $decoded_metar{'temperature'}{'dew_f'} = $v3.int(($v2 * (9/5)) + 32).'M-';
         }
         $had_dc = 1;
      } elsif ($part =~ /A([0-9]{4})/) {
         $msg = "$part - Altimeter.";
         # The pressure measured in inHg.
         $v1 = $1;
         $tr = 'altimeter';
         $tmptr = $tr;
         $tmpn = 0;
         while (defined $decoded_metar{$tmptr}) {
            $tmpn++;
            $tmptr = $tr.$tmpn;
         }
         $decoded_metar{$tmptr}{'inhg'} = number_format($v1/100, 2); # $tmptr = 'altimeter'.[nn]
         # The pressure measured in mmHg, hPa and atm */
         $decoded_metar{$tmptr}{'mmhg'} = number_format($v1 * 0.254, 1);
         $decoded_metar{$tmptr}{'hpa'}  = int($v1 * 0.33864);
         $decoded_metar{$tmptr}{'atm'}  = number_format(($v1 * 3.3421e-4), 3);
         $msg .= " ($tmptr)";
         $had_dc = 1;
      } elsif ( $part =~ /^Q([0-9]{4})/ ) {
         $msg = "$part - Q Altimeter.";
         $v1 = $1;
         $tr = 'altimeter';
         $tmptr = $tr;
         $tmpn = 0;
         while (defined $decoded_metar{$tmptr}) {
            $tmpn++;
            $tmptr = $tr.$tmpn;
         }
         # The specification doesn't say anything about
         # the Qxxxx-form, but it's in the METARs.
         # /* The pressure measured in hPa */
         $decoded_metar{$tmptr}{'hpa'}  = int($v1);   # $tmptr = 'altimeter'.[nn]
         # /* The pressure measured in mmHg, inHg and atm */
         $decoded_metar{$tmptr}{'mmhg'} = number_format($v1 * 0.75006, 1);
         $decoded_metar{$tmptr}{'inhg'} = number_format($v1 * 0.02953, 2);
         $decoded_metar{$tmptr}{'atm'}  = number_format($v1 * 9.8692e-4, 3);
         $msg .= " ($tmptr)";
         $had_dc = 1;
      } elsif ( $part =~ /^QNH([0-9]{4})INS/ ) {
         $msg = "$part - QNH Altimeter.";
         $v1 = $1;
         $tr = 'altimeter';
         $tmptr = $tr;
         $tmpn = 0;
         while (defined $decoded_metar{$tmptr}) {
            $tmpn++;
            $tmptr = $tr.$tmpn;
         }
         $decoded_metar{$tmptr}{'inhg'} = number_format($v1 / 100, 2);   # $tmptr = 'altimeter'.[nn]
         $decoded_metar{$tmptr}{'mmhg'} = number_format($v1 * 0.254, 2);   # 100 inch to mm
         $decoded_metar{$tmptr}{'hpa'}   = number_format($v1 * 0.338639, 2);
         $decoded_metar{$tmptr}{'atm'}  = number_format(($v1 * 3.3421e-4), 3);
         $msg .= " ($tmptr)";
         $had_dc = 1;
      } elsif ($part =~ /^T([0-9]{4})([0-9]{4})/ ) {
         prtw("WARNING:1: [$part] NOT YET HANDLED!\n", $tt );
#         * Temperature/Dew Point Group, coded to tenth of degree Celsius.
#   $this->store_temp($regs[1] / 10,
#           $decoded_metar['temperature']['temp_c'],
#           $decoded_metar['temperature']['temp_f']);
#   $this->store_temp($regs[2] / 10,
#           $decoded_metar['temperature']['dew_c'],
#           $decoded_metar['temperature']['dew_f']);
      } elsif ($part =~ /^T([0-9]{4}$)/) {
         prtw("WARNING:2: [$part] NOT YET HANDLED!\n", $tt );
#   $this->store_temp($regs[1],
#           $decoded_metar['temperature']['temp_c'],
#           $decoded_metar['temperature']['temp_f']);
      } elsif ($part =~ /^1([0-9]{4}$)/) {
         prtw("WARNING:3: [$part] NOT YET HANDLED!\n", $tt );
#         * 6 hour maximum temperature Celsius, coded to tenth of degree
#   $this->store_temp($regs[1] / 10,
#           $decoded_metar['temp_min_max']['max6h_c'],
#           $decoded_metar['temp_min_max']['max6h_f']);
      } elsif ($part =~ /^2([0-9]{4}$)/) {
         prtw("WARNING:4: [$part] NOT YET HANDLED!\n", $tt );
#         * 6 hour minimum temperature Celsius, coded to tenth of degree
#   $this->store_temp($regs[1] / 10,
#           $decoded_metar['temp_min_max']['min6h_c'],
#           $decoded_metar['temp_min_max']['min6h_f']);
      } elsif ($part =~ /^4([0-9]{4})([0-9]{4})$/) {
         prtw("WARNING:5: [$part] NOT YET HANDLED!\n", $tt );
#         * 24 hour maximum and minimum temperature Celsius, coded to
#         * tenth of degree
#   $this->store_temp($regs[1] / 10,
#           $decoded_metar['temp_min_max']['max24h_c'],
#           $decoded_metar['temp_min_max']['max24h_f']);
#   $this->store_temp($regs[2] / 10,
#           $decoded_metar['temp_min_max']['min24h_c'],
#           $decoded_metar['temp_min_max']['min24h_f']);
      } elsif ($part =~ /^P([0-9]{4})/) {
         prtw("WARNING:6: [$part] NOT YET HANDLED!\n", $tt );
#         * Precipitation during last hour in hundredths of an inch
#   if ($regs[1] == '0000') {
#     $decoded_metar['precipitation']['in'] = -1;
#     $decoded_metar['precipitation']['mm'] = -1;
#   } else {
#          $decoded_metar['precipitation']['in'] =
#            number_format($regs[1]/100, 2);
#          $decoded_metar['precipitation']['mm'] =
#            number_format($regs[1]*0.254, 2);
#   }
      } elsif ($part =~ /^6([0-9]{4})/) {
         $msg = "$part - Precipitation during last 3 or 6 hours in hundredths of an inch.";
         $v1 = $1;
         $tr = 'precititation';
         $tmptr = $tr;
         $tmpn = 0;
         while (defined $decoded_metar{$tmptr}) {
            $tmpn++;
            $tmptr = $tr.$tmpn;
         }
         if ($v1 eq '0000') {
            $decoded_metar{$tmptr}{'in_6h'} = -1;
            $decoded_metar{$tmptr}{'mm_6h'} = -1;
         } else {
            $decoded_metar{$tmptr}{'in_6h'} = number_format($v1/100, 2);
            $decoded_metar{$tmptr}{'mm_6h'} = number_format($v1*0.254, 2);
         }
         $msg .= " ($tmptr)";
         $had_dc = 1;
      } elsif ($part =~ /^7([0-9]{4})/ ) {
         prtw("WARNING:8: [$part] NOT YET HANDLED!\n", $tt );
#         * Precipitation during last 24 hours in hundredths of an inch.
#   if ($regs[1] == '0000') {
#     $decoded_metar['precipitation']['in_24h'] = -1;
#     $decoded_metar['precipitation']['mm_24h'] = -1;
#   } else {
#          $decoded_metar['precipitation']['in_24h'] =
#            number_format($regs[1]/100, 2, '.', '');
#          $decoded_metar['precipitation']['mm_24h'] =
#            number_format($regs[1]*0.254, 2, '.', '');
#   }
      } elsif ($part =~ /^4\/([0-9]{3})/) {
         prtw("WARNING:9: [$part] NOT YET HANDLED!\n", $tt );
#         * Snow depth in inches
#   if ($regs[1] == '0000') {
#     $decoded_metar['precipitation']['snow_in'] = -1;
#     $decoded_metar['precipitation']['snow_mm'] = -1;
#   } else {
#     $decoded_metar['precipitation']['snow_in'] = $regs[1] * 1;
#     $decoded_metar['precipitation']['snow_mm'] = round($regs[1] * 25.4);
#   }
      } elsif ($part =~ /^PROB([0-9]{1,2})/) {
         $msg = "$part - Probability.";
         # PROB40 2022 Probability. The probability of a weather event occurring is given in percent
         # along with the 2-digit Zulu hour start and end of the event. 
         $v1 = $1;
         $decoded_metar{'probability'}{'percent'} = $v1;
         if (($i + 1) < $num_parts) {
            $part = $parts[$i+1];
            if ($part =~ /^([0-9]{2})([0-9]{2})$/) {
               $v1 = $1;
               $v2 = $2;
               $decoded_metar{'probability'}{'start'} = $v1;
               $decoded_metar{'probability'}{'end'} = $v2;
               $msg .= " (Bgn=$v1, End=$v2)";
               $i++;
            }
         }
         $had_dc = 1;
      } elsif ($part =~ /^M?(([0-9]?)[ ]?([0-9])(\/?)([0-9]*))SM$/ ) {
         # Examples:
         # 1/2SM - Visibility one-half statute mile 
         # 2 1/4SM - Visibility two and one-quarter statute miles 
         # 5SM - Visibility five statute miles 
         # P6SM - Visibility more than six statute miles  
         $v1 = $1;
         $v2 = $2;
         $v3 = $3;
         $v4 = $4;
         prtw("WARNING:10: [$part] NOT YET HANDLED! v1=[$v1] v2=[$v2] v3=[$v3] v4=[$v4] \n", $tt );
      } elsif ($part =~ /([0-9]{2})([0-9]{2})([0-9]{2})/) {
         $v1 = $1;
         $v2 = $2;
         $v3 = $3;
         $tr = 'time-range';
         $tmptr = $tr;
         $tmpn = 0;
         while (defined $decoded_metar{$tmptr}) {
            $tmpn++;
            $tmptr = $tr.$tmpn;
         }
         $decoded_metar{$tmptr}{'day'} = $v1;
         $decoded_metar{$tmptr}{'begin-hour'} = $v2;
         $decoded_metar{$tmptr}{'end-hour'} = $v3;
      } elsif ($part =~ /^FM([0-9]{2})([0-9]{2})/) {
         # eg FM1930 = FroM and 2-digit hour and 2-digit minute
         # beginning time: indicates significant change.
         # Each FM starts on a new line, indented 5 spaces.
         $v1 = $1;
         $v2 = $2;
         $tr = 'time-range';
         $tmptr = $tr;
         $tmpn = 0;
         while (defined $decoded_metar{$tmptr}) {
            $tmpn++;
            $tmptr = $tr.$tmpn;
         }
         $decoded_metar{$tmptr}{'begin-hour'} = $v1;
         $decoded_metar{$tmptr}{'begin-mins'} = $v2;
      } elsif ($part =~ /^FM([0-9]{2})$/) {
         # eg FM19 = FroM and 2-digit hour assume 00 minute
         # beginning time: indicates significant change.
         # Each FM starts on a new line, indented 5 spaces.
         $v1 = $1;
         $v2 = '00';
         $tr = 'time-range';
         $tmptr = $tr;
         $tmpn = 0;
         while (defined $decoded_metar{$tmptr}) {
            $tmpn++;
            $tmptr = $tr.$tmpn;
         }
         $decoded_metar{$tmptr}{'begin-hour'} = $v1;
         $decoded_metar{$tmptr}{'begin-mins'} = $v2;
      } else {
#      } else {
#         * If we couldn't match the group, we assume that it was a remark.
#   $decoded_metar['remarks'] .= ' ' . $part;
#      }
#    }
         prtw("WARNING:ELSE: [$part] NO CASE FOR THIS!\n", $tt );
         if (defined $decoded_metar{'UNDECODED'}) {
            $decoded_metar{'UNDECODED'} .= ' '.$part;
         } else {
            $decoded_metar{'UNDECODED'} = $part;
         }
      }
   }
   return %decoded_metar;
}
#  function decode_metar($index=false) {
#    /* initialization */
#    $temp_visibility_miles = '';
#    $decoded_metar['remarks'] = '';
#    $decoded_metar['location'] = $this->get_location();
#
#    /* Make sure we got the metar */
#    $tmp_metar = $this->get_metar();
#
#    /* Setup other variables */
#    if ($index===false) { /* We are getting the current METAR */
#      $decoded_metar['metar'] = $tmp_metar;
#      $decoded_metar['time'] = $this->metar_time;
#    }
#    else {
#      if ($this->metar_arch===false) { /* error */
#   return false;
#      } 
#      $tmp_metar = $this->metar_arch[$index]['metar'];
#      $decoded_metar['metar'] = $tmp_metar;
#      $decoded_metar['time'] = $this->metar_arch[$index]['time'];
#    }
#
#    /* We parse the METAR */
#    $parts = explode(' ', $tmp_metar);
#    $num_parts = count($parts);
#    
#    for ($i = 0; $i < $num_parts; $i++) {
#      $part = $parts[$i];
#      
#      if (ereg('RMK|AFT|TEMPO|BECMG|INTER', $part)) {
#        /* The rest of the METAR is either a remark or temporary
#         * information. We keep the remark.
#         */
#   for($j=$i;$j<$num_parts; $j++)
#     $decoded_metar['remarks'] .= ' ' . $parts[$j];
#   $decoded_metar['remarks'] = trim($decoded_metar['remarks']);
#    break;
#      } elseif ($part == 'METAR') {
#        /*
#         * Type of Report: METAR
#         */
#   $decoded_metar['type'] = 'METAR';
#      } elseif ($part == 'SPECI') {
#        /*
#         * Type of Report: SPECI
#         */
#   $decoded_metar['type'] = 'SPECI';
#      } elseif (ereg('^[A-Z]{4}$', $part) &&
#                empty($decoded_metar['icao']))  {
#        /*
#         * Station Identifier
#         */
#   $decoded_metar['icao']  = $part;
#//       } elseif (ereg('([0-9]{2})([0-9]{2})([0-9]{2})Z', $part, $regs)) {
#//         /*
#//          * Date and Time of Report.
#//          *
#//          * We return a standard Unix UTC/GMT timestamp suitable for
#//          * gmdate().
#//          *
#//          * If you experience incorrect timestamps but cannot set the
#//          * clock, then you can set $this->properties['offset'] to be
#//          * the offset in hours to add. For example, if your times
#//          * generated are 1 hour too early (so METARs appear an hour
#//          * older than they are), set $this->properties['offset'] to be
#//          * +1 in your defaults.php file.
#//          */
#
#//     if ($regs[1] > gmdate('j')) {
#//            /* The day is greather that the current day of month => the
#//             * report is from last month. 
#//             */
#//       $month = gmdate('n') - 1;
#//     } else {
#//       $month = gmdate('n');
#//     }
#
#//     $decoded_metar['time'] =
#//           gmmktime($regs[2] + $this->properties['offset'],
#//                    $regs[3], 0, $month, $regs[1], gmdate('Y'));
#
#
#      } elseif (ereg('(AUTO|COR|RTD|CC[A-Z]|RR[A-Z])', $part, $regs)) {
#        /*
#         * Report Modifier: AUTO, COR, CCx or RRx
#         */
#        $decoded_metar['report_mod'] = $regs[1];
#      } elseif (ereg('([0-9]{3}|VRB)([0-9]{2,3})G?([0-9]{2,3})?(KT|MPS|KMH)', $part, $regs)) {
#        
#        /* Wind Group */
#   
#   $decoded_metar['wind']['deg'] = $regs[1];
#   
#   $this->store_speed($regs[2],
#            $regs[4],
#            $decoded_metar['wind']['knots'],
#            $decoded_metar['wind']['meters_per_second'],
#            $decoded_metar['wind']['miles_per_hour']);
#   
#   if (!empty($regs[3])) {
#          
#          /* We have a report with information about the gust.
#           * First we have the gust measured in knots.
#           */
#     $this->store_speed($regs[3],
#              $regs[4],
#              $decoded_metar['wind']['gust_knots'],
#              $decoded_metar['wind']['gust_meters_per_second'],
#              $decoded_metar['wind']['gust_miles_per_hour']);
#   }
#      } elseif (ereg('^([0-9]{3})V([0-9]{3})$', $part, $regs) &&
#                !empty($decoded_metar['wind'])) {
#        
#        /*
#         * Variable wind-direction
#         */
#        $decoded_metar['wind']['var_beg'] = $regs[1];
#   $decoded_metar['wind']['var_end'] = $regs[2];
#      } elseif (ereg('^([0-9]{4})([NS]?[EW]?)$', $part, $regs)) {
#        /* 
#         * Visibility in meters (4 digits only)
#         */
#        unset($group);
#
#        if ($regs[1] == '0000') {
#          /* Special low value */
#          
#     $group['prefix'] = -1; /* Less than */
#          $group['meter']  = 50;
#          $group['km']     = 0.05;
#          $group['ft']     = 164;
#          $group['miles']  = 0.031;
#   } elseif ($regs[1] == '9999') {
#          /* Special high value */
#          $group['prefix'] = 1; 
#          $group['meter']  = 10000;
#          $group['km']     = 10;
#          $group['ft']     = 32800;
#          $group['miles']  = 6.2;
#   } else {
#          /* Normal visibility, returned in both small and large units. */
#          $group['prefix'] = 0; 
#          $group['km']     = number_format($regs[1]/1000, 1);
#          $group['miles']  = number_format($regs[1]/1609.344, 1);
#          $group['meter']  = $regs[1] * 1;
#          $group['ft']     = round($regs[1] * 3.28084);
#   }
#   if (!empty($regs[2])) {
#     $group['deg'] = $regs[2];
#   }
#        $decoded_metar['visibility'][] = $group;
#
#      } elseif (ereg('^[0-9]$', $part)) {
#        /*
#         * Temp Visibility Group, single digit followed by space.
#         */
#        $temp_visibility_miles = $part;
#      } elseif (ereg('^M?(([0-9]?)[ ]?([0-9])(/?)([0-9]*))SM$',
#                     $temp_visibility_miles . ' ' . $part, $regs)) {
#        /*
#         * Visibility Group
#         */
#        unset($group);
#
#   if ($regs[4] == '/') {
#     $vis_miles = $regs[2] + $regs[3]/$regs[5];
#        } else {
#          $vis_miles = $regs[1];
#        }
#        if ($regs[0][0] == 'M') {
#          /* Prefix - less than */
#          $group['prefix'] = -1;
#        } else {
#          $group['prefix'] = 0;
#        }
#        
#        /* The visibility measured in miles */
#        $group['miles']  = number_format($vis_miles, 1);
#        
#        /* The visibility measured in feet */
#        $group['ft']     = round($vis_miles * 5280, 1);
#        
#        /* The visibility measured in kilometers */
#        $group['km']     = number_format($vis_miles * 1.6093, 1);
#        
#        /* The visibility measured in meters */
#        $group['meter']  = round($vis_miles * 1609.3);
#
#        $decoded_metar['visibility'][] = $group;
#      } elseif ($part == 'CAVOK') {
#        /* CAVOK is used when the visibility is greater than 10
#         * kilometers, the lowest cloud-base is at 5000 feet or more
#         * and there is no significant weather.
#         */
#        unset($group);
#        $group['prefix'] = 1; 
#        $group['km']     = 10;
#        $group['meter']  = 10000;
#        $group['miles']  = 6.2;
#        $group['ft']     = 32800;
#        $decoded_metar['visibility'][] = $group;
#        $decoded_metar['clouds'][]['condition'] = 'CAVOK';
#
#      } elseif (ereg('^R([0-9]{2})([RLC]?)/([MP]?)([0-9]{4})' .
#                     '([DNU]?)V?(P?)([0-9]{4})?([DNU]?)$', $part, $regs)) {
#        /* Runway-group */
#        unset($group);
#        $group['nr'] = $regs[1];
#   if (!empty($regs[2])) {
#     $group['approach'] = $regs[2];
#   }
#   
#   if (!empty($regs[7])) {
#          /* We have both min and max visibility since $regs[7] holds
#           * the max visibility.
#           */
#          if (!empty($regs[5])) { 
#            /* $regs[5] is tendency for min visibility. */
#            $group['min_tendency'] = $regs[5];
#     }
#     
#          if (!empty($regs[8])) { 
#            /* $regs[8] is tendency for max visibility. */
#            $group['max_tendency'] = $regs[8];
#     }
#     
#     if ($regs[3] == 'M') {
#            /* Less than. */
#            $group['min_prefix'] = -1;
#     }
#          $group['min_meter'] = $regs[4] * 1;
#          $group['min_ft']    = round($regs[4] * 3.2808);
#     
#     if ($regs[6] == 'P') {
#            /* Greater than. */
#            $group['max_prefix'] = 1;
#     }
#          $group['max_meter'] = $regs[7] * 1;
#          $group['max_ft']    = round($regs[7] * 3.2808);
#     
#   } else {
#          /* We only have a single visibility. */
#          
#          if (!empty($regs[5])) { 
#            /* $regs[5] holds the tendency for visibility. */
#            $group['tendency'] = $regs[5];
#     }
#     
#     if ($regs[3] == 'M') {
#            /* Less than. */
#            $group['prefix'] = -1;
#     } elseif ($regs[3] == 'P') {
#            /* Greater than. */
#            $group['prefix'] = 1;
#     }
#          $group['meter'] = $regs[4] * 1;
#          $group['ft']    = round($regs[4] * 3.2808);
#   }
#        $decoded_metar['runway'][] = $group;
#        
#      } elseif (ereg('^(VC)?' .                           /* Proximity */
#           '(-|\+)?' .                          /* Intensity */
#           '(MI|PR|BC|DR|BL|SH|TS|FZ)?' .       /* Descriptor */
#           '((DZ|RA|SN|SG|IC|PL|GR|GS|UP)+)?' . /* Precipitation */
#           '(BR|FG|FU|VA|DU|SA|HZ|PY)?' .       /* Obscuration */
#           '(PO|SQ|FC|SS)?$',                   /* Other */
#           $part, $regs)) {
#        /*
#         * Current weather-group.
#         */
#        $decoded_metar['weather'][] =
#          array('proximity'     => $regs[1],
#                'intensity'     => $regs[2],
#                'descriptor'    => $regs[3],
#                'precipitation' => $regs[4],
#                'obscuration'   => $regs[6],
#                'other'         => $regs[7]);
#        
#      } elseif ($part == 'SKC' || $part == 'CLR') {
#        /* Cloud-group */
#        $decoded_metar['clouds'][]['condition'] = $part;
#
#      } elseif (ereg('^(VV|FEW|SCT|BKN|OVC)([0-9]{3}|///)' .
#                     '(CB|TCU)?$', $part, $regs)) {
#        /* We have found (another) a cloud-layer-group. */
#        unset($group);
#
#   $group['condition'] = $regs[1];
#   if (!empty($regs[3])) {
#     $group['cumulus'] = $regs[3];
#   }
#   if ($regs[2] == '000') {
#          /* '000' is a special height. */
#          $group['ft']     = 100;
#          $group['meter']  = 30;
#          $group['prefix'] = -1; /* Less than */
#   } elseif ($regs[2] == '///') {
#          /* '///' means height nil */
#          $group['ft']     = 'nil';
#          $group['meter']  = 'nil';
#   } else {
#          $group['ft']     = $regs[2] *100;
#          $group['meter']  = round($regs[2] * 30.48);
#   }
#        $decoded_metar['clouds'][] = $group;
#
#      } elseif (ereg('^(M?[0-9]{2})/(M?[0-9]{2}|//)?$', $part, $regs)) {
#        /*
#         * Temperature/Dew Point Group.
#         */
#        $decoded_metar['temperature']['temp_c'] =
#          round(strtr($regs[1], 'M', '-'));
#        $decoded_metar['temperature']['temp_f'] =
#          round(strtr($regs[1], 'M', '-') * (9/5) + 32);
#        
#        /* The dewpoint could be missing, this is indicated by the
#         * second group being empty at most places, but in the UK they
#         * use '//' instead of the missing temperature... */
#   if (!empty($regs[2]) && $regs[2] != '//') {
#          $decoded_metar['temperature']['dew_c'] =
#            round(strtr($regs[2], 'M', '-'));
#          $decoded_metar['temperature']['dew_f'] =
#            round(strtr($regs[2], 'M', '-') * (9/5) + 32);
#   }
#      } elseif (ereg('A([0-9]{4})', $part, $regs)) {
#        /*
#         * Altimeter.
#         * The pressure measured in inHg.
#         */
#        $decoded_metar['altimeter']['inhg'] =
#          number_format($regs[1]/100, 2);
#        
#        /* The pressure measured in mmHg, hPa and atm */
#        $decoded_metar['altimeter']['mmhg'] =
#          number_format($regs[1] * 0.254, 1, '.', '');
#        $decoded_metar['altimeter']['hpa']  =
#          round($regs[1] * 0.33864);
#   $decoded_metar['altimeter']['atm']  =
#          number_format($regs[1] * 3.3421e-4, 3, '.', '');
#      } elseif (ereg('Q([0-9]{4})', $part, $regs)) {
#        /*
#         * Altimeter.
#         * The specification doesn't say anything about
#         * the Qxxxx-form, but it's in the METARs.
#         */
#        
#        /* The pressure measured in hPa */
#        $decoded_metar['altimeter']['hpa']  = round($regs[1]);
#        
#        /* The pressure measured in mmHg, inHg and atm */
#        $decoded_metar['altimeter']['mmhg'] =
#          number_format($regs[1] * 0.75006, 1, '.', '');
#        $decoded_metar['altimeter']['inhg'] =
#          number_format($regs[1] * 0.02953, 2);
#        $decoded_metar['altimeter']['atm']  =
#          number_format($regs[1] * 9.8692e-4, 3, '.', '');
#      } elseif (ereg('^T([0-9]{4})([0-9]{4})', $part, $regs)) {
#        
#        /*
#         * Temperature/Dew Point Group, coded to tenth of degree Celsius.
#         */
#   $this->store_temp($regs[1] / 10,
#           $decoded_metar['temperature']['temp_c'],
#           $decoded_metar['temperature']['temp_f']);
#   $this->store_temp($regs[2] / 10,
#           $decoded_metar['temperature']['dew_c'],
#           $decoded_metar['temperature']['dew_f']);
#      } elseif (ereg('^T([0-9]{4}$)', $part, $regs)) {
#   $this->store_temp($regs[1],
#           $decoded_metar['temperature']['temp_c'],
#           $decoded_metar['temperature']['temp_f']);
#      } elseif (ereg('^1([0-9]{4}$)', $part, $regs)) {
#        
#        /*
#         * 6 hour maximum temperature Celsius, coded to tenth of degree
#         */
#   $this->store_temp($regs[1] / 10,
#           $decoded_metar['temp_min_max']['max6h_c'],
#           $decoded_metar['temp_min_max']['max6h_f']);
#      } elseif (ereg('^2([0-9]{4}$)', $part, $regs)) {
#        
#        /*
#         * 6 hour minimum temperature Celsius, coded to tenth of degree
#         */
#   $this->store_temp($regs[1] / 10,
#           $decoded_metar['temp_min_max']['min6h_c'],
#           $decoded_metar['temp_min_max']['min6h_f']);
#      } elseif (ereg('^4([0-9]{4})([0-9]{4})$', $part, $regs)) {
#        
#        /*
#         * 24 hour maximum and minimum temperature Celsius, coded to
#         * tenth of degree
#         */
#   $this->store_temp($regs[1] / 10,
#           $decoded_metar['temp_min_max']['max24h_c'],
#           $decoded_metar['temp_min_max']['max24h_f']);
#   $this->store_temp($regs[2] / 10,
#           $decoded_metar['temp_min_max']['min24h_c'],
#           $decoded_metar['temp_min_max']['min24h_f']);
#      } elseif (ereg('^P([0-9]{4})', $part, $regs)) {
#        
#        /*
#         * Precipitation during last hour in hundredths of an inch
#         */
#   if ($regs[1] == '0000') {
#     $decoded_metar['precipitation']['in'] = -1;
#     $decoded_metar['precipitation']['mm'] = -1;
#   } else {
#          $decoded_metar['precipitation']['in'] =
#            number_format($regs[1]/100, 2);
#          $decoded_metar['precipitation']['mm'] =
#            number_format($regs[1]*0.254, 2);
#   }
#      } elseif (ereg('^6([0-9]{4})', $part, $regs)) {
#        
#        /*
#         * Precipitation during last 3 or 6 hours in hundredths of an
#         * inch.
#         */
#   if ($regs[1] == '0000') {
#     $decoded_metar['precipitation']['in_6h'] = -1;
#     $decoded_metar['precipitation']['mm_6h'] = -1;
#   } else {
#          $decoded_metar['precipitation']['in_6h'] =
#            number_format($regs[1]/100, 2);
#          $decoded_metar['precipitation']['mm_6h'] =
#            number_format($regs[1]*0.254, 2);
#   }
#      } elseif (ereg('^7([0-9]{4})', $part, $regs)) {
#        
#        /*
#         * Precipitation during last 24 hours in hundredths of an inch.
#         */
#   if ($regs[1] == '0000') {
#     $decoded_metar['precipitation']['in_24h'] = -1;
#     $decoded_metar['precipitation']['mm_24h'] = -1;
#   } else {
#          $decoded_metar['precipitation']['in_24h'] =
#            number_format($regs[1]/100, 2, '.', '');
#          $decoded_metar['precipitation']['mm_24h'] =
#            number_format($regs[1]*0.254, 2, '.', '');
#   }
#      } elseif (ereg('^4/([0-9]{3})', $part, $regs)) {
#        
#        /*
#         * Snow depth in inches
#         */
#   if ($regs[1] == '0000') {
#     $decoded_metar['precipitation']['snow_in'] = -1;
#     $decoded_metar['precipitation']['snow_mm'] = -1;
#   } else {
#     $decoded_metar['precipitation']['snow_in'] = $regs[1] * 1;
#     $decoded_metar['precipitation']['snow_mm'] = round($regs[1] * 25.4);
#   }
#      } else {
#        
#        /*
#         * If we couldn't match the group, we assume that it was a
#         * remark.
#         */
#   $decoded_metar['remarks'] .= ' ' . $part;
#      }
#    }
#    
#    /*
#     * Relative humidity
#     */
#    if (!empty($decoded_metar['temperature']['temp_c']) &&
#   !empty($decoded_metar['temperature']['dew_c'])) {
#
#      $decoded_metar['rel_humidity'] =
#        number_format(pow(10, (1779.75 * ($decoded_metar['temperature']['dew_c'] -
#                                          $decoded_metar['temperature']['temp_c'])
#                               / ((237.3 + $decoded_metar['temperature']['dew_c']) *
#                                  (237.3 + $decoded_metar['temperature']['temp_c']))
#                               + 2)), 1);
#    } 
#    
#    
#    /*
#     *  Compute windchill if temp < 40f and windspeed > 3 mph
#     */
#    if (!empty($decoded_metar['temperature']['temp_f']) && 
#        $decoded_metar['temperature']['temp_f'] <= 40 &&
#        !empty($decoded_metar['wind']['miles_per_hour']) &&
#        $decoded_metar['wind']['miles_per_hour'] > 3) {
#      $decoded_metar['windchill']['windchill_f'] = 
#        number_format(35.74 + 0.6215*$decoded_metar['temperature']['temp_f'] 
#                      - 35.75*pow((float)$decoded_metar['wind']['miles_per_hour'], 0.16) 
#                      + 0.4275*$decoded_metar['temperature']['temp_f'] * 
#                      pow((float)$decoded_metar['wind']['miles_per_hour'], 0.16));
#      $decoded_metar['windchill']['windchill_c'] = 
#        number_format(13.112 + 0.6215*$decoded_metar['temperature']['temp_c']
#                      - 13.37*pow(($decoded_metar['wind']['miles_per_hour']/1.609), 0.16)
#                      + 0.3965*$decoded_metar['temperature']['temp_c'] *
#                      pow(($decoded_metar['wind']['miles_per_hour']/1.609), 0.16));
#    }
#   
#    /*
#     * Compute heat index if temp > 70F
#     */
#    if (!empty($decoded_metar['temperature']['temp_f']) &&
#        $decoded_metar['temperature']['temp_f'] > 70 &&
#        !empty($decoded_metar['rel_humidity'])) {
#      $decoded_metar['heatindex']['heatindex_f'] =
#        number_format(-42.379
#                      + 2.04901523 * $decoded_metar['temperature']['temp_f']
#                      + 10.1433312 * $decoded_metar['rel_humidity']
#                      - 0.22475541 * $decoded_metar['temperature']['temp_f']
#                                   * $decoded_metar['rel_humidity']
#                      - 0.00683783 * $decoded_metar['temperature']['temp_f']
#                                   * $decoded_metar['temperature']['temp_f']
#                      - 0.05481717 * $decoded_metar['rel_humidity']
#                                   * $decoded_metar['rel_humidity']
#                      + 0.00122874 * $decoded_metar['temperature']['temp_f']
#                                   * $decoded_metar['temperature']['temp_f']
#                                   * $decoded_metar['rel_humidity']
#                      + 0.00085282 * $decoded_metar['temperature']['temp_f']
#                                   * $decoded_metar['rel_humidity']
#                                   * $decoded_metar['rel_humidity']
#                      - 0.00000199 * $decoded_metar['temperature']['temp_f']
#                                   * $decoded_metar['temperature']['temp_f']
#                                   * $decoded_metar['rel_humidity']
#                                   * $decoded_metar['rel_humidity']);
#     $decoded_metar['heatindex']['heatindex_c'] =
#       number_format(($decoded_metar['heatindex']['heatindex_f'] - 32) / 1.8);
#    }
#
#    /*
#     * Compute the humidity index
#     */
#    if (!empty($decoded_metar['rel_humidity'])) {
#      $e = (6.112 * pow(10, 7.5 * $decoded_metar['temperature']['temp_c']
#                        / (237.7 + $decoded_metar['temperature']['temp_c']))
#            * $decoded_metar['rel_humidity'] / 100) - 10;
#      $decoded_metar['humidex']['humidex_c'] =
#        number_format($decoded_metar['temperature']['temp_c'] + 5/9 * $e, 1);
#      $decoded_metar['humidex']['humidex_f'] =
#        number_format($decoded_metar['humidex']['humidex_c'] * 9/5 + 32, 1);
#    }
#
#
#    /* Finally we store our decoded METAR in $this->decoded_metar so
#     * that other methods can use it.
#     */
#    if ($index===false) $this->decoded_metar = $decoded_metar;
#    else $this->decoded_metar_arch[$index] = $decoded_metar;
#
#    return $decoded_metar;
#  }
sub load_airport_file {
   my ($aptdat) = shift;   # = $APTFILE;
   my ($line, $alat, $alon, $icao, $name, $rlat, $rlon);
   my (@arr, @arr2);
   prt("\nLoading $aptdat file ...\n");
   mydie("ERROR: Can NOT locate $aptdat ...$!...\n") if ( !( -f $aptdat) );
   ###open IF, "<$aptdat" or mydie("OOPS, failed to open [$aptdat] ... check name and location ...\n");
   open IF, "gzip -d -c $aptdat|" or mydie( "ERROR: CAN NOT OPEN $aptdat...$!...\n" );
   my @lines = <IF>;
   close IF;
   my $cnt = scalar @lines;
   prt( "Processing $cnt lines ...\n" );
   my $apt = '';
   my $rwycnt = 0;
   my $glat = 0;
   my $glon = 0;
   my $totaptcnt = 0;   # count another AIRPORT
   foreach $line (@lines) {
      $line = trim_all($line);
      ###prt("$line\n");
      @arr = split(/ /,$line);
      if ($line =~ /^$aln\s+/) {   # start with '1'
         if (length($apt) && ($rwycnt > 0)) {
            $alat = $glat / $rwycnt;
            $alon = $glon / $rwycnt;
            @arr2 = split(/ /,$apt);
            $icao = $arr2[4];
            $name = join(' ', splice(@arr2,5));
            push(@aptlist, [$icao, $name, $alat, $alon]);
         }
         $apt = $line;
         $rwycnt = 0;
         $glat = 0;
         $glon = 0;
         $totaptcnt++;   # count another AIRPORT
      } elsif ($line =~ /^$rln\s+/) {
         $rlat = $arr[1];
         $rlon = $arr[2];
         ###prt( "$line [$rlat, $rlon]\n" );
         $glat += $rlat;
         $glon += $rlon;
         $rwycnt++;
      } elsif ($line =~ /^$lastln\s?/) {   # 99, followed by space, count 0 or more ...
         prt( "Reached END OF FILE ... \n" );
         last;
      }
   }
         if (length($apt) && ($rwycnt > 0)) {
            $alat = $glat / $rwycnt;
            $alon = $glon / $rwycnt;
            @arr2 = split(/ /,$apt);
            $icao = $arr2[4];
            $name = join(' ', splice(@arr2,5));
            push(@aptlist, [$icao, $name, $alat, $alon]);
         }
}
sub get_fix_len {
   my ($d) = shift;
   my $stg = sprintf("%03.7f", $d);
   my @arr = split(/\./,$stg);
   if (scalar @arr == 2) {
      $arr[0] = ' '.$arr[0] while ( length($arr[0]) < 4 );
      $stg = $arr[0].'.'.$arr[1];
   }
   return $stg;
}
sub show_airport {
   my ($off) = shift;
   # push(@aptlist, [$icao, $name, $alat, $alon]);
   my $cnt = scalar @aptlist;
   if (($off > 0) && ($off <= $cnt)) {
      $off--;   # back up to logical
      my $icao = $aptlist[$off][0];
      $icao .= ' ' while (length($icao) < 4);
      my $name = $aptlist[$off][1];
      my $alat = $aptlist[$off][2];
      my $alon = $aptlist[$off][3];
      my $slat = get_fix_len($alat);
      my $slon = get_fix_len($alon);
      prt( "$icao $slat $slon $name\n" );
   }
}
# eof

index -|- top

checked by tidy  Valid HTML 4.01 Transitional