var ajaxVersion  = "9.11";
var ajaxVersDate = "19-Jan-2010"; /* Release date
+------------------------------------------------------------------------------+
|    Project: Cartelake/TNET/Saratoga PWS Website templates (WD)               |
|     Module: ajaxWDws.js   (packed version is: ajaxWDwx-packed.js)            |
|    Purpose: Ajax update from WD clientraw.txt for weather station websites.  |
|Description: This alternative ajaxWDwx.js script has been heavily modified    |
|             and has many new ajax tags. Setup has been simplified and many   |
|             new features have been added (see Version History below).        |
|Discussions: For a discussion and new releases go to the Weather-Watch forum: |
|             http://www.weather-watch.com/smf/index.php/topic,43859.0.html    |
|    Authors: Matthew Romer ..       http://wawaweather.net                    |
|             Kevin Reed .....       http://www.tnetweather.com                |
|             Pinto ..........       http://www.joske-online.be                |
|             Tom ............       http://CarterLake.org                     |
|             Ken True ....... v2.00 http://Saratoga-weather.org               |
|             Mike Challis ...       http://www.carmosaic.com/weather/         |
|             FourOhFour .....       http://skigod.us (at wxforum.net)         |
|             Jim ............       http://jcweather.us                       |
|             Scott .......... v3.00 http://www.WebsterWeatherLIVE.com         |
|             Rainer ......... v9.00 http://www.bashewa.com                    |
| Modifid by: Rainer Finkeldeh, rainer@bashewa.com, www.bashewa.com            |
|  Copyright: (c) 2006-2010 Copyright Bashewa Weather Station and those above. |
|Source code: http://www.bashewa.com/downloads/bws-script-ajaxWDwx.zip         |
| ---------------------------------------------------------------------------- |
| NOTES: This version of "ajaxWDwx.js" has been modified by www.bashewa.com    |
|        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 go to:                     |
|           http://www.bashewa.com/wxclientrawparser.php                       |
| ---------------------------------------------------------------------------- |
| JS SIZE REDUCTION:                                                           |
| If you want to pack this script after you have made 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)                             |
+------------------------------------------------------------------------------+
| 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                  |
+------------------------------------------------------------------------------+


+--------------------------------------------------------------------------------------------+
| ICON & GRAPHIC DOWNLOADS:                                                                  |
| ... unzip in root folder 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)|
+--------------------------------------------------------------------------------------------+


--------------------------------------------------------------------------------
VERSION HISTORY v2.00 - Saratoga Weather ........... http://saratoga-weather.org
--------------------------------------------------------------------------------
Updates available at: http://saratoga-weather.org/scripts-WD-AJAX.php
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
Announcements of new versions will be on weather-watch.com and wxforum.net
--------------------------------------------------------------------------------
Version 1.00 - 24-Nov-2006 -- added flash-green on data update functions - Ken True
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 -----------------------------------------------------
  Added 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 -----------------------------------------------------
Overhaul.... major ovehaul of script.
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 ].
Added....... support for UOM switching on static field values.
Modified.... [url=http://www.weather-watch.com/smf/index.php/topic,43750.0.html][color=blue]thermometer.php[/color][/url] 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 functions convertSnow & convertDist.

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....... 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)
Removed..... ajaxLoaderInBody - can no longer be supported i.e. <body onload="ajaxLoader(...)">
Added....... ClientExtra will now always be loaded as well.
Implemented. external "ajaxWDwx-settings.js" for separate setup outside of this script.

Version 9.06 - 11-Jan-2010 -----------------------------------------------------
Fixed....... problem with incorrect language translations.
Added....... modified "language-??.js" files to installation zip.
Added....... tag "ajaxVPleaf" ... VP leaf wetness
Added....... alert to your visitors if you have Weather Station problems.
Simpilfied.. the setup in the external settings file "ajaxWDwx-settings.js".

Version 9.07 - 13-Jan-2010 -----------------------------------------------------
Added....... support to use English Windrose images only (for Multilingual Systems).
Simpilfied.. the setup in the external settings file "ajaxWDwx-settings.js" even more.
             Your external settings file will now be compatible with all future versions of the script.

Version 9.08 - 17-Jan-2010 -----------------------------------------------------
Fixed ...... problem with dates when set to AM/PM in WDisplay.

Version 9.09 - 17-Jan-2010[/color][/url]
Fixed ...... problem with JS Date function showing 00:15pm instead of 12:15pm

Version 9.10 - 19-Jan-2010 -----------------------------------------------------
Fixed ...... problem with dates showing 19:00pm instead of 07:00pm when switching UOM.

Version 9.11 - 19-Jan-2010 -----------------------------------------------------
Fixed ...... added code for displaying JavaScript errors on page.
--------------------------------------------------------------------------------




================================================================================
                       HOW TO IMPLEMENT UOM SWITCHING                          .
================================================================================
for implementation see:  http://www.bashewa.com/ajax-dashboard.php?sce=view
Add the following code somewhere into 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;">IMPERIAL</span></b>
    </div>
    ----------------------------------------------------------------------------
For static field that don't have an "ajaxtag" you need to add one of the
following classes to your fields:
    ----------------------------------------------------------------------------
    <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
    <span class="convDate">20-10-2009</span>   ...for dates
    <span class="convTime">  15:32:27</span>   ...for times
    ----------------------------------------------------------------------------
NOTE: the value in the span must include the units-of-measure for them be converted.
You'll also need the modified "thermometer.php" script that supports UOM switching.
Get it here:  http://www.weather-watch.com/smf/index.php/topic,43750.0.html
================================================================================
*/



