// ----------------------------------------------------------------------------+
// VERSION: 9.05 - 10-Jan-2009 - www.bashewa.com - rainer@bashewa.com          |
// ----------------------------------------------------------------------------|
// NOTES  : This version of "ajaxWDwx.js" has been modified by www.bashewa.com |
//          Download latest version of this script from:                       |
//          ... http://www.bashewa.com/downloads/bws-script-ajaxWDwx.zip       |
//          To see how changes to this script have been implemented go to:     |
//          ... http://www.bashewa.com/ajax-dashboard.php?sce=view             |
//          For available "ajax tags" and descriptions see bottom of this page.|
// ----------------------------------------------------------------------------|
// JS SIZE REDUCTION:                                                          |
//   If you want to pack this script after you have made your changes, go here:|
//   ... http://dean.edwards.name/packer/                                      |
//   ... make a "ajaxWDwx-packed.js" file and change this line in "top.php" to:|
//       <script type="text/javascript" src="ajaxWDwx-packed.js"></script>     |
//   ... This will reduce the size to ±34% of it's original size (±38kb).      |
// ----------------------------------------------------------------------------|
// SCRIPT DOWNLOADS:                                                           |
//       Cloud base graphic:  http://www.bashewa.com/download-cloud-base.php   |
//     Gradient thermometer:  http://www.bashewa.com/download-thermometer.php  |
//   Dynamic condition icon:  (not yet implemented)                            |
// ----------------------------------------------------------------------------+

// -------------------------------------------------------------------------------------------|
// ICON & GRAPHIC DOWNLOADS:                                                                  |
// ... unzip in root with "use folder names" when unziping                                    |
// All of the below icons  :  http://www.bashewa.com/downloads/bws-iconsets.zip (2.5mb)       |
// -------------------------------------------------------------------------------------------|
// Current conditions icons:  http://www.bashewa.com/downloads/bws-icons-current.zip   (269kb)|
//            Forcast icons:  http://www.bashewa.com/downloads/bws-icons-forecast.zip  (1.1mb)|
//  Sun/Moon bg, Moon ph x4:  http://www.bashewa.com/downloads/bws-icons-moonphase.zip ( 19kb)|
//        Moon pictures x28:  http://www.bashewa.com/downloads/bws-icons-moon.zip      (188kb)|
//       Fire Weather Index:  http://www.bashewa.com/downloads/bws-icons-fire.zip      (291kb)|
//                 UV icons:  http://www.bashewa.com/downloads/bws-icons-uv.zip        ( 20kb)|
//          Wind Rose icons:  http://www.bashewa.com/downloads/bws-icons-wind.zip      (822kb)|
// -------------------------------------------------------------------------------------------|


// ========================================================================== //
// USAGE and WARRANTY:                                                        //
// -------------------------------------------------------------------------- //
// You may copy/modify/use this script as you see fit.                        //
// No warranty is expressed or implied.                                       //
//                                                                            //
// This program is free software; you can redistribute it and/or modify it    //
// under the terms of the GNU General Public License as published by the Free //
// Software Foundation; either version 2 of the License, or (at your option)  //
// any later version.                                                         //
//                                                                            //
// This program is distributed in the hope that it will be useful, but        //
// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY //
// or FITNESS FOR A PARTICULAR PURPOSE.                                       //
// See the GNU General Public License for more details.                       //
//                                                                            //
// You should have received a copy of the GNU General Public License along    //
// with this program; if not, write to the:                                   //
//    Free Software Foundation, Inc.,                                         //
//    59 Temple Place - Suite 330, Boston, MA  02111-1307, USA                //
// ========================================================================== //


// -----------------------------------------------------------------------------
// VERSION HISTORY v2.00 - Saratoga Weather ... http://saratoga-weather.org
// -----------------------------------------------------------------------------
// Special thanks to: Kevin Reed http://www.tnetweather.com/
// Kevin was the first to decode the clientraw in PHP
// Special thanks to: Pinto http://www.joske-online.be/
// Pinto wrote the basic AJAX code for this page!
// Cheerfully borrowed from Tom at CarterLake.org and adapted by Ken True - Saratoga-weather.org  21-May-2006
// Updates available at: http://saratoga-weather.org/scripts-WD-AJAX.php
// Announcements of new versions will be on weather-watch.com and wxforum.net
// --- added flash-green on data update functions - Ken True  24-Nov-2006
// --- Version 2.00 - 13-Dec-2006 -- Ken True -repackaged AJAX function, added metric/english units
//     also included Mike Challis' counter script to display seconds since last update and error
//     handling for the fetch to fix to fix random error: NS_ERROR_NOT_AVAILABLE
//     Mike's site: http://www.carmosaic.com/weather/index.php
//     Thanks to FourOhFour on wxforum.net ( http://skigod.us/ ) for replacing all the
//     x.responseText.split(' ')[n] calls with a simple array lookup.. much better speed and
//     for his streamlined version of getUVrange.
// --- Version 2.01 - 17-Dec-2006 -- Corrected cloud height calculation
// --- Version 2.02 - 20-Dec-2006 -- added unescape to set_ajax_obs comparison for lastobs
// --- Version 2.03 - 07-Jan-2006 -- added wind m/s or km/h for metric variables
// --- Version 2.04 - 08-Jan-2006 -- use epoch time for get (thanks to johnnywx on WD forum)
//                                   so a numeric time without HTMLencoded characters is used
// --- Version 2.05 - 30-Jan-2006 -- added new 'anti-NaN' check from johnnywx to make sure full
//                                   clientraw.txt is read by looking for
//                                   '12345' at start and '!!' at end of record
// --- Version 2.06 - 24-Jun-2007 -- added '/' as delimiter for currentcond
// --- Version 2.07 - 21-Sep-2007 -- added support for dynamic thermometer.php display refresh
// --- Version 2.08 - 07-Nov-2007 -- added useMPH to force wind display in Miles-per-hour and
//                                   added optional Wind-Rose, optional new current icon display graphics
// --- Version 2.09 - 23-Dec-2007 -- added maxupdates feature, new ajax variables from K. Reed www.tnetweather.com
// --- Version 2.10 - 18-Jan-2008 -- fixed icon=34 for ra1.jpg
// --- Version 2.11 - 21-Feb-2008 -- added icon=35 for windyrain.gif/.jpg
// --- Version 2.12 - 07-Mar-2008 -- added fix for 'flashing icon/thermometer' from Jim at jcweather.us
// --- Version 2.13 - 11-Mar-2008 -- changed Wind-rose defaults to .png type (Carterlake/AJAX/PHP templates)
// --- Version 2.14 - 29-Mar-2008 -- fixed UV words with  color: black; for display on dark/black template (MCHALLIS)
// --- Version 2.15 - 28-Apr-2008 -- added ajaxFixConditions() and translation capability
// --- Version 2.16 - 20-May-2008 -- added headcolorword processing V1.0 from MCHALLIS
// --- Version 2.17 - 25-Jun-2008 -- added gizmo-specific ajax variables
// --- Version 2.18 - 20-Mar-2008 -- added fix for 'green-flash' issue with Internet Explorer 8
// --- Version 2.19 - 03-Jul-2009 -- additional gizmo-specific ajax added, and useHpa variable for pressure

// -----------------------------------------------------------------------------
// VERSION HISTORY v3.00 - Webster Weather ... http://www.WebsterWeatherLIVE.com
// -----------------------------------------------------------------------------
// Updates available at: www.WebsterWeatherLIVE.com or scott@websterweatherlive.com
// --- Version 2.80 - 15-Apr-2009 -- added Lightning ajax variables
// --- Version 3.00 - 14-May-2009 -- added many additional ajax variables
// --- Version 4.10 - 25-Sep-2009 -- added support for Nexstorm Lightning distance and direction
// --- Version 4.20 - 11-Oct-2009 -- added support for UV reading 0 during the day - shows "updating..." if so.

// -----------------------------------------------------------------------------
// VERSION HISTORY v9.00 - Bashewa Weather ... http://www.bashewa.com
// -----------------------------------------------------------------------------
// Updates available at: http://www.bashewa.com/downloads.php
// --- Version 9.00 - 15-Apr-2009 -- modifications by Rainer Finkeldeh (www.bashewa.com)
//       Added fetching of "clientrawextra.txt" for history data (e.g. rain etc.).
//       Added tag "ajaxrainSun" ...... for last Sunday's rain
//                    ..thru..
//                 "ajaxrainSat" ...... for last Saturday's rain
//       Added tag "ajaxwinddeg" ...... for wind in degrees e.g. 334°
//       Added tag "ajaxsnowDepth" .... for current snow depth
//                 "ajaxsnowToday" .... for todays snow
//                 "ajaxsnowMonth" .... for this months snow
//                 "ajaxsnowSeason" ... for this seasons snow
//       Added tag "ajaxwebcamimg" .... for webcam image support
//       Added tag "ajaxmoonimg" ...... for moon image support
//       Added tag "ajaxmoonphase" .... for current phase e.g. "First Quarter"
//       Added tag "ajaxmoonpct" ...... for current moon illumination e.g. 24%
//       Added tag "ajaxcloudheightimg" for cloud height graphic
//       Added tag "ajaxuvimg" ........ for UV graphic (current UV)
//       Added tag "ajaxuvburnrate" ... for UV skin burn rate (in minutes)
//       Added "REFRESH" hyperlink to "Updates paused" for restarting ajax script.
//       Added window.onload function to prevent early ajax loading.
//             -----------------------------------------------------------------
//       Added support for UOM switching [ metric | english ].
//             ... see: http://www.bashewa.com/ajax-dashboard.php?sce=view
//             Add the following code to your "ajax-dashboard.php":
//             -----------------------------------------------------------------
//             <div onClick="javascript:ajax_changeUnits();"
//                  style="cursor: pointer;"><b>
//                  <span id="uomM" style="color: gray;">METRIC</span> |
//                  <span id="uomE" style="color: blue;">ENGLISH</span></b>
//             </div>
//             -----------------------------------------------------------------
//       Added support for UOM switching on static field values.
//             ... see: http://www.bashewa.com/ajax-dashboard.php?sce=view
//             Add one of the following classes to your fields:
//             NOTE: the value in the span must include the units-of-measure for them be converted.
//             -----------------------------------------------------------------
//             <span class="convTemp">82.7&deg;F</span>   ...for temp
//             <span class="convWind">   2.7 mph</span>   ...for wind
//             <span class="convBaro">30.30 inHg</span>   ...for temp
//             <span class="convRain">   1.04 in</span>   ...for rain
//             <span class="convSnow">   12.4 in</span>   ...for snow
//             <span class="convAlti">   2793 ft</span>   ...for altitude
//             <span class="convDist">  15 miles</span>   ...for distance
//             -----------------------------------------------------------------
//    Modified thermometer.php to support UOM switching and different styles.
//    Modified UV color words to official web colors as specified by WHO, WMO & UNEP
//    Modified overall settings setup for easier configuration.
//    Modified UOM conversions and added convertSnow & convertDist.
// End Version 9.00 ------------------------------------------------------------
// --- Version 9.01 - 05-Jan-2010 - Fixed problem with Moon Phase.
// --- Version 9.02 - 07-Jan-2010 - Added Webster Weather modifications (v2.80, v3.00, v4.10)
// --- Version 9.03 - 10-Jan-2010 - Added the following ajax tags:
//        Added tag "ajaxwebcamimg" .... for webcam image support
//        Added tag "ajaxRcdRain" ......... rain record (record all-time daily rain)
//        Added tag "ajaxRcdRainTime" ..... rain record time
//        Added tag "ajaxRcdRainDate" ..... rain record date
//        Added tag "ajaxRcdRainHr" ....... rain record Hr (record all-time daily rain in 1 hour)
//        Added tag "ajaxRcdRainHrTime" ... rain record Hr time
//        Added tag "ajaxRcdRainHrDate" ... rain record Hr date
//        Added tag "ajaxDaysRain" ........ rain days (MTD)
//        Added tag "ajaxDaysNoRain" ...... rain absent days
// --- Version 9.04 - 10-Jan-2010 - Implemented Webcam support for useCamAtNight and delayDayNight
// --- Version 9.05 - 10-Jan-2010 ----------------------------------------------
//        Fixed problem with "number_format" function not showing correct decimal value.
//        Added ALERT when "clientraw.txt" file can not be found (error 404)
//        ajaxLoaderInBody no longer possible i.e. <body onload="ajaxLoader(...)">
//        ClientExtra will now always be loaded as well.
//        Implemented external "ajaxWDwx-settings.js" for seperate settings outside of this script (see below).
// -----------------------------------------------------------------------------




//============================================================================\\
//                             S E T I N G S                                  \\
// You can have seperate settings in "ajaxWDwx-settings.js" so that you don't \\
// have to redo them each time a new version of this script is released.      \\
// -------------------------------------------------------------------------- \\
// If you have seperate settings in a file "ajaxWDwx-settings.js" then you    \\
// need to add the following line to your "top.php" file:                     \\
//     <script type="text/javascript" src="ajaxWDwx-settings.js"></script>    \\
// below this line in "top.php":                                              \\
//     <script type="text/javascript" src="ajaxWDwx.js"></script>             \\
//============================================================================\\

// -----------------------------------------------------------------------------
// Settings (required)                                                         .
// -----------------------------------------------------------------------------
var clientrawFile = '/clientraw.txt'; // location of clientraw.txt relative to this page on website
var useUOM = 'M';   // [ E | M ] ... Units Of Measure: 'E'=English/Imperial or 'M'=Metric
var stationAlt = 0; // your station altitude in meters for cloud height graphic if you want ASL (meters = ft / 3.2808399)


// -----------------------------------------------------------------------------
// Settings (optional)                                                         .
// -----------------------------------------------------------------------------
var reloadTime = 5000;      // reload AJAX conditions every 5 seconds (= 5000 ms)
var maxupdates = 36;        // Maximum number of updates/fetches allowed (set to zero for unlimited)
                            // maxupdates * reloadTime / 1000 = number of seconds to update
                            // i.e. 36 x 5000 / 1000 = 180 seconds (3 minutes)
                            // Note: if you upload your clientraw.txt file every 30 seconds
                            //       then the visitor will see (180/30) = 6 updates in total.
var allowRefresh = true;    // show REFRESH hyperlink after "maxupdates" have been exceeded.

var flashcolor = '#00CC00'; // color to flash for changed observations (RGB) (def #00CC00 = green)
var flashRed   = '#FF0000'; // color to flash red for warnings/alarms  (RGB) (def #FF0000 = red)
var flashtime  = 2000;      // milliseconds to keep flash color on (2000 = 2 seconds);

var showUOM = true;         // set to false if no units should be displayed
                            // i.e. if the UOM is outside the "ajaxtag" spans.
                            // Note: If you have implemented UOM switching this needs to be TRUE.


//------------------------------------------------------------------------------
// STATIC IMAGES                                                               .
//------------------------------------------------------------------------------
// IMAGE LOCATION: root folder for graphics images/icons
// ... (for root folder specify "./")
var imgDir = './ajax-images/'; // with trailing slash

// NOTE: do not delete any of the words below between the #'s  e.g  #PIC#
//       They'll get replaced by their corresponding values later in the script.

//------------------------------------------------------------------------------
// STICKER ICONS: optional settings for the current conditions graphic for Anole's wxsticker icon.
// tag: "ajaxconditionicon"
// e.g. graphic name: "./ajax-images/icon/0/day_partly_cloudy.jpg"
var wxIconSet0 =
   {src    : imgDir+"icon/0/#PIC#.gif" // where #PIC# will = picname from table in ajax_getIconName0() function
   ,width  : 25 ,height: 25 ,hspace: 0 ,vspace: 0 ,border: 0
   ,style  : ""  // eg. "border: 2px solid silver"
   ,align  : ""  // [ left | right | top | bottom | middle | texttop | absbottom | absmiddle ]
   ,useName: 0   // must be 0 for this icon set ... Anole's icon nameing convention ... see ajax_getIconName0()
   };


//------------------------------------------------------------------------------
// DASHBOARD ICONS: optional settings for current conditions graphic for dashboard
// tag: "ajaxconditionicon2"
// .... grab the animated icons for set 2 here: http://www.bashewa.com/downloads/bws-icons-current.zip

// Specify the "wxIconSet" to use further down below ... at the end of this section
// and set up the corresponding set below.

// NOTE: Do not delete the #PIC# part in the "src" settings.

