'Cookie: pwp_mig_status=0'); $needCookie = array('kflhuds05.tripod.com' => 'Cookie: CookieStatus=COOKIE_OK,MEMBER_PAGE=kflhuds05/VWS_stickertags.htm,REFERRER=' ); // special handling for websites with Last-modified header not correct //#needTimeAdjust = array('briantet.tripod.com' => 7100); (time adjust in seconds) $needTimeAdjust = array('briantet.tripod.com' => 7100 ); // ------------------------------------------------------------- // ------- end of settings ------ /// ------ begin code ---------- if (isset($_REQUEST['sce']) && strtolower($_REQUEST['sce']) == 'view' ) { //--self downloader -- $filenameReal = __FILE__; $download_size = filesize($filenameReal); header('Pragma: public'); header('Cache-Control: private'); header('Cache-Control: no-cache, must-revalidate'); header("Content-type: text/plain"); header("Accept-Ranges: bytes"); header("Content-Length: $download_size"); header('Connection: close'); readfile($filenameReal); exit; } // Map specific settings .. DO NOT CHANGE unless graphic is changed to match these $MapWidth = 621; // map image width in px $MapHeight = 547; // map image height in px $LegendX = 290; // left: for rotating legend display in px $LegendY = 215; // top: for rotating legend display in px $ControlsX = 10; // left: for control display in px $ControlsY = 10; // top: for control display in px //------------ end of map-specific settings --------------- // include the settings override file if it exists if ($includeConfig and file_exists("SWN-mesomap-config.txt")) { require_once("SWN-mesomap-config.txt"); } // Check parameters and force defaults/ranges $IncludeMode = false; $PrintMode = true; $showNoData = false; // exclude table rows with no conditions data available.. screws up sort if enabled if (isset($doPrintSWN) && ! $doPrintSWN ) { $PrintMode = false; } if (isset($_REQUEST['inc']) && strtolower($_REQUEST['inc']) == 'noprint' ) { $PrintMode = false; } if (isset($_REQUEST['inc']) && strtolower($_REQUEST['inc']) == 'y') { $IncludeMode = true; } if (isset($doIncludeSWN)) { $IncludeMode = $doIncludeSWN; } if ( ! isset($_REQUEST['inc']) ) $_REQUEST['inc']=""; $includeOnly = strtolower($_REQUEST['inc']); // any nonblank is ok if ($includeOnly) {$includeOnly = "Y";} if (isset($_REQUEST['inc']) and strtoupper($_REQUEST['inc']) == 'CSS') {$CSSonly = true;} else {$CSSonly = false;} // show map with hotspots outlined if (isset($_REQUEST['show']) and strtolower($_REQUEST['show']) == 'map' ) { $ShowMap = '&show=map'; $genJPEG = true; } else { $ShowMap = ''; // no outlines for map $genJPEG = false; } if($windArrowDir && ! file_exists("$windArrowDir" . 'NNE.gif') ) { $windArrowDir = ''; // bad spec.. no arrows found } if($condIconsDir && ! file_exists("$condIconsDir" . 'day_clear.gif') ) { $condIconsDir = ''; // bad spec.. no icons found } if (isset($_REQUEST['cfg']) and strtolower($_REQUEST['cfg']) == 'debug') { $doDebug = true; } else { $doDebug = false; } $doDebug = true; $Debug = "\n"; if (isset($_REQUEST['cache']) and strtolower($_REQUEST['cache']) == 'no') { $refetchSeconds = 10; // set short period for refresh of cache } $maxAge = $maxAge + $refetchSeconds + 10; // no age penalty from caching $maxAgeMetar = $maxAgeMetar + $refetchSeconds + 10; // no cache penalty // HTML specific overrides if desired $otherParms = ''; if (isset($_REQUEST['gen']) and strtolower($_REQUEST['gen']) == 'xhtml' ) { $TARGET = ''; // no target for XHTML 1.0-Strict $otherParms = "&gen=xhtml"; } else { $TARGET = "target=\"_blank\""; $otherParms = "&gen=html"; } if(!isset($PHP_SELF)) {$PHP_SELF = $_SERVER['PHP_SELF']; } $t = pathinfo($PHP_SELF); $Program = $t['basename']; $ourHost = $_SERVER['HTTP_HOST']; $mc = parse_url($masterCacheURL); $masterHost = $mc['host']; $onMasterHost = false; if ($ourHost == $masterHost) {$onMasterHost = true; } $Debug .= "\n"; // Establish timezone offset for time display if (! ini_get('safe_mode') ) { putenv("TZ=$ourTZ"); // set our timezone for 'as of' date on file } // ---------------------main program ----------------------------------- // open and read links file global $Debug,$doDebug,$cacheName,$refetchSeconds,$Icons,$windArrowDir,$wxInfo, $metarPtr, $group; global $showTownName; $updatedOn = filemtime($LinksFile); // for our 'as of' date $updatedOnG = filemtime($Graphic); // for graphic file $Stations = array(); // storage area for the station info $StationData = array(); // storage area for current conditions $StationStats = array(); // storage for fetch stats for station $wxInfo = array(); $timeStamp = time(); $currentTime = date($timeFormat,$timeStamp); $METARcache = array(); // so we only have to fetch once a metar for this execution $METARcacheHits = array(); // count of hits on $METARcache load_config($LinksFile); // load up the $Stations from the config file // show jpg image of map with hotspots outlined if (isset($_REQUEST['show']) and strtolower($_REQUEST['show']) == 'map' ) { $ShowMap = '&show=map'; $genJPEG = 1; } else { $ShowMap = ''; // no outlines for map $genJPEG = 0; } // show image of map with hotspots outlined if (isset($_REQUEST['show']) and strtolower($_REQUEST['show']) == 'hotspots' ) { $ourGraphic = $SCRIPT_URI . "?show=map"; $toggleState = "Now showing Hotspots -- click to show normal graphic.\n"; } else { $ourGraphic = $Graphic; // no outlines for map $toggleState = "Now showing normal graphic -- click to show hotspots outlined.\n"; } if ($genJPEG) { // just produce the map with hotspots outlined outline_hotspots($ourGraphic); exit; } load_strings(); // Load up the CSS and boilerplates $Units = load_units($myUOM); gen_CSS(); // generate the CSS first if ($CSSonly) { // just print the CSS and exit print $CSS; return; } load_iconDefs(); // create definitions for condition icons $TotalTime = load_weather_data(); // this is the time consumer :-) reset($Stations); // and reset the list from the config file $lastState = ''; // to handle the sublists // generate the links list sorted by State, Station name while (list($key, $val) = each($Stations)) { list($State,$Name) = explode("\t",$key); list($URL,$Coords,$Features,$DataPage) = explode("\t",$Stations["$key"]); if ($lastState <> $State) { if ($lastState) { // not first state $html .= " \n"; $html .= " \n"; } $html .= "
  • $State\n"; $html .= '
      ' . "\n"; $lastState = $State; } // different state $t = ''; if ($TARGET) {$t = " $TARGET";} $html .= "
    1. $Name [ " . $Features . " ]
    2. \n"; } // end while $html .= "
    \n"; $html .= "
  • \n"; $html .= "\n"; // generate the MAP list sorted by State, Station name $html .= '' . "\n"; prt_tablehead(); // initialize the $table area with col heads reset($Stations); // and reset the list so we can start at begining $lastState = ''; // to handle the sublists while (list($key, $val) = each($Stations)) { list($State,$Name) = explode("\t",$key); list($URL,$Coords,$Features,$DataPage) = explode("\t",$Stations["$key"]); prt_tabledata($key); if ($lastState <> $State) { $html .= "\n"; $lastState = $State; } $t = ''; if ($TARGET) {$t = "\n $TARGET";} $html .= " \""\n"; } // end while // --------------- customize HTML if you like ----------------------- $table .= "\n\n

     

    \n\n"; // finish up the CSS/HTML assembly strings $html .= "
    \n"; $oldestData = 9999999999999999; $newestData = 0; foreach ($StationData as $key => $vals) { list($TEMP,$HUMID,$WDIR,$WSPD,$RAIN,$BARO,$BTRND,$COND,$CTXT,$DEWPT,$GUST,$UDATE,$FTIME) = preg_split("/\,/",$vals); if($UDATE > 1000) { $oldestData = min($UDATE,$oldestData); $newestData = max($UDATE,$newestData); } } $scroller .= " \n"; $scroller .= "

    Conditions data shown was collected
    from " . date($timeFormat,$oldestData) . " to " . date($timeFormat,$newestData) . "

    \n"; $table .= "\n"; // text is done now in $html if ($PrintMode and ! $includeOnly and ! $genJPEG) { // print headers only if inc parm omitted ?> Generate SWN mesomap code - <?php echo $Version ?>

    Southwestern Weather Network mesomap -

    Detailed instructions on how to implement/maintain on your website are available here.

    New PHP users: You can download a starter .zip file, unpack it and upload to your website. It includes all files required by the script and the proper subdirectory structure (for ./SWN-images/). Then you can use the links below to refresh the components.

    PHP users: Download graphic file updated on " . date($timeFormat,$updatedOnG) . "
        (Right click on link above and save to $Graphic on your offline copy of your website,
         then upload it to your website).
    PHP users: Download data file updated on " . date($timeFormat,$updatedOn) . "
        (Right click on link above and save to $LinksFile on your website)
    PHP users: If needed, download PHP source for $scriptName $Version.
        (Note: only needed if your copy of the script is older than this one)
        (Right click on link above, then save page as SWN-mesomap.php on your website).

    HTML users: Please use the IFRAME method to include the mesomap in your HTML-only website.

    Top of page | Preview of code

    "; print "

    Preview of SWN meso-map

    \n

    $toggleState

    \n"; print $htmlstart . $ourGraphic . $htmlnext . $scroller . $html; print prt_jscript(); print $table; if ($doDebug) { print $Debug; } print '

    Generating '; if ($TARGET <> '') { print "HTML 4.01"; $toggleGenState = "XHTML 1.0-Strict"; } else { print "XHTML 1.0-Strict"; $toggleGenState = "HTML 4.01"; } print ' code (change to '. $toggleGenState . ')

    '; $scriptName = substr($PHP_SELF,1); print "

    Top of page | Preview of code

    Generated by $scriptName - $Version
    Author: Ken True - webmaster@saratoga-weather.org

    "; } else if ($PrintMode) { // if including .. just print it print $htmlstart . $ourGraphic . $htmlnext . $scroller . $html; print prt_jscript(); print $table; if ($doDebug) {print $Debug; } } else { // end of if not includeOnly global $SWN_MAP, $SWN_TABLE, $SWN_CSS; $SWN_MAP = $htmlstart . $ourGraphic . $htmlnext . $scroller . $html . prt_jscript(); $SWN_TABLE = $table; $SWN_CSS = $CSS; if ($doDebug) {$SWN_TABLE .= $Debug; } } return; //-------------------end of main program ------------------- //----------------------------functions ----------------------------------- // Generate CSS for positioning rollover conditions display function gen_CSS () { global $CSS, $Stations, $LegendX, $LegendY; $Top = 35; // default location for values legend on map $Left = 350; if ($LegendX) {$Left = $LegendX;} if ($LegendY) {$Top = $LegendY;} //------------customize this CSS entry for font/color/background for legend $CSS .= "#mesolegend { top: ${Top}px; left: ${Left}px; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 14pt; font-weight: bold; color: #FFFFFF; padding: 6px 6px; border: 1px solid white; } "; while (list($key, $val) = each($Stations)) { list($State,$Name,$Seqno) = explode("\t",$key); list($URL,$Coords,$Features,$DataPage,$RawDataType,$RawDataURL,$Offsets) = explode("\t",$Stations["$key"]); $URLparts = parse_url($URL); $host = $URLparts['host']; $hostalias = preg_replace('/www\.|\.\w{3}|\W/s','',$host); $hostalias = preg_replace('/weather/','wx',$hostalias); $hostalias .= "S$Seqno"; // generate the CSS to place the rotating display over the map $Coords = preg_replace("|\s|is","",$Coords); list($Left,$Top,$Right,$Bottom) = explode(",",$Coords . ',,,,'); list($OLeft,$OTop) = explode(",",$Offsets . ',,'); if (! $Offsets) { // use default positioning $Top = $Top - 2; $Left = $Right + 2; } else { // use relative positioning from bottom/left $Top = $Bottom + $OTop; $Left = $Right + $OLeft; } $CSS .= "#$hostalias { top: ${Top}px; left: ${Left}px; } "; } // end while $Stations $CSS .= "\n\n"; reset($Stations); // and reset the list return; } // end gen_CSS // ------------------------------------------------------------------ // produce the table heading row function prt_tablehead ( ){ global $Units, $table, $scroller, $CSS, $LegendX, $LegendY,$showTownName; // --------------- customize HTML if you like ----------------------- $table .= "

    Note: Click on table column heading below to sort table by that column's vaues.

    "; $scroller .= "

     Temperature   Dew Point   Humidity   Wind from direction @ Speed/Gust   Rain today   Barometer & Trend   Current Conditions   Fire Danger based on 
     Chandler Burn Index 
    "; if($showTownName) { $scroller .= "  City/Town "; } $scroller .= "

    \n"; $scroller .= '

    '; return; } // end function prt_tablehead // ------------------------------------------------------------------ // produce one row of current conditions data function prt_tabledata($key) { global $StationData,$Stations,$Units,$table,$scroller,$CSS,$StationStats; global $skipNoData,$windArrowDir,$showNoData,$TARGET, $windArrowSize,$Icons,$condIconsDir; global $IconsText, $showBaroTrendArrow, $showMapCondIcons, $NAtext, $showTownName; if ($skipNoData && ! isset($StationData["$key"])) { return; } list($State,$Name,$Seqno) = explode("\t",$key); list($URL,$Coords,$Features,$DataPage,$RawDataType,$RawDataURL) = explode("\t",$Stations["$key"]); $URLparts = parse_url($URL); $host = $URLparts['host']; $hostalias = preg_replace('/www\.|\.\w{3}|\W/s','',$host); $hostalias = preg_replace('/weather/','wx',$hostalias); $hostalias .= "S$Seqno"; if ($windArrowSize == 'S') { $windGIF = '-sm.gif'; $windSIZE = 'height="9" width="9"'; } else { $windGIF = '.gif'; $windSIZE = 'height="14" width="14"'; } if (! isset($StationData["$key"])) { if ($showNoData) { $table .= " "; } // end showNoData //---------------------------- $scroller .= "

    $NAtext $NAtext $NAtext $NAtext $NAtext $NAtext $NAtext $NAtext "; if($showTownName) { $scroller .= " $Name"; } $scroller .= "

    \n"; //---------------------------- return; } // got data for one of our stations.. format the table entry list($TEMP,$HUMID,$WDIR,$WSPD,$RAIN,$BARO,$BTRND,$COND,$CTXT,$DEWPT,$GUST,$UDATE,$FTIME) = preg_split("/\,/",$StationData["$key"]); // --------------- customize HTML if you like ----------------------- $t = ''; if ($TARGET) {$t = " $TARGET";} $table .= " \n"; // generate the data for the changing conditions display // NOTE: changes here may break the rotating conditions display.. $scroller .= "

    $TEMP " . $Units['temp'] . " DP $DEWPT " . $Units['temp'] . " $HUMID " . $Units['humid'] . " "; $wda = ''; if ($WDIR <> 'n/a') { $wda = $WDIR; if ($windArrowDir) { $scroller .= "\"Wind"; } $gust = ''; if ($GUST > 0) {$gust = "G $GUST"; } $scroller .= $WDIR . "  $WSPD $gust " . $Units['wind'] ; } else { $scroller .= $WDIR; } $scroller .= " $RAIN ". $Units['rain'] . " "; if ($BARO <> '') { $scroller .= "$BARO ". $Units['baro']; if ($showBaroTrendArrow) { $scroller .= getBaroTrendArrow($BTRND); } else { list($t,$q) = explode(" ",$BTRND); $scroller .= " $BTRND"; } } $scroller .= " "; if ($showMapCondIcons and preg_match('|.gif$|',$COND) && $condIconsDir) { $scroller .= "\"$CTXT\" "; } list($mt,$t) = explode(":",$CTXT . '::'); if ($t <> '') { $scroller .= trim($t); } else { $scroller .= trim($mt); } $scroller .= "\n"; $scroller .= "" . getFireDanger($TEMP,$HUMID) . "\n"; // if($showTownName) { $tname = explode(',',$Name.','); // take the short name if commas are found $tname = $tname[0]; $scroller .= " $tname"; } $scroller .= "

    \n"; return; } // end prt_tabledata // ------------------------------------------------------------------ // load JPG image for hotspot work function loadJPEG ($imgname) { $im = @imagecreatefromjpeg ($imgname); /* Attempt to open */ if (!$im) { /* See if it failed */ $im = imagecreate (150, 30); /* Create a blank image */ $bgc = imagecolorallocate ($im, 255, 255, 255); $tc = imagecolorallocate ($im, 0, 0, 0); imagefilledrectangle ($im, 0, 0, 150, 30, $bgc); /* Output an errmsg */ imagestring ($im, 1, 5, 5, "Error loading $imgname", $tc); } return $im; } // ------------------------------------------------------------------ // load the configuration file and set up $Stations function load_config($LinksFile) { global $Stations; $rawlinks = file($LinksFile); // read file into array // strip comment records, build $Stations indexed array $nrec = 0; $Seqno = 0; foreach ($rawlinks as $rec) { $Seqno++; $rec = preg_replace("|[\n\r]*|","",$rec); $len = strlen($rec); if($rec and substr($rec,0,1) <> "#") { //only take non-comments // echo "Rec $nrec ($len): $rec\n"; list($State,$URL,$Name,$Coords,$Features,$DataPage,$RawDataType,$RawDataURL,$Offsets,$METAR,$LatLong) = explode("|",trim($rec) . '||||||||||||'); $Stations["$State\t$Name\t$Seqno"] = "$URL\t$Coords\t$Features\t$DataPage\t$RawDataType\t$RawDataURL\t$Offsets\t$METAR\t$LatLong"; // prepare for sort // echo "$Name $State, coord=\"$Coords\"\n"; } elseif (strlen($rec) > 0) { // echo "comment $nrec ($len): $rec\n"; } else { // echo "blank record ignored\n"; } $nrec++; } ksort($Stations); // now sort the keys (state, station name) } // ------------------------------------------------------------------ // fetch the weather data from stations and place in $StationData function load_weather_data() { global $Stations,$StationData,$StationRawData,$Debug,$maxAge, $cacheName,$refetchSeconds,$masterCacheURL,$onMasterHost,$StationStats,$timeFormat,$needTimeAdjust; // use cache if current and available if ($onMasterHost or ($cacheName<>'' and file_exists($cacheName) and filemtime($cacheName) + $refetchSeconds > time())) { $rawcache = file($cacheName); if (preg_match('|\t\d+\||',$rawcache[0])) { $Debug .= "\n"; if($onMasterHost) {$Debug .= "\n"; } foreach ($rawcache as $rec) { list($key,$val) = explode('|',trim($rec).'|'); if ($key <> '') { $StationData["$key"] = $val; } } return; } else { $Debug .= "\n"; } } // Fetch master cache data if available if ($masterCacheURL <> '' and ! $onMasterHost) { $Debug .= "\n"; $rawcache = fetchURLWithoutHanging($masterCacheURL,false); list($headers,$content) = explode("\r\n\r\n",$rawcache); $cache = explode("\n",$content); $html = ''; if ($cache and preg_match('| 200 OK|i',$headers) and preg_match('|\t\d+\||',$cache[0])) { foreach ($cache as $rec) { $html .= trim($rec) . "\n"; list($key,$val) = explode('|',trim($rec) . '|'); if ($key <> '') { $StationData["$key"] = $val; } } $fp = fopen($cacheName, "w"); if (! $fp ) { $Debug .= "\n"; } else { $write = fputs($fp, $html); fclose($fp); $Debug .= "\n"; } return; } else { // failed to get master cache so have to load the hard way $Debug .= "\n"; $Debug .= "\n"; $cache = ''; } } $total_time = 0; $Debug .= "\n"; while (list($key, $val) = each($Stations)) { list($State,$Name) = explode("\t",$key); list($URL,$Coords,$Features,$DataPage,$RawDataType,$RawDataURL,$Offsets,$METAR,$LatLong) = explode("\t",$Stations["$key"]); if (! $RawDataURL && $DataPage) { // fetch datapage instead $RawDataType = 'SWN'; $RawDataURL = "$DataPage"; } if(preg_match('|^http|i',$RawDataURL)) { // do nothing.. url fully formed } else { $URLparts = parse_url($URL); $RawDataURL = 'http://' . $URLparts['host'] . '/' . $RawDataURL; } if($RawDataURL && $RawDataType ) { $Debug .= "\n\n"; $useFopen = false; if ($RawDataType == 'STF' || $RawDataType == 'CRF') { $useFopen = true; } $time_start = microtime_float(); $rawhtml = fetchUrlWithoutHanging($RawDataURL,$useFopen); $time_stop = microtime_float(); $total_time += ($time_stop - $time_start); $time_fetch = sprintf("%01.3f",round($time_stop - $time_start,3)); $RC = ''; if (preg_match("|^HTTP\/\S+ (.*)\r\n|",$rawhtml,$matches)) { $RC = trim($matches[1]); } $Debug .= "\n"; // list($headers,$content) = explode("\r\n\r\n",$rawhtml); // split headers from html $i = strpos($rawhtml,"\r\n\r\n"); $headers = substr($rawhtml,0,$i-1); $content = substr($rawhtml,$i+2); $html = explode("\n",$content); // put HTML area as separate lines $age = 0; if(preg_match('|\nLast-Modified: (.*)\n|Ui',$headers,$match)) { $udate = trim($match[1]); $utimestamp = strtotime($udate); $age = abs(time() - $utimestamp); // age in seconds // do time fixup if need be for hosts with funky Last-modified: dates foreach ($needTimeAdjust as $th => $tadj) { if(preg_match("|".$th."|Ui",$RawDataURL) and $age > 1 * $tadj ) { $age = $age - 1 * $tadj; $Debug .= "\n"; } } $Debug .= "\n"; } $metric = implode('',$html); // now put as one long string $metric = preg_replace('||is','',$metric); // clean out any javascript $metric = preg_replace('|<[^>]+>|is','',$metric); // clean out any HTML markup $metric = preg_replace('|\s+,|is',',',$metric); // clean out unwanted spaces $metric = preg_replace('|\s{2,}0\s*$|is',' ',$metric); // clean out unwanted junk at end of record $metric = preg_replace('|\s+|is',' ',$metric); // prune multi-spaces to single spaces $metric = preg_replace('|^\S{3}\s+|is','',$metric); // Tehachapi/tripod.net tweak for bad html $metric = trim($metric); // stickertag metric should be ok $Debug .= "\n"; if (!preg_match('|200 |',$RC) or (! preg_match('|^\d|',$metric) && $RawDataType <> 'SWN') ) { $Debug .= "\n"; $Debug .= "\n"; } else { if ($age <= $maxAge) { $StationData["$key"] = parse_data($metric,$RawDataType,$METAR,$DataPage) . ",$utimestamp,$time_fetch"; // save away the raw values $Debug .= "\n\n"; } else { $Debug .= "\n\n"; } } } // if $RawDataURL $localUdate = date($timeFormat,strtotime($udate)); // $StationStats["$key"] = "$RawDataType\t$time_fetch\t$age\t$localUdate"; } // end while $Debug .= "\n"; if ($cacheName <> '') { // create cache of values $html = ''; while (list($key, $val) = each($StationData)) { $html .= $key . "|" . $val . "\n"; } $fp = fopen($cacheName, "w"); if (! $fp ) { $Debug .= "\n"; } else { $write = fputs($fp, $html); fclose($fp); $Debug .= "\n"; } } } // ------------------------------------------------------------------ function microtime_float() { list($usec, $sec) = explode(" ", microtime()); return ((float)$usec + (float)$sec); } // ------------------------------------------------------------------ function parse_data($metric,$RawDataType,$METAR,$DataPage) { global $Debug,$Icons,$IconsText,$dpTemp,$dpBaro,$dpRain,$dpWind,$myUOM,$Units; // from the returned data, select the variables we'll use if ($RawDataType == 'ST' || $RawDataType == 'STF') { // a stickertag format for international: // // 0: , // 1: , // 2: , // 3: , // 4: , // 5: , // 6: , // 7: , // 8: , // 9: , //10: , //11: // old record ended here '12:44pm,7/3/06,99,101,97,31,63,29.90,Falling,2,SE,0.00,3' //12: ^curr_cconds1^ in VWS, null for WeatherLink //13: //14: //15: , //16: , //17: ||| // '3:55,28/08/08,14.8,14.9,14.8,90,13.2,1016.9,Falling Slowly,1.6,WNW,0.0,, 6:31,20:25,1.8,8.0,°C|km/hr|mb|mm' // $v = explode(",",$metric); $SuomTemp = $Units['temp']; // make (possibly bad) assumption that station is reporting using the $SuomWind = $Units['wind']; // same units of measure as the mesomap, so no conversion will be done $SuomBaro = $Units['baro']; $SuomRain = $Units['rain']; if(preg_match('/\|\S+\|/',$metric)) { $Debug .= "\n"; // handle international style tags if(isset($v[17]) and preg_match('/\|/',$v[17])) { $UNITS = explode('|',trim($v[17]).'||||'); if($UNITS[3] <> '' and strlen($UNITS[3]) > 2) { $UNITS[3] = substr($UNITS[3],0,2); } if($UNITS[0] <> '') {$SuomTemp = $UNITS[0];} if($UNITS[1] <> '') {$SuomWind = $UNITS[1];} if($UNITS[2] <> '') {$SuomBaro = $UNITS[2];} if($UNITS[3] <> '') {$SuomRain = $UNITS[3];} $Debug .= "\n"; } else { $SuomTemp = $Units['temp']; // make (possibly bad) assumption that station is reporting using the $SuomWind = $Units['wind']; // same units of measure as the mesomap, so no conversion will be done $SuomBaro = $Units['baro']; $SuomRain = $Units['rain']; $Debug .= "\n"; } $TEMP = convertTemp(trim($v[2]),$SuomTemp); $HUMID= round(trim($v[5]),0); $DEWPT = convertTemp(trim($v[6]),$SuomTemp); $WDIR = split(" ",trim($v[10])); $WDIR = $WDIR[0]; // handle spaces in wind-dir from edhweather if (preg_match('|\d+|',$WDIR)) { $Debug .= "\n"; // handle USA style stickertags // 0: , // 1: , // 2: , // 3: , // 4: , // 5: , // 6: , // 7: , // 8: , // 9: , //10: , //11: //'12:44pm,7/3/06,99,101,97,31,63,29.90,Falling,2,SE,0.00,3' $SuomTemp = $Units['temp']; // make (possibly bad) assumption that station is reporting using the $SuomWind = $Units['wind']; // same units of measure as the mesomap, so no conversion will be done $SuomBaro = $Units['baro']; $SuomRain = $Units['rain']; $v = explode(",",$metric); $TEMP = convertTemp($v[2],$SuomTemp); $HUMID= round(trim($v[5]),0); $DEWPT = convertTemp($v[6],$SuomTemp); $WDIR = split(" ",trim($v[10])); $WDIR = $WDIR[0]; // handle spaces in wind-dir from edhweather if (preg_match('|\d+|',$WDIR)) { $Debug .= "\n"; $TEMP = convertTemp($v[2],$SuomTemp); $MINITEMP = convertTemp($v[28],$SuomTemp); $DEWPT = convertTemp($v[4],$SuomTemp); $HUMID= round(trim($v[3]), 0); $WDIR = trim($v[11]); $WSPD = convertWind( trim($v[5]),$SuomWind); $WGST = convertWind( trim($v[40]),$SuomWind); $MAXWIND = convertWind($v[30],$SuomWind); $MAXGUST = convertWind($v[32],$SuomWind); $RAIN = convertRain(trim($v[9]),$SuomRain); $YMRAIN = convertRain(trim($v[21]),$SuomRain); $MRAIN = convertRain(trim($v[20]),$SuomRain); $RRATE = convertRain(trim($v[8]),$SuomRain); $BARO = convertBaro(trim($v[10]),$SuomBaro); $BTRND = set_barotrend(trim($v[18])); $TIME = $v[1]; $COND = ''; // no conditions from Cumulus realtime.txt file if ($METAR <> '') { list($Sky,$Weather) = explode("|",getMetar($METAR)); $COND = decode_VWS_conds('',strtoupper($Sky),'',''); if ($COND <> '') { $CTXT = "Metar $METAR: $Sky"; } } $OLDRAIN = 0; } // end STCU type if ($RawDataType == 'CR' || $RawDataType == 'CRF') { // WeatherDisplay clientraw.txt format // clientraw is in metric always $v = explode(" ",$metric); // clientraw is space-delimited $SuomTemp = 'C'; // clientraw.txt is always in C,kts,hPa,mm $SuomWind = 'kts'; $SuomBaro = 'hPa'; $SuomRain = 'mm'; $Debug .= "\n"; // $DATE = "$v[74]"; // $TIME = sprintf ("%02d:%02d", $v[29], $v[30]); $WDIR = getWindDir($v[3]); $WSPD = convertWind($v[1],$SuomWind); $GUST = convertWind($v[2],$SuomWind); $TEMP = convertTemp($v[4],$SuomTemp); $HUMID = round(trim($v[5]),0); $BARO = convertBaro($v[6],$SuomBaro); $BTRND = set_barotrend($v[50]); $RAIN = convertRain($v[7],$SuomRain); if(M_NETID == 'NZWN' and isset($v[162]) and !preg_match($v[162],'/^!!C/')) { // NZ Rain value $Debug .= "\n"; $RAIN = convertRain($v[162],$SuomRain); } // $WDCH = round((1.8*$v[44]) + 32),1); $DEWPT = convertTemp($v[72],$SuomTemp); // $HEAT = round((1.8*$v[112]) + 32),1); // $SPCT = "$v[34]"; // $SOLR = "$v[127]"; // $UV = "$v[79]"; $COND = $Icons[$v[48]]; // condition icon $CTXT = $IconsText[$v[48]]; // Text description } // end CR (clientraw) type //V2.01 - bad sensor removal based on SwnData entries if(preg_match('/notemp|nohum|norain|nobaro|nowind/i',$DataPage)) { $Debug .= "\n"; } if(preg_match('/notemp/i',$DataPage)) { $Debug .= "\n"; $TEMP = '-'; } if(preg_match('/nohum/i',$DataPage)) { $Debug .= "\n"; $HUMID = '-'; } if(preg_match('/notemp|nohum/i',$DataPage)) { $Debug .= "\n"; $DEWPT = '-'; } if(preg_match('/norain/i',$DataPage)) { $Debug .= "\n"; $RAIN = '-'; } if(preg_match('/nobaro/i',$DataPage)) { $Debug .= "\n"; $BARO = '-'; $BTRND = '-'; } if(preg_match('/nowind/i',$DataPage)) { $Debug .= "\n"; $WSPD = '-'; $WDIR = '-'; $GUST = '-'; } return("$TEMP,$HUMID,$WDIR,$WSPD,$RAIN,$BARO,$BTRND,$COND,$CTXT,$DEWPT,$GUST"); } // ------------------------------------------------------------ // utility functions to handle conversions from clientraw data to desired units-of-measure function convertTemp ($rawtemp,$usedunit) { global $myUOM,$dpTemp; if ($myUOM == 'E') { if (preg_match('|C|i',$usedunit)) { // convert C to F return( sprintf("%01.${dpTemp}f",round((1.8 * $rawtemp) + 32.0,$dpTemp))); } else { // leave as F return (sprintf("%01.${dpTemp}f", round($rawtemp*1.0,$dpTemp))); } } if ($myUOM == 'M') { if (preg_match('|F|i',$usedunit)) { // convert F to C return( sprintf("%01.${dpTemp}f",round(($rawtemp-32.0) / 1.8,$dpTemp))); } else { // leave as C return (sprintf("%01.${dpTemp}f", round($rawtemp*1.0,$dpTemp))); } } } function convertWind ( $rawwind,$usedunit) { global $myUOM,$useKnots,$useMPH,$useMPS,$dpWind,$Debug; $using = ''; $WIND = ''; // first convert all winds to knots $WINDkts = 0.0; if (preg_match('/kts/i',$usedunit)) { $WINDkts = $rawwind * 1.0; } elseif (preg_match('/mph/i',$usedunit)) { $WINDkts = $rawwind * 0.8689762; } elseif (preg_match('/mps|m\/s/i',$usedunit)) { $WINDkts = $rawwind * 1.94384449; } elseif (preg_match('/kmh|km\/h/i',$usedunit)) { $WINDkts = $rawwind * 0.539956803; } else { $Debug .= "\n"; $WINDkts = $rawwind * 1.0; } // now $WINDkts is wind speed in Knots convert to desired form and decimals if ($myUOM == 'M' and ! ($useKnots || $useMPH || $useMPS)) { // output KMH $WIND = sprintf($dpWind?"%02.${dpWind}f":"%d",round($WINDkts * 1.85200,$dpWind)); $using = 'KMH'; } if (($myUOM == 'E' or $useMPH) and ! ($useKnots || $useMPS)) { $WIND = sprintf($dpWind?"%02.${dpWind}f":"%d",round($WINDkts * 1.15077945,$dpWind)); $using = 'MPH'; } if ($useMPS) { $WIND = sprintf($dpWind?"%02.${dpWind}f":"%d",round($WINDkts * 0.514444444,$dpWind)); $using = 'M/S'; } if ($useKnots or $WIND == '') { $WIND = sprintf($dpWind?"%02.${dpWind}f":"%d",round($WINDkts * 1.0,$dpWind)); $using = 'KTS'; } $Debug .= "\n"; return($WIND); } function convertBaro ( $rawpress,$usedunit ) { global $myUOM,$dpBaro; if ($myUOM == 'E') { // convert hPa to inHg if (preg_match('/hPa|mb/i',$usedunit)) { return (sprintf("%02.${dpBaro}f",round($rawpress / 33.86388158,$dpBaro))); } elseif (preg_match('/mm/i',$usedunit)) { return (sprintf("%02.${dpBaro}f",round($rawpress * 0.0393700787,$dpBaro))); } else { return (sprintf("%02.${dpBaro}f",round($rawpress * 1.0,$dpBaro))); // leave in hPa } } if ($myUOM == 'M') { // convert inHg to hPa if (preg_match('/hPa|mb/i',$usedunit)) { return (sprintf("%02.${dpBaro}f",round($rawpress * 1.0,$dpBaro))); // leave in hPa } elseif (preg_match('/mm/i',$usedunit)) { return (sprintf("%02.${dpBaro}f",round($rawpress * 1.333224,$dpBaro))); } else { return (sprintf("%02.${dpBaro}f",round($rawpress / 33.86388158,$dpBaro))); } } } function convertRain ( $rawrain,$usedunit ) { global $myUOM,$dpRain; if ($myUOM == 'E') { // convert mm to inches if ($usedunit == "mm") { return (sprintf("%02.${dpRain}f",round($rawrain * .0393700787,$dpRain))); } else { return (sprintf("%02.${dpRain}f",round($rawrain * 1.0,$dpRain))); // leave in mm } } if ($myUOM == 'M') { // convert inches to mm if ($usedunit == "mm") { return (sprintf("%02.${dpRain}f",round($rawrain * 1.0,$dpRain))); // leave in mm } else { return (sprintf("%02.${dpRain}f",round($rawrain * .0393700787,$dpRain))); } } } // ------------------------------------------------------------ function getMetar($icao) { global $Debug,$wxInfo,$maxAgeMetar; $Sky = ''; $Weather = ''; $Debug .= "\n"; $host = 'weather.noaa.gov'; $path = '/pub/data/observations/metar/stations/'; $MetarURL = 'http://' . $host . $path . $icao . '.TXT'; $time_start = microtime_float(); $rawhtml = fetchUrlWithoutHanging($MetarURL,false); list($headers,$html) = explode("\r\n\r\n",$rawhtml); $time_stop = microtime_float(); $total_time += ($time_stop - $time_start); $time_fetch = sprintf("%01.3f",round($time_stop - $time_start,3)); $Debug .= "\n"; $raw_metar = ereg_replace("[\n\r ]+", ' ', trim(implode(' ', (array)$html))); $Debug .= "\n"; $metar = trim($raw_metar); $metarDate = preg_replace('|/|','-',substr($metar,0,16)) . ':00 GMT'; $age = abs(time() - strtotime($metarDate)); // age in seconds $Debug .= "\n"; if ($age >= $maxAgeMetar) { $Debug .= "\n"; return('' . '|' . ''); } error_reporting(E_ALL); process_metar($metar,$icao); error_reporting(0); $Debug .= "\n"; $Sky = trim($wxInfo['CLOUDS']); $Weather = trim($wxInfo['CONDITIONS']); if ($Sky && $Weather) { $Sky = $Weather; } if ($Sky && ! $Weather) { $Weather = $Sky; } return($Sky . '|' . $Weather); } // end getMetar functions // ------------------------------------------------------------ // get contents from one URL and return as string function fetchUrlWithoutHanging($url,$useFopen) { // thanks to Tom at Carterlake.org for this script fragment global $Debug, $needCookie,$timeStamp,$TOTALtime; $overall_start = time(); if (! $useFopen) { // Set maximum number of seconds (can have floating-point) to wait for feed before displaying page without feed $numberOfSeconds=4; // Suppress error reporting so Web site visitors are unaware if the feed fails error_reporting(0); // Extract resource path and domain from URL ready for fsockopen $FullUrl = $url; $urlParts = parse_url($url); $domain = $urlParts['host']; if(isset($urlParts['port'])) { $port = $urlParts['port']; } else { $port = 80; } $resourcePath = $urlParts['path']; $resourcePath = preg_replace('|nocache|','?'.$timeStamp,$resourcePath); if(isset($urlParts['query'])) {$resourcePath .= "?" . $urlParts['query']; } if(isset($urlParts['fragment'])) {$resourcePath .= "#" . $urlParts['fragment']; } $T_start = microtime_float(); $hostIP = gethostbyname($domain); $T_dns = microtime_float(); $ms_dns = sprintf("%01.3f",round($T_dns - $T_start,3)); $Debug .= "\n"; // print "GET $resourcePath HTTP/1.1 \n Host: $domain Port: $port IP=$hostIP\n"; // Establish a connection $socketConnection = fsockopen($hostIP, $port, $errno, $errstr, $numberOfSeconds); $T_connect = microtime_float(); $T_puts = 0; $T_gets = 0; $T_close = 0; if (!$socketConnection) { // You may wish to remove the following debugging line on a live Web site $Debug .= "\n"; // print "Network error: $errstr ($errno)\n"; } // end if else { $xml = ''; $getString = "GET $resourcePath HTTP/1.1\r\nHost: $domain\r\nConnection: Close\r\n"; if (isset($needCookie[$domain])) { $getString .= $needCookie[$domain] . "\r\n"; $Debug .= "\n"; } $getString .= "\r\n"; // print "Sending:\n$getString\n\n"; fputs($socketConnection, $getString); $T_puts = microtime_float(); // Loop until end of file $TGETstats = array(); $TGETcount = 0; while (!feof($socketConnection)) { $T_getstart = microtime_float(); $xml .= fgets($socketConnection, 16384); $T_getend = microtime_float(); $TGETcount++; $TGETstats[$TGETcount] = sprintf("%01.3f",round($T_getend - $T_getstart,3)); } // end while $T_gets = microtime_float(); fclose ($socketConnection); $T_close = microtime_float(); } // end else $ms_connect = sprintf("%01.3f",round($T_connect - $T_dns,3)); if($T_close > 0) { $ms_puts = sprintf("%01.3f",round($T_puts - $T_connect,3)); $ms_gets = sprintf("%01.3f",round($T_gets - $T_puts,3)); $ms_close = sprintf("%01.3f",round($T_close - $T_gets,3)); $ms_total = sprintf("%01.3f",round($T_close - $T_start,3)); } else { $ms_puts = 'n/a'; $ms_gets = 'n/a'; $ms_close = 'n/a'; $ms_total = sprintf("%01.3f",round($T_connect - $T_start,3)); } $Debug .= "\n"; // print "HTTP stats: dns=$ms_dns conn=$ms_connect put=$ms_puts get($TGETcount blocks)=$ms_gets close=$ms_close total=$ms_total secs \n"; // foreach ($TGETstats as $block => $mstimes) { // print "HTTP Block $block took $mstimes\n"; // } $TOTALtime+= ($T_close - $T_start); $overall_end = time(); $overall_elapsed = $overall_end - $overall_start; $Debug .= "\n"; // print "fetch function elapsed= $overall_elapsed secs.\n"; return($xml); } else { // print "\n"; $T_start = microtime_float(); $xml = implode('',file($url)); $T_close = microtime_float(); $ms_total = sprintf("%01.3f",round($T_close - $T_start,3)); $Debug .= "\n"; // print " file() stats: total=$ms_total secs.\n"; $TOTALtime+= ($T_close - $T_start); $overall_end = time(); $overall_elapsed = $overall_end - $overall_start; $Debug .= "\n"; // print "fetch function elapsed= $overall_elapsed secs.\n"; return($xml); } } // end fetchUrlWithoutHanging // ------------------------------------------------------------------ // load the image and draw hotspots on it function outline_hotspots($Graphic) { global $Stations; $image = loadJPEG($Graphic); // fetch our map image $color = imagecolorallocate($image, 0, 255, 0); $MaxX = imagesx($image); $MaxY = imagesy($image); while (list($key, $val) = each($Stations)) { //write each hotspot list($State,$Name) = explode("\t",$key); list($URL,$Coords,$Features) = explode("\t",$Stations["$key"]); list($X1,$Y1,$X2,$Y2) = explode(",",$Coords); // make sure images in top-left, bottom-right order if($X1 > $X2) { $tmp = $X2; $X2 = $X1; $X1 = $tmp; } if($Y1 > $Y2) { $tmp = $Y2; $Y2 = $Y1; $Y1 = $tmp; } imagerectangle($image, $X1, $Y1, $X2, $Y2, $color); } $msg = "Green rectangles outline the hotspots on the image map. DON'T SAVE THIS IMAGE."; imagestring($image, 3, 45, 2, $msg, $color); header("Content-type: image/jpeg"); // now send to browser imagejpeg($image); imagedestroy($image); } // ------------------------------------------------------------------ function getFireDanger( $ctemp, $rh) { global $myUOM,$Units; // from SLOWeather.com = calculate fire danger based on temperature and relative humidity if (preg_match('|C|i',$Units['temp'])) { // Convert F temp to C temp $ctemp = ($ftemp - 32) * 0.5556; } // Start Index Calcs // Chandler Index $cbi = (((110 - 1.373 * $rh) - 0.54 * (10.20 - $ctemp)) * (124 * pow(10,(-0.0142*"$rh"))))/60; // CBI = (((110 - 1.373*RH) - 0.54 * (10.20 - T)) * (124 * 10**(-0.0142*RH)))/60 //Sort out the Chandler Index $cbitextcolor = "white"; if ($cbi > "97.5") { $cbitxt = "Extreme"; $cbicolor = "red"; $cbiimg= "fdl_extreme.gif"; } elseif ($cbi >="90") { $cbitxt = "Very High"; $cbicolor = "orange"; $cbitextcolor = "black"; $cbiimg= "fdl_vhigh.gif"; } elseif ($cbi >= "75") { $cbitxt = "High"; $cbicolor = "yellow"; $cbitextcolor = "black"; $cbiimg= "fdl_high.gif"; } elseif ($cbi >= "50") { $cbitxt = "Moderate"; $cbicolor = "blue"; $cbiimg= "fdl_moderate.gif"; } else { $cbitxt="Low"; $cbicolor = "green"; $cbiimg= "fdl_low.gif"; } $val = ' ' . $cbitxt . ' '; return("$val"); // (CBI " . round($cbi,0) . ")"); } // ------------------------------------------------------------------ // convert degrees into wind direction abbreviation function getWindDir ($degrees) { // figure out a text value for compass direction // Given the wind direction, return the text label // for that value. 16 point compass $winddir = $degrees; if ($winddir == "n/a") { return($winddir); } if (!isset($winddir)) { return "---"; } if (!is_numeric($winddir)) { return($winddir); } $windlabel = array ("N","NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW","SW", "WSW", "W", "WNW", "NW", "NNW"); $dir = $windlabel[ fmod((($winddir + 11) / 22.5),16) ]; return($dir); } // end function getWindDir // ------------------------------------------------------------------ function set_barotrend($baromtrend) { // routine from Anole's wxsticker PHP (adapted) // Barometric Trend(3 hour) // Change Rates // Rapidly: =.06" H; 1.5 mm Hg; 2 hPa; 2 mb // Slowly: =.02" H; 0.5 mm Hg; 0.7 hPa; 0.7 mb // 5 Arrow Positions: // Rising Rapidly // Rising Slowly // Steady // Falling Slowly // Falling Rapidly // Page 52 of the PDF Manual // http://www.davisnet.com/product_documents/weather/manuals/07395.234-VP2_Manual.pdf // figure out a text value for barometric pressure trend settype($baromtrend, "float"); switch (TRUE) { case (($baromtrend >= -.6) and ($baromtrend <= .6)): $baromtrendwords = "Steady"; break; case (($baromtrend > .6) and ($baromtrend < 2)): $baromtrendwords = "Rising Slowly"; break; case ($baromtrend >= 2): $baromtrendwords = "Rising Rapidly"; break; case (($baromtrend < -.6) and ($baromtrend > -2)): $baromtrendwords = "Falling Slowly"; break; case ($baromtrend <= -2): $baromtrendwords = "Falling Rapidly"; break; } // end switch return($baromtrendwords); } // generate the alt=/title= text for area statement tooltip popups function gen_tag($ID) { global $StationData,$Stations,$Units; list($State,$Name) = preg_split("/\t/","$ID"); list($URL,$Coords,$Features,$DataPage,$RawDataType,$RawDataURL) = preg_split("/\t/",$Stations["$ID"]); if (! isset($StationData["$ID"]) ) { return "$Name - no current conditions report"; } list($TEMP,$HUMID,$WDIR,$WSPD,$RAIN,$BARO,$BTRND,$COND,$CTXT,$DEWPT,$GUST,$UDATE) = preg_split("/\,/",$StationData["$ID"]); // --------------- customize HTML if you like ----------------------- // note: only IE supports using new-line and tabs in tooltip displays // Firefox, Netscape and Opera all ignore these formatting characters, // or display a funky character instead. $gust = ''; if ($GUST > 0) { $gust = "G $GUST "; } $tag = "$Name: " . "$TEMP". $Units['temp'] . ", " . "DP $DEWPT".$Units['temp'] . ", " . "$HUMID" . $Units['humid'] . ", " . "$WDIR $WSPD $gust" . $Units['wind'] . ", " . "Rain: $RAIN". $Units['rain'] . ", " . "Baro: $BARO". $Units['baro'] . " " . $BTRND . ", $CTXT"; return $tag; } // end gen_tag // ------------------------------------------------------------------ function load_units($UOM) { global $dpRain,$dpWind,$dpBaro,$dpTemp,$useKnots,$useMPH,$useMPS,$useMB; $Units = array(); if ($UOM == 'M') { $Units = array( // metric with native wind units 'wind' => 'kph', 'temp' => '°C', 'baro' => 'hPa', 'humid' => '%', 'rain' => 'mm', 'dist' => 'km'); $dpRain = 1; $dpBaro = 1; $dpTemp = 1; $dpWind = 0; } else { $Units = array( // english with native wind units 'wind' => 'mph', 'temp' => '°F', 'baro' => 'in', 'humid' => '%', 'rain' => 'in', 'dist' => 'nm'); $dpRain = 2; $dpBaro = 2; $dpTemp = 0; $dpWind = 0; } $Units['time'] = ''; if ($useKnots) { $Units['wind'] = 'kts'; } if ($useMPH) { $Units['wind'] = 'mph'; } if ($useMPS) { $Units['wind'] = 'm/s'; $dpWind = 1; } if ($useMB and $UOM == 'M') { $Units['baro'] = 'mb';} return $Units; } // end load_units // ------------------------------------------------------------------ // generate the rotation JavaScript to browser page function prt_jscript () { global $showTownName; // NOTE: the following is not PHP, it's JavaScript // no changes should be required here. $t = ' '; $t .= ' '; return($t); } // end prt_jscript // ------------------------------------------------------------------ // initalize the assembly string for CSS function load_strings () { global $CSS,$Graphic,$Version,$Program,$ControlsX, $ControlsY; // top of CSS for mesomap display $CSS ='

    State

    Station
    Curr
    Cond
    Temp
    " . $Units['temp'] . "
    Dew Pt.
    " . $Units['temp'] . "
    Hum
    " . $Units['humid'] . "
    Wind Avg
    " . $Units['wind'] . "
    Gust
    " . $Units['wind'] . "
    Rain
    " . $Units['rain'] . "
    Baro
    " . $Units['baro'] . "
    Baro
    Trend
    Data
    Updated
    $State $Name No current conditions report.
    $State $Name "; if (preg_match('|.gif$|',$COND) && $condIconsDir) { $table .= "\"$CTXT\""; } else { $table .= "$COND"; } $table .= " $TEMP $DEWPT $HUMID "; if ($WDIR == 'n/a') { $table .= $WDIR; } else { $wda = $WDIR; $table .= $wda; if ($windArrowDir and $wda <> '-') { $table .= " \"Wind"; } $table .= " " . $WSPD; } $table .= " $GUST $RAIN
    $BARO"; if($showBaroTrendArrow) { $table .= getBaroTrendArrow($BTRND); } $table .="
    $BTRND " . date('H:i:s',$UDATE) . "