//============================================================================\\
//                             S E T I N G S                                  \\
//             P L E A S E   R E A D    T H I S   F I R S T                   \\
// 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.      \\
// I suggest strongly that you do so and also to use the packed version of    \\
// this script i.e. ajaxWDwx-packed.js.                                       \\
// -------------------------------------------------------------------------- \\
// 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 ... should be done in ajaxWDwx-settings.js)              .
//==============================================================================
var clientrawFile = './clientraw.txt'; // location of clientraw.txt relative to this page on website

var useUOM = 'E';   // [ E | M ] ... Units Of Measure:
                    //               E = English/Imperial
                    //               M = Metric
                    // NOTE: You can change individual units below in UNITS-OF-MEASURE.

var showUOM = true; // set to FALSE if no units should be displayed inside "ajaxtags".
                    // i.e. if your UOM's are outside the of the "ajaxtag" spans.
                    // Note: If you have implemented UOM switching this needs to
                    //       be TRUE and all your UOM's need to be on the inside
                    //       of your "ajaxtags".

//==============================================================================
// Settings (optional ... should be done in ajaxWDwx-settings.js)              .
//==============================================================================

var wxStation =   // Your Weather Station status
   {problemNr : 6 // Pick a problemMsg number from below
   ,problemMsg:   // Problem reports ... the selected message below by "problemNr" will be reported in the wxStation.useTag box
      {0:'No problems'
       ,1:'<span style="color:red; font-weight:bold">Note: Our Thermo-Hygro Sensor wired side appears to have failed.</span><br/>Updates will now be slower via wireless. The wire will be repaired ASAP.<br/>We apologize for any inconveniences.<br />'
       ,2:'<span style="color:red; font-weight:bold">Note: Our station is currently out of order and/or off-line.</span><br />We hope to have it up and running by next week.<br />'
       ,3:'<span style="color:red; font-weight:bold">Note: Our Anemometer is currently frozen or out of order.</span><br />Wind speed and direction may be affected.<br />'
       ,4:'<span style="color:red; font-weight:bold">Note: Our Rain Bucket is currently frozen or out of order.</span><br />Precipitation measurements will be made manually via our 4" rain gauge.<br />'
       ,5:'<span style="color:red; font-weight:bold">UPDATE: Space Weather Observations, Alerts, and Forecast Added</span><br />Specifically for our Amateur Radio Operators. <a href="wxspace.php">Click here</a><br />'
       ,6:'<span style="color:red; font-weight:bold">HEAVY SNOWFALL NOTICE:</span><br />Due to the extreme snowfall we are experiencing we will update our snowfall about once an hour.<br />Power outages are widespread so if station goes offline we apologize in advance.<br />'
	  } // you can add as many problem messages as you like to the above ... just number them properly
//   ,stopUpdates: false // Stop the ajax updates for the problem reported ... you should do so if your station is out-of-order
//   ,showAlert  : false // Show an alert box instead of a msg in wxStation.useTag box. Use "\n" for line breaks.
   ,useTag     : "ajaxindicator" // you can specify a different "ajaxtag" here to suit your requirements
   };