// 1: NWS icons (55x58)
//    e.g. graphic name: "./ajax-images/bkn.gif"
var wxIconSet1 =
   {src    : imgDir+"#PIC#.jpg" // where #PIC# will = picname from table in ajax_getIconName1() function
   ,width  : 55 ,height: 58 ,hspace: 0 ,vspace: 0 ,border: 0
   ,style  : ""  // eg. "border: 2px solid silver"
   ,align  : ""  // [ left | right | top | bottom | middle | texttop | absbottom | absmiddle ]
   ,useName: 1   // must be 1 for this icon set ... NWS icon nameing convention ... see ajax_getIconName1())
   };

// 2: Bashewa animated icons (75x60)
//    e.g. graphic name: "./ajax-images/icon/2/2-bkn.gif"
var wxIconSet2 =
   {src    : imgDir+"icon/2/#PIC#.gif" // where #PIC# will = picname from table in ajax_getIconName2() function
   ,width  : 75 ,height: 60 ,hspace: 0 ,vspace: 0 ,border: 0
   ,style  : ""  // eg. "border: 2px solid silver"
   ,align  : ""  // [ left | right | top | bottom | middle | texttop | absbottom | absmiddle ]
   ,useName: 2   // must be 2 for this icon set ... Bashewa.com  icon nameing convention ... see ajax_getIconName2())
   };

// 3: Your own icons (any size)
//    e.g. graphic name: "./ajax-images/icon/3/bkn.gif"
var wxIconSet3 =
   {src    : imgDir+"icon/3/#PIC#.jpg" // where #PIC# will = picname from table specified in wxIconSet3.useName
   ,width  : 75 ,height: 60 ,hspace: 0 ,vspace: 0 ,border: 0
   ,style  : ""  // eg. "border: 2px solid silver"
   ,align  : ""  // [ left | right | top | bottom | middle | texttop | absbottom | absmiddle ]
   ,useName: 1   // [ 0| 1 | 2 ] function for getting icon names ...
   };            //              0 = Anole's icon names ....... see ajax_getIconName0()
                 //              1 = NWS icon names ........... see ajax_getIconName1()
                 //              2 = Bashewa.com icon names ... see ajax_getIconName2()
// 4: You can add more icon sets here

// D: Dynamic generated icon set (170x127) ... NOT IMPLEMENTED
//    ... you'll need: http://www.bashewa.com/download-dynamic-icon.php
var wxIconSetD =
   {src    : "./dynamic-icon.php" // path and script for dynamic conditions image (optional)
   ,width  : 170 ,height: 127 ,hspace: 0 ,vspace: 0 ,border: 0
   ,style  : "border: 2px solid silver;"
   ,align  : ""
   ,useName: 9 // must be 9 for generating dynamic icons
   };

var wxIconSet = wxIconSet1; // choose from an icon set above that you want to use.
                            // If we had a uniform icon nameing convention the above would not be necessary.

//------------------------------------------------------------------------------
// WIND ROSE: optional settings for the Wind Rose graphic
// tag: "ajaxwindiconwr"
// e.g. graphic name: "./ajax-images/wr-SSE.gif"  or  "./ajax-images/wr-nl-SSE.gif"
// .... grab the wind rose icons here: http://www.bashewa.com/downloads/bws-icons-wind.zip
wrImg =
   {src   : imgDir+"wr-#LANG##DIR#.gif"  // where #DIR# will = wind dir (e.g. NNW), #LANG# = wrImg.lang
   ,lang  : ""     // with trailing dash (e.g. "nl-" will result in graphic name: "./ajax-images/wind/wr-nl-SSE.gif")
   ,calm  : "calm" // substitution for #DIR# (e.g "wr-calm.gif") ... specify "" if not to be shown or not available
   ,width : 58 ,height: 58 ,hspace: 0 ,vspace: 0 ,border: 0
   ,style : ""
   ,align : "" // [ left | right | top | bottom | middle | texttop | absbottom | absmiddle ]
   };


//------------------------------------------------------------------------------
// UV: optional settings for the UV graphic
// tag: "ajaxuvimg"
// e.g. graphic name: "./ajax-images/uv/1/uv12.gif"
// .... grab UV pics here: http://www.bashewa.com/download/bws-icons-uv.zip
var uvImg =
   {src   : imgDir+"uv/1/uv#INDEX#.gif" // where #INDEX# will = UV index (0 to 11)
   ,width : 34 ,height: 65 ,hspace: 0 ,vspace: 0 ,border: 0
   ,style : ""
   ,align : ""
   };


//------------------------------------------------------------------------------
// MOON: optional settings for the moon phase graphic
// tag: "ajaxmoonimg"
// e.g. graphic name: "./ajax-images/moon/w/NH-moon07.gif"
// .... grab the Moon images here: http://www.bashewa.com/downloads/bws-icons-moon.zip
var moonImg =
   {src   : imgDir+"moon/#BG#/#NS#-moon#AGE#.gif" // #BG# = [ w | b ] from moonImg.bg, #NS# = [ NH | SH ] from latitude, #AGE# = 2 digit moonage (0 to 28) from getMoonInfo
   ,bg    : "w" // [ w | b ] moon background (w=white, b=black)
   ,width : 50 ,height: 50 ,hspace: 0 ,vspace: 0 ,border: 0
   ,style : ""
   ,align : ""
   };


//------------------------------------------------------------------------------
// FIRE INDEX: optional setting for the fire risk graphic
// tag: "ajaxfireimg"
// e.g. graphic name: "./ajax-images/fire/fire3.gif"
// .... grab the FWI icons here: http://www.bashewa.com/downloads/bws-icons-fire.zip
var fireImg =
   {src   : imgDir+"fire/7/fire-#INDEX#.jpg" // where #INDEX# will = fire index (0=very low, 1=low, 2=moderate, 3=high, 4=extreme) from clientraw
   ,width : 100 ,height: 65 ,hspace: 0 ,vspace: 0 ,border: 0
   ,style : "border: 2px solid silver;"
   ,align : ""
   };


//------------------------------------------------------------------------------
// WEBCAM IMAGE: optional setting for the webcam graphic
// tag: "ajaxwebcamimg"
// e.g. picture name: "./ajax-images/webcam/snap00.jpg"
var webcamUpdate =  5; // Webcam update interval in minutes (set to 0 for no updates i.e. visitor must reload page for updates)
var swapIconWithWebcam = false; // swap current conditions icon (tag "ajaxconditionicon2") with webcam image during day and night unless useCamAtNight=false;
var useCamAtNight = false; // use current conditions icon at night time instead of webcam image
var delayDayNight = 15;    // day starts given minutes before sunrise and night starts given min after sunset - for night icon switch
var webcamImg =
   {src   : imgDir+"webcam/snap00.jpg" // full path and image name of your current webcam picture
   ,srcNgt: imgDir+"webcam/snap00.jpg" // full path and image name of your current nightcam picture (after/before "delayDayNight")
   ,width : 170 ,height: 127 ,hspace: 0 ,vspace: 0 ,border: 0
   ,style : "border: 2px solid silver;"
   ,align : ""
   };


//------------------------------------------------------------------------------
// DYNAMIC SCRIPT IMAGES                                                       .
//------------------------------------------------------------------------------

// THERMOMETER: optional setting for the dynamic thermometer graphic
// tag: "ajaxthermometer"
// ... you'll need the new thermometer.php script from www.bashewa.com for UOM switching.
// ... read here  : http://www.weather-watch.com/smf/index.php/topic,39180.0.html
// ... get it here: http://www.bashewa.com/download-thermometer.php
var thermometerImg =
   {src   : "./thermometer.php" // path and script for dynamic thermometer PNG image (optional)
   ,width : 54 ,height: 170 ,hspace: 0 ,vspace: 0 ,border: 0
   ,style : ""
   ,align : ""
   };


//------------------------------------------------------------------------------
// CLOUD BASE: optional setting for the dynamic cloud height graphic
// tag: "ajaxcloudheightimg"
// ... you'll need the cloud-base.php script from www.bashewa.com
// ... get it here: http://www.bashewa.com/download-cloud-base.php
var cloudImg =
   {src   : "./cloud-base.php" // path and script for dynamic cloud height image (optional)
   ,width : 100 ,height: 200 ,hspace: 0 ,vspace: 0 ,border: 0
   ,style : "border: 2px solid silver;"
   ,align : ""
   };


//------------------------------------------------------------------------------
// DYNAMIC CURRENT ICON: optional setting for the dynamic current conditions graphic
// tag: "ajaxconditionicon2"
// ... you'll need the dynamic-icon.php script from www.bashewa.com
// ... get it here: (NOT YET IMPLEMENTED)
// See wxIconSetD above in DASHBOARD ICONS.


//------------------------------------------------------------------------------
// UNITS-OF-MEASURE / UOM (optional)
// ... change to your desired UOM's and decimal places
//----------------------------------------------------------------------
// ENGLISH (Imperial)
var imperialUOM =
   {Temp: '&deg;F' // [ &dec;C | &dec;F ] ......................... Temp
   ,Wind: 'mph'    // [ kts | mph | kph  | m/s  ] ................. Wind
   ,Baro: 'inHg'   // [ hPa | mb  | inHg | mmHg ] ................. Baro
   ,Rain: 'in'     // [ mm  | in  ] ............................... Rain
   ,Snow: 'in'     // [ cm  | in  ] ............................... Snow
   ,Alti: 'ft'     // [ m   | ft  ] ........................... Altitude
   ,Dist: 'miles'  // [ m   | km  | miles] .................... Distance
   ,Deg : '&deg;'  // [ deg | &deg; ] ..................... Direction/UV
   ,dateFmt: "m/j/Y"  // 04/26/2009 ... same format as "date" function in php ( eg. for US use "m/j/Y", for GB use "d/M/Y" )
   ,timeFmt: "g:i:s a" // 3:27:01 pm ... same format as "date" function in php ( for 24h clock use "H:i:s" )
   ,timeHM : "g:i a"   // 3:27 pm ...... same format as "date" function in php ( for 24h clock use "H:i" )
   };
var imperialDP = // decimal places
   { Temp:1 ,Wind:1 ,Baro:2 ,Rain:2 ,Snow:2 ,Alti:0 ,Dist:2 ,UV:0 };
//----------------------------------------------------------------------
// METRIC
var metricUOM =
   {Temp: '&deg;C' // [ &dec;C | &dec;F ] ..........................Temp
   ,Wind: 'kph'    // [ kts | mph | kph  | m/s  ] ................. Wind
   ,Baro: 'hPa'    // [ hPa | mb  | inHg | mmHg ] ................. Baro
   ,Rain: 'mm'     // [ mm  | in  ] ............................... Rain
   ,Snow: 'cm'     // [ cm  | in  ] ............................... Snow
   ,Alti: 'm'      // [ m   | ft  ] ........................... Altitude
   ,Dist: 'km'     // [ m   | km  | miles] .................... Distance
   ,Deg : '&deg;'  // [ deg | &deg; ] ........................ Direction
   ,dateFmt: "j-M-Y" // same format as "date" function in php (eg. for DE use "j.M.Y", for NL use "j-M-Y)
   ,timeFmt: "H:i:s" // 15:27:01 ...same format as "date" function in php  ( for 12h clock use "g:i:s a" )
   ,timeHM : "H:i"   // 15:27 ......same format as "date" function in php  ( for 12h clock use "g:i a" )
   };
var metricDP = // decimal places
   { Temp:1 ,Wind:1 ,Baro:0 ,Rain:1 ,Snow:0 ,Alti:0 ,Dist:2 ,UV:0 };


// =============================================================================
//                            I M P O R T A N T                                .
//                          LANGUAGE TRANSLATION                               .
//           No need to change if you're using the Multilingual Templates:     .
//           (af, de, dk, el, en, es, fi, fr, it, nl, no, pl, pt, se, us)      .
// =============================================================================
// You don't need to customize this area if you're using English or if you're  .
// using the Canada/World Mutilingual templates. Instead change your language  .
// in "Settings.php" i.e. $SITE['lang']='nl';                                  .
// =============================================================================
var langRestart  = 'Restart live updates';
var langRefresh  = 'REFRESH'; // RESTART
var langPauseMsg = 'Updates paused';
var langMonths   = new Array ("January","February","March","April","May","June","July","August","September","October","November","December");
var langDays     = new Array ("Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday");
var langDaySuf   = new Array ("st","nd","rd","th"); // day suffix as in 1st, 2nd, 3rd, 4th
var langAM_PM    = new Array ("am","pm","AM","PM");
var langWindUOM  = new Array ("kts", "mph", "km/h", "m/s");

var langBaroTrend = new Array ("Steady", "Rising Slowly", "Rising Rapidly", "Falling Slowly", "Falling Rapidly");

var langUVWords = new Array (
 "None", "Low", "Medium", "High",
 "Very&nbsp;High", /* be sure to include &nbsp; for space */
 "Extreme", "Unknown" );

var langBeaufort = new Array ( /* Beaufort 0 to 12 in array */
 "Calm", "Light air", "Light breeze", "Gentle breeze", "Moderate breeze", "Fresh breeze",
 "Strong breeze", "Near gale", "Gale", "Strong gale", "Storm", "Violent storm", "Hurricane");

var langWindDir = new Array( /* used for alt and title tags on wind dir arrow and wind direction display */
   "N", "NNE", "NE", "ENE",
   "E", "ESE", "SE", "SSE",
   "S", "SSW", "SW", "WSW",
   "W", "WNW", "NW", "NNW");

var langWindCalm = 'Calm';
var langGustNone = 'None';
var langWindFrom = 'Wind from '; /* used on alt/title tags on wind direction arrow*/

var langThermoCurrently = 'Currently: '; /* used on alt/title tags for thermometer */
var langThermoMax = 'Max: ';
var langThermoMin = 'Min: ';

var langTempRising    = 'Warmer %s'; /* used for trend arrow alt/title tags .. %s marks where value will be placed */
var langTempFalling   = 'Colder %s';
var langTempLastHour  = ' than last hour.';
var langTempYesterday = ' than yesterday.';

var langBaroRising  = 'Rising %s '; /* used for trend arrow alt/title tags .. %s marks where value will be placed */
var langBaroFalling = 'Falling %s ';
var langBaroPerHour = '/hour.'; /* will be assembled as rising/falling + value + uom + perhour text */

var langHeatWords = new Array (
 'Unknown', 'Extreme Heat Danger', 'Heat Danger', 'Extreme Heat Caution', 'Extremely Hot', 'Uncomfortably Hot',
 'Hot', 'Warm', 'Comfortable', 'Cool', 'Cold', 'Uncomfortably Cold', 'Very Cold', 'Extreme Cold' );

var langMoonPhases = new Array (
 'NEW MOON' , 'Evening Crescent', 'FIRST QUARTER', 'Waxing Gibbous',
 'FULL MOON', 'Waning Gibbous'  , 'LAST QUARTER' , 'Morning Crescent' );

// =============================================================================
//                      E N D   of   S E T T I N G S                           .
// =============================================================================





// =============================================================================
//                            I M P O R T A N T                                .
//           DO NOT customize any of the stuff below this point.               .
//            Everything is controlled by your settings above.                 .
// =============================================================================

// FOR DEBUGING --
var doTooltip = 0; // set to 1 to have ajaxed variable names appear as tooltips (except for graphics)

// always override the settings above if testing on a local host
if (document.location.protocol=="file:"
||  document.location.href.search("localhost")!=-1) {
   maxupdates = 0;
   reloadTime = 5000;
}
// END DEBUGING --

// -----------------------------------------------------------------------------
var ie4     = document.all;
var browser = navigator.appName;
var ie8 = false;
if (ie4 && /MSIE (\d+\.\d+);/.test(navigator.userAgent)) { //test for MSIE x.x;
var ieversion = new Number(RegExp.$1); // capture x.x portion and store as a number
   if (ieversion>=8) {
      ie4=false;
      ie8=true;
    }
}

var langTransLookup = new Object;  // storage area for key/value for current conditions translation
var timerAjaxLoader = null; // for resetting loading timeouts
var notify = 0;     // for error 404 alerts
var extraRetry = 6; // retry time in seconds to fetch clientrawextra.txt
var extraRetryInterval = 10000; // fetch retry in milliseconds for clientrawextra.txt
var clientrawextra = null;

var updates = 0; // update counter for limit by maxupdates
var counterSecs = 0; // for MCHALLIS counter script from weather-watch.com (adapted by K. True)
var lastajaxtimeformat = null; // used for reseting the counter when a real update is done

var ajaxElements = new Array(); // used for reseting green flashing elements
var uomElements  = new Array(); // used for storing page values for switching units-of-measure

var PauseMsg  = ""; // leave blank
var Indicator = ""; // leave blank
var gotSettings, uom, dp;

