PageSourceSearch

https://saratoga-weather.org/swx-ajaxWDwx.js

js saratoga-weather.org collected 2026-10-04 00:10:46 UTC 42,277 bytes, 987 lines download raw bytes

1// <![CDATA[
2
3// Special thanks to: Kevin Reed http://www.tnetweather.com/
4// Kevin was the first to decode the clientraw in PHP
5// Special thanks to: Pinto http://www.joske-online.be/
6// Pinto wrote the basic AJAX code for this page!
7// Cheerfully borrowed from Tom at CarterLake.org and adapted by
8// Ken True - Saratoga-weather.org  21-May-2006
9// --- added flash-green on data update functions - Ken True  24-Nov-2006
10//
11// --- Version 2.00 - 13-Dec-2006 -- Ken True -repackaged AJAX function, added metric/english units
12//     also included Mike Challis' counter script to display seconds since last update and error
13//     handling for the fetch to fix to fix random error: NS_ERROR_NOT_AVAILABLE
14//     Mike's site: http://www.642weather.com/weather/index.php
15//     Thanks to FourOhFour on wxforum.net ( http://skigod.us/ ) for replacing all the
16//     x.responseText.split(' ')[n] calls with a simple array lookup.. much better speed and
17//     for his streamlined version of getUVrange.
18// --- Version 2.01 - 17-Dec-2006 -- Corrected cloud height calculation
19// --- Version 2.02 - 20-Dec-2006 -- added unescape to set_ajax_obs comparison for lastobs
20// --- Version 2.03 - 07-Jan-2006 -- added wind m/s or km/h for metric variables
21// --- Version 2.04 - 08-Jan-2006 -- use epoch time for get (thanks to johnnywx on WD forum)
22//                                   so a numeric time without HTMLencoded characters is used
23// --- Version 2.05a - 30-Jan-2006 -- added new 'anti-NaN' check from johnnywx to make sure full
24//                                   clientraw.txt is read by looking for
25//                                   '12345' at start and '!!' at end of record
26// --- Version 2.06 - 24-Jun-2007 -- added '/' as delimiter for currentcond
27// --- Version 2.07 - 21-Sep-2007 -- added support for dynamic thermometer.php display refresh
28// --- Version 2.08 - 07-Nov-2007 -- added useMPH to force wind display in Miles-per-hour and
29//                                   added optional Wind-Rose, optional new current icon display graphics
30// --- Version 2.09 - 23-Dec-2007 -- added maxupdates feature, new ajax variables from K. Reed www.tnetweather.com
31// --- Version 2.10 - 18-Jan-2008 -- fixed icon=34 for ra1.jpg
32// --- Version 2.11 - 21-Feb-2008 -- added icon=35 for windyrain.gif/.jpg
33// --- Version 2.12 - 07-Mar-2008 -- added fix for 'flashing icon/thermometer' from Jim at jcweather.us
34// --- Version 2.13 - 11-Mar-2008 -- changed Wind-rose defaults to .png type (Carterlake/AJAX/PHP templates)
35// --- Version 2.14 - 29-Mar-2008 -- fixed UV words with  color: black; for display on dark/black template (MCHALLIS)
36// --- Version 2.15 - 28-Apr-2008 -- added ajaxFixConditions() and translation capability
37// --- Version 2.16 - 20-May-2008 -- added headcolorword processing V1.0 from MCHALLIS
38// --- Version 2.17 - 25-Jun-2008 -- added gizmo-specific ajax variables
39// --- Version 2.18 - 20-Mar-2009 -- added fix for 'green-flash' issue with Internet Explorer 8
40// --- Version 2.19 - 03-Jul-2009 -- additional gizmo-specific ajax added, and useHpa variable for pressure
41// --- Version 2.20 - 16-Jul-2010 -- reduced JS warning msgs by adding var and new x-browser request method finder
42// --- Version 2.21 - 17-Feb-2011 -- added decimal comma option for international display
43// --- Version 2.22 - 01-Oct-2011 -- added support for alternative animated icon set from http://www.meteotreviglio.com/
44// --- Version 2.23 - 29-Nov-2011 -- added improved conditions translation support
45// --- Version 2.24 - 13-Dec-2011 -- added useinHg to force baro to inHg for English/Metric selections
46// --- Version 2.25 - 30-Sep-2017 -- added ajaxdewNoU for trends page, changed ajaxbaroNoU decimals
47//
48// for updates to this script, see http://saratoga-weather.org/scripts-WD-AJAX.php
49// announcements of new versions will be on weather-watch.com and wxforum.net
50
51// -- begin settings --------------------------------------------------------------------------
52var flashcolor = '#00CC00'; // color to flash for changed observations RGB
53var flashtime  = 2000;       // miliseconds to keep flash color on (2000 = 2 seconds);
54var reloadTime = 10000;       // reload AJAX conditions every 5 seconds (= 5000 ms)
55var maxupdates = 12;	         // Maxium Number of updates allowed (set to zero for unlimited)
56                             // maxupdates * reloadTime / 1000 = number of seconds to update
57var clientrawFile = '/clientraw.txt'; // location of clientraw.txt relative to this page on website
58var ajaxLoaderInBody = false; // set to true if you have <body onload="ajaxLoader(..."
59var imagedir = './ajax-images';  // place for wind arrows, rising/falling arrows, etc.
60var condIconType = '.jpg';   // ='.jpg' default, ='.gif' for animated meteotreviglio condition icons
61var useunits = 'E';         // 'E'=USA(English) or 'M'=Metric
62var decimalComma = false;    // =false for '.' as decimal point, =true for ',' (comma) as decimal point
63var useKnots = false;       // set to true to use wind speed in Knots (otherwise 
64							// wind in km/hr for Metric or mph for English will be used.
65var useMPS   = false;       // set to true for meters/second for metric wind speeds, false= km/h
66var useMPH   = false;       // set to true to force MPH for both English and Metric units
67var useFeet  = false;       // set to true to force Feet for height in both English and Metric
68var usehPa  = false;        // =true to force hPa for baro in both English and Metric
69var useinHg = false;        // =true to force baro to inHg for both English and Metric
70var showUnits = true;       //  set to false if no units are to be displayed
71var thermometer = './thermometer.php'; // script for dynamic thermometer PNG image (optional)
72// optional settings for the Wind Rose graphic in ajaxwindiconwr as wrName + winddir + wrType
73var wrName   = 'wr-';       // first part of the graphic filename (followed by winddir to complete it)
74var wrType   = '.png';      // extension of the graphic filename
75var wrHeight = '58';        // windrose graphic height=
76var wrWidth  = '58';        // windrose graphic width=
77var wrCalm   = 'wr-calm.png';  // set to full name of graphic for calm display ('wr-calm.gif')
78// -- end of settings -------------------------------------------------------------------------
79
80// -- language settings -- you don't need to customize this area if you are using English -----
81
82var langPauseMsg = 'Updates paused - reload page to start'; // substitute this for ajaxindicator when
83                             // maxupdates has been reached and updating paused.
84
85var langMonths = new Array ( "January","February","March","April","May",
86			"June","July","August","September","October","November","December");
87var langDays = new Array ( "Sun","Mon","Tue","Wed","Thu","Fri","Sat","Sun");	
88
89var langBaroTrend = new Array (
90 "Steady", "Rising Slowly", "Rising Rapidly", "Falling Slowly", "Falling Rapidly");
91
92var langUVWords = new Array (
93 "None", "Low", "Medium", "High",
94 "Very&nbsp;High", /* be sure to include &nbsp; for space */
95 "Extreme" );
96
97var langBeaufort = new Array ( /* Beaufort 0 to 12 in array */
98 "Calm", "Light air", "Light breeze", "Gentle breeze", "Moderate breeze", "Fresh breeze",
99 "Strong breeze", "Near gale", "Gale", "Strong gale", "Storm",
100 "Violent storm", "Hurricane"
101);
102
103var langWindDir = new Array( /* used for alt and title tags on wind dir arrow and wind direction display */
104	"N", "NNE", "NE", "ENE", 
105	"E", "ESE", "SE", "SSE", 
106	"S", "SSW", "SW", "WSW", 
107	"W", "WNW", "NW", "NNW");
108
109var langWindCalm = 'Calm';
110var langGustNone = 'None';
111var langWindFrom = 'Wind from '; /* used on alt/title tags on wind direction arrow*/
112
113var langBaroRising = 'Rising %s '; /* used for trend arrow alt/title tags .. %s marks where value will be placed */
114var langBaroFalling = 'Falling %s ';
115var langBaroPerHour = '/hour.'; /* will be assembled as rising/falling + value + uom + perhour text */
116
117var langThermoCurrently = 'Currently: '; /* used on alt/title tags for thermometer */
118var langThermoMax     = 'Max: ';
119var langThermoMin     = 'Min: ';
120
121var langTempRising = 'Warmer %s '; /* used for trend arrow alt/title tags .. %s marks where value will be placed */
122var langTempFalling = 'Colder %s ';
123var langTempLastHour = ' than last hour.';
124
125var langTransLookup = new Object;  // storage area for key/value for current conditions translation
126
127var langHeatWords = new Array (
128 'Unknown', 'Extreme Heat Danger', 'Heat Danger', 'Extreme Heat Caution', 'Extremely Hot', 'Uncomfortably Hot',
129 'Hot', 'Warm', 'Comfortable', 'Cool', 'Cold', 'Uncomfortably Cold', 'Very Cold', 'Extreme Cold' );
130
131// -- end of language settings ----------------------------------------------------------
132
133// --- you don't need to customize the stuff below, the actions are controlled by the 
134//  settings above.  
135
136var ie4=document.all;
137var browser = navigator.appName;
138var ie8 = false;
139if (ie4 && /MSIE (\d+\.\d+);/.test(navigator.userAgent)){ //test for MSIE x.x;
140 var ieversion=new Number(RegExp.$1) // capture x.x portion and store as a number
141 if (ieversion>=8) {
142   ie4=false;
143   ie8=true;
144 }
145}
146var counterSecs = 0;  // for MCHALLIS counter script from weather-watch.com (adapted by K. True)
147var updates = 0;		// update counter for limit by maxupdates
148var lastajaxtimeformat = 'unknown'; //used to reset the counter when a real update is done
149var doTooltip = 0;   // set to 1 to have ajaxed variable names appear as tooltips (except for graphics)
150
151// handle setup options for units-of-measure and whether to show them at all
152var uomTemp = '&deg;F';
153var uomWind = ' mph';
154var uomBaro = ' inHg';
155var uomRain = ' in';
156var uomHeight = ' ft';
157var dpBaro = 2;
158var dpBaroNoU = 3; // default for Imperial trends data
159var dpRain = 2;
160
161
162function ajax_set_units( units ) {
163  useunits = units;
164  if (useunits != 'E') { // set to metric
165	uomTemp = '&deg;C';
166	uomWind = ' km/h';
167	uomBaro = ' hPa';
168	uomRain = ' mm';
169	uomHeight = ' m';
170	dpBaro = 1;
171	dbBaroNoU = 1;
172	dpRain = 1;
173  }
174  if(useKnots) { uomWind = ' kts'; }
175  if(useMPS)   { uomWind = ' m/s'; }
176  if(useMPH)   { uomWind = ' mph'; }
177  if(useFeet)  { uomHeight = ' ft'; }
178  if(usehPa)   { uomBaro = ' hPa'; }
179  if(useinHg)  { uomBaro = ' inHg'; }
180  if (! showUnits) {
181	uomTemp = '';
182	uomWind = '';
183	uomBaro = '';
184	uomRain = '';
185	uomHeight = '';
186  }
187}
188
189ajax_set_units(useunits);
190
191// utility functions to navigate the HTML tags in the page
192function get_ajax_tags ( ) {
193// search all the span tags and return the list with class="ajax" in it
194//
195  if (ie4 && browser != "Opera" && ! ie8) {
196    var elem = document.body.getElementsByTagName('span');
197	var lookfor = 'className';
198  } else {
199    var elem = document.getElementsByTagName('span');
200	var lookfor = 'class';
201  }
202     var arr = new Array();
203	 var iarr = 0;
204     for(var i = 0; i < elem.length; i++) {
205          var att = elem[i].getAttribute(lookfor);
206          if(att == 'ajax') {
207               arr[iarr] = elem[i];
208               iarr++;
209          }
210     }
211
212	 return arr;
213
214}
215
216function reset_ajax_color( usecolor ) {
217// reset all the <span class="ajax"...> styles to have no color override
218      var elements = get_ajax_tags();
219	  var numelements = elements.length;
220	  for (var index=0;index!=numelements;index++) {
221         var element = elements[index];
222	     element.style.color=usecolor;
223 
224      }
225}
226
227function set_ajax_obs( name, inValue ) {
228// store away the current value in both the doc and the span as lastobs="value"
229// change color if value != lastobs
230        var value = inValue;
231        if(decimalComma) {
232			value = inValue.replace(/(\d)\.(\d)/,"$1,$2");
233		}
234
235		var element = document.getElementById(name);
236		if (! element ) { return; } // V1.04 -- don't set if missing the <span id=name> tag
237		var lastobs = element.getAttribute("lastobs");
238		element.setAttribute("lastobs",value);
239		if (value != unescape(lastobs)) {
240          element.style.color=flashcolor;
241		  if ( doTooltip ) { element.setAttribute("title",'AJAX tag '+name); }
242		  element.innerHTML =  value; // moved inside to fix flashing issue (Jim at jcweather.us)
243		}
244}
245
246function set_ajax_uom( name, onoroff ) {
247// this function will set an ID= to visible or hidden by setting the style="display: "
248// from 'inline' or 'none'
249
250		var element = document.getElementById(name);
251		if (! element ) { return; } 
252		if (onoroff) {
253          element.style.display='inline';
254		} else {
255          element.style.display='none';
256		}
257}
258
259// --- end of flash-green functions
260
261function windDir ($winddir)
262// Take wind direction value, return the
263// text label based upon 16 point compass -- function by beeker425
264//  see http://www.weather-watch.com/smf/index.php/topic,20097.0.html
265{
266   var $windlabel = new Array("N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW");
267   return $windlabel[Math.floor(((parseInt($winddir) + 11) / 22.5) % 16 )];
268}
269
270function windDirLang ($winddir)
271// Take wind direction value, return the
272// text label based upon 16 point compass -- function by beeker425
273//  see http://www.weather-watch.com/smf/index.php/topic,20097.0.html
274{
275   return langWindDir[Math.floor(((parseInt($winddir) + 11) / 22.5) % 16 )];
276}
277
278
279function ajax_wxIcon ( iconWD ) { 
280// perform a lookup and return the graphic for the condition icon (using anole's
281// wxsticker icon names
282  var $iconList = new Array(
283	"day_clear.gif",           //  0 imagesunny.visible
284	"night_clear.gif",         //  1 imageclearnight.visible
285	"day_partly_cloudy.gif",   //  2 imagecloudy.visible
286	"day_partly_cloudy.gif",   //  3 imagecloudy2.visible
287	"night_partly_cloudy.gif", //  4 imagecloudynight.visible
288	"day_clear.gif",           //  5 imagedry.visible
289	"fog.gif",                 //  6 imagefog.visible
290	"haze-sm.gif",             //  7 imagehaze.visible
291	"day_heavy_rain.gif",      //  8 imageheavyrain.visible
292	"day_mostly_sunny.gif",    //  9 imagemainlyfine.visible
293	"mist-sm.gif",             // 10 imagemist.visible
294	"fog.gif",                 // 11 imagenightfog.visible
295	"night_heavy_rain.gif",    // 12 imagenightheavyrain.visible
296	"night_cloudy.gif",        // 13 imagenightovercast.visible
297	"night_rain.gif",          // 14 imagenightrain.visible
298	"night_light_rain.gif",    // 15 imagenightshowers.visible
299	"night_snow.gif",          // 16 imagenightsnow.visible
300	"night_tstorm.gif",        // 17 imagenightthunder.visible
301	"day_cloudy.gif",          // 18 imageovercast.visible
302	"day_partly_cloudy.gif",   // 19 imagepartlycloudy.visible
303	"day_rain.gif",            // 20 imagerain.visible
304	"day_rain.gif",            // 21 imagerain2.visible
305	"day_light_rain.gif",      // 22 imageshowers2.visible
306	"day_sleet.gif",           // 23 imagesleet.visible
307	"day_sleet.gif",           // 24 imagesleetshowers.visible
308	"day_snow.gif",            // 25 imagesnow.visible
309	"day_snow.gif",            // 26 imagesnowmelt.visible
310	"day_snow.gif",            // 27 imagesnowshowers2.visible
311	"day_clear.gif",           // 28 imagesunny.visible
312	"day_tstorm.gif",          // 29 imagethundershowers.visible
313	"day_tstorm.gif",          // 30 imagethundershowers2.visible
314	"day_tstorm.gif",          // 31 imagethunderstorms.visible
315	"tornado.gif",             // 32 imagetornado.visible
316	"windy-sm.gif",            // 33 imagewindy.visible
317	"day_partly_cloudy.gif",   // 34 stopped rainning
318	"windyrain-sm.gif"         // 35 windy/rain (new with V2.11)
319	);					
320
321  if (iconWD >= 0 && iconWD <= 35) { 
322    return ("<img src=\"" + imagedir + "/" + $iconList[iconWD] + "\" " +
323				"width=\"25\" height=\"25\" alt=\"Current condition icon\" />" );
324  } else {
325	return '';
326  }
327
328}
329
330function ajax_wxIconJPG ( iconWD ) { 
331// perform a lookup and return the graphic for the condition icon (using NWS icons)
332  var $iconListJPG = new Array(
333	"skc.jpg",          //  0 imagesunny.visible
334	"nskc.jpg",         //  1 imageclearnight.visible
335	"bkn.jpg",          //  2 imagecloudy.visible
336	"sct.jpg",          //  3 imagecloudy2.visible
337	"nbkn.jpg",         //  4 imagecloudynight.visible
338	"sct.jpg",          //  5 imagedry.visible
339	"fg.jpg",           //  6 imagefog.visible
340	"hazy.jpg",         //  7 imagehaze.visible
341	"ra.jpg",           //  8 imageheavyrain.visible
342	"few.jpg",          //  9 imagemainlyfine.visible
343	"mist.jpg",         // 10 imagemist.visible
344	"nfg.jpg",          // 11 imagenightfog.visible
345	"nra.jpg",          // 12 imagenightheavyrain.visible
346	"novc.jpg",         // 13 imagenightovercast.visible
347	"nra.jpg",          // 14 imagenightrain.visible
348	"nshra.jpg",        // 15 imagenightshowers.visible
349	"nsn.jpg",          // 16 imagenightsnow.visible
350	"ntsra.jpg",        // 17 imagenightthunder.visible
351	"ovc.jpg",          // 18 imageovercast.visible
352	"bkn.jpg",          // 19 imagepartlycloudy.visible
353	"ra.jpg",           // 20 imagerain.visible
354	"ra.jpg",           // 21 imagerain2.visible
355	"shra.jpg",         // 22 imageshowers2.visible
356	"ip.jpg",           // 23 imagesleet.visible
357	"ip.jpg",           // 24 imagesleetshowers.visible
358	"sn.jpg",           // 25 imagesnow.visible
359	"sn.jpg",           // 26 imagesnowmelt.visible
360	"sn.jpg",           // 27 imagesnowshowers2.visible
361	"skc.jpg",          // 28 imagesunny.visible
362	"scttsra.jpg",      // 29 imagethundershowers.visible
363	"hi_tsra.jpg",      // 30 imagethundershowers2.visible
364	"tsra.jpg",         // 31 imagethunderstorms.visible
365	"nsvrtsra.jpg",     // 32 imagetornado.visible
366	"wind.jpg",         // 33 imagewindy.visible
367	"ra1.jpg",          // 34 stopped rainning
368	"windyrain.jpg"     // 35 windy/rain (new with V2.11)
369	);					
370
371  if (iconWD >= 0 && iconWD <= 35) {
372	var ticon = $iconListJPG[iconWD];
373	if (condIconType !== '.jpg') {ticon = ticon.replace(/\.jpg/,condIconType);} 
374    return ("<img src=\"" + imagedir + "/" + ticon + "\" " +
375				"width=\"55\" height=\"58\" alt=\"Current condition icon\" />" );
376  } else {
377	return '';
378  }
379
380}
381
382// utility functions to handle conversions from clientraw data to desired units-of-measure
383function convertTemp ( rawtemp ) {
384	if (useunits == 'E') { // convert C to F
385		return( (1.8 * rawtemp) + 32.0);
386	} else {  // leave as C
387		return (rawtemp * 1.0);
388	}
389}
390
391function convertWind  ( rawwind ) {
392	if (useKnots) { return(rawwind * 1.0); } //force usage of knots for speed
393	if (useunits == 'E' || useMPH ) { // convert knots to mph
394		return(rawwind * 1.1507794);
395	} else {  
396	    if (useMPS) { // convert knots to m/s
397		  return (rawwind * 0.514444444);
398		} else { // convert knots to km/hr
399		  return (rawwind * 1.852);
400		}
401	}
402}
403
404function convertBaro ( rawpress ) {
405	if (! usehPa && (useunits == 'E' || useinHg) ) { // convert hPa to inHg
406	   return (rawpress  / 33.86388158);
407	} else {
408	   return (rawpress * 1.0); // leave in hPa
409	}
410}
411
412function convertRain ( rawrain ) {
413	if (useunits == 'E') { // convert mm to inches
414	   return (rawrain * .0393700787);
415	} else {
416	   return (rawrain * 1.0); // leave in mm
417	}
418}
419
420function convertHeight ( rawheight ) {
421	if (useunits == 'E' || useFeet ) { // convert feet to meters if metric
422	   return (Math.round(rawheight * 1.0).toFixed(0)); // leave in feet
423	} else {
424	   return (Math.round(rawheight / 3.2808399).toFixed(0));
425	}
426}
427
428function ajax_get_beaufort_number ( wind ) { 
429// return a number for the beaufort scale based on wind knots (native WD format)
430  if (wind < 1 ) {return("0"); }
431  if (wind < 4 ) {return("1"); }
432  if (wind < 7 ) {return("2"); }
433  if (wind < 11 ) {return("3"); }
434  if (wind < 17 ) {return("4"); }
435  if (wind < 22 ) {return("5"); }
436  if (wind < 28 ) {return("6"); }
437  if (wind < 34 ) {return("7"); }
438  if (wind < 41 ) {return("8"); }
439  if (wind < 48 ) {return("9"); }
440  if (wind < 56 ) {return("10"); }
441  if (wind < 64 ) {return("11"); }
442  if (wind >= 64 ) {return("12"); }
443  return("0");
444}
445
446function ajax_get_barotrend(btrnd) {
447// routine from Anole's wxsticker PHP (adapted to JS by Ken True)
448// input: trend in hPa or millibars
449//   Barometric Trend(3 hour)
450
451// Change Rates
452// Rapidly: =.06 inHg; 1.5 mm Hg; 2 hPa; 2 mb
453// Slowly: =.02 inHg; 0.5 mm Hg; 0.7 hPa; 0.7 mb
454
455// 5 conditions
456// Rising Rapidly
457// Rising Slowly
458// Steady
459// Falling Slowly
460// Falling Rapidly
461
462// Page 52 of the PDF Manual
463// http://www.davisnet.com/product_documents/weather/manuals/07395.234-VP2_Manual.pdf
464// figure out a text value for barometric pressure trend
465   if ((btrnd >= -0.7) && (btrnd <= 0.7)) { return(langBaroTrend[0]); }
466   if ((btrnd > 0.7) && (btrnd < 2.0)) { return(langBaroTrend[1]); }
467   if (btrnd >= 2.0) { return(langBaroTrend[2]); }
468   if ((btrnd < -0.7) && (btrnd > -2.0)) { return(langBaroTrend[3]); }
469   if (btrnd <= -2.0) { return(langBaroTrend[4]); }
470  return(btrnd);
471}
472
473function ajax_getUVrange ( uv ) { // code simplified by FourOhFour on wxforum.net
474   var uvword = "Unspec.";
475   if (uv <= 0) {
476       uvword = langUVWords[0];
477   } else if (uv < 3) {
478       uvword = "<span style=\"border: solid 1px; color: black; background-color: #A4CE6a;\">&nbsp;"+langUVWords[1]+"&nbsp;</span>";
479   } else if (uv < 6) {
480       uvword = "<span style=\"border: solid 1px; color: black; background-color: #FBEE09;\">&nbsp;"+langUVWords[2]+"&nbsp;</span>";
481   } else if (uv < 8) {
482       uvword =  "<span style=\"border: solid 1px; color: black; background-color: #FD9125;\">&nbsp;"+langUVWords[3]+"&nbsp;</span>";
483   } else if (uv < 11) {
484       uvword =  "<span style=\"border: solid 1px; color: #FFFFFF; background-color: #F63F37;\">&nbsp;"+langUVWords[4]+"&nbsp;</span>";
485   } else {
486       uvword =  "<span style=\"border: solid 1px; color: #FFFF00; background-color: #807780;\">&nbsp;"+langUVWords[5]+"&nbsp;</span>";
487   }
488   return uvword;
489} // end ajax_getUVrange function
490
491function ajax_genarrow( nowTemp, yesterTemp, Legend, textUP, textDN, numDp) {
492// generate an <img> tag with alt= and title= for rising/falling values	
493	
494  var diff = nowTemp.toFixed(3) - yesterTemp.toFixed(3);
495  var absDiff = Math.abs(diff);
496  var diffStr = '' + diff.toFixed(numDp);  // sprintf("%01.0f",$diff);
497  var absDiffStr = '' + absDiff.toFixed(numDp); // sprintf("%01.0f",$absDiff);
498  var image = '';
499  var msg = '';
500  
501  if (diff == 0) {
502 // no change
503    image = '&nbsp;'; 
504  } else if (diff > 0) {
505// today is greater 
506//    msg = textUP + " by " + diff.toFixed(1); // sprintf($textDN,$absDiff); 
507	msg = textUP.replace(/\%s/,absDiffStr);
508    image = "<img src=\"" + imagedir + "/rising.gif\" alt=\"" + msg + 
509	"\" title=\""+ msg + 
510	"\" width=\"7\" height=\"8\" style=\"border: 0; margin: 1px 3px;\" />";
511  } else {
512// today is lesser
513    msg = textDN.replace(/\%s/,absDiffStr); // sprintf($textDN,$absDiff); 
514//	msg = textDN.replace(/\%s/,absDiffStr);
515    image = "<img src=\"" + imagedir + "/falling.gif\" alt=\"" + msg + 
516	"\" title=\""+ msg + 
517	"\" width=\"7\" height=\"8\" style=\"border: 0; margin: 1px 3px;\" />";
518   
519  }
520
521   if (Legend) {
522       return (diff + Legend + image);
523	} else {
524	   return image;
525	}
526} // end genarrow function
527
528// function to add colored heatColorWord by Mike Challis
529// final version 1.00 
530function heatColor(temp,WindChill,Humidex) {
531  var hcWord = langHeatWords[0];
532 if (temp > 32 && Humidex > 29) {
533  if (Humidex > 54) { return ('<span style="border: solid 1px; color: white; background-color: #BA1928;">&nbsp;'+langHeatWords[1]+'&nbsp;</span>'); }
534  if (Humidex > 45) { return ('<span style="border: solid 1px; color: white; background-color: #E02538;">&nbsp;'+langHeatWords[2]+'&nbsp;</span>'); }
535  if (Humidex > 39) { return ('<span style="border: solid 1px; color: black; background-color: #E178A1;">&nbsp;'+langHeatWords[4]+'&nbsp;</span>'); }
536  if (Humidex > 29) { return ('<span style="border: solid 1px; color: white; background-color: #CC6633;">&nbsp;'+langHeatWords[6]+'&nbsp;</span>'); }
537 } else if (WindChill < 16 ) {
538  if (WindChill < -18) { return ('<span style="border: solid 1px; color: black; background-color: #91ACFF;">&nbsp;'+langHeatWords[13]+'&nbsp;</span>'); }
539  if (WindChill < -9)  { return ('<span style="border: solid 1px; color: white; background-color: #806AF9;">&nbsp;'+langHeatWords[12]+'&nbsp;</span>'); }
540  if (WindChill < -1)  { return ('<span style="border: solid 1px; color: white; background-color: #3366FF;">&nbsp;'+langHeatWords[11]+'&nbsp;</span>'); }
541  if (WindChill < 8)   { return ('<span style="border: solid 1px; color: white; background-color: #6699FF;">&nbsp;'+langHeatWords[10]+'&nbsp;</span>'); }
542  if (WindChill < 16)  { return ('<span style="border: solid 1px; color: black; background-color: #89B2EA;">&nbsp;'+langHeatWords[9]+'&nbsp;</span>'); }
543 }  else if (WindChill >= 16 && temp <= 32) {
544  if (temp < 26) { return ('<span style="border: solid 1px; color: black; background-color: #C6EF8C;">&nbsp;'+langHeatWords[8]+'&nbsp;</span>'); }
545  if (temp <= 32) { return ('<span style="border: solid 1px; color: black; background-color: #CC9933;">&nbsp;'+langHeatWords[7]+'&nbsp;</span>'); }
546  }
547  return hcWord;
548}
549
550// Mike Challis' counter function (adapted by Ken True)
551//
552function ajax_countup() {
553 var element = document.getElementById("ajaxcounter");
554 if (element) {
555  element.innerHTML = counterSecs;
556  counterSecs++;
557 }
558}
559
560function ucFirst ( str ) {
561   return str.substr(0,1).toUpperCase() + str.substr(1,str.length);
562}
563//
564// slice and dice the clientraw[49] for possible translation of current weather
565//
566function ajaxFixupCondition( rawcond ) {
567
568  var cond = rawcond;
569  cond = cond.replace(/_/gm,' ');  // replace any _ with blank.
570  cond = cond.replace(/ -/gm,'');  // replace any  - with null.
571  cond = cond.replace(/[\r\n]/gm,'');  // remove embedded CR and/or LF
572  var conds = cond.split('/');  // split up the arguments.
573  var tstr = '';
574  for (var i = 0;i<conds.length;i++) {
575    var t = conds[i];
576	t = t.toLowerCase();
577	t = ucFirst(t);
578    t = t.replace(/\s+$/,'');  // trim trailing blanks
579	if(langTransLookup[t]) { 
580	  conds[i] = langTransLookup[t];
581	} else {
582	  conds[i] = t;
583	}
584  }
585  if (conds[0].length == 0) { conds.splice(0,1);  } // remove blank entry
586  if (conds[0] == conds[2]) { conds.splice(2,1); } // remove duplicate last entry
587  
588  return(conds.join(', '));
589
590
591}
592
593function ajaxRequest () {
594	/* find the handler for AJAX based on availability of the request object */
595	try { var request = new XMLHttpRequest() /* non IE browser (or IE8 native) */ }
596	catch(e1) {
597		try { request = ActiveXObject("Msxml2.XMLHTTP") /* try IE6+ */ }
598		catch(e2) {
599			try { request = ActiveXObject("Microsoft.XMLHTTP") /* try IE5 */}
600			catch(e3) // no Ajax support
601			{ request = false; alert('Sorry.. AJAX updates are not available for your browser.') }
602		}
603	}
604	if (! request) { maxupdates = 1; }
605	return request;
606}
607
608// ------------------------------------------------------------------------------------------
609//  main function.. read clientraw.txt and format <span class="ajax" id="ajax..."></span> areas
610// ------------------------------------------------------------------------------------------
611function ajaxLoader(url) {
612/*
613  if (document.getElementById) {
614	if (typeof(window.ActiveXObject) != "undefined") {
615    var x = new ActiveXObject("Microsoft.XMLHTTP");
616	} else {
617	var x = new XMLHttpRequest(url);
618	}
619  }
620*/
621  var x = new ajaxRequest();
622  
623  if (x) { // got something back
624    x.onreadystatechange = function() {
625    try { if (x.readyState == 4 && x.status == 200) { // Mike Challis added fix to fix random error: NS_ERROR_NOT_AVAILABLE 
626    var clientraw = x.responseText.split(' ');
627	// now make sure we got the entire clientraw.txt  -- thanks to Johnnywx
628	// valid clientraw.txt has '12345' at start and '!!' at end of record
629	var wdpattern=/\d+\.\d+.*!!/; // looks for '!!nn.nn!!' version string 
630	// If we have a valid clientraw file AND updates is < maxupdates
631	if(clientraw[0] == '12345' && wdpattern.test(x.responseText) && 
632	    ( updates <= maxupdates || maxupdates > 0  ) ) {
633		if (maxupdates > 0 ) {updates++; } // increment counter if needed
634
635		//Temperature
636		var temp = convertTemp(clientraw[4]);
637		set_ajax_obs("ajaxtemp", temp.toFixed(1) + uomTemp);
638		set_ajax_obs("ajaxtempNoU", temp.toFixed(1));
639		set_ajax_obs("gizmotemp", temp.toFixed(1) + uomTemp);
640		set_ajax_obs("ajaxbigtemp",temp.toFixed(0) + uomTemp);
641
642		var templast = convertTemp(clientraw[90]);
643		var temparrow = ajax_genarrow(temp, templast, '', 
644			 langTempRising+uomTemp+langTempLastHour,
645			 langTempFalling+uomTemp+langTempLastHour,1)
646		
647		set_ajax_obs("ajaxtemparrow",temparrow); 
648		set_ajax_obs("gizmotemparrow",temparrow); 
649		   
650	    var temprate = temp - templast;
651		temprate = temprate.toFixed(1);
652		if (temprate > 0.0) { temprate = '+' + temprate;} // add '+' for positive rates
653		set_ajax_obs("ajaxtemprate",temprate + uomTemp);
654		set_ajax_obs("gizmotemprate",temprate + uomTemp);
655
656		var tempmax = convertTemp(clientraw[46]);
657		set_ajax_obs("ajaxtempmax",tempmax.toFixed(1) + uomTemp);
658
659		var tempmin = convertTemp(clientraw[47]);
660		set_ajax_obs("ajaxtempmin",tempmin.toFixed(1) + uomTemp);
661		
662		var thermometerstr = langThermoCurrently +  + temp.toFixed(1) + uomTemp + 
663		  ", " + langThermoMax + tempmax.toFixed(1) + uomTemp +
664		  ", " + langThermoMin + tempmin.toFixed(1) + uomTemp;
665
666		set_ajax_obs("ajaxthermometer",
667			"<img src=\"" + thermometer + "?t=" + temp.toFixed(1) + "\" " +
668				"width=\"54\" height=\"170\" " +
669				"alt=\"" + thermometerstr + "\" " +
670				"title=\"" + thermometerstr + "\" />" );
671
672		//Humidity ...
673		var humidity = clientraw[5];
674		set_ajax_obs("ajaxhumidity",humidity);
675		set_ajax_obs("gizmohumidity",humidity);
676		// sorry.. no min/max data for humidity available in clientraw.txt
677		
678		//Dewpoint ...
679		var dew = convertTemp(clientraw[72]);
680		set_ajax_obs("ajaxdew",dew.toFixed(1) + uomTemp);
681		set_ajax_obs('ajaxdewNoU',dew.toFixed(1));
682		set_ajax_obs("gizmodew",dew.toFixed(1) + uomTemp);
683		var dewmin = convertTemp(clientraw[139]);
684		set_ajax_obs("ajaxdewmin",dewmin.toFixed(1) + uomTemp);
685		var dewmax = convertTemp(clientraw[138]);
686		set_ajax_obs("ajaxdewmax",dewmax.toFixed(1) + uomTemp);
687
688		// Humidex
689		var humidex = convertTemp(clientraw[45]);
690		set_ajax_obs("ajaxhumidex",humidex.toFixed(1) + uomTemp);
691		var humidexmin = convertTemp(clientraw[76]);
692		set_ajax_obs("ajaxhumidexmin",humidexmin.toFixed(1) + uomTemp);
693		var humidexmax = convertTemp(clientraw[75]);
694		set_ajax_obs("ajaxhumidexmax",humidexmax.toFixed(1) + uomTemp);
695
696		//  WindChill
697		var windchill = convertTemp(clientraw[44]);
698		set_ajax_obs("ajaxwindchill",windchill.toFixed(1) + uomTemp);
699		var windchillmin = convertTemp(clientraw[78]);
700		set_ajax_obs("ajaxwindchillmin",windchillmin.toFixed(1) + uomTemp);
701		var windchillmax = convertTemp(clientraw[77]);
702		set_ajax_obs("ajaxwindchillmax",windchillmax.toFixed(1) + uomTemp);
703
704		// Heat Index
705		var heatidx = convertTemp(clientraw[112]);
706		set_ajax_obs("ajaxheatidx",heatidx.toFixed(1) + uomTemp);
707		var heatidxmin = convertTemp(clientraw[111]);
708		set_ajax_obs("ajaxheatidxmin",heatidxmin.toFixed(1) + uomTemp);
709		var heatidxmax = convertTemp(clientraw[110]);
710		set_ajax_obs("ajaxheatidxmax",heatidxmax.toFixed(1) + uomTemp);
711
712		// FeelsLike
713		temp = clientraw[4]; // note.. temp in C
714        if (temp <= 16.0 ) {
715		  feelslike = clientraw[44]; //use WindChill
716		} else if (temp >=27.0) {
717		  feelslike = clientraw[45]; //use Humidex
718		} else {
719		  feelslike = temp;   // use temperature
720		}
721		var feelslike  = Math.round(convertTemp(feelslike));
722        set_ajax_obs("ajaxfeelslike",feelslike + uomTemp);
723
724		// # mike challis added heatColorWord feature
725		var heatColorWord = heatColor(clientraw[4],clientraw[44],clientraw[45]);
726		set_ajax_obs("ajaxheatcolorword",heatColorWord);
727		
728		// Apparent temperature
729		var apparenttemp = convertTemp(clientraw[130]);
730		set_ajax_obs("ajaxapparenttemp",apparenttemp.toFixed(1) + uomTemp);
731		var apparenttempmin = convertTemp(clientraw[136]);
732		set_ajax_obs("ajaxapparenttempmin",apparenttempmin.toFixed(1) + uomTemp);
733		var apparenttempmax = convertTemp(clientraw[137]);
734		set_ajax_obs("ajaxapparenttempmax",apparenttempmax.toFixed(1) + uomTemp);
735		
736		//Pressure...
737		var pressure = convertBaro(clientraw[6]);
738		set_ajax_obs("ajaxbaro",pressure.toFixed(dpBaro) + uomBaro);
739		set_ajax_obs("ajaxbaroNoU",pressure.toFixed(dpBaroNoU));
740		set_ajax_obs("gizmobaro",pressure.toFixed(dpBaro) + uomBaro);
741		var pressuretrend = convertBaro(clientraw[50]);
742		pressuretrend = pressuretrend.toFixed(dpBaro+1);
743		if (pressuretrend > 0.0) {pressuretrend = '+' + pressuretrend; } // add '+' to rate
744		set_ajax_obs("ajaxbarotrend",pressuretrend + uomBaro);
745		set_ajax_obs("gizmobarotrend",pressuretrend + uomBaro);
746		set_ajax_obs("ajaxbaroarrow",
747		   ajax_genarrow(pressure, pressure-pressuretrend, '', 
748			 langBaroRising+uomBaro+langBaroPerHour,
749			 langBaroFalling+uomBaro+langBaroPerHour,2)
750			 );	
751		var barotrendtext = ajax_get_barotrend(clientraw[50]);
752		set_ajax_obs("ajaxbarotrendtext",barotrendtext);
753		set_ajax_obs("gizmobarotrendtext",barotrendtext);
754
755		var pressuremin = convertBaro(clientraw[132]);
756		set_ajax_obs("ajaxbaromin",pressuremin.toFixed(dpBaro) + uomBaro);
757		var pressuremax = convertBaro(clientraw[131]);
758		set_ajax_obs("ajaxbaromax",pressuremax.toFixed(dpBaro) + uomBaro);
759
760        //Wind gust
761		var gust    = convertWind(clientraw[140]);
762		var maxgust = convertWind(clientraw[71]);
763		if (maxgust > 0.0 ) {
764		  set_ajax_obs("ajaxmaxgust",maxgust.toFixed(1) + uomWind);
765		} else {
766		  set_ajax_obs("ajaxmaxgust",'None');
767		}
768
769		//Windspeed ...
770		var wind = convertWind(clientraw[2]);
771		var beaufortnum = ajax_get_beaufort_number(clientraw[2]);
772		set_ajax_obs("ajaxbeaufortnum",beaufortnum);
773		set_ajax_obs("ajaxbeaufort",langBeaufort[beaufortnum]);
774
775       //WIND DIRECTION ...
776        var val = windDir(clientraw[3]);
777		var valLang = windDirLang(clientraw[3]); /* to enable translations */
778
779       if (wind > 0.0) {
780		set_ajax_obs("ajaxwind",wind.toFixed(1) + uomWind);
781		set_ajax_obs("ajaxwindNoU",wind.toFixed(1));
782		set_ajax_obs("gizmowind",wind.toFixed(1) + uomWind);
783		set_ajax_uom("ajaxwinduom",true);
784	   } else {
785		set_ajax_obs("ajaxwind",langWindCalm);
786		set_ajax_obs("ajaxwindNoU",langWindCalm);
787		set_ajax_obs("gizmowind",langWindCalm);
788		set_ajax_uom("ajaxwinduom",false);
789	   }
790	   
791	   if (gust > 0.0) {
792		set_ajax_obs("ajaxgust",gust.toFixed(1) + uomWind);
793		set_ajax_obs("ajaxgustNoU",gust.toFixed(1));
794		set_ajax_obs("gizmogust",gust.toFixed(1) + uomWind);
795		set_ajax_uom("ajaxgustuom",true);
796	   } else {
797		set_ajax_obs("ajaxgust",langGustNone);
798		set_ajax_obs("ajaxgustNoU",langGustNone);
799		set_ajax_obs("gizmogust",langGustNone);
800		set_ajax_uom("ajaxgustuom",false);
801	   }
802	   
803   	   if (gust > 0.0 || wind > 0.0) {
804		var windicon = 	"<img src=\"" + imagedir + "/" +  val + ".gif\" width=\"14\" height=\"14\" alt=\"" + 
805		  langWindFrom + valLang + "\" title=\"" + langWindFrom + valLang + "\" /> ";
806 		set_ajax_obs("ajaxwindicon",windicon);
807		set_ajax_obs("gizmowindicon",windicon);
808 		set_ajax_obs("ajaxwindiconwr",
809		  "<img src=\"" + imagedir + "/" +wrName +  val + wrType + "\" width=\""+
810		   wrWidth+"\" height=\""+wrHeight+"\" alt=\"" + 
811		  langWindFrom + valLang + "\" title=\"" +langWindFrom + valLang + "\" /> ");
812		set_ajax_obs("ajaxwinddir",valLang);
813		set_ajax_obs("gizmowinddir",valLang);
814	   } else {
815 		set_ajax_obs("ajaxwindicon","");
816 		set_ajax_obs("gizmowindicon","");
817		set_ajax_obs("ajaxwinddir","");
818		set_ajax_obs("gizmowinddir","");
819		if (wrCalm != '') {
820 		 set_ajax_obs("ajaxwindiconwr",
821		  "<img src=\"" + imagedir + "/" + wrCalm + "\" width=\""+
822		   wrWidth+"\" height=\""+wrHeight+"\" alt=\"" + 
823		  langBeaufort[0] + "\" title=\"" +langBeaufort[0] + "\" /> ");
824		}
825	   }
826
827		var windmaxavg = convertWind(clientraw[113]);
828		set_ajax_obs("ajaxwindmaxavg",windmaxavg.toFixed(1) + uomWind);
829		
830		var windmaxgust = convertWind(clientraw[71]);
831		set_ajax_obs("ajaxwindmaxgust",windmaxgust.toFixed(1) + uomWind);
832
833		var windmaxgusttime = clientraw[135];
834		windmaxgusttime = windmaxgusttime.toLowerCase();
835		windmaxgusttime = windmaxgusttime.replace( "_" , "");
836		set_ajax_obs("ajaxwindmaxgusttime",windmaxgusttime);
837		
838
839		//  Solar Radiation
840		var solar    = clientraw[127] * 1.0;
841		set_ajax_obs("ajaxsolar",solar.toFixed(0));
842
843        var solarpct = clientraw[34];
844		set_ajax_obs("ajaxsolarpct",solarpct);
845		
846		// UV Index		
847		var uv       = clientraw[79];
848		set_ajax_obs("ajaxuv",uv) ;
849		set_ajax_obs("gizmouv",uv) ;
850
851		var uvword = ajax_getUVrange(uv);
852		set_ajax_obs("ajaxuvword",uvword);
853		set_ajax_obs("gizmouvword",uvword);
854
855		//Rain ...
856		var rain = convertRain(clientraw[7]);
857		set_ajax_obs("ajaxrain",rain.toFixed(dpRain) + uomRain);
858		set_ajax_obs("ajaxrainNoU",rain.toFixed(dpRain));
859		set_ajax_obs("gizmorain",rain.toFixed(dpRain) + uomRain);
860
861		var rainydy = convertRain(clientraw[19]);
862		set_ajax_obs("ajaxrainydy",rainydy.toFixed(dpRain)+ uomRain);
863
864		var rainmo = convertRain(clientraw[8]);
865		set_ajax_obs("ajaxrainmo",rainmo.toFixed(dpRain) + uomRain);
866
867		var rainyr = convertRain(clientraw[9]);
868		set_ajax_obs("ajaxrainyr",rainyr.toFixed(dpRain) + uomRain);
869
870		var rainratehr = convertRain(clientraw[10]) * 60; // make per hour rate.
871		set_ajax_obs("ajaxrainratehr",rainratehr.toFixed(dpRain+1) + uomRain);
872
873		var rainratemax = convertRain(clientraw[11]) * 60; // make per hour rate
874		set_ajax_obs("ajaxrainratemax",rainratemax.toFixed(dpRain+1) + uomRain);
875
876		// Provides Date String Objects in the form of
877		// ntime = HH:MM                as in 17:24
878		// ndate = Mon DD, YYYY         as in Nov 14, 2007
879		// tday  = 3 letter Abr of Day  as in Wed
880		//
881		// All combined you could end up with   Mon Nov 14, 2007
882		// 
883		// Uses clientraw elements:
884		// Hour 29  Min 30  Day 35  Month 36  Year 141
885		// Added 2007-11-14 by Kevin Reed TNETWeather.com
886		//======================================================================
887		var ntime = clientraw[29] + ":" + clientraw[30];
888		var ndate = langMonths[ clientraw[36] -1 ].substring(0,3) + " " + clientraw[35] + " " + clientraw[141];
889		var ndate2 = clientraw[35] + "-" +langMonths[ clientraw[36] -1 ].substring(0,3) + "-" +  clientraw[141];
890		var myDate = new Date( langMonths[ clientraw[36] - 1 ] + " " + clientraw[35] + ", " + clientraw[141] );
891		var tday = langDays[myDate.getDay()];
892		//
893		set_ajax_obs("ajaxndate", ndate );
894		set_ajax_obs("ajaxndate2",ndate2);
895		set_ajax_obs("ajaxntime", ntime );
896		set_ajax_obs("ajaxntimess", ntime + ":" + clientraw[31]);
897		set_ajax_obs("ajaxdname", tday );
898
899		// current date and time of observation in clientraw.txt
900		var ajaxtimeformat = clientraw[32];
901		var ajaxdateformat = clientraw[74];
902		ajaxtimeformat = ajaxtimeformat.split('-')[1];
903		ajaxtimeformat = ajaxtimeformat.replace( "_" , "");
904		ajaxtimeformat = ajaxtimeformat.toLowerCase();
905
906		set_ajax_obs("ajaxdatetime",ajaxdateformat + " " +ajaxtimeformat);
907		set_ajax_obs("ajaxdate",ajaxdateformat);
908		set_ajax_obs("ajaxtime",ajaxtimeformat);
909		set_ajax_obs("gizmodate",ajaxdateformat);
910		set_ajax_obs("gizmotime",ajaxtimeformat);
911		
912		if (lastajaxtimeformat != ajaxtimeformat) {
913			counterSecs = 0;                      // reset timer
914			lastajaxtimeformat = ajaxtimeformat; // remember this time
915		}
916		
917		// current condition icon and description
918		set_ajax_obs("ajaxconditionicon",
919			ajax_wxIcon(clientraw[48])
920			);
921
922		set_ajax_obs("ajaxconditionicon2",
923			ajax_wxIconJPG(clientraw[48])
924			);
925
926
927		var currentcond = clientraw[49];
928//		currentcond = currentcond.replace(/_/g,' ');
929//		currentcond = currentcond.replace(/^\/Dry\//g,'');
930		currentcond = currentcond.replace(/\\/g,', ');
931//		currentcond = currentcond.replace(/\//g,', ');
932        currentcond = ajaxFixupCondition(currentcond);
933		set_ajax_obs("ajaxcurrentcond",currentcond);
934		set_ajax_obs("gizmocurrentcond",currentcond);
935		
936		// cloud height
937		var cloudheight = clientraw[73];
938		set_ajax_obs("ajaxcloudheight",convertHeight(cloudheight) + uomHeight);
939		
940		// now ensure that the indicator flashes on every AJAX fetch
941        var element = document.getElementById("ajaxindicator");
942		if (element) {
943          element.style.color = flashcolor;
944		}
945        var element = document.getElementById("gizmoindicator"); // separate gizmo ajax variable
946		if (element) {
947          element.style.color = flashcolor;
948		}
949		if (maxupdates > 0 && updates > maxupdates-1) { /* chg indicator to pause message */
950			set_ajax_obs("ajaxindicator",langPauseMsg);
951			set_ajax_obs("gizmoindicator",langPauseMsg);
952		}
953		set_ajax_obs('ajaxupdatecount',updates);       /* for test pages */
954		set_ajax_obs('ajaxmaxupdatecount',maxupdates); /* for test pages */
955
956 	  } // END if(clientraw[0] = '12345' and '!!' at end)
957
958	 } // END if (x.readyState == 4 && x.status == 200)
959
960    } // END try
961
962   	catch(e){}  // Mike Challis added fix to fix random error: NS_ERROR_NOT_AVAILABLE
963
964    } // END x.onreadystatechange = function() {
965    x.open("GET", url, true);
966    x.send(null);
967
968//  reset the flash colors, and restart the update unless maxupdate limit is reached
969
970    setTimeout("reset_ajax_color('')",flashtime); // change text back to default color 
971
972	if ( (maxupdates == 0) || (updates < maxupdates-1)) {
973      setTimeout("ajaxLoader(clientrawFile + '?' + new Date().getTime())", reloadTime); // get new data 
974    }
975  }
976} // end ajaxLoader function
977
978//element = document.getElementById("ajaxcounter");
979//if (element) {
980  window.setInterval("ajax_countup()", 1000); // run the counter for seconds since update
981//}
982
983// invoke when first loaded on page
984if (! ajaxLoaderInBody) { ajaxLoader(clientrawFile + '?' + new Date().getTime(), reloadTime); }
985
986
987// ]]>

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.