var update = // for ajax update interval
   {reloadtime: 5000   // fetch clientraw.txt file every 5 seconds (1000 ms = 1 second )
   ,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).
   ,showRefresh: true  // show REFRESH hyperlink after "maxupdates" have been exceeded.
   };

var flash = // for update indicator
   {color: '#048404'   // color to flash for changed observations (RGB) (def #00CC00 = green)
   ,red  : '#FF0000'   // color to flash red for warnings/alarms  (RGB) (def #FF0000 = red)
   ,time : 2000        // milliseconds to keep flash color on (2000 = 2 seconds);
   };


//==============================================================================
// STATIC IMAGES                                                               .
//==============================================================================
// IMAGE LOCATION: default root folder for graphic images & icons
// ... (for root folder specify "./")

var imgDir = './ajax-images/'; // with trailing slash

// NOTE: do not delete any of the words enclosed in {} in the src parts eg. {PIC}
//       They'll get replaced by their corresponding values later in the script.

//------------------------------------------------------------------------------
// DASHBOARD ICONS: optional settings for current conditions graphic for dashboard
// tag: "ajaxconditionicon" or "ajaxconditionicon2" ... specify it below in wxIcon.useTag
// e.g. graphic name: "./ajax-images/bkn.gif"
// .... grab the animated icons for set 2 here: http://www.bashewa.com/downloads/bws-icons-current.zip
var wxIcon =
   {src    : imgDir+"{PIC}.jpg" // where {PIC} will = picname from function specified in wxIcon.useName below
   ,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 ]
   ,useTag : "ajaxconditionicon2" // [ ajaxconditionicon | ajaxconditionicon2 ] ... ajax tagname to use
   ,useName: 1   // [ 0| 1 | 2 | 9 ] function for getting icon names ...
   };            //                  0 = Anole's icon names ............ see ajax_getIconName0()
                 //                  1 = NWS icon names ................ see ajax_getIconName1()
                 //                  2 = Bashewa numbered icon names ... see ajax_getIconName2()
                 //                  9 = Dynamic current icons ......... NOT IMPLEMENTED


//------------------------------------------------------------------------------
// 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}.png"  // where {DIR} will = wind dir (e.g. NNW), {LANG} = wrImg.lang
   ,width : 58 ,height: 58 ,hspace: 0 ,vspace: 0 ,border: 0
   ,style : ""
   ,align : "" // [ left | right | top | bottom | middle | texttop | absbottom | absmiddle ]
   ,lang  : ""     // with trailing dash (e.g. "nl-" will result in graphic name: "./ajax-images/wr-nl-SSE.gif")
   ,calm  : "calm" // substitution for {DIR} (e.g "wr-calm.gif") ... specify "" if not to be shown or not available
   ,xlate : true   // translate wind direction for icon names (multilingual system)
   ,useTag: "ajaxwindiconwr" // ajax tagname to use where the windrose icon should be placed
   };


//------------------------------------------------------------------------------
// 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{INDEX}.gif" // where {INDEX} will = UV index (0 to 11)
   ,width : 34 ,height: 65 ,hspace: 0 ,vspace: 0 ,border: 0
   ,style : ""
   ,align : ""
   ,useTag: "ajaxuvimg"
   };


//------------------------------------------------------------------------------
// 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 : ""
   ,useTag: "ajaxmoonimg"
   };


//------------------------------------------------------------------------------
// 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-{IMGNR}.png" // where {IMGNR} will = fire index (0=very low, 1=low, 2=moderate, 3=high, 4=extreme) from fireImg.imgNrs below
   ,width : 60 ,height: 65 ,hspace: 0 ,vspace: 0 ,border: 0
   ,style : ""
   ,align : ""
   ,imgNrs: // we all have different numbering systems for our FWI icons it seems ... specify the 5 icon numbers below
      {0:"0"  ,1:"16"  ,2:"25"  ,3:"31" ,4:"32"}
   ,useTag: "ajaxfireimg"
   };