//-------------------------------------------------------------- functions start
function initialize() {
   extraUrl = clientrawFile.replace("clientraw","clientrawextra");
   uom = (useUOM=='M')? metricUOM : imperialUOM;
   dp  = (useUOM=='M')? metricDP  : imperialDP;

   if (!showUOM) { // Strip UOM if not required i.e. if the UOM is outside the ajaxtag spans
      imperialUOM.Temp=''; metricUOM.Temp='';
      imperialUOM.Wind=''; metricUOM.Wind='';
      imperialUOM.Baro=''; metricUOM.Baro='';
      imperialUOM.Rain=''; metricUOM.Rain='';
      imperialUOM.Snow=''; metricUOM.Snow='';
      imperialUOM.Alti=''; metricUOM.Alti='';
      imperialUOM.Dist=''; metricUOM.Dist='';
      imperialUOM.Deg =''; metricUOM.Deg ='';
   }
};

function ajaxLoader_restart() {
updates = 0;
counterSecs = 0;
lastajaxtimeformat = null;
set_ajax_obs("ajaxindicator",Indicator);
ajaxLoader_clientextra(extraUrl + '?' + new Date().getTime());
if (timerAjaxLoader!="null") clearTimeout(timerAjaxLoader);
timerAjaxLoader = setTimeout("ajaxLoader(clientrawFile + '?' + new Date().getTime())", 20);
};


// toggle the units-of-measure between METRIC and ENGLISH
function ajax_changeUnits () {
useUOM  = (useUOM=="E") ? "M" : "E" ;
uom     = (useUOM=="M") ? metricUOM : imperialUOM;
dp      = (useUOM=="M") ? metricDP  : imperialDP ;
colorM  = (useUOM=="E") ? "gray"    : "blue";
colorE  = (useUOM=="M") ? "gray"    : "blue";
var uomM = document.getElementById("uomM"); if (uomM) uomM.style.color = colorM;
var uomE = document.getElementById("uomE"); if (uomE) uomE.style.color = colorE;

switch (uom.Wind) {
case "mph": uom.langWind = langWindUOM[1]; break;
case "kph": uom.langWind = langWindUOM[2]; break;
case "m/s": uom.langWind = langWindUOM[3]; break;
default   : uom.langWind = langWindUOM[0];
}
// also convert tags convTemp, convWind ... etc.
ajax_page_convertTags();
updates = 0;
set_ajax_obs("ajaxindicator",new Date().getTime(),Indicator,flashRed);
ajaxLoader_restart();
};


// return all the elements for a given tag name on a page e.g. <span ..>
function ajax_getElements ( name ) { // name = [span, div, ...]
if (ie4 && browser != "Opera" && ! ie8)
     return (document.body.getElementsByTagName(name));
else return (document     .getElementsByTagName(name));
};

// return the "class name" for a given element (as in: class="ajax convTemp noprint")
function ajax_getClassName( element ) {
if (ie4 && browser != "Opera" && ! ie8)
     return (element.getAttribute("className"));
else return (element.getAttribute("class"));
};

String.prototype.getUnits = function() {
// match and return any [ °C |°F | &dec;C | &dec;F | mm | in | cm | ft | mb | hPa | inHg | mmHg | kts | m/s | mph | kph ]
return (this.match(/°C|°F|&dec;F|&dec;C|[a-z]+\/?[a-z]?/i));
};

// return the value
function ajax_page_getTagValue ( element, type ) {
var html = element.innerHTML;
var val  = parseFloat(html);
var uom  = html.getUnits();
return ( val.converToMetric(uom, type) );
};

// utility functions to navigate the <span class="..."> tags on the page and save their values
function ajax_page_saveTags () {
uom     = (useUOM=="M") ? metricUOM : imperialUOM;
dp      = (useUOM=="M") ? metricDP  : imperialDP ;
colorM  = (useUOM=="E") ? "gray"    : "blue";
colorE  = (useUOM=="M") ? "gray"    : "blue";
var uomM = document.getElementById("uomM"); if (uomM) uomM.style.color = colorM;
var uomE = document.getElementById("uomE"); if (uomE) uomE.style.color = colorE;
switch (uom.Wind) {
case "mph": uom.langWind = langWindUOM[1]; break;
case "kph": uom.langWind = langWindUOM[2]; break;
case "m/s": uom.langWind = langWindUOM[3]; break;
default   : uom.langWind = langWindUOM[0];
}
var i, name , iC = iF =0;
var pgElements = ajax_getElements('span');
   for(i=0; i<pgElements.length; i++) {
      name = ajax_getClassName(pgElements[i]); // could be: class="ajax convTemp"
      if (name!=null) {
         // conversion elements
         if (name.search(/convTemp|convWind|convBaro|convRain|convSnow|convDist|convAlti/i) > -1) {
            uomElements[iC++]  = [ pgElements[i], name, ajax_page_getTagValue(pgElements[i],name) ];
            ajaxElements[iF++] = pgElements[i]; // also add to flashing elements
         }
         // flashing elements
         if (name.search(/ajax/i) > -1)
            ajaxElements[iF++] = pgElements[i];
      }
   }
   var element = document.getElementById("ajaxindicator");
   if (element) Indicator = element.innerHTML;
   ajax_page_convertTags();
};

// convert "conv..." tags to required UOM
function ajax_page_convertTags () {
var i, name, val, ret;
   for(i=0; i<uomElements.length; i++) {
      name = uomElements[i][1];
      val  = uomElements[i][2];
      ret = null;
      switch (name) {
      case "convTemp": ret = val.convertTemp().toFixed(dp.Temp)+uom.Temp; break;
      case "convWind": ret = val.convertWind().toFixed(dp.Wind)+' '+uom.langWind; break;
      case "convBaro": ret = val.convertBaro().toFixed(dp.Baro)+' '+uom.Baro; break;
      case "convRain": ret = val.convertRain().toFixed(dp.Rain)+' '+uom.Rain; break;
      case "convSnow": ret = val.convertSnow().toFixed(dp.Snow)+' '+uom.Snow; break;
      case "convDist": ret = val.convertDist().toFixed(dp.Dist)+' '+uom.Dist; break;
      case "convAlti": ret = val.convertAlti().toFixed(dp.Alti)+' '+uom.Alti; break;
      }
      if (ret!=null) {
         uomElements[i][0].innerHTML = ret;
         uomElements[i][0].style.color = flashcolor;
      }
   }
};


// function for setting green flashing object
function ajax_flash_green ( name ) {
   var element = document.getElementById(name);
   if (element)  element.style.color = flashcolor;
};

// function for resetting green flashing object
function ajax_flash_reset( usecolor ) {
// reset all the <span class="ajax"...> styles to have no color override
   for(var i=0; i<ajaxElements.length; i++) {
      element = ajaxElements[i];
      element.style.color = usecolor;
   }
};


function set_ajax_obs( name, value , html , red) {
// store away the current value in both the doc and the span as lastobs="value"
// change color if value != lastobs
   var element = document.getElementById(name);
   if (! element ) { return; } // V1.04 -- don't set if missing the <span id=name> tag
   var lastobs = element.getAttribute("lastobs");
   element.setAttribute("lastobs",value);
   if (value != unescape(lastobs)) {
      element.style.color = (red)? flashRed : flashcolor;
      if ( doTooltip ) element.setAttribute("title",'AJAX tag '+name);
      element.innerHTML = ((typeof html=='undefined')?value:html); // moved inside to fix flashing issue (Jim at jcweather.us)
   }
};

function set_ajax_uom( name, show ) {
// this function will set an ID= to visible or hidden by setting the style="display: " from 'inline' or 'none'
   var element = document.getElementById(name);
   if (! element ) { return; }
   if (show) element.style.display='inline';
   else      element.style.display='none';
};
// --- end of flash-green functions


function ajax_getWindDir (winddir) {
// Take wind direction value, return the
// text label based upon 16 point compass -- function by beeker425
//  see http://www.weather-watch.com/smf/index.php/topic,20097.0.html
   windlabel = new Array("N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW");
   return windlabel[Math.floor(((parseInt(winddir) + 11) / 22.5) % 16 )];
};

function ajax_getWindDirLang (winddir) {
// Take wind direction value, return the
// text label based upon 16 point compass -- function by beeker425
// ... see http://www.weather-watch.com/smf/index.php/topic,20097.0.html
   return langWindDir[Math.floor(((parseInt(winddir) + 11) / 22.5) % 16 )];
};

function ajax_getIconName0 ( iconNr ,iconSet ) {
// perform a lookup and return the graphic name for the condition icon
// (using anole's wxsticker icon nameing convention)
  iconList = new Array(
   "day_clear",           //  0 sunny
   "night_clear",         //  1 clearnight
   "day_partly_cloudy",   //  2 cloudy
   "day_partly_cloudy",   //  3 cloudy2
   "night_partly_cloudy", //  4 cloudynight
   "day_clear",           //  5 dry
   "fog",                 //  6 fog
   "haze",                //  7 haze
   "day_heavy_rain",      //  8 heavyrain
   "day_mostly_sunny",    //  9 mainlyfine
   "mist",                // 10 mist
   "fog",                 // 11 nightfog
   "night_heavy_rain",    // 12 nightheavyrain
   "night_cloudy",        // 13 nightovercast
   "night_rain",          // 14 nightrain
   "night_light_rain",    // 15 nightshowers
   "night_snow",          // 16 nightsnow
   "night_tstorm",        // 17 nightthunder
   "day_cloudy",          // 18 overcast
   "day_partly_cloudy",   // 19 partlycloudy
   "day_rain",            // 20 rain
   "day_rain",            // 21 rain2
   "day_light_rain",      // 22 showers2
   "day_sleet",           // 23 sleet
   "day_sleet",           // 24 sleetshowers
   "day_snow",            // 25 snow
   "day_snow",            // 26 snowmelt
   "day_snow",            // 27 snowshowers2
   "day_clear",           // 28 sunny
   "day_tstorm",          // 29 thundershowers
   "day_tstorm",          // 30 thundershowers2
   "day_tstorm",          // 31 thunderstorms
   "tornado",             // 32 tornado
   "windy",               // 33 windy
   "day_partly_cloudy",   // 34 stopped rainning
   "windyrain"            // 35 windy/rain (new with V2.11)
   );

   if (iconNr >= 0 && iconNr <= 35) {
      return ('<img src="'+ iconSet.src.replace("#PIC#", iconList[iconNr])
             +'" width="' + iconSet.width
             +'" height="'+ iconSet.height
             +'" border="'+ iconSet.border
             +'" vspace="'+ iconSet.vspace
             +'" hspace="'+ iconSet.hspace
             +'" style="' + iconSet.style
             +'" align="' + iconSet.align
             +'" alt="Current conditions" />');
   }  else return '';
};


function ajax_getIconName1 ( iconNr ,iconSet ) {
// perform a lookup and return the graphic for the condition icon
// (using NWS icon nameing convention)
  iconList = new Array(
   "skc",          //  0 sunny
   "nskc",         //  1 clearnight
   "bkn",          //  2 cloudy
   "sct",          //  3 cloudy2
   "nbkn",         //  4 cloudynight
   "sct",          //  5 dry
   "fg",           //  6 fog
   "hazy",         //  7 haze
   "ra",           //  8 heavyrain
   "few",          //  9 mainlyfine
   "mist",         // 10 mist
   "nfg",          // 11 nightfog
   "nra",          // 12 nightheavyrain
   "novc",         // 13 nightovercast
   "nra",          // 14 nightrain
   "nshra",        // 15 nightshowers
   "nsn",          // 16 nightsnow
   "ntsra",        // 17 nightthunder
   "ovc",          // 18 overcast
   "bkn",          // 19 partlycloudy
   "ra",           // 20 rain
   "ra",           // 21 rain2
   "shra",         // 22 showers2
   "ip",           // 23 sleet
   "ip",           // 24 sleetshowers
   "sn",           // 25 snow
   "sn",           // 26 snowmelt
   "sn",           // 27 snowshowers2
   "skc",          // 28 sunny
   "scttsra",      // 29 thundershowers
   "hi_tsra",      // 30 thundershowers2
   "tsra",         // 31 thunderstorms
   "nsvrtsra",     // 32 tornado
   "wind",         // 33 windy
   "ra1",          // 34 stopped rainning
   "windyrain",    // 35 windy/rain (new with V2.11)
   "sunrise",      // 36 sunrise
   "sunset"        // 37 sunset
   );

   if (iconNr >= 0 && iconNr <= 37) {
      return ('<img src="'+ iconSet.src.replace("#PIC#", iconList[iconNr])
             +'" width="' + iconSet.width
             +'" height="'+ iconSet.height
             +'" border="'+ iconSet.border
             +'" vspace="'+ iconSet.vspace
             +'" hspace="'+ iconSet.hspace
             +'" style="' + iconSet.style
             +'" align="' + iconSet.align
             +'" alt="Current conditions" />');
   }  else return '';
};


function ajax_getIconName2 ( iconNr , iconSet ) {
// perform a lookup and return the graphic image for the condition icon
// (using Bashewa icon nameing convention)
iconList = new Array(
   "0-skc",           //  0 sunny
   "1-nskc",          //  1 clear night
   "2-bkn",           //  2 cloudy
   "3-sct",           //  3 mainly fine (only a few clouds)
   "4-nbkn",          //  4 cloudy night
   "5-skc",           //  5 dry (cloudy periods)
   "6-fg",            //  6 fog
   "7-hazy",          //  7 haze
   "8-hra",           //  8 heavy rain
   "9-few",           //  9 mainly fine
   "10-mist",         // 10 mist
   "11-nfg",          // 11 night fog
   "12-nhra",         // 12 night heavy rain
   "13-novc",         // 13 night overcast
   "14-nra",          // 14 night rain
   "15-nshra",        // 15 night showers
   "16-nsn",          // 16 night snow
   "17-ntsra",        // 17 night thunder
   "18-ovc",          // 18 overcast
   "19-pcld",         // 19 partly cloudy
   "20-ra",           // 20 rain
   "21-lra",          // 21 light rain
   "22-shra",         // 22 showers (light rain/drizzle)
   "23-ip",           // 23 sleet
   "24-ipra",         // 24 sleetshowers
   "25-sn",           // 25 snow
   "26-snm",          // 26 snowmelt
   "27-snsh",         // 27 snow showers (light snow/snow showers)
   "28-skc",          // 28 sunny
   "29-scttsra",      // 29 thundershowers
   "30-hi-tsra",      // 30 thundershowers2
   "31-tsra",         // 31 thunderstorms
   "32-nsvrtsra",     // 32 tornado
   "33-windy",        // 33 windy
   "34-ras",          // 34 stopped rainning
   "35-windyrain",    // 35 windy & rain
   "36-sunrise",      // 36 sunrise
   "37-sunset"        // 37 sunset
   );

   if (iconNr >= 0 && iconNr <= 37) {
      return ('<img src="'+ iconSet.src.replace("#PIC#", iconList[iconNr])
             +'" width="' + iconSet.width
             +'" height="'+ iconSet.height
             +'" border="'+ iconSet.border
             +'" vspace="'+ iconSet.vspace
             +'" hspace="'+ iconSet.hspace
             +'" style="' + iconSet.style
             +'" align="' + iconSet.align
             +'" alt="Current conditions" />');
   }  else return '';
};

//------------------------------------------------------------------------------
// CONVERSIONS: prototypes to handle conversions from clientraw data to desired units-of-measure
//------------------------------------------------------------------------------
Number.prototype.converToMetric = function ( units, type ) { // convert to C, kts, hPa, mm, cm or meters
type = (typeof type == 'undefined')? "" : type;
   switch (units.toString().toLowerCase()) { // lowercase in case we get FT or KMH etc
// temp to °C
   case "°f"    :
   case "&deg;f": return((this - 32) / 1.8); // Celsius = (this - 32) * 0.556
// wind mph, km/h and m/s to kts
   case "kmh"   :
   case "kph"   :
   case "km/h"  : return (this * 0.539956803);
   case "mph"   : return (this / 1.150779450);
   case "m/s"   : return (this / 0.514444444);
// baro inHg, mmHg and kPa to hPa
   case "inhg"  : return (this * 33.86388667);
   case "mmhg"  : return (this * 1.3332239);
   case "kpa"   : return (this * 10.0);
// rain to mm and snow to cm
   case "in"    : if (type=="convSnow") return (this * 2.54);
                  else                  return (this * 25.4);
// distance miles and meters to km
   case "m"     : return (this / 1000);
   case "miles" : return (this / 1.150779450);
// altitude to meters
   case "ft"    : return (this / 3.2808399);
   default      : return (this * 1.0);
   }
};


Number.prototype.convertTemp = function() { // °C
   switch (uom.Temp) {
   case "&deg;F": return((this * 1.8) + 32.0);
   default      : return (this * 1.0);
   }
};