//------------------------------------------------------------------------------
// WEBCAM IMAGE: optional setting for the webcam graphic
// tag: "ajaxwebcamimg"
// e.g. picture name: "./ajax-images/webcam/snap00.jpg"
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 : ""
   ,align : ""
   ,webcamUpdate      : 5     // Webcam update interval in minutes (set to 0 for no updates i.e. visitor must reload page for updates)
   ,swapIconWithWebcam: false // swap current conditions icon (tag "ajaxconditionicon2") with webcam image during day and night unless useCamAtNight=false;
   ,useCamAtNight     : false // use current conditions icon at night time instead of webcam image
   ,delayDayNight     : 15    // day starts given minutes before sunrise and night starts given min after sunset - for night icon switch
   ,useTag: "ajaxwebcamimg"
   };


//==============================================================================
// 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 : ""
   ,useTag: "ajaxthermometer"
   };


//------------------------------------------------------------------------------
// 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 : 85 ,height: 200 ,hspace: 0 ,vspace: 0 ,border: 0
   ,style : ""
   ,align : ""
   ,stationAlt: 0 // your station altitude in meters for cloud height graphic if you want ASL (meters = ft / 3.2808399)
   ,useTag: "ajaxcloudheightimg"
   };


//------------------------------------------------------------------------------
// DYNAMIC CURRENT ICON: settings 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)
// Set this up in wxIcon in DASHBOARD ICONS above:  { src: "./dynamic-icon.php" ,width: 170 ,height: 127, useName: 9 }



//==============================================================================
// 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: "j M 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: "H:i:s" // 3:27:01 pm ... same format as "date" function in php ( for 24h clock use "H:i:s" )
   ,timeHM : "H:i"   // 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" // 26-04-2009 ... 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';                                  .
// If translations are incorrect then edit the "language-??.js" files.         .
//==============================================================================
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", "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 same time 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.                 .
//==============================================================================

;;;var doTooltip = 0; // set to 1 to have ajaxed variable names appear as tooltips (except for graphics)

// -----------------------------------------------------------------------------
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 ajaxUpdates = 0; // update counter for limit by update.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=false, uom, dp, clientrawextraFile;

//-------------------------------------------------------------- functions start
function initialize() {
   // FOR DEBUGING -- always override the settings above if testing on a local host
   if (document.location.protocol=="file:"
   ||  document.location.href.search("localhost")!=-1) {
      //update.maxupdates = 0;
      update.reloadtime = 5000;
   }
   // END DEBUGING --

   if (typeof jserrNr!="undefined" && jserrNr!=null) {
      str = jserrors.replace(" in "," in:<br />");
      jsmsg = '<div style="border-bottom: 1px solid gray;">'+str+'</div>';
      set_ajax_obs(wxStation.useTag,jsmsg);
      jsErrNr = null;
   } else
   if (wxStation.problemNr>0) {
      pMsg= wxStation.problemMsg[wxStation.problemNr];
      if (wxStation.showAlert) alert(pMsg);
      else set_ajax_obs(wxStation.useTag,pMsg);
      if (wxStation.stopUpdates) update.maxupdates = 2;
   }

   clientrawextraFile = clientrawFile.replace("clientraw","clientrawextra");
   uom = (useUOM=='M')? metricUOM : imperialUOM;
   dp  = (useUOM=='M')? metricDP  : imperialDP;

   if (!showUOM) { // Strip UOMs 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() {
   ajaxUpdates = 0;
   counterSecs = 0;
   lastajaxtimeformat = null;
   set_ajax_obs("ajaxindicator",Indicator);
   ajaxLoader_clientextra(clientrawextraFile + '?' + 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];
   }
   ajax_page_convertTags(); // also convert tags convTemp, convWind ... etc.
   ajaxUpdates = 0;
   set_ajax_obs("ajaxindicator",new Date().getTime(),Indicator,flash.red);
   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.convertToMetric(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 = flash.color;
      }
   }
};


// function for setting green flashing object
function ajax_flash_green ( name ) {
   var element = document.getElementById(name);
   if (element)  element.style.color = flash.color;
};