Number.prototype.convertWind = function() { // kts
   switch (uom.Wind) {
   case "mph" : return (this * 1.15077945);
   case "kph" : return (this * 1.852);
   case "m/s" : return (this * 0.514444444);
   default    : return (this * 1.0);
   }
};

Number.prototype.convertBaro = function() { // hPa
   switch (uom.Baro) {
   case "inHg": return (this / 33.863886666667);
   case "mmHg": return (this / 1.3332239);
   case "kPa" : return (this * 0.1);
   default    : return (this * 1.0);
   }
};

Number.prototype.convertRain = function() { // mm
   switch (uom.Rain) {
   case "in" : return (this * 0.0393700787402);
   case "cm" : return (this * 0.1);
   default   : return (this * 1.0);
   }
};

Number.prototype.convertAlti = function() { // meters
   switch (uom.Alti) {
   case "ft" : return (this * 3.2808399); break;
   default   : return (this * 1.0);
   }
};

Number.prototype.convertSnow = function() { // cm
   switch (uom.Snow) {
   case "in" : return (this * 0.3937007874020);
   case "ft" : return (this * 0.0328083989501);
   case "mm" : return (this * 10.0);
   case "m"  : return (this * 0.1);
   default   : return (this * 1.0);
   }
};

Number.prototype.convertDist = function() { // km
   switch (uom.Dist) {
   case "m"     : return (this / 1000);
   case "miles" : return (this / 1.150779450);
   default   : return (this * 1.0);
   }
};
//----------------------------------------------------------- end of conversions


function ajax_getBeaufortNumber ( wind ) {
// return a number for the beaufort scale based on wind knots (native WD format)
  if (wind <  1 ) {return("0"); }
  if (wind <  4 ) {return("1"); }
  if (wind <  7 ) {return("2"); }
  if (wind < 11 ) {return("3"); }
  if (wind < 17 ) {return("4"); }
  if (wind < 22 ) {return("5"); }
  if (wind < 28 ) {return("6"); }
  if (wind < 34 ) {return("7"); }
  if (wind < 41 ) {return("8"); }
  if (wind < 48 ) {return("9"); }
  if (wind < 56 ) {return("10"); }
  if (wind < 64 ) {return("11"); }
  if (wind >=64 ) {return("12"); }
  return("0");
};


function ajax_getBaroTrend(btrnd) {
// routine from Anole's wxsticker PHP (adapted to JS by Ken True)
// input: trend in hPa or millibars
//   Barometric Trend(3 hour)

// Change Rates
// Rapidly: =.06 inHg; 1.5 mmHg; 2.0 hPa; 2.0 mb
// Slowly : =.02 inHg; 0.5 mmHg; 0.7 hPa; 0.7 mb

// 5 conditions
// 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
   if ((btrnd >= -0.7) && (btrnd <= 0.7)) { return(langBaroTrend[0]); }
   if ((btrnd >   0.7) && (btrnd <  2.0)) { return(langBaroTrend[1]); }
   if (btrnd >=   2.0)                    { return(langBaroTrend[2]); }
   if ((btrnd <  -0.7) && (btrnd > -2.0)) { return(langBaroTrend[3]); }
   if (btrnd <=  -2.0)                    { return(langBaroTrend[4]); }
  return(btrnd);
};

// Official colours for UV as specified by WHO, WMO & UNEP
var UVColor = new Array
   ( "none"    //  0
   , "#4EB400" //  1 Low
   , "#A0CE00" //  2
   , "#F7E400" //  3 Medium
   , "#F8B600" //  4
   , "#F88700" //  5
   , "#F85900" //  6 High
   , "#E82C0E" //  7
   , "#D8001D" //  8 Very High
   , "#FF0099" //  9
   , "#B54CFF" // 10
   , "#998CFF" // 11+Extreme
   );

function ajax_getUVrange ( uv ) { // code simplified by FourOhFour on wxforum.net
   var uvword = "None";
   var uvclr1  = UVColor[Math.min(11,Math.round(uv))];
   switch (true) {
   case (uv < 0): uvword = langUVWords[6]; uvclr2 = 'none';    break; // UV sensor is not sending
   case (uv = 0): uvword = langUVWords[0]; uvclr2 = 'none';    break; // None
   case (uv < 3): uvword = langUVWords[1]; uvclr2 = '#4EB400'; break; // Low
   case (uv < 6): uvword = langUVWords[2]; uvclr2 = '#F7E400'; break; // Medium
   case (uv < 8): uvword = langUVWords[3]; uvclr2 = '#F85900'; break; // High
   case (uv <11): uvword = langUVWords[4]; uvclr2 = '#D8001D'; break; // Very High
   case (uv >18): uvword = langUVWords[6]; uvclr2 = 'none';    break; // UV sensor is not sending
   default      : uvword = langUVWords[5]; uvclr2 = '#998CFF';        // Extreme
   }
   return ('<span style="border: 1px solid gray; text-transform: uppercase; font-weight: bold; padding-bottom: 1px; background-color: '+ uvclr1 +';">&nbsp;'+Math.round(uv) +'&nbsp;'+ uvword +'&nbsp;</span>');
}; // end ajax_getUVrange function


function ajax_getUVburnRate ( uv ) {
   var uvIdx  = Math.min(18,Math.round(uv));
   switch (uvIdx) {
   case  1: uvrate = 112;  break;
   case  2: uvrate =  56;  break;
   case  3: uvrate =  37;  break;
   case  4: uvrate =  28;  break;
   case  5: uvrate =  22;  break;
   case  6: uvrate =  19;  break;
   case  7: uvrate =  16;  break;
   case  8: uvrate =  14;  break;
   case  9: uvrate =  12;  break;
   case 10: uvrate =  11;  break;
   case 11: uvrate =  10;  break;
   case 12: uvrate =   9;  break;
   case 13: uvrate =   9;  break;
   case 14: uvrate =   8;  break;
   case 15: uvrate =   7;  break;
   case 16: uvrate =   6;  break;
   case 17: uvrate =   5;  break;
   case 18: uvrate =   4;  break;
   default: uvrate =   "--";
   }
   return uvrate;
}; // end ajax_getUVburnRate function


function ajax_getTrendArrow( nowTemp, yesterTemp, Legend, textUP, textDN, numDp) {
// generate an <img> tag with alt= and title= for rising/falling values
var diff = nowTemp.toFixed(3) - yesterTemp.toFixed(3);
var absDiff = Math.abs(diff);
var diffStr = '' + diff.toFixed(numDp);
var absDiffStr = '' + absDiff.toFixed(numDp);
var image = '';
var msg = '';

   if (diff == 0) { // no change
      msg = '';
      image = '<img src="' + imgDir + 'steady.gif'
            + '" alt="'    + msg
            + '" title="'  + msg
            + '" width="7" height="8" style="border: 0; margin: 1px 3px;" />';
   } else if (diff > 0) { // today is greater
      msg = textUP.replace(/\%s/,absDiffStr);
      image = '<img src="' + imgDir + 'rising.gif'
            + '" alt="'    + msg
            + '" title="'  + msg
            + '" width="7" height="8" style="border: 0; margin: 1px 3px;" />';
   } else { // today is lesser
      msg = textDN.replace(/\%s/,absDiffStr);
      image = '<img src="' + imgDir + 'falling.gif'
            + '" alt="'    + msg
            + '" title="'  + msg
            + '" width="7" height="8" style="border: 0; margin: 1px 3px;" />';
   }
   return ((Legend) ? (diff + Legend + image) : image);
}; // end ajax_getTrendArrow function


// function to add colored heatColorWord by Mike Challis
function ajax_getHeatColor(temp ,WindChill, Humidex) {
var fg = bg = hw = "";
var hcWord = langHeatWords[0];
var val = { fg:'', bg:'', hw:'' };
   if (temp > 32 && Humidex > 29) {
      switch (true) {
      case (Humidex   > 54): fg = "white"; bg = "#BA1928"; hw = langHeatWords[ 1]; break;
      case (Humidex   > 45): fg = "white"; bg = "#E02538"; hw = langHeatWords[ 2]; break;
      case (Humidex   > 39): fg = "black"; bg = "#E178A1"; hw = langHeatWords[ 4]; break;
      case (Humidex   > 29): fg = "white"; bg = "#CC6633"; hw = langHeatWords[ 6]; break;
      }
   } else if (WindChill < 16 ) {
      switch (true) {
      case (WindChill <-18): fg = "black"; bg = "#91ACFF"; hw = langHeatWords[13]; break;
      case (WindChill < -9): fg = "white"; bg = "#806AF9"; hw = langHeatWords[12]; break;
      case (WindChill < -1): fg = "white"; bg = "#3366FF"; hw = langHeatWords[11]; break;
      case (WindChill <  8): fg = "white"; bg = "#6699FF"; hw = langHeatWords[10]; break;
      case (WindChill < 16): fg = "black"; bg = "#89B2EA"; hw = langHeatWords[ 9]; break;
      }
   }  else if (WindChill >= 16 && temp <= 32) {
      switch (true) {
      case (temp      < 26): fg = "black"; bg = "#C6EF8C"; hw = langHeatWords[ 8]; break;
      case (temp      <=32): fg = "black"; bg = "#CC9933"; hw = langHeatWords[ 7]; break;
      }
   }
   val.fg = fg;
   val.bg = bg;
   val.hw = hw;
   return val;
}; // end ajax_getHeatColor function

function ajax_getHeatColorWord(temp ,WindChill, Humidex) {
var val = ajax_getHeatColor(temp ,WindChill, Humidex);
return ((val.fg=="")? val.hw
                    : '<span style="border: solid 1px; color: '+val.fg+'; background-color: '+val.bg+';">&nbsp;'+val.hw+'&nbsp;</span>'
                    );
};

function ajax_getHeatColorTemp(temp ,WindChill, Humidex, actTemp) {
var val = ajax_getHeatColor(temp ,WindChill, Humidex);
return ((val.fg=="")? actTemp.toFixed(dp.Temp)+uom.Temp
                    : '<span style="border: solid 1px; color: '+val.fg+'; background-color: '+val.bg+';">&nbsp;'+actTemp.toFixed(dp.Temp)+uom.Temp+'&nbsp;</span>'
                    );
};

//
// slice and dice the clientraw[49] for possible translation of current weather
//
function ajax_fixupCondition( rawcond ) {
var cond  = rawcond;
    cond  = cond.replace(/_/gm,' ');     // replace any _ with blank.
    cond  = cond.replace(/[\r\n]/gm,''); // remove embedded CR and/or LF
var conds = cond.split('/');             // split up the arguments.
var tstr = '';
   for (var i = 0;i<conds.length;i++) {
      var t = conds[i];
      t = t.toLowerCase();
      t = t.ucfirst();
      t = t.replace(/\s+$/,'');  // trim trailing blanks
      if(langTransLookup[t]) conds[i] = langTransLookup[t];
      else                   conds[i] = t;
   }
   if (conds[0].length == 0) { conds.splice(0,1);  } // remove blank entry
   if (conds[0] == conds[2]) { conds.splice(2,1); } // remove duplicate last entry
   return(conds.join(', '));
}; // end ajax_fixupCondition function


// Mike Challis' counter function (adapted by Ken True)
function ajax_countup() {
var element = document.getElementById("ajaxcounter");
   if (element) {
      element.innerHTML = counterSecs;
      counterSecs++;
   }
};


function ajax_getFireIndex ( fwi ) {
   switch (true) {
     case (fwi==0): idx = 0; break;
     case (fwi< 7): idx = 1; break;
     case (fwi<16): idx = 2; break;
     case (fwi<31): idx = 3; break;
     default      : idx = 4;
   }
return idx;
};

// -----------------------------------------------------------------------------
// MOON FUNTIONS                                                               .
// -----------------------------------------------------------------------------
function getMoonInfo () { // very crude way of determining moon phase (but very accurate)
newMoons = new Array( // Timestamp of New Moons (UNIX seconds UTC)
/* 2009 */ 1232956694, 1235525859, 1238083702, 1240629891, 1243167207, 1245699441, 1248230173, 1250762572, 1253299546, 1255844071, 1258398911, 1260965011,
/* 2010 */ 1263539579, 1266116026, 1268687080, 1271248355, 1273799231, 1276341392, 1278877313, 1281409748, 1283941880, 1286477210, 1289019244, 1291570681,
/* 2011 */ 1294131882, 1294131882, 1296700310, 1299271605, 1301841272, 1304405628, 1306962312, 1309510520, 1312051217, 1314587095, 1317121886, 1319659182, 1322201551, 1324750113,
/* 2012 */ 1327304495, 1329863812, 1332427106, 1334992779, 1337557778, 1340118351, 1342672008, 1345218916, 1347761485, 1350302723, 1352844709, 1355388222,
/* 2013 */ 1357933472, 1360480904, 1363031660, 1365586707, 1368145814, 1370707094, 1373267883, 1375826087, 1378381094, 1380933332, 1383483138, 1386030341,
/* 2014 */ 1388574989, 1388574989, 1391117983, 1393660864, 1396205280, 1398752305, 1401302565, 1403856551, 1406414595, 1408976167, 1411539417, 1414101518, 1416659662, 1419212321,
/* 2015 */ 1421759787, 1424303328, 1426844236, 1429383570, 1431922626, 1434463716, 1437009944, 1439564065, 1442126635, 1444694970, 1447264236, 1449829922,
/* 2016 */ 1452389564, 1454942453, 1457488541, 1460028286, 1462563113, 1465095782, 1467630271, 1470170826, 1472720703, 1475280802, 1477849249, 1480422119, 1482994606,
/* 2017 */ 1485562175, 1488121237, 1490669959, 1493209111, 1495741652, 1498271627, 1500803297, 1503340348, 1505885501, 1508440395, 1511005389, 1513578751,
/* 2018 */ 1516155614, 1518728902, 1521292492, 1523844016, 1526385048, 1528919174, 1531450217, 1533981591, 1536516226, 1539056950, 1541606661, 1544167329,
/* 2019 */ 1546738169, 1546738169, 1549314291, 1551888383, 1554454433, 1557010114, 1559556250, 1562095076, 1564629201, 1567161553, 1569695379, 1572234119, 1574780933, 1577337352,
/* 2020 */ 1579902223, 1582471950, 1585042163, 1587608928, 1590169341, 1592721853, 1595266463, 1597804950, 1600340550, 1602876914, 1605417056, 1607962750,
/* 2021 */ 1610514135, 1613070484, 1615630968, 1618194705, 1620759694, 1623322579, 1625880033, 1628430728, 1630975950, 1633518455, 1636060737, 1638604010,
/* 2022 */ 1641148542);

Q1Moons = new Array ( // Timestamp of First Quarter moons
/* 2009 */ 1233616466, 1236152804, 1238682880, 1241210710, 1243740198, 1246274983, 1248818470, 1251373426, 1253940727, 1256517860, 1259098851, 1261676274,
/* 2010 */ 1264244160, 1266799526, 1269342167, 1271874084, 1274399029, 1276921861, 1279447915, 1281982452, 1284529794, 1287091742, 1289666474, 1292248863,
/* 2011 */ 1294831983, 1297408815, 1299973706, 1302523729, 1305059664, 1307585465, 1310106634, 1312628984, 1315157981, 1317698107, 1320251955, 1322819685,
/* 2012 */ 1325398640, 1325398640, 1327983093, 1330564986, 1333136607, 1335693660, 1338236313, 1340767931, 1343293087, 1345816543, 1348342960, 1350876793, 1353421929, 1355980814,
/* 2013 */ 1358552834, 1361133174, 1363714105, 1366288392, 1368851851, 1371403608, 1373944894, 1376477938, 1379005859, 1381532690, 1384063167, 1386601987,
/* 2014 */ 1389152424, 1391714650, 1394285377, 1396859597, 1399432632, 1402000814, 1404561612, 1407113513, 1409656417, 1412192069, 1414723797, 1417255693, 1419791608,
/* 2015 */ 1422334224, 1424884553, 1427442299, 1430006302, 1432574532, 1435143885, 1437710718, 1440271962, 1442826096, 1445373215, 1447914541, 1450451752,
/* 2016 */ 1452986905, 1455522519, 1458061466, 1460606450, 1463159100, 1465719254, 1468284944, 1470853418, 1473421879, 1475987724, 1478548421, 1481101538,
/* 2017 */ 1483645726, 1483645726, 1486182021, 1488713651, 1491244864, 1493779693, 1496321050, 1498870464, 1501428399, 1503994581, 1506567362, 1509143005, 1511715876, 1514280154,
/* 2018 */ 1516832539, 1519373438, 1521905803, 1524433630, 1526961046, 1529491957, 1532030045, 1534578648, 1537139881, 1539713098, 1542293801, 1544874670,
/* 2019 */ 1547448455, 1550010518, 1552559383, 1555096065, 1557623598, 1560146437, 1562669805, 1565199138, 1567739474, 1570294143, 1572863214, 1575442912,
/* 2020 */ 1578026860, 1578026860, 1580607780, 1583179179, 1585736697, 1588279266, 1590809474, 1593332232, 1595853289, 1598378356, 1600912525, 1603459429, 1606020444, 1608594245,
/* 2021 */ 1611176623, 1613760504, 1616337726, 1618902128, 1621451743, 1623988602, 1626516776, 1629040931, 1631565713, 1634095636, 1636634866, 1639186642);

fullMoons = new Array ( // Timestamp of Full moons
/* 2009 */ 1234190988, 1236739201, 1239289163, 1241841830, 1244398374, 1246958600, 1249520262, 1252080269, 1254636636, 1257189302, 1259739205, 1262286957,
/* 2010 */ 1264832305, 1267375090, 1269916047, 1272457350, 1275001851, 1277551927, 1280108252, 1282669583, 1285233603, 1287797924, 1290360530, 1292919327,
/* 2011 */ 1295472210, 1298018189, 1300558247, 1303094731, 1305630683, 1308168989, 1310712091, 1313261900, 1315819668, 1318385317, 1320956377, 1323527942,
/* 2012 */ 1326094328, 1328651742, 1331199679, 1333740049, 1336275429, 1338808434, 1341341662, 1343878168, 1346421577, 1348975200, 1351540279, 1354114099, 1356690230,
/* 2013 */ 1359261660, 1361824109, 1364376586, 1366919999, 1369456050, 1371987276, 1374517074, 1377049609, 1379589306, 1382139600, 1384701470, 1387272584,
/* 2014 */ 1389848076, 1392422184, 1394989887, 1397547905, 1400095110, 1402632803, 1405164397, 1407694291, 1410226824, 1412765578, 1415312729, 1417868963,
/* 2015 */ 1420433724, 1420433724, 1423005055, 1425578868, 1428149319, 1430711135, 1433262117, 1435803682, 1438339471, 1440873466, 1443408809, 1445947679, 1448491600, 1451042032,
/* 2016 */ 1453600098, 1456165312, 1458734525, 1461302743, 1463865496, 1466420769, 1468969123, 1471512470, 1474052842, 1476591987, 1479131745, 1481674090,
/* 2017 */ 1484220954, 1486773338, 1489330638, 1491891034, 1494452655, 1497013965, 1499573437, 1502129587, 1504681408, 1507228860, 1509773133, 1512316253,
/* 2018 */ 1514859977, 1514859977, 1517405248, 1519951989, 1522500055, 1525050132, 1527603711, 1530161701, 1532723016, 1535284782, 1537844070, 1540399595, 1542951703, 1545501121,
/* 2019 */ 1548047852, 1550591600, 1553132599, 1555672512, 1558214120, 1560760403, 1563313184, 1565872275, 1568435781, 1571001115, 1573565842, 1576127677,
/* 2020 */ 1578684217, 1581233663, 1583776093, 1586313366, 1588848475, 1591384562, 1593924454, 1596470448, 1599024204, 1601586454, 1604155975, 1606728791, 1609299038,
/* 2021 */ 1611861485, 1614413932, 1616957405, 1619494418, 1622027786, 1624560153, 1627094368, 1629633848, 1632182189, 1634741926, 1637312421, 1639888739);

Q3Moons = new Array ( // Timestamp of Last Quarter moons
/* 2009 */ 1237398554, 1239975466, 1242545259, 1245104206, 1247651745, 1250189868, 1252721896, 1255251494, 1257782304, 1260317778,
/* 2010 */ 1262860934, 1262860934, 1265413841, 1267976670, 1270546815, 1273119452, 1275689669, 1278254175, 1280811609, 1283361852, 1285905310, 1288442904, 1290976733, 1293510087,
/* 2011 */ 1296046804, 1298590089, 1301141351, 1303699776, 1306263281, 1308829815, 1311397391, 1313963712, 1316526039, 1319081627, 1321629108, 1324169377,
/* 2012 */ 1326705010, 1329239192, 1331774851, 1334314300, 1336859342, 1339411467, 1341971482, 1344538657, 1347110203, 1349681719, 1352248700, 1354808040,
/* 2013 */ 1357358410, 1357358410, 1359899928, 1362434127, 1364963957, 1367493412, 1370026835, 1372568168, 1375119984, 1377682703, 1380254316, 1382830996, 1385407802, 1387979429,
/* 2014 */ 1390540983, 1393089540, 1395625715, 1398153221, 1400677281, 1403203235, 1405735774, 1408278416, 1410833214, 1413400494, 1415978328, 1418561609,
/* 2015 */ 1421142546, 1423713235, 1426269127, 1428810457, 1431340708, 1433864649, 1436387200, 1438913113, 1441446945, 1443992837, 1446553565, 1449128630,
/* 2016 */ 1451712795, 1451712795, 1454297382, 1456873985, 1459437627, 1461987181, 1464524152, 1467051723, 1469574205, 1472096693, 1474624743, 1477163701, 1479717285, 1482285534,
/* 2017 */ 1484864187, 1487446512, 1490025613, 1492595980, 1495154214, 1497699414, 1500233342, 1502759895, 1505284098, 1507811282, 1510346276, 1512892376,
/* 2018 */ 1515450448, 1518018995, 1520594566, 1523172020, 1525745451, 1528310038, 1530863620, 1533406873, 1535942448, 1538473719, 1541004204, 1543537321, 1546076238,
/* 2019 */ 1548623544, 1551180574, 1553746356, 1556317272, 1558888523, 1561456062, 1564017575, 1566572324, 1569120293, 1571661795, 1574198048, 1576731612,
/* 2020 */ 1579266095, 1581805160, 1584351341, 1586905111, 1589465159, 1592029616, 1594596688, 1597164374, 1599730051, 1602290567, 1604843375, 1607387941,
/* 2021 */ 1609925954, 1609925954, 1612460371, 1614994355, 1617530669, 1620071534, 1622618844, 1625174059, 1627737579, 1630307754, 1632880756, 1635451674, 1638016263, 1640572030);

   dt = new Date().getTime()/1000;  // Unix timestamp
   if (dt < newMoons[1])                 alert("Moon date must be after " +newMoons[1].date());
   if (dt > newMoons[newMoons.length-1]) alert("Moon date must be before "+newMoons[newMoons.length-1].date());

   for (mi in newMoons) // find next New Moon from given date
      if (newMoons[mi]>dt) break;

   // Get Moon dates
   NM = newMoons [mi-1]; // previous new moon
   Q1 = Q1Moons  [mi-1]; // 1st Q end
   Q2 = fullMoons[mi-1]; // 2nd Q end - Full moon
   Q3 = Q3Moons  [mi-1]; // 3rd Q end
   Q4 = newMoons [mi  ]; // 4th Q end - next new moon

   // Divide each phase into 7 periods (4 phases x 7 = 28 periods)
   Q1p = Math.round((Q1-NM)/7);
   Q2p = Math.round((Q2-Q1)/7);
   Q3p = Math.round((Q3-Q2)/7);
   Q4p = Math.round((Q4-Q3)/7);

   // Determine start and end times for major phases (lasting 1 period of 28)
   NMe = NM+(Q1p/2);                      //  0% .... - New moon
   Q1s = Q1-(Q1p/2);  Q1e = Q1+(Q2p/2);   // 50% 1stQ - First Quarter
   Q2s = Q2-(Q2p/2);  Q2e = Q2+(Q3p/2);   //100% 2ndQ - Full moon
   Q3s = Q3-(Q3p/2);  Q3e = Q3+(Q4p/2);   // 50% 3rdQ - Last Quarter
   NMs = Q4-(Q4p/2);                      //  0% 4thQ - New Moon

// Determine age of moon in days since last new moon
   age = (dt - newMoons[mi-1])/86400; // age in days since last new moon
   dd  = Math.floor(age);
   hh  = Math.floor((age-dd)*24);
   mm  = Math.floor((((age-dd)*24)-hh)*60);
   age = dd+' days, '+hh+' hours, '+mm+' minutes';

// Illumination
   switch (true) { // Determine moon age in degrees (0 to 360)
   case (dt<=Q1): ma = (dt - NM) * (90 / (Q1 - NM))+  0; break; // NM to Q1
   case (dt<=Q2): ma = (dt - Q1) * (90 / (Q2 - Q1))+ 90; break; // Q1 to FM
   case (dt<=Q3): ma = (dt - Q2) * (90 / (Q3 - Q2))+180; break; // FM to Q3
   case (dt<=Q4): ma = (dt - Q3) * (90 / (Q4 - Q3))+270; break; // Q3 to NM
   }
   ill = Math.abs(Math.round(100*(1+Math.cos(ma*(Math.PI/180)))/2)-100);

// Deterime picture number (0-27) and moon phase
   switch (true) {
   case (dt<=NMe): pic =  0;                  ph = langMoonPhases[0]; break;
   case (dt< Q1s): pic =  1  +((dt-NMe)/Q1p); ph = langMoonPhases[1]; break; // or Waxing Crescent
   case (dt<=Q1e): pic =  7;                  ph = langMoonPhases[2]; break;
   case (dt< Q2s): pic =  7.5+((dt-Q1e)/Q2p); ph = langMoonPhases[3]; break;
   case (dt<=Q2e): pic = 14;                  ph = langMoonPhases[4]; break;
   case (dt< Q3s): pic = 14.5+((dt-Q2e)/Q3p); ph = langMoonPhases[5]; break;
   case (dt<=Q3e): pic = 21;                  ph = langMoonPhases[6]; break;
   case (dt< NMs): pic = 21.5+((dt-Q3e)/Q4p); ph = langMoonPhases[7]; break; // or Waning Crecent
   default       : pic =  0;                  ph = langMoonPhases[0];
   }
   info =
      {pic  : Math.round(pic)
      ,phase: ph
      ,age  : age
      ,ill  : ill
      };
return info;
}; // end getMoonInfo function


// ----------
// PROTOTYPES (PHP equivalents)
// ----------

// Padding: left and right .. similar to "str_pad" function in php
String.prototype.str_pad = function ( cnt, chr, typ ) {
var sPad = "";
var char = (typeof chr == 'undefined')? "0" : chr;
var type = (typeof typ == 'undefined')? "R" : typ;
var iPad = cnt - Math.floor(this).toString().length;
   for (var i=0;i<iPad;i++) sPad+=char;
   return ((type=="R")? (sPad+this) : (this+sPad));
};

// Make a string's first character uppercase ... similar to "ucfirst" function in php
String.prototype.ucfirst = function () {
   return this.substr(0,1).toUpperCase() + this.substr(1,this.length);
};

// Date formating ... similar to "date" function in php
Date.prototype.date = function ( fmt ) { // for fmt see "date" function in php eg. str = dt.date("d/m/Y H:i:s") = "28/04/2009 17:37:09"
// formats not supported: N, z, W, t, L, o, B, u, e, I, O, P, T, c, r, U
   if (typeof fmt == 'undefined')
      return (this.toLocaleString()); // ... 26 April 2009 02:12:58 PM

   day = this.getDay();      // 0-6  (0=Sunday)
   dat = this.getDate();     // 1-31
   mth = this.getMonth()+1;  // 1-12 (1=January)
   yer = this.getFullYear(); // eg. 2009
   hrs = this.getHours();    // 0-23
   min = this.getMinutes();  // 0-59
   sec = this.getSeconds();  // 0-59
   tzo = this.getTimezoneOffset()*60; // -43200 through 50400 seconds
   switch (dat%10) { // day suffix eg. 23rd
   case  1: suf = dat==11? langDaySuf[3] : langDaySuf[0];
   case  2: suf = dat==12? langDaySuf[3] : langDaySuf[1];
   case  3: suf = dat==13? langDaySuf[3] : langDaySuf[2];
   default: suf =          langDaySuf[3];
   }

// date (d, j)
   fmt = fmt.replace("d" ,dat.toString().str_pad(2)); // 01 to 31
   fmt = fmt.replace("j" ,dat); //  1 to 31
// week (w)
   fmt = fmt.replace("w" ,day); //  0 to 6
// month (m, n)
   fmt = fmt.replace("m" ,mth.toString().str_pad(2)); //  01 to 12
   fmt = fmt.replace("n" ,mth); // 1 to 12
// year (Y, y)
   fmt = fmt.replace("Y" ,yer);
   fmt = fmt.replace("y" ,yer%100);
// am/pm (A, a)
   ampm = (hrs<12)? langAM_PM[0] : langAM_PM[1];
   AMPM = (hrs<12)? langAM_PM[2] : langAM_PM[3];
   fmt = fmt.replace("a" ,ampm);
   fmt = fmt.replace("A" ,AMPM);
// hours (g, G, h, H)
   fmt = fmt.replace("g" ,hrs%12); // 1 to 12
   fmt = fmt.replace("G" ,hrs);    // 1 to 23
   fmt = fmt.replace("h" ,(hrs%12).toString().str_pad(2)); // 00 to 12
   fmt = fmt.replace("H" ,hrs.toString().str_pad(2));      // 00 to 23
// minutes (i)
   fmt = fmt.replace("i" ,min.toString().str_pad(2)); // 00 to 59
// seconds (s)
   fmt = fmt.replace("s" ,sec.toString().str_pad(2)); // 00 to 59
// timezone (Z)
   fmt = fmt.replace("Z" ,tzo); // -43200 through 50400 seconds
// other (S ,l ,D ,F, M)
   fmt = fmt.replace(/(\d+)S/g ,"$1"+suf); // eg. rd
   fmt = fmt.replace(/l(\s|,|-|\.)/ ,langDays[day]+"$1");                    // eg. Sunday
   fmt = fmt.replace(/D(\s|,|-|\.)/ ,langDays[day].substring(0,3)+"$1");     // eg. Sun
   fmt = fmt.replace(/F(\s|,|-|\.)/ ,langMonths[mth-1]+"$1");                // eg. January
   fmt = fmt.replace(/M(\s|,|-|\.)/ ,langMonths[mth-1].substring(0,3)+"$1"); // eg. Jan
   return (fmt);
};

// returns "-" if number is less than 0
Number.prototype.sign = function () {
   return (this<0)? "-" : "";
};
// return rounded integer value of a number
Number.prototype.intval = function( dp ) {
   return (Math.floor(Math.abs(this.toFixed(dp))));
};
// return fraction as a rounded integer number
Number.prototype.fraction = function( dp ) {
   frac = Math.abs(this) - Math.floor(Math.abs(this));
   return frac.toFixed(dp);
};

// Number formating ... thousands seperator and decimal point ... similar to "number_format" function in php
// Format a number with grouped thousands eg. str = num.number_format("23823.87273") = "23,823.87"
Number.prototype.number_format = function ( dp ,dpSep ,thouSep ) {
if (typeof dp == 'undefined') dp = 0;
if (typeof dpSep == 'undefined') dpSep = ".";
if (typeof thouSep == 'undefined') thouSep = ",";
var inum = this.intval(dp).toString();
var frac = this.fraction(dp).toString().substr(2);
var ret  = this.sign();
var f = (inum.length%3==0) ? 3 : inum.length%3;
   ret+= inum.substr(0, f);
   for (i=f; i<inum.length; i+=3)
      ret+= thouSep+inum.substr(i,3);
   if (dp>0) ret+=dpSep+frac;
return (ret);
};

// =============================================================================
// Get clientrawextra.txt data  (only needs to be loaded once)                 .
// -----------------------------------------------------------------------------
function ajaxLoader_clientextra(urlExtra) {
var rawextra;
if (document.getElementById)
var x = (window.ActiveXObject) ? new ActiveXObject("Microsoft.XMLHTTP") : new XMLHttpRequest(urlExtra);

if (x) { // got something back
   x.onreadystatechange = function() {
      try {
         if (x.readyState==4 && x.status==404) { // not found
            if (notify==1) alert("DASHBOARD ERROR:\nYour \""+extraUrl+"\" file could not be found.");
            notify++;
         } else
         if (x.readyState==4 && x.status==200) { // Mike Challis added fix to fix random error: NS_ERROR_NOT_AVAILABLE
            rawextra = x.responseText.split(' ');
            var wdpattern=/\d+\.\d+.*!!/; // looks for '!!nn.nn!!' version string
            if (rawextra[0]=='12345' && (wdpattern.test(x.responseText)) )
               clientrawextra = rawextra;
            else // only save if fully downloaded
               setTimeout("ajaxLoader_clientextra(extraUrl + '?' + new Date().getTime())", extraRetryInterval);
            notify=0;
         } // END if (x.readyState == 4 && x.status == 200)
      } // END try
      catch(e){}  // Mike Challis added fix to fix random error: NS_ERROR_NOT_AVAILABLE
   }; // END x.onreadystatechange = function()

   x.open("GET", urlExtra, true);
   x.send(null);
} // END if(x)
};