// 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)? flash.red : flash.color;
      ;;;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#|\{PIC\})/i, 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#|\{PIC\})/i, 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#|\{PIC\})/i, 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.convertToMetric = 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 ,bg:bg ,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 , fireImg ) {
   switch (true) {
     case (fwi==0): idx = fireImg.imgNrs[0]; break;
     case (fwi< 7): idx = fireImg.imgNrs[1]; break;
     case (fwi<16): idx = fireImg.imgNrs[2]; break;
     case (fwi<31): idx = fireImg.imgNrs[3]; break;
     default      : idx = fireImg.imgNrs[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 = 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)
   hrs12 = (hrs%12==0)? 12 : hrs%12;
   fmt = fmt.replace("g" ,hrs12); // 1 to 12
   fmt = fmt.replace("G" ,hrs);   // 0 to 23
   fmt = fmt.replace("h" ,hrs12.toString().str_pad(2)); // 01 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 \""+clientrawextraFile+"\" 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(clientrawextraFile + '?' + 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 ajaxUpdates is < update.maxupdates

   if (clientraw[0] == '12345'
   &&  wdpattern.test(x.responseText)
   && (ajaxUpdates <= update.maxupdates || update.maxupdates > 0) ) {
   ;;;set_ajax_obs('ajaxProgress',rand+'start','-- START --');

   if (update.maxupdates > 0) ajaxUpdates++; // 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' // small arrow direction
            + '" 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#|\{LANG\})/i, wrImg.lang);
         src = src.replace      (/(#DIR#|\{DIR\})/i  , wrImg.xlate? valLang : windDir);
         set_ajax_obs(wrImg.useTag, 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#|\{LANG\})/i, wrImg.lang);
         src = src.replace      (/(#DIR#|\{DIR\})/i  , wrImg.calm);
         set_ajax_obs(wrImg.useTag , 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#|\{INDEX\})/i, UVI);
      set_ajax_obs(uvImg.useTag, 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 + cloudImg.stationAlt; // in meters
      altitude = Math.round(cloudheight.convertAlti());
      above = (cloudImg.stationAlt>0)? ' ASL' : ' AGL';
      cloudText = altitude.toString() + uom.Alti + above;
      param = '?uom=' + useUOM + '&buster=' + altitude + pres + beaufortnum + rain;
      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 ,fireImg);
         src = fireImg.src.replace(/(#IMGNR#|\{IMGNR\})/i ,idx);
         set_ajax_obs(fireImg.useTag, 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
            + '" />');
      }


// Leaf wetness ...
      ;;;set_ajax_obs('ajaxProgress',rand+'leaf','in Leaf wetness');
      VPleaf = clientraw[156];
      set_ajax_obs("ajaxVPleaf" ,VPleaf);


// Sun/Moon rise/set (needed by all functions below) ...
      if (clientrawextra!=null) {
         ;;;set_ajax_obs('ajaxProgress',rand+'getMS','stuck in sun/moon info');
         YY = clientraw[141];
         MM = clientraw[36];
         DD = clientraw[35];
         SR = clientrawextra[556]; // sunrise
         SS = clientrawextra[557]; // sunset
         MR = clientrawextra[558]; // moonrise
         MS = clientrawextra[559]; // moonset
         // Sun rise/set
         sunriseWD   = MM+'/'+DD+'/'+YY+' '+SR.replace(/AM/i," AM").replace(/PM/i," PM");
         sunsetWD    = MM+'/'+DD+'/'+YY+' '+SS.replace(/AM/i," AM").replace(/PM/i," PM");
         sunrise     = new Date(sunriseWD);
         sunset      = new Date(sunsetWD);
         sunriseWC   = sunrise.getTime() - (webcamImg.delayDayNight*60*1000);
         sunsetWC    = sunset.getTime()  + (webcamImg.delayDayNight*60*1000);
         // Moon rise/set
         moonriseWD = MM+'/'+DD+'/'+YY+' '+MR.replace(/AM/i," AM").replace(/PM/i," PM");
         moonsetWD  = MM+'/'+DD+'/'+YY+' '+MS.replace(/AM/i," AM").replace(/PM/i," PM");
         moonrise   = new Date(moonriseWD);
         moonset    = new Date(moonsetWD);
         // 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#|\{BG\})/i  , moonImg.bg);
      src = src.replace        (/(#NS#|\{NS\})/i  , moonNS);
      src = src.replace        (/(#AGE#|\{AGE\})/i, mooninfo.pic.toString().str_pad(2));
      set_ajax_obs(moonImg.useTag, 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
         + '" />');

      // 100x00 black background img for Astronomy page
      src = moonImg.src.replace(/(#BG#|\{BG\})/i  , 'b');
      src = src.replace        (/(#NS#|\{NS\})/i  , moonNS);
      src = src.replace        (/(#AGE#|\{AGE\})/i, 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 conditions description and icon ...
      ;;;set_ajax_obs('ajaxProgress',rand+'cond','in Conditions');
      // check if we need the icon instead of the webcam image at night
      if (!webcamImg.useCamAtNight && clientrawextra!=null) {
         if (WDnow < sunriseWC || WDnow > sunsetWC)
            webcamImg.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);

      if (!webcamImg.swapIconWithWebcam) {
         switch (wxIcon.useName) { // dashboard icons
          case 0: set_ajax_obs(wxIcon.useTag ,clientraw[48] ,ajax_getIconName0(currIconNr,wxIcon)); break; // Anole's icon names
          case 1: set_ajax_obs(wxIcon.useTag ,clientraw[48] ,ajax_getIconName1(currIconNr,wxIcon)); break; // NWS icon names
          case 2: set_ajax_obs(wxIcon.useTag ,clientraw[48] ,ajax_getIconName2(currIconNr,wxIcon)); break; // Bashewa numbered icon names
          case 9: //Dynamic icon creation similar to cloud height (not yet implemented)
                  param = '?uom=' + useUOM
                        + '&con=' + currentcond
                        + '&iW='  + wxIcon.width
                        + '&iH='  + wxIcon.height;
                  set_ajax_obs(wxIcon.useTag, param
                     ,'<img src="'  + wxIcon.src + param
                     + '" alt="'    + currentcond
                     + '" title="'  + currentcond
                     + '" width="'  + wxIcon.width
                     + '" height="' + wxIcon.height
                     + '" hspace="' + wxIcon.hspace
                     + '" vspace="' + wxIcon.vspace
                     + '" border="' + wxIcon.border
                     + '" align="'  + wxIcon.align
                     + '" style="'  + wxIcon.style
                     + '" />');
                  break;
         default: set_ajax_obs(wxIcon.useTag ,'<div style="border: 2px solid red">INVALID ICON FUNCTION #'+wxIcon.useName+'"</div>');
                  set_ajax_obs(wxIcon.useTag ,'<div style="border: 2px solid red">INVALID ICON FUNCTION #'+wxIcon.useName+'"</div>');
         }
      }


// Current webcam snap ...
      ;;;set_ajax_obs('ajaxProgress',rand+'webcam','in Webcam');
      if (webcamImg.swapIconWithWebcam)
           ajaxTag = wxIcon.useTag;
      else ajaxTag = webcamImg.useTag;

      if (webcamImg.webcamUpdate!=0) { // if 0 then no ajax updates requested
         now = new Date();
         minutes  = (now.getHours()*60) + now.getMinutes();
         interval = Math.floor(minutes / webcamImg.webcamUpdate);
         param = '?buster=' + interval;
         if (clientrawextra!=null && (WDnow<sunriseWC || WDnow>sunsetWC))
              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'   ,ajaxUpdates);        /* for test pages */
    set_ajax_obs('ajaxmaxupdatecount',update.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("AJAX 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('')",flash.time); // change text back to default color

    if (update.maxupdates == 0 || ajaxUpdates < update.maxupdates-1) {
       timerAjaxLoader = setTimeout("ajaxLoader(clientrawFile + '?' + new Date().getTime())", update.reloadtime); // get new data
    } else {
       counterSecs = 0; // reset timer
       stopTime = new Date().getTime();
       PauseMsg = '';
       if (update.showRefresh)
          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);
    }
  } else {// if (x)
    set_ajax_obs('ajaxProgress',rand+'http',"AJAX DASHBOARD ERROR:\nNo HTTP Request");
  }
}; // end ajaxLoader function



// invoke when first loaded on page
window.onload=function() {
   if (gotSettings) loadSettings(); // we've got a seperate settings file
   initialize();
   ajax_page_saveTags();
   ajaxLoader_clientextra(clientrawextraFile + '?' + new Date().getTime());
   window.setInterval("ajax_countup()", 1000); // run the counter for seconds since update
   ajaxLoader(clientrawFile        + '?' + new Date().getTime());
};