// ================================================================================
//  Get clientraw.txt data and format <span class="ajax" id="ajax..."></span> areas
// --------------------------------------------------------------------------------
function ajaxLoader(url) {
var rand = new Date().getTime();

if (document.getElementById) {
   var x = (window.ActiveXObject) ? new ActiveXObject("Microsoft.XMLHTTP") : new XMLHttpRequest(url);
} else
   set_ajax_obs('ajaxProgress',rand+'elem','ERROR: No elements');

if (x) { // got something back
x.onreadystatechange = function() {
try {
   set_ajax_obs('ajaxProgress',rand+'ready','-- READY --');
   if (x.readyState==4 && x.status==200) { // Mike Challis added fix to fix random error: NS_ERROR_NOT_AVAILABLE
   var clientraw = x.responseText.split(' ');
   // now make sure we got the entire clientraw.txt  -- thanks to Johnnywx
   // valid clientraw.txt has '12345' at start and '!!' at end of record
   var wdpattern=/\d+\.\d+.*!!/; // looks for '!!nn.nn!!' version string
   // If we have a valid clientraw file AND updates is < maxupdates

   if (clientraw[0] == '12345'
   &&  wdpattern.test(x.responseText)
   && (updates <= maxupdates || maxupdates > 0) ) {
   set_ajax_obs('ajaxProgress',rand+'start','-- START --');

   if (maxupdates > 0) updates++; // increment counter if needed

// -----------------------------------------------------------------------------
// Date / Time (WD)
      set_ajax_obs('ajaxProgress',rand+'date','in Dates');
      WDdt = new Date( clientraw[141], clientraw[36]-1, clientraw[35], clientraw[29], clientraw[30], clientraw[31]);

      set_ajax_obs("ajaxndate"   , WDdt.date("M j, Y")); // Apr 16, 2009
      set_ajax_obs("ajaxndate2"  , WDdt.date("d-M-Y"));  // 16-Apr-2009
      set_ajax_obs("ajaxntime"   , WDdt.date("H:i"));    // 14:37
      set_ajax_obs("ajaxntimess" , WDdt.date("H:i:s"));  // 14:37:07
      set_ajax_obs("ajaxdname"   , WDdt.date("D"));      // Mon

      // current date and time of observation in clientraw.txt
      set_ajax_obs("ajaxdatetime", WDdt.date(uom.dateFmt+' '+uom.timeFmt)); // 16/4/2009 02:37:07pm
      set_ajax_obs("ajaxdate@"   , WDdt.date(uom.dateFmt) + ' @ '); // 6/4/2009 @
      set_ajax_obs("ajaxdate"    , WDdt.date(uom.dateFmt)); // 16/4/2009
      set_ajax_obs("ajaxtime"    , WDdt.date(uom.timeFmt)); // 02:37:07pm
      set_ajax_obs("gizmodate"   , WDdt.date(uom.dateFmt)); // 16/4/2009
      set_ajax_obs("gizmotime"   , WDdt.date(uom.timeFmt)); // 02:37:07pm


// Outdoor temperature ... (°C)
//clientraw[4] = 40.7; // uncomment this for debugging
      set_ajax_obs('ajaxProgress',rand+'temp','in Temp'); // "ajaxProgress" tag is for debugging and can be deleted
      temp     = parseFloat(clientraw[ 4]).convertTemp();
      templast = parseFloat(clientraw[90]).convertTemp(); // last hours temp
      tempmax  = parseFloat(clientraw[46]).convertTemp();
      tempmin  = parseFloat(clientraw[47]).convertTemp();
      if (clientrawextra!=null)
           temp24hAgo = parseFloat(clientrawextra[21]).convertTemp();
      else temp24hAgo = temp;
      temp24hDiff = temp - temp24hAgo;

      set_ajax_obs("ajaxtemp"   , temp.toFixed(dp.Temp) + uom.Temp);
      set_ajax_obs("ajaxtempNoU", temp.toFixed(dp.Temp));
      set_ajax_obs("gizmotemp"  , temp.toFixed(dp.Temp) + uom.Temp);
      set_ajax_obs("ajaxbigtemp", temp.toFixed(0) + uom.Temp);

      temparrow = ajax_getTrendArrow( temp
                                    , templast
                                    , ''
                                    , langTempRising+uom.Temp+langTempLastHour
                                    , langTempFalling+uom.Temp+langTempLastHour
                                    , 1
                                    );
      set_ajax_obs("ajaxtemparrow" , (temp-templast).toFixed(dp.Temp), temparrow);
      set_ajax_obs("gizmotemparrow", temparrow);

      temprate = temp - templast;
      temprate = temprate.toFixed(1);
      if (temprate > 0.0) { temprate = '+' + temprate; } // add a '+' for positive rates
      set_ajax_obs("ajaxtemprate" , temprate + uom.Temp);
      set_ajax_obs("gizmotemprate", temprate + uom.Temp);

      set_ajax_obs("ajaxtempmax"   , tempmax    .toFixed(dp.Temp) + uom.Temp);
      set_ajax_obs("ajaxtempmin"   , tempmin    .toFixed(dp.Temp) + uom.Temp);

      set_ajax_obs("ajax24hDiff"   , temp24hDiff.toFixed(dp.Temp) + uom.Temp);
      diffarrow = ajax_getTrendArrow( temp
                                    , temp24hAgo
                                    , ''
                                    , langTempRising+uom.Temp+langTempYesterday
                                    , langTempFalling+uom.Temp+langTempYesterday
                                    , 1
                                    );
      set_ajax_obs("ajax24hDiffarrow", (temp-temp24hDiff).toFixed(dp.Temp), diffarrow);


// Thermometer ...
      set_ajax_obs('ajaxProgress',rand+'term','in Thermometer');
      thermometerText = langThermoCurrently + temp.toFixed(dp.Temp) + uom.Temp
                  + ", " + langThermoMax + tempmax.toFixed(dp.Temp) + uom.Temp
                  + ", " + langThermoMin + tempmin.toFixed(dp.Temp) + uom.Temp;

      param = '?uom=' + useUOM
            + '&t='   + temp.toFixed(dp.Temp)
            + '&iW='  + thermometerImg.width
            + '&iH='  + thermometerImg.height;
      set_ajax_obs("ajaxthermometer", param
         , '<img src="' + thermometerImg.src + param
         + '" alt="'    + thermometerText
         + '" title="'  + thermometerText
         + '" width="'  + thermometerImg.width
         + '" height="' + thermometerImg.height
         + '" hspace="' + thermometerImg.hspace
         + '" vspace="' + thermometerImg.vspace
         + '" border="' + thermometerImg.border
         + '" align="'  + thermometerImg.align
         + '" style="'  + thermometerImg.style
         + '" />');


// Dewpoint ... (°C)
//clientraw[72] = -2.4
      set_ajax_obs('ajaxProgress',rand+'dewp','in Dewpoint');
      dew    = parseFloat(clientraw[ 72]).convertTemp();
      dewmin = parseFloat(clientraw[139]).convertTemp();
      dewmax = parseFloat(clientraw[138]).convertTemp();

      set_ajax_obs("ajaxdew"   , dew   .toFixed(dp.Temp) + uom.Temp);
      set_ajax_obs("gizmodew"  , dew   .toFixed(dp.Temp) + uom.Temp);
      set_ajax_obs("ajaxdewmin", dewmin.toFixed(dp.Temp) + uom.Temp);
      set_ajax_obs("ajaxdewmax", dewmax.toFixed(dp.Temp) + uom.Temp);


// WetBulb ... (°C)
      set_ajax_obs('ajaxProgress',rand+'wetb','in Wetbulb');
      wetbulb = parseFloat(clientraw[159]).convertTemp();
      set_ajax_obs("ajaxwetbulb",wetbulb.toFixed(dp.Temp) + uom.Temp);

// Humidex ... (°C)
      humidex    = parseFloat(clientraw[45]).convertTemp();
      humidexmin = parseFloat(clientraw[76]).convertTemp();
      humidexmax = parseFloat(clientraw[75]).convertTemp();

      set_ajax_obs("ajaxhumidex"   , humidex   .toFixed(dp.Temp) + uom.Temp);
      set_ajax_obs("ajaxhumidexmin", humidexmin.toFixed(dp.Temp) + uom.Temp);
      set_ajax_obs("ajaxhumidexmax", humidexmax.toFixed(dp.Temp) + uom.Temp);


// Heat Index ... (°C)
      heatidx    = parseFloat(clientraw[112]).convertTemp();
      heatidxmin = parseFloat(clientraw[111]).convertTemp();
      heatidxmax = parseFloat(clientraw[110]).convertTemp();

      set_ajax_obs("ajaxheatidx"   , heatidx   .toFixed(dp.Temp) + uom.Temp);
      set_ajax_obs("ajaxheatidxmin", heatidxmin.toFixed(dp.Temp) + uom.Temp);
      set_ajax_obs("ajaxheatidxmax", heatidxmax.toFixed(dp.Temp) + uom.Temp);


// WindChill ... (°C)
      windchill    = parseFloat(clientraw[44]).convertTemp();
      windchillmin = parseFloat(clientraw[78]).convertTemp();
      windchillmax = parseFloat(clientraw[77]).convertTemp();

      set_ajax_obs("ajaxwindchill"   , windchill   .toFixed(dp.Temp) + uom.Temp);
      set_ajax_obs("ajaxwindchillmin", windchillmin.toFixed(dp.Temp) + uom.Temp);
      set_ajax_obs("ajaxwindchillmax", windchillmax.toFixed(dp.Temp) + uom.Temp);


// FeelsLike ... (°C)
      set_ajax_obs('ajaxProgress',rand+'feel','in Feelslike');
      temp = clientraw[4]; // note.. temp in C
      switch (true) {
      case (temp<=16.0): feelslike = clientraw[44]; break; // use WindChill
      case (temp>=27.0): feelslike = clientraw[45]; break; // use Humidex
      default          : feelslike = temp;                 // use temperature
      }
      feelslike  = Math.round(parseFloat(feelslike).convertTemp());
      set_ajax_obs("ajaxfeelslike" , feelslike + uom.Temp);

      // mike challis added heatColorWord feature
      heatColorWord = ajax_getHeatColorWord(clientraw[4],clientraw[44],clientraw[45]);
      set_ajax_obs("ajaxheatcolorword", heatColorWord);

      temp = parseFloat(clientraw[ 4]).convertTemp();
      tempColorBg = ajax_getHeatColorTemp(clientraw[4],clientraw[44],clientraw[45], temp);
      set_ajax_obs("ajaxtempcolor", temp.toFixed(dp.Temp), tempColorBg);


// Apparent temperature ... (°C)
      apparenttemp    = parseFloat(clientraw[130]).convertTemp();
      apparenttempmin = parseFloat(clientraw[136]).convertTemp();
      apparenttempmax = parseFloat(clientraw[137]).convertTemp();

      set_ajax_obs("ajaxapparenttemp"   , apparenttemp   .toFixed(dp.Temp) + uom.Temp);
      set_ajax_obs("ajaxapparenttempmin", apparenttempmin.toFixed(dp.Temp) + uom.Temp);
      set_ajax_obs("ajaxapparenttempmax", apparenttempmax.toFixed(dp.Temp) + uom.Temp);


// Humidity ... %
//clientraw[5] = 100;
      set_ajax_obs('ajaxProgress',rand+'humi','in Humidity');
      humidity = clientraw[5];
      set_ajax_obs("ajaxhumidity" , humidity);
      set_ajax_obs("gizmohumidity", humidity);
      // sorry.. no min/max data for humidity available in clientraw.txt


// Pressure ... (hPa)
      set_ajax_obs('ajaxProgress',rand+'baro','in Baro');
      pressure      = parseFloat(clientraw[  6]).convertBaro();
      pressuremin   = parseFloat(clientraw[132]).convertBaro();;
      pressuremax   = parseFloat(clientraw[131]).convertBaro();;
      pressuretrend = parseFloat(clientraw[ 50]).convertBaro();
      barotrendtext = ajax_getBaroTrend(clientraw[50]);

      set_ajax_obs("ajaxbaro"      , pressure.toFixed(dp.Baro) +' '+ uom.Baro);
      set_ajax_obs("ajaxbaroNoU"   , pressure.toFixed(dp.Baro));
      set_ajax_obs("gizmobaro"     , pressure.toFixed(dp.Baro) +' '+ uom.Baro);

      pressuretrend = pressuretrend.toFixed(dp.Baro+1);
      if (pressuretrend > 0.0) {pressuretrend = '+' + pressuretrend; } // add '+' to rate
      set_ajax_obs("ajaxbarotrend" , pressuretrend + uom.Baro);
      set_ajax_obs("gizmobarotrend", pressuretrend + uom.Baro);
      baroarrow = ajax_getTrendArrow( pressure
                                    , pressure-pressuretrend
                                    , ''
                                    , langBaroRising +uom.Baro+langBaroPerHour
                                    , langBaroFalling+uom.Baro+langBaroPerHour
                                    , 2
                                    );
      set_ajax_obs("ajaxbaroarrow"     , pressuretrend, baroarrow);
      set_ajax_obs("ajaxbarotrendtext" , barotrendtext);
      set_ajax_obs("gizmobarotrendtext", barotrendtext);
      set_ajax_obs("ajaxbaromin"       , pressuremin.toFixed(dp.Baro) +' '+ uom.Baro);
      set_ajax_obs("ajaxbaromax"       , pressuremax.toFixed(dp.Baro) +' '+ uom.Baro);


// Wind ... (kts)
//clientraw[  2] = 10.2;
//clientraw[140] = 20.2;
      set_ajax_obs('ajaxProgress',rand+'wspd','in WindSpeed');
      wind        = parseFloat(clientraw[  2]).convertWind(); // Wind gust
      gust        = parseFloat(clientraw[140]).convertWind(); // Max wind gust in last minute
      windmaxavg  = parseFloat(clientraw[113]).convertWind(); // Max avg speed
      maxgust     = parseFloat(clientraw[ 71]).convertWind(); // Max wind gust
      maxgusttime = clientraw[135];                           // Max wind gust time
      beaufortnum = ajax_getBeaufortNumber(clientraw[2]);

   // Wind gust
      if (maxgust > 0.0 )
           set_ajax_obs("ajaxmaxgust"   , maxgust.toFixed(dp.Wind) +' '+ uom.langWind);
      else set_ajax_obs("ajaxmaxgust"   , 'None');

   // Max wind gust
      set_ajax_obs("ajaxwindmaxgust"    , maxgust.toFixed(dp.Wind) +' '+ uom.langWind);
      set_ajax_obs("ajaxwindmaxgusttime", maxgusttime);

   // Windspeed ... beaufort
      set_ajax_obs("ajaxbeaufortnum"    , beaufortnum);
      set_ajax_obs("ajaxbeaufort"       , langBeaufort[beaufortnum]);

   // Max avg speed
      set_ajax_obs("ajaxwindmaxavg"     , windmaxavg.toFixed(dp.Wind) +' '+ uom.langWind);

   // Current wind speed
      if (wind > 0.0) {
      set_ajax_obs("ajaxwind"      , wind.toFixed(dp.Wind) +' '+ uom.langWind);
      set_ajax_obs("ajaxwindNoU"   , wind.toFixed(dp.Wind));
      set_ajax_obs("gizmowind"     , wind.toFixed(dp.Wind) +' '+ uom.langWind);
      set_ajax_uom("ajaxwinduom"   , true);
      } else {
      set_ajax_obs("ajaxwind"      , langWindCalm);
      set_ajax_obs("ajaxwindNoU"   , langWindCalm);
      set_ajax_obs("gizmowind"     , langWindCalm);
      set_ajax_uom("ajaxwinduom"   , false);
      }

   // Current gust speed
      if (gust > 0.0) {
      set_ajax_obs("ajaxgust"      , gust.toFixed(dp.Wind) +' '+ uom.langWind);
      set_ajax_obs("ajaxgustNoU"   , gust.toFixed(dp.Wind));
      set_ajax_obs("gizmogust"     , gust.toFixed(dp.Wind) +' '+ uom.langWind);
      set_ajax_uom("ajaxgustuom"   , true);
      } else {
      set_ajax_obs("ajaxgust"      , langGustNone);
      set_ajax_obs("ajaxgustNoU"   , langGustNone);
      set_ajax_obs("gizmogust"     , langGustNone);
      set_ajax_uom("ajaxgustuom"   , false);
      }


// Wind direction & wind rose grapic ...
      set_ajax_obs('ajaxProgress',rand+'wdir','in WindDir');
      windDeg = parseFloat(clientraw[3]);
      windDir = ajax_getWindDir(clientraw[3]);
      valLang = ajax_getWindDirLang(clientraw[3]); /* to enable translations */

      set_ajax_obs('ajaxProgress',rand+'rose','in WindRose');
      if (gust > 0.0 || wind > 0.0 || wrImg.calm=="") {
         windicon = '<img src="' + imgDir + windDir + '.gif'
            + '" alt="'   + langWindFrom + valLang
            + '" title="' + langWindFrom + valLang
            + '" width="14" height="14" />';
         set_ajax_obs("ajaxwindicon"  , valLang, windicon);
         set_ajax_obs("gizmowindicon" , valLang, windicon);
         set_ajax_obs("ajaxwinddir"   , valLang);
         set_ajax_obs("gizmowinddir"  , valLang);
         set_ajax_obs("ajaxwinddeg"   , windDeg + uom.Deg);
         set_ajax_obs("gizmowinddeg"  , windDeg + uom.Deg);

         src = wrImg.src.replace("#LANG#" , wrImg.lang);
         src = src.replace      ("#DIR#"  , valLang);
         set_ajax_obs("ajaxwindiconwr", src
            , '<img src="' + src
            + '" alt="'    + langWindFrom + valLang
            + '" title="'  + langWindFrom + valLang
            + '" width="'  + wrImg.width
            + '" height="' + wrImg.height
            + '" hspace="' + wrImg.hspace
            + '" vspace="' + wrImg.vspace
            + '" border="' + wrImg.border
            + '" align="'  + wrImg.align
            + '" style="'  + wrImg.style
            + '" />');
      } else { // Wind calm
         set_ajax_obs("ajaxwindicon"  , "");
         set_ajax_obs("gizmowindicon" , "");
         set_ajax_obs("ajaxwinddir"   , "");
         set_ajax_obs("gizmowinddir"  , "");
         set_ajax_obs("ajaxwinddeg"   , "");
         set_ajax_obs("gizmowinddeg"  , "");

         src = wrImg.src.replace("#LANG#", wrImg.lang);
         src = src.replace      ("#DIR#" , wrImg.calm);
         set_ajax_obs("ajaxwindiconwr" , src
            , '<img src="' + src
            + '" alt="'    + langBeaufort[0]
            + '" title="'  + langBeaufort[0]
            + '" width="'  + wrImg.width
            + '" height="' + wrImg.height
            + '" hspace="' + wrImg.hspace
            + '" vspace="' + wrImg.vspace
            + '" border="' + wrImg.border
            + '" align="'  + wrImg.align
            + '" style="'  + wrImg.style
            + '" />');
      }


// Solar Radiation
      set_ajax_obs('ajaxProgress',rand+'sol','in Solar');
      solar    = clientraw[127] * 1.0;
      solarpct = clientraw[34];
      set_ajax_obs("ajaxsolar"   ,solar.toFixed(0));
      set_ajax_obs("ajaxsolarpct",solarpct);


// UV Index
      set_ajax_obs('ajaxProgress',rand+'uv','in UV');
      uv = parseInt(clientraw[79]);
      set_ajax_obs("ajaxuv"   ,uv.toFixed(dp.UV));
      set_ajax_obs("ajaxuvNoD",uv.toFixed(0));
      set_ajax_obs("gizmouv"  ,uv.toFixed(dp.UV)) ;

      uvword = ajax_getUVrange(uv);
      set_ajax_obs("ajaxuvword" ,uv, uvword);
      set_ajax_obs("gizmouvword",uv, uvword);

      uvburnrate = ajax_getUVburnRate(uv);
      set_ajax_obs("ajaxuvburnrate",uvburnrate);

      UVI = Math.min(11,Math.round(uv));
      src = uvImg.src.replace("#INDEX#" ,UVI);
      set_ajax_obs("ajaxuvimg", UVI
         ,'<img src="'  + src
         + '" alt="'    + UVI
         + '" title="'  + UVI
         + '" width="'  + uvImg.width
         + '" height="' + uvImg.height
         + '" hspace="' + uvImg.hspace
         + '" vspace="' + uvImg.vspace
         + '" border="' + uvImg.border
         + '" align="'  + uvImg.align
         + '" style="'  + uvImg.style
         + '" />');

// Rain ... (mm)
      set_ajax_obs('ajaxProgress',rand+'rain','in Rain');
      rain        = parseFloat( clientraw[ 7]).convertRain();
      rainYes     = parseFloat( clientraw[19]).convertRain();
      rainMonth   = parseFloat( clientraw[ 8]).convertRain();
      rainYear    = parseFloat( clientraw[ 9]).convertRain();
      rainratehr  = parseFloat((clientraw[10])*60).convertRain(); // make per hour rate.
      rainratemax = parseFloat((clientraw[11])*60).convertRain(); // make per hour rate

      set_ajax_obs("ajaxrainratehr" ,rainratehr .toFixed(dp.Rain+1) +' '+ uom.Rain);
      set_ajax_obs("ajaxrainratemax",rainratemax.toFixed(dp.Rain+1) +' '+ uom.Rain);

      set_ajax_obs("ajaxrain"       ,rain   .toFixed(dp.Rain)   +' '+ uom.Rain);
      set_ajax_obs("ajaxrainYes"    ,rainYes.toFixed(dp.Rain)   +' '+ uom.Rain);
      set_ajax_obs("ajaxrainydy"    ,rainYes.toFixed(dp.Rain)   +' '+ uom.Rain); // old yesterdays rain tag for compatibility

      set_ajax_obs("ajaxrainmo"     ,rainMonth.toFixed(dp.Rain) +' '+ uom.Rain);
      set_ajax_obs("ajaxrainyr"     ,rainYear .toFixed(dp.Rain) +' '+ uom.Rain);

      set_ajax_obs("ajaxrainNoU"    ,rain     .toFixed(dp.Rain));
      set_ajax_obs("gizmorain"      ,rain     .toFixed(dp.Rain) +' '+ uom.Rain);

      if (clientrawextra!=null) {
         set_ajax_obs('ajaxProgress',rand+'rainex','in Rain Extra');
         // Rain in last week
         rainMon = parseFloat((clientrawextra[484])/10).convertRain();
         rainTue = parseFloat((clientrawextra[485])/10).convertRain();
         rainWed = parseFloat((clientrawextra[486])/10).convertRain();
         rainThu = parseFloat((clientrawextra[487])/10).convertRain();
         rainFri = parseFloat((clientrawextra[488])/10).convertRain();
         rainSat = parseFloat((clientrawextra[489])/10).convertRain();
         rainSun = parseFloat((clientrawextra[490])/10).convertRain();
         set_ajax_obs("ajaxrainSun" ,rainSun.toFixed(dp.Rain) +' '+ uom.Rain);
         set_ajax_obs("ajaxrainMon" ,rainMon.toFixed(dp.Rain) +' '+ uom.Rain);
         set_ajax_obs("ajaxrainTue" ,rainTue.toFixed(dp.Rain) +' '+ uom.Rain);
         set_ajax_obs("ajaxrainWed" ,rainWed.toFixed(dp.Rain) +' '+ uom.Rain);
         set_ajax_obs("ajaxrainThu" ,rainThu.toFixed(dp.Rain) +' '+ uom.Rain);
         set_ajax_obs("ajaxrainFri" ,rainFri.toFixed(dp.Rain) +' '+ uom.Rain);
         set_ajax_obs("ajaxrainSat" ,rainSat.toFixed(dp.Rain) +' '+ uom.Rain);

         // Record alltime daily rain
         rcdRain   = parseFloat(clientrawextra[349]).convertRain();
         rcdRainDt = new Date ( clientrawextra[354], clientrawextra[353]-1, clientrawextra[352] // YMD
                              , clientrawextra[350], clientrawextra[351]  , 0); //HMS
         set_ajax_obs("ajaxRcdRain"    , rcdRain.toFixed(dp.Rain) +' '+ uom.Rain);
         set_ajax_obs("ajaxRcdRainTime", rcdRainDt.date(uom.timeHM));
         set_ajax_obs("ajaxRcdRainDate", rcdRainDt.date(uom.dateFmt));

         // Record alltime daily rain in 1 hour
         rcdRainHr   = parseFloat(clientrawextra[355]).convertRain();
         rcdRainHrDt = new Date ( clientrawextra[360], clientrawextra[359]-1, clientrawextra[358] // YMD
                                , clientrawextra[356], clientrawextra[357]  , 0); //HMS
         set_ajax_obs("ajaxRcdRainHr"    , rcdRainHr.toFixed(dp.Rain) +' '+ uom.Rain);
         set_ajax_obs("ajaxRcdRainHrTime", rcdRainHrDt.date(uom.timeHM));
         set_ajax_obs("ajaxRcdRainHrDate", rcdRainHrDt.date(uom.dateFmt));

         // Days with/without rain
         daysRain   = parseInt( clientrawextra[483]); // nr of days with rain (MTD)
         daysNoRain = parseInt( clientrawextra[482]); // nr of days since last rain
         set_ajax_obs("ajaxDaysRain"  , daysRain   );
         set_ajax_obs("ajaxDaysNoRain", daysNoRain );
      }


// Snow ... (cm)
      set_ajax_obs('ajaxProgress',rand+'snow','in Snow');
      if (clientrawextra!=null) {
         snowToday  = parseFloat(clientrawextra[479]).convertSnow();
         snowMonth  = parseFloat(clientrawextra[480]).convertSnow();
         snowSeason = parseFloat(clientrawextra[481]).convertSnow();
         snowDepth  = parseFloat(clientrawextra[697]).convertSnow();
         set_ajax_obs("ajaxsnowToday" ,snowToday .toFixed(dp.Snow) +' '+ uom.Snow);
         set_ajax_obs("ajaxsnowMonth" ,snowMonth .toFixed(dp.Snow) +' '+ uom.Snow);
         set_ajax_obs("ajaxsnowSeason",snowSeason.toFixed(dp.Snow) +' '+ uom.Snow);
         set_ajax_obs("ajaxsnowDepth" ,snowDepth .toFixed(dp.Snow) +' '+ uom.Snow);
      }


// Lightning ...
      set_ajax_obs('ajaxProgress',rand+'ligh','in Lightning');

      lighteningcountlastminute = clientraw[114];
      set_ajax_obs("ajaxlightning",lighteningcountlastminute);

      lighteningcountlasttime = clientraw[115] + " " + clientraw[116];
      set_ajax_obs("ajaxlightningtime",lighteningcountlasttime);

      lighteningdistance = parseFloat(clientraw[118]).convertDist();
      set_ajax_obs("ajaxlightningdist",lighteningdistance +' '+ uom.Dist);

      lighteningbearing = clientraw[119];
      set_ajax_obs("ajaxlightningbearing",lighteningbearing + uom.Deg);


// Cloud Height ... (meters)
      set_ajax_obs('ajaxProgress',rand+'cloud','in Clouds');
      temp = clientraw[ 4];
      dewp = clientraw[72];
      pres = parseFloat(clientraw[6]).convertBaro();
      rain = parseFloat(clientraw[7]).convertRain();
      wind = parseFloat(clientraw[1]).convertWind(); // gust = clientraw[2]
      wdir = ajax_getWindDirLang(clientraw[3]);
      cloudheight = Math.max(0,(temp-dewp)/0.00802)*1.0 + stationAlt; // in meters
      altitude = Math.round(cloudheight.convertAlti());
      above = (stationAlt>0)? ' ASL' : ' AGL';
      cloudText = altitude.toString() + uom.Alti + above;
//    param = '?uom=' + useUOM  + '&alti=' + uom.Alti + '&wind=' + uom.Wind + '&buster=' + altitude + pres + wind + wdir + rain;
      param = '?uom=' + useUOM + '&buster=' + altitude;
      set_ajax_obs("ajaxcloudheightimg", param
         ,'<img src="'  + cloudImg.src + param
         + '" alt="'    + cloudText
         + '" title="'  + cloudText
         + '" width="'  + cloudImg.width
         + '" height="' + cloudImg.height
         + '" hspace="' + cloudImg.hspace
         + '" vspace="' + cloudImg.vspace
         + '" align="'  + cloudImg.align
         + '" border="' + cloudImg.border
         + '" style="'  + cloudImg.style
         + '" />');
      set_ajax_obs("ajaxcloudheight",cloudText);


// Fire Risk ... (FWI)
      set_ajax_obs('ajaxProgress',rand+'fire','in Fire Risk');
      if (clientrawextra!=null) {
         FWI = parseFloat(clientrawextra[635]);
         set_ajax_obs("ajaxfireindex",FWI);
         idx = ajax_getFireIndex(FWI);
         src = fireImg.src.replace("#INDEX#" ,idx);
         set_ajax_obs("ajaxfireimg", idx
            ,'<img src="'  + src
            + '" alt="'    + FWI
            + '" title="'  + FWI
            + '" width="'  + fireImg.width
            + '" height="' + fireImg.height
            + '" hspace="' + fireImg.hspace
            + '" vspace="' + fireImg.vspace
            + '" border="' + fireImg.border
            + '" align="'  + fireImg.align
            + '" style="'  + fireImg.style
            + '" />');
      }


// Sun/Moon rise/set (needed by functions below) ...
      if (clientrawextra!=null) {
         // Sun rise/set
         sunriseWD  = clientrawextra[556].split(":");
         sunsetWD   = clientrawextra[557].split(":");
         sunrise    = new Date( clientraw[141], clientraw[36]-1, clientraw[35], sunriseWD[0], sunriseWD[1], 0);
         sunset     = new Date( clientraw[141], clientraw[36]-1, clientraw[35], sunsetWD[0] , sunsetWD[1] , 0);
         sunriseT   = sunrise.getTime() - (delayDayNight*60*1000);
         sunsetT    = sunset.getTime()  + (delayDayNight*60*1000);
         // Moon rise/set
         moonriseWD = clientrawextra[558].split(":");
         moonsetWD  = clientrawextra[559].split(":");
         moonrise   = new Date( clientraw[141], clientraw[36]-1, clientraw[35], moonriseWD[0], moonriseWD[1], 0);
         moonset    = new Date( clientraw[141], clientraw[36]-1, clientraw[35], moonsetWD[0] , moonsetWD[1] , 0);
         // Time now
      }
      WDnow = WDdt.getTime();

// Moon / Sun ... rise & set, pic, phase, illumination
      set_ajax_obs('ajaxProgress',rand+'moon','in Moon');
      mooninfo = getMoonInfo();
      moonNS   = parseFloat(clientraw[160])>0 ? "NH" : "SH"; // latitude
      set_ajax_obs("ajaxmoonphase",mooninfo.phase);
      set_ajax_obs("ajaxmoonpct"  ,mooninfo.ill+'%');
      moonText = mooninfo.phase + ', Moon at ' + mooninfo.age + ' in cycle (' + mooninfo.ill + '%)';
      src = moonImg.src.replace("#BG#" , moonImg.bg);
      src = src.replace        ("#NS#" , moonNS);
      src = src.replace        ("#AGE#", mooninfo.pic.toString().str_pad(2));
      set_ajax_obs("ajaxmoonimg", mooninfo.age+mooninfo.ill+mooninfo.pic
         ,'<img src="'  + src
         + '" alt="'    + moonText
         + '" title="'  + moonText
         + '" width="'  + moonImg.width
         + '" height="' + moonImg.height
         + '" hspace="' + moonImg.hspace
         + '" vspace="' + moonImg.vspace
         + '" border="' + moonImg.border
         + '" align="'  + moonImg.align
         + '" style="'  + moonImg.style
         + '" />');

      src = moonImg.src.replace("#BG#" , 'b');
      src = src.replace        ("#NS#" , moonNS);
      src = src.replace        ("#AGE#", mooninfo.pic.toString().str_pad(2));
      set_ajax_obs("ajaxmoonimg100", mooninfo.age+mooninfo.ill+mooninfo.pic
         ,'<img src="'  + src
         + '" alt="'    + moonText
         + '" title="'  + moonText
         + '" width="100" height="100" />');

      if (clientrawextra!=null) {
         set_ajax_obs("ajaxsunrise" ,sunrise.date(uom.timeHM));
         set_ajax_obs("ajaxsunset"  ,sunset.date(uom.timeHM));
         set_ajax_obs("ajaxmoonrise",moonrise.date(uom.timeHM));
         set_ajax_obs("ajaxmoonset" ,moonset.date(uom.timeHM));
      }


// Current condition icon and description ...
      set_ajax_obs('ajaxProgress',rand+'cond','in Conditions');
      // check if we need the icon instead of the webcam image at night
      if (!useCamAtNight && clientrawextra!=null) {
         if (WDnow < sunriseT || WDnow > sunsetT)
            swapIconWithWebcam = false;
      }
      currentcond = clientraw[49];
      // currentcond = currentcond.replace(/_/g,' ');
      // currentcond = currentcond.replace(/^\/Dry\//g,'');
      currentcond = currentcond.replace(/\\/g,', ');
      // currentcond = currentcond.replace(/\//g,', ');
      currentcond = ajax_fixupCondition(currentcond);
      currIconNr  = parseInt(clientraw[48]);
      set_ajax_obs("ajaxcurrentcond" ,currentcond);
      set_ajax_obs("gizmocurrentcond",currentcond);

      set_ajax_obs("ajaxconditionicon",clientraw[48],ajax_getIconName0(currIconNr,wxIconSet0)); // sticker icon

      if (!swapIconWithWebcam) {
         switch (wxIconSet.useName) { // dashboard icon
          case 1: set_ajax_obs("ajaxconditionicon2",clientraw[48],ajax_getIconName1(currIconNr,wxIconSet)); break;
          case 2: set_ajax_obs("ajaxconditionicon2",clientraw[48],ajax_getIconName2(currIconNr,wxIconSet)); break;
          case 9: //Dynamic icon creation similar to cloud height (not yet implemented)
                  param = '?uom=' + useUOM
                        + '&con=' + currentcond
                        + '&iW='  + wxIconSet.width
                        + '&iH='  + wxIconSet.height;
                  set_ajax_obs("ajaxconditionicon2", param
                     ,'<img src="'  + wxIconSet.src + param
                     + '" alt="'    + currentcond
                     + '" title="'  + currentcond
                     + '" width="'  + wxIconSet.width
                     + '" height="' + wxIconSet.height
                     + '" hspace="' + wxIconSet.hspace
                     + '" vspace="' + wxIconSet.vspace
                     + '" border="' + wxIconSet.border
                     + '" align="'  + wxIconSet.align
                     + '" style="'  + wxIconSet.style
                     + '" />');
                  break;
         default: set_ajax_obs("ajaxconditionicon2",'<div style="border: 2px solid red">INVALID ICON NAME #'+wxIconSet.useName+'"</div>'); break;
         }
      }


// Current webcam snap ...
      set_ajax_obs('ajaxProgress',rand+'webcam','in Webcam');
      if (swapIconWithWebcam)
           ajaxTag = "ajaxconditionicon2";
      else ajaxTag = "ajaxwebcamimg";

      if (webcamUpdate!=0) { // if 0 then no ajax updates requested
         now = new Date();
         minutes  = (now.getHours()*60) + now.getMinutes();
         interval = Math.floor(minutes / webcamUpdate);
         param = '?buster=' + interval;
         if (clientrawextra!=null && (WDnow<sunriseT || WDnow>sunsetT))
              src = webcamImg.srcNgt;
         else src = webcamImg.src;
         set_ajax_obs(ajaxTag, interval
            ,'<img src="'  + src + param
            + '" alt="'    + currentcond
            + '" title="'  + currentcond
            + '" width="'  + webcamImg.width
            + '" height="' + webcamImg.height
            + '" hspace="' + webcamImg.hspace
            + '" vspace="' + webcamImg.vspace
            + '" border="' + webcamImg.border
            + '" align="'  + webcamImg.align
            + '" style="'  + webcamImg.style
            + '" />');
      }
// ----------------------------------------------------------------- end of tags

      if (lastajaxtimeformat != WDdt.date("d-m-Y H:i:s")) {
         counterSecs = 0; // reset timer
         lastajaxtimeformat = WDdt.date("d-m-Y H:i:s"); // remember this time
      }

     } // END if(clientraw[0] = '12345' and '!!' at end)
     notify=0;
    } // END if (x.readyState == 4 && x.status == 200)

    set_ajax_obs('ajaxupdatecount'   ,updates   ); /* for test pages */
    set_ajax_obs('ajaxmaxupdatecount',maxupdates); /* for test pages */
    set_ajax_obs('ajaxState' , x.readyState);      /* for test pages */
    set_ajax_obs('ajaxStatus', x.statusText);      /* for test pages */
    if (x.readyState==4 && x.status==404) { // not found
       if (notify==1) alert("DASHBOARD ERROR:\nYour \""+clientrawFile+"\" file could not be found.");
       notify++;
    }
    set_ajax_obs('ajaxProgress',rand+'done','-- DONE --');
    } // END try

    catch(e){}  // Mike Challis added fix to fix random error: NS_ERROR_NOT_AVAILABLE

    }; // END x.onreadystatechange = function()

    x.open("GET", url, true);
    x.send(null);

    // now ensure that the indicator flashes on every AJAX fetch
    ajax_flash_green("ajaxindicator");
    ajax_flash_green("gizmoindicator");

    //  reset the flash colors, and restart the update unless maxupdate limit is reached
    setTimeout("ajax_flash_reset('')",flashtime); // change text back to default color

    if (maxupdates == 0 || updates < maxupdates-1) {
       timerAjaxLoader = setTimeout("ajaxLoader(clientrawFile + '?' + new Date().getTime())", reloadTime); // get new data
    } else {
       counterSecs = 0; // reset timer
       stopTime = new Date().getTime();
       PauseMsg = '';
       if (allowRefresh)
          PauseMsg = '<span onclick="javascript:ajaxLoader_restart();" style="color:blue; cursor:pointer;" title="'+langRestart+'"><b>'+langRefresh+'</b></span>&nbsp;&nbsp;&nbsp;';
       PauseMsg+= '<b style="color:red">'+langPauseMsg+'</b>';
       set_ajax_obs("ajaxindicator",stopTime,PauseMsg);
    }
  } // if (x)
  else set_ajax_obs('ajaxProgress',rand+'http','ERROR: No HTTP Request');
}; // end ajaxLoader function


window.setInterval("ajax_countup()", 1000); // run the counter for seconds since update

// invoke when first loaded on page
window.onload=function() {
   if (gotSettings) { // seperate settings file
      if (SettingsVersion!=9.00)
         alert("DASHBOARD ERROR:\nYour \"ajaxWDwx-settings.js\" version "+SettingsVersion.number_format(2)
              +" is not\ncompatible with this version of \"ajaxWDwx.js\""
              +"\n\nPlease upgrade to the new version.");
      else loadSettings();
   }
   initialize();
   ajaxLoader_clientextra(extraUrl + '?' + new Date().getTime());
   ajax_page_saveTags();
   ajaxLoader(clientrawFile + '?' + new Date().getTime());
};
/*
================================================================================
SUMMARY OF AJAX ID TAGS: <span class="ajax" id="ajax..."> ... </span>
================================================================================
Example: <span class="ajax" id="ajaxtemp">77°F</span>

TEMPEREATURE (outdoor):
   "ajaxtemp" ................ current temperature
   "ajaxtempNoU" ............. current temperature (no units)
   "ajaxtemparrow" ........... rising/falling image
   "ajaxtemprate" ............ temperature rate
   "ajaxtempmin" ............. min temperature today
   "ajaxtempmax" ............. max temperature today
   "ajax24hDiff" ............. 24h temperature difference
   "ajaxthermometer" ......... thermometer image
   "ajaxtempcolor" ........... current temperature in a colored box

HUMIDITY:
   "ajaxhumidity" ............ current humidity (%)

DEWPOINT:
   "ajaxdew" ................. current dew-point
   "ajaxdewmin" .............. min dew-point today
   "ajaxdewmax" .............. max dew-point today

HUMIDEX:
   "ajaxhumidex" ............. current humidex
   "ajaxhumidexmin" .......... min humidex today
   "ajaxhumidexmax" .......... max humidex today

HEAT INDEX:
   "ajaxheatidx" ............. current heat index
   "ajaxheatidxmin" .......... min heat index today
   "ajaxheatidxmax" .......... max heat index today

WINDCHILL:
   "ajaxwindchill" ........... current windchill
   "ajaxwindchillmin" ........ min windchill today
   "ajaxwindchillmax" ........ max windchill today

FEELS LIKE:
   "ajaxfeelslike" ........... current feels like (temperature)
   "ajaxheatcolorword" ....... current colored heat/chill word

APPARENT TEMPERATURE:
   "ajaxapparenttemp" ........ current apparent temperature
   "ajaxapparenttempmin" ..... min apparent temperature today
   "ajaxapparenttempmax" ..... max apparent temperature today

PRESSURE / BARO:
   "ajaxbaro" ................ current baro pressure
   "ajaxbaroNoU" ............. current baro pressure (no units)
   "ajaxbarotrend" ........... current baro trend (units)
   "gizmobarotrend" .......... current baro trend (units)
   "ajaxbaroarrow" ........... rising/falling image (up/down)
   "ajaxbarotrendtext" ....... baro trend text (rising/steady/falling)
   "ajaxbaromin" ............. min baro pressure today
   "ajaxbaromax" ............. max baro pressure today

WIND SPEEDS:
   "ajaxmaxgust" ............. max gust
   "ajaxwindmaxgust" ......... max gust
   "ajaxwindmaxgusttime" ..... max gust time (hh:mm)
   "ajaxwindmaxavg" .......... current max average speed
   "ajaxwind" ................ current wind speed
   "ajaxwindNoU" ............. current wind speed (no units)
   "ajaxwinduom" ............. hides wind units of measure when calm
   "ajaxgust" ................ current gust speed
   "ajaxgustNoU" ............. current gust speed (no units)
   "ajaxgustuom" ............. hides gust units of measure when calm
   "ajaxbeaufortnum" ......... wind beaufort number
   "ajaxbeaufort" ............ wind beaufort name

WIND direction:
   "ajaxwinddir" ............. wind direction (name e.g. NNW)
   "ajaxwinddeg" ............. wind direction in degrees (e.g. 338°)

WIND ICONS:
   "ajaxwindicon" ............ wind icon arrow direction image (14x14)
   "ajaxwindiconwr" .......... wind rose image

SOLAR RADIATION / UV INDEX
   "ajaxsolar" ............... current solar radiation
   "ajaxsolarpct" ............ percent solar radiation
   "ajaxuv" .................. current UV level
   "ajaxuvNoD" ............... current UV level (no decimal)
   "ajaxuvburnrate" .......... skin burn rate in minutes at current UV level
   "ajaxuvword" .............. None, Low, Medium, High, Very High, Extreme.
   "ajaxuvimg" ............... UV picture

RAIN:
   "ajaxrainratehr" .......... current rain rate per hour
   "ajaxrainratemax" ......... max rain rate

   "ajaxrain" ...............  rain total Today
   "ajaxrainNoU" ............. rain total Today (no units)
   "ajaxrainYes" ............. rain total Yesterday
   "ajaxrainmo" .............. rain total for this Month
   "ajaxrainyr" .............. rain total for this Year

   "ajaxrainSun" ............. rain total last Sunday
   "ajaxrainMon" ............. rain total last Monday
   "ajaxrainTue" ............. rain total last Tuesday
   "ajaxrainWed" ............. rain total last Wednesday
   "ajaxrainThu" ............. rain total last Thursday
   "ajaxrainFri" ............. rain total last Friday
   "ajaxrainSat" ............. rain total last Saturday
   "ajaxrainydy" ............. rain total Yesterday (for compatibility)

   "ajaxRcdRain" ............. rain record (record all-time daily rain)
   "ajaxRcdRainTime" ......... rain record time
   "ajaxRcdRainDate" ......... rain record date

   "ajaxRcdRainHr" ........... rain record Hr (record all-time daily rain in 1 hour)
   "ajaxRcdRainHrTime" ....... rain record Hr time
   "ajaxRcdRainHrDate" ....... rain record Hr date

   "ajaxDaysRain" ............ rain days (MTD)
   "ajaxDaysNoRain" .......... rain absent days

SNOW:
   "ajaxsnowToday" ........... snow total Today
   "ajaxsnowMonth" ........... snow total for this Month
   "ajaxsnowSeason" .......... snow total for Season
   "ajaxsnowDepth" ........... current snow depth

CURRENT CONDITION ICON:
   "ajaxcurrentcond" ......... current weather conditions
   "ajaxconditionicon" ....... current condition icon for Anole Sticker (gif icons 25x25)
   "ajaxconditionicon2" ...... current condition icon (any size)

WEBCAM:
   "ajaxwebcamimg" ........... current webcam snap (170x127)

CLOUD HEIGHT:
   "ajaxcloudheightImg" ...... cloud height image

MOON:
   "ajaxmoonphase" ........... moon phase names
   "ajaxmoonimg" ............. moon phase image
   "ajaxmoonpct" ............. moon illumination %

FIRE RISK:
   "ajaxfireindex" ........... fire risk index
   "ajaxfireimg" ............. fire risk image

LIGHTNING:
   "ajaxlightning" ........... lightning strikes
   "ajaxlightningtime" ....... lightning strike time
   "ajaxlightningdist" ....... lightning strike distance
   "ajaxlightningbearing" .... lightning strike bearing

WET BULB:
   "ajaxwetbulb" ............. wet bulb temperature

DATE & TIME: (notes below use 16 Apr 2009 @ 14:37:07)
   "ajaxndate" ............... Apr 16, 2009
   "ajaxndate2" .............. 16-Apr-2009
   "ajaxntime" ............... 14:37
   "ajaxntimess" ............. 14:37:07
   "ajaxdname" ............... Thu
   "ajaxdatetime" ............ 16/4/2009 02:37:07pm (WD date & time format)
   "ajaxdate@" ............... 16/4/2009 @          (clientraw.txt date format)
   "ajaxdate" ................ 16/4/2009            (clientraw.txt date format)
   "ajaxtime" ................ 02:37:07pm           (clientraw.txt time format)

INDICATORS:
   "ajaxindicator" ........... flash indicator for HTTP fetch request (e.g Updated)

DEBUG TAGS:
   "ajaxupdatecount" ......... number of updates so far
   "ajaxmaxupdatecount ....... maximum number of updates
   "ajaxState" ............... HTTP request state
   "ajaxStatus" .............. HTTP request status
   "ajaxProgress" ............ progress inside ajaxLoader



================================================================================
SUMMARY OF CLASS TAGS FOR UOM SWITCHING: <span class="conv...."> ... </span>
================================================================================
This is used for UOM switching where static values do not have an "ajaxtag".
NOTE: the value in the span must include the units-of-measure for them be converted.
Example: <span class="convWind">8.2 mph</span>

   "convTemp" ................ for temperature placeholders (°C, °F)
   "convWind" ................ for wind speed  placeholders (kts, mph, km/h)
   "convBaro" ................ for pressure    placeholders (hPa, inHg)
   "convRain" ................ for rainfall    placeholders (mm, in)
   "convSnow" ................ for snow depth  placeholders (cm, in)
   "convDist" ................ for distances   placeholders (km, miles)
   "convAlti" ................ for altitudes   placeholders (m, ft)



================================================================================
SUMMARY OF GISMO ID TAGS: <span class="ajax" id="gizmo..."> ... </span>
================================================================================
Example: <span class="ajax" id="gizmotemp">77°F</span>

TEMPERATURE (outdoor):
   "ajaxbigtemp" ............. current temperature - big (no decimal)
   "gizmotemp" ............... current temperature
   "gizmotemparrow" .......... rising/falling image
   "gizmotemprate" ...........

HUMIDITY:
   "gizmohumidity"  .......... current humidity

DEWPOINT:
   "gizmodew" ................ current dew point

PRESSURE / BARO:
   "gizmobaro" ............... current baro pressure
   "gizmobarotrendtext" ...... baro trend text (rising/steady/falling)

WIND:
   "gizmowind" ............... current wind speed
   "gizmogust" ............... current gust speed
   "gizmowindicon" ........... wind icon arrow direction image
   "gizmowinddir" ............ wind direction (name e.g. NNW)
   "gizmowinddeg" ............ wind direction in degrees (e.g. 338°)

UV RATE:
   "gizmouv" ................. current UV level
   "gizmouvword" ............. None, Low, Medium, High, Very High, Extreme.

RAIN:
   "gizmorain" ............... rain total Today

CURRENT CONDITION ICON:
   "gizmocurrentcond" ........ current weather conditions

DATE & TIME: (notes use 16 Apr 2009 @ 14:37:07)
   "gizmodate" ............... 16/4/2009  (clientraw.txt date format)
   "gizmotime" ............... 02:37:07pm (clientraw.txt time format)

INDICATORS:
   "gizmoindicator" .......... flash indicator for HTTP fetch request (e.g Updated)
================================================================================
*/
