//=========================================================
//
// Define latitude/longitude and other constants
//
//=========================================================
	latitude = 34.31
	longitude = -83.86
	solar_constant = 1366
	solar_attenuation_factor = .18
	degrees_to_radians = Math.PI / 180
	radians_to_degrees = 180 / Math.PI
	PI_2 = 2 * Math.PI
	small_font = "<font size=\"1\" face=\"Arial\" color=\"#000000\">"

//=========================================================
//
// Names for months
//
//=========================================================
	text_month = new Array(13)
	text_month[1]  = "January"
	text_month[2]  = "February"
	text_month[3]  = "March"
	text_month[4]  = "April"
	text_month[5]  = "May"
	text_month[6]  = "June"
	text_month[7]  = "July"
	text_month[8]  = "August"
	text_month[9]  = "September"
	text_month[10] = "October"
	text_month[11] = "November"
	text_month[12] = "December"

//=========================================================
//
// Number of days in each month
//
//=========================================================
	days_in_month = new Array(13)
	days_in_month[1]  = 31
	days_in_month[2]  = 28
	days_in_month[3]  = 31
	days_in_month[4]  = 30
	days_in_month[5]  = 31
	days_in_month[6]  = 30
	days_in_month[7]  = 31
	days_in_month[8]  = 31
	days_in_month[9]  = 30
	days_in_month[10] = 31
	days_in_month[11] = 30
	days_in_month[12] = 31
	
//=========================================================
//
// Names for days of week
//
//=========================================================
	text_day = new Array(8)
	text_day[1] = "Sunday"
	text_day[2] = "Monday"
	text_day[3] = "Tuesday"
	text_day[4] = "Wednesday"
	text_day[5] = "Thursday"
	text_day[6] = "Friday"
	text_day[7] = "Saturday"
	
//=========================================================
//
// Suffix for numeric days of month
//
//=========================================================
	function dateSuffix(numeric_day)
	{suffix = "th"
	if (numeric_day == 1)  {suffix = "st"}
	if (numeric_day == 2)  {suffix = "nd"}
	if (numeric_day == 3)  {suffix = "rd"}
	if (numeric_day == 21) {suffix = "st"}
	if (numeric_day == 22) {suffix = "nd"}
	if (numeric_day == 23) {suffix = "rd"}
	if (numeric_day == 31) {suffix = "st"}
	return suffix}
	
//=========================================================
//
// Calculates first day of the year
//
//=========================================================
function calcFirstDay(this_year)
	{loop_year = 2000; first_day = 7 // Year 2000 started on a Saturday
	while (loop_year < this_year) {
		first_day = first_day + 1
		if (loop_year % 4 == 0) {first_day = first_day + 1}
		if (first_day > 7) {first_day = first_day - 7}
	loop_year++}
	return first_day}

//=========================================================
//
// Calculates Julian day of the year
//
//=========================================================
function calcJday(current_month, current_day, current_year)
	{i = 1
	if (current_year % 4 == 0) {days_in_month[2] = 29} else {days_in_month[2] = 28}
	prior_days = 0
	while (i < current_month) {prior_days = prior_days + days_in_month[i], i++}
	Jday = prior_days + current_day
	return Jday}

//=========================================================
//
// Calculates day of week from Julian date
//
//=========================================================
function calcDayOfWeek(jday, yy)
	{week = Math.floor(jday / 7)
	day_in_week = jday - (7 * week) + calcFirstDay(yy) - 1
	if (day_in_week == 0) {day_in_week = 7}
	if (day_in_week > 7) {day_in_week = day_in_week - 7}
	return text_day[day_in_week]}

//=========================================================
//
// Calculates start and end dates for DST 
//
//=========================================================
function calcDSTDates(cur_year)
	{DST_start_month = 3; start_sunday = 2
	DST_end_month = 11; end_sunday = 1
	start_date = 1
	sundays = 0
	loop_end = start_sunday * 7
	counter = 0
	while (counter <= loop_end) {
		date = start_date + counter
		jul_date = calcJday(DST_start_month, date, cur_year)
		day_name = calcDayOfWeek(jul_date, cur_year)
		if (day_name == "Sunday") {sundays = sundays + 1}
		if (sundays == start_sunday) {DST_start_date = date, counter = loop_end}
	counter++}
	sundays = 0
	loop_end = end_sunday * 7
	counter = 0
	while (counter <= loop_end) {
		date = start_date + counter
		jul_date = calcJday(DST_end_month, date, cur_year)
		day_name = calcDayOfWeek(jul_date, cur_year)
		if (day_name == "Sunday") {sundays = sundays + 1}
		if (sundays == end_sunday) {DST_end_date = date, counter = loop_end}
	counter++}
	return}

//=========================================================
//
// Truncates numeric value to specified number of places
//
//=========================================================
function setDecimal(value, places)
	{if (value < 0) {sign = "–"} else {sign = ""}
	value = Math.abs(value)
	factor = Math.pow(10, places)
	valInt = Math.round(value * factor)
	if (places == 0 && valInt == 0) {sign = ""}
	if (places == 0) {return sign + valInt}
	valStr = valInt.toString(10)
	len = valStr.length
	radix = len - places - 1
	radShift = 0
	if (radix < 0) {radShift = -radix, radix = 0}
	for (i = 0; i < radShift; i++) {valStr = "0" + valStr}
	intStr = valStr.substring(0, radix + 1)
	decStr = valStr.substring(radix + 1, len + radShift)
	valStr = sign + intStr + "." + decStr
	return valStr}

//=========================================================
//
// Converts Farenheit to Celsius
//
//=========================================================
function Far2Cel(tFar)
	{tCel = (tFar-32) * (5/9)
	return tCel}

//=========================================================
//
// Converts Celsius to Farenheit
//
//=========================================================
function Cel2Far (tCel)
	{tFar = tCel * (9/5) + 32
	return tFar}

//=========================================================
//
// Converts inches to millimeters
//
//=========================================================
function Inches2mm (inches)
	{mm = inches * 25.4
	return mm}

//=========================================================
//
// Converts millibars to inches of mercury
//
//=========================================================
function mb2inches(pressMB)
	{pressIN = pressMB/33.864
	return pressIN}
	
//=========================================================
//
// Converts inches to millibars of mercury
//
//=========================================================
function inches2mb(pressIN)
	{pressMB = pressIN * 33.864
	return pressMB}


//=========================================================
//
// Converts miles per hour to knots
//
//=========================================================
function mph2kts(speedMPH)
	{speedKTS = speedMPH*0.869
	return speedKTS}

//=========================================================
//
// Converts miles per hour to kilometers per hour
//
//=========================================================
function mph2kph(speedMPH)
	{speedKPH = speedMPH*1.609344
	return speedKPH}

//=========================================================
//
// Computes wet-bulb temperature
//
//=========================================================
function calcWetbulb(pressure_mb, temp_far, dewpoint_far)
	{temp_celsius = Far2Cel(temp_far)
	dewpoint_celsius = Far2Cel(dewpoint_far)
	tmin = Math.min(dewpoint_celsius, temp_celsius)
	tmax = Math.max(dewpoint_celsius, temp_celsius)
	vapor_pressure = 6.112 * Math.pow(10, (7.5 * dewpoint_celsius) / (237.7 + dewpoint_celsius))
	while (true)
	   	{tcur = (tmax + tmin) / 2
	   	vpcur = 6.112 * Math.pow(10, (7.5 * tcur) / (237.7 + tcur))
	   	peq = 0.00066 * (1+0.00155 * tcur) * pressure_mb * (temp_celsius - tcur)
	   	diff = peq - vpcur + vapor_pressure
	   	if (Math.abs(diff) < 0.01) break
	   	if (diff < 0) {tmax = tcur} else {tmin = tcur}}
	wetbulb_far = Cel2Far(tcur)    
	return wetbulb_far}

//=========================================================
//
// Calculates monthly precip departure
//
//=========================================================
function monthlyDepart(monthprecip, dayofmonth, monthofyear) 
	{normaltodate = 0
	i = 1
	while (i <= dayofmonth) {normaltodate = normaltodate + parseFloat(normals_records [monthofyear] [i].substring(6,9)), i++}
	departmonth = monthprecip - normaltodate
	return departmonth}

//=========================================================
//
// Calculates yearly precip departure
//
//=========================================================
function yearlyDepart(monthofyear, yearprecip, norm_month_to_date)
	{normal_prior_rain = 0
	i = 1
	while (i < monthofyear) {normal_prior_rain = normal_prior_rain + monthly_avg_rain[i], i++}
	normaltotal = normal_prior_rain + norm_month_to_date
	departyear = yearprecip - normaltotal
	return departyear} 

//=========================================================
//
// Calculates monthly snowfall departure
//
//=========================================================
function monthlySnowDepart(monthsnow, dayofmonth, monthofyear) 
	{normalsnowtodate = (monthly_avg_snow[monthofyear] / days_in_month[monthofyear]) * dayofmonth
	departsnow = monthsnow - normalsnowtodate
	return departsnow}

//=========================================================
//
// Calculates yearly snowfall departure
//
//=========================================================
function seasonSnowDepart(monthofyear, seasonsnow, norm_month_to_date)
	{i = 7
	normal_through_dec = 0
	while (i <= 12) {normal_through_dec = normal_through_dec + monthly_avg_snow[i], i++}
	if (monthofyear < 7) {i = 1, normal_prior_snow = normal_through_dec} else {i = 7, normal_prior_snow = 0}
	while (i < monthofyear) {normal_prior_snow = normal_prior_snow + monthly_avg_snow[i], i++}
	normalsnow = normal_prior_snow + norm_month_to_date
	departseason = seasonsnow - normalsnow
	return departseason} 
	
//=========================================================
//
// Computes sun time relative to local noon
//
//=========================================================
function sunTime(sunrise, sunset, time_now)
	{solar_noon = (sunrise + sunset)/2 
	suntime = solar_noon - time_now
	return suntime}

//=========================================================
//
// Calculates solar altitude angle based on lat, date, time
//
//=========================================================
function solarAltitude(sun_declination, suntime, latitude)
	{sun_hour = (15 * suntime) * degrees_to_radians
	decl = sun_declination * degrees_to_radians
	lat = latitude * degrees_to_radians
	sin_alt = (Math.cos(lat) * Math.cos(decl) * Math.cos(sun_hour)) + (Math.sin(lat) * Math.sin(decl))
	altitude_angle = Math.asin(sin_alt) * radians_to_degrees
	return altitude_angle}

//=========================================================
//
// Calculates solar azimuth angle based on lat, date, time
//
//=========================================================
function solarAzimuth(sun_declination, suntime, latitude)
	{sun_hour = (15 * suntime) * degrees_to_radians
	lat = latitude * degrees_to_radians
	decl = sun_declination * degrees_to_radians
	y_azm = (-1 * (Math.cos(sun_hour)) * Math.cos(decl) * Math.sin(lat)) + (Math.cos(lat) * Math.sin(decl))
	x_azm = Math.sin(sun_hour) * Math.cos(decl)
	azimuth_angle = Math.atan(x_azm/y_azm) * radians_to_degrees
	if (x_azm > 0 && y_azm > 0) {azimuth_angle = azimuth_angle}
	if (x_azm >= 0 && y_azm <= 0 || x_azm < 0 && y_azm < 0) {azimuth_angle = 180 + azimuth_angle}
	if (x_azm <= 0 && y_azm >= 0) {azimuth_angle = 360 + azimuth_angle}
	return azimuth_angle}

//=========================================================
//
// Calculates max possible radiation for given sun angle
//
//=========================================================
function maxSolar(solar_elevation)
	{maxradpossible = solar_constant * Math.sin(solar_elevation * degrees_to_radians)
	attenuation = maxradpossible * (solar_attenuation_factor * Math.sqrt(Math.cos(solar_elevation * degrees_to_radians) + 1))
	maxradpossible = maxradpossible - attenuation
	if (maxradpossible < 0) {maxradpossible = 0}
	return maxradpossible}

//=========================================================
//
// Computes moonrise and moonset for a given date
//
//=========================================================
function moontimes(Y, M, D, Time_Offset)
	{A5 = 0
	D5 = 0
	V0 = 0
	C = 0
	S = 0
	Rstring = ""
	Sstring = ""
	V1 = 0
	m = new Array(14)
	m[13] = 1.00021
	m[14] = 60.40974
	n = new Array
	x = new Array
	moon = 0
	moonrise = "00:-1"
	moonset = "00:-1"
	rise = ""
	set = ""
	Day = D
	Month = M
	m[M] = days_in_month[M]
	Year = Y
	mr = 13
	B5 = parseFloat(latitude)
	L5 = parseFloat(longitude)
	H = parseFloat(Time_Offset)
	Y = parseFloat(Y)
	M = parseFloat(M)
	D = parseFloat(D)
	P2 = PI_2
	DR = degrees_to_radians
	R1 = DR
	K1 = 15 * DR * 1.0027379
	P1 = Math.PI
	L5 = L5 / 360
	Z0 = H / 2
	subroutine6(Y, D, M)
	T = F + (J - 2451545)
	TT = T / 36525 + 1
	subroutine2(T, Z0, L5, DR)
	T = T + Z0
	subroutine5(T, TT, P2)
	AX = A5
	DX = D5
	T = T + 1
	subroutine5(T, TT, P2)
	AY = A5
	DY = D5
	if (AY < AX) {AY = AY + P2}
	Z1 = DR * 90.833
	S = Math.sin(B5 * DR)
	C = Math.cos(B5 * DR)
	Z = Math.cos(Z1)
	M8 = 0
	W8 = 0
	A0 = AX
	D0 = DX
	DA = AY - AX
	DD = DY - DX
	for (C0 = 0; C0 <= 23;) 
	   	{P = (C0 + 1) / 24
	   	A2 = AX + P * DA
	   	D2 = DX + P * DD
	   	subroutine3(T0, A0, A2, D0, D2, V0, K1, C0, C, S, Rstring, Z, V1, mr, P1)
	   	A0 = A2
	   	D0 = D2
	   	V0 = V2
	   	hs = A0
	   	if (rise == "") {rise = "00:-1"}
	   	if (set == "") {set = "00:-1"}
	   	if (alt < -.73) {rise = "00:-1", set = "00:-1"}
	   	alt = Math.floor(alt * 100 + .5) / 100
	   	if (alt < 0 && alt > -.73) {alt = 0}
	   	C0++}
	moon = 1
	mr = 14
	Z0 = H / 24
	subroutine6(Y, D, M)
	T = F + (J - 2451545)
	subroutine2(T, Z0, L5, DR)
	T = T + Z0
	subroutine4(T, P2)
	n[1] = A5
	n[2] = D5
	n[3] = R5
	T = T + 0.5
	subroutine4(T, P2)
	n[4] = A5
	n[5] = D5
	n[6] = R5
	T = T + 0.5
	subroutine4(T, P2)
	n[7] = A5
	n[8] = D5
	n[9] = R5
	if (n[4] <= n[1]) {n[4] = n[4] + P2}
	if (n[7] <= n[4]) {n[7] = n[7] + P2}
	Z1 = R1 * (90.567 - 41.685 / n[6])
	S = Math.sin(B5 * R1)
	C = Math.cos(B5 * R1)
	Z = Math.cos(Z1)
	M8 = 0
	W8 = 0
	A0 = n[1]
	D0 = n[2]
	for (var C0 = 0; C0 <= 23;)
	   	{P = (C0 + 1) / 24
	   	F0 = n[1]
	   	F1 = n[4]
	   	F2 = n[7]
	   	subroutine1(F1, F0, F2, P, B)
	   	A2 = F
	   	F0 = n[2]
	   	F1 = n[5]
	   	F2 = n[8]
	   	subroutine1(F1, F0, F2, P, B)
	   	D2 = F
	   	subroutine3(T0, A0, A2, D0, D2, V0, K1, C0, C, S, Rstring, Z, V1, mr, P1)
	   	A0 = A2
	   	D0 = D2
	   	V0 = V2
	   	if (ri == 1) {moonrise = rise}
	   	if (st == 1) {moonset = set}
	   	C0++}
	mrise = moonrise
	mset = moonset}

//=========================================================
function subroutine1(F1, F0, F2, P, B)
	{A = F1 - F0
	B = F2 - F1 - A
	F = F0 + P * (2 * A + B * (2 * P - 1))
	return}

//=========================================================
function subroutine2(T, Z0, L5, DR)
	{T0 = T / 36525
	S = 24110.5 + 8640184.813 * T0
	S = S + 86636.6 * Z0 + 86400 * L5
	S = S / 86400
	S = S - Math.floor(S)
	T0 = S * 360 * DR
	return}

//=========================================================	 
function subroutine3(T0, A0, A2, D0, D2, V0, K1, C0, C, S, Rstring, Z, V1, mr, P1)
	{ri = 0
	st = 0
	L0 = T0 + C0 * K1
	L2 = L0 + K1
	if (mr == 14) {if (A2 < A0) {A2 = A2 + PI_2}}
	H0 = L0 - A0
	H2 = L2 - A2
	H1 = (H2 + H0) / 2
	D1 = (D2 + D0) / 2
	if (moon == 0) {
		dxc = D1 * 57.29578 + .005
	   	dxc = Math.floor(dxc * 100) / 100; 
	   	alt = 90 - latitude + dxc;
	   	if (alt > 90) {alt = 180 - alt}}
	if (C0 == 0) {V0 = S * Math.sin(D0) + C * Math.cos(D0) * Math.cos(H0) - Z} 
	V2 = S * Math.sin(D2) + C * Math.cos(D2) * Math.cos(H2) - Z
	VS = V0 * V2
	if (VS > 0) {return}
	V1 = S * Math.sin(D1) + C * Math.cos(D1) * Math.cos(H1) - Z
	A = 2 * V2 - 4 * V1 + 2 * V0
	B = 4 * V1 - 3 * V0 - V2
	D = B * B - 4 * A * V0
	if (D < 0) {return}
	D = Math.sqrt(D)
	if (V2 > 0 && V0 < 0) {ri = 1; M8 = 1}
	if (V2 < 0 && V0 > 0) {st = 1; W8 = 1}
	E = (-B + D) / (2 * A)
	if (E > 1 || E < 0) {E = (-B - D) / (2 * A)} 
	T3 = C0 + E + 1 / 120
	H7 = H0 + E * (H2 - H0)
	N7 = -1 * Math.cos(D1) * Math.sin(H7)
	D7 = C * Math.sin(D1) - S * Math.cos(D1) * Math.cos(H7)
	AZ = Math.atan(N7 / D7) / DR
	H3 = Math.floor(T3)
	M3 = Math.floor((T3 - H3) * 60)
	if (ri == 1) {rise = convertTime(H3, M3)}
	if (st == 1) {set = convertTime(H3, M3)}
	return}

//=========================================================	 
function subroutine4(T, P2)
	{L = 0.606434 + 0.03660110129 * T
	M = 0.374897 + 0.03629164709 * T
	F = 0.259091 + 0.03674819520 * T
	D = 0.827362 + 0.03386319198 * T
	N = 0.347343 - 0.00014709391 * T
	G = 0.993126 + 0.00273777850 * T
	L = L - Math.floor(L)
	M = M - Math.floor(M)
	F = F - Math.floor(F)
	D = D - Math.floor(D)
	N = N - Math.floor(N)
	G = G - Math.floor(G)
	L = L * P2
	M = M * P2
	F = F * P2
	D = D * P2
	N = N * P2
	G = G * P2
	V = 0.39558 * Math.sin(F + N)
	V = V + 0.08200 * Math.sin(F)
	V = V + 0.03257 * Math.sin(M - F - N)
	V = V + 0.01092 * Math.sin(M + F + N)
	V = V + 0.00666 * Math.sin(M - F)
	V = V - 0.00644 * Math.sin(M + F - 2 * D + N)
	V = V - 0.00331 * Math.sin(F - 2 * D + N)
	V = V - 0.00304 * Math.sin(F - 2 * D)
	V = V - 0.00240 * Math.sin(M - F - 2 * D - N)
	V = V + 0.00226 * Math.sin(M + F)
	V = V - 0.00108 * Math.sin(M + F - 2 * D)
	V = V - 0.00079 * Math.sin(F - N)
	V = V + 0.00078 * Math.sin(F + 2 * D + N)
	U = 1 - 0.10828 * Math.cos(M)
	U = U - 0.01880 * Math.cos(M - 2 * D)
	U = U - 0.01479 * Math.cos(2 * D)
	U = U + 0.00181 * Math.cos(2 * M - 2 * D)
	U = U - 0.00147 * Math.cos(2 * M)
	U = U - 0.00105 * Math.cos(2 * D - G)
	U = U - 0.00075 * Math.cos(M - 2 * D + G)
	W = 0.10478 * Math.sin(M)
	W = W - 0.04105 * Math.sin( 2 * F + 2 * N)
	W = W - 0.02130 * Math.sin(M - 2 * D)
	W = W - 0.01779 * Math.sin(2 * F + N)
	W = W + 0.01774 * Math.sin(N)
	W = W + 0.00987 * Math.sin(2 * D)
	W = W - 0.00338 * Math.sin(M - 2 * F - 2 * N)
	W = W - 0.00309 *Math.sin(G)
	W = W - 0.00190 * Math.sin(2 * F)
	W = W - 0.00144 * Math.sin(M + N)
	W = W - 0.00144 * Math.sin(M - 2 * F - N)
	W = W - 0.00113 * Math.sin(M + 2 * F + 2 * N)
	W = W - 0.00094 * Math.sin(M - 2 * D + G)
	W = W - 0.00092 * Math.sin(2 * M - 2 * D)
	S = W / Math.sqrt(U - V * V)
	A5 = L + Math.atan(S / Math.sqrt(1 - S * S))
	S = V / Math.sqrt(U)
	D5 = Math.atan(S / Math.sqrt(1 - S * S))
	R5 = 60.40974 * Math.sqrt(U)
	return}

//=========================================================	
function subroutine5(T, TT, P2)
	{L = .779072 + .00273790931 * T
	G = .993126 + .0027377785 * T
	L = L - Math.floor(L)
	G = G - Math.floor(G)
	L = L * P2
	G = G * P2
	V = .39785 * Math.sin(L)
	V = V - .01000 * Math.sin(L - G)
	V = V + .00333 * Math.sin(L + G)
	V = V - .00021 * TT * Math.sin(L)
	U = 1 - .03349 * Math.cos(G)
	U = U - .00014 * Math.cos(2 * L)
	U = U + .00008 * Math.cos(L)
	W = -.00010 - .04129 * Math.sin(2 * L)
	W = W + .03211 * Math.sin(G)
	W = W + .00104 * Math.sin(2 * L - G)
	W = W - .00035 * Math.sin(2 * L + G)
	W = W - .00008 * TT * Math.sin(G)
	return}

//=========================================================	
function subroutine6(Y, D, M)
	{G = 1
	if (Y < 1583) {G = 0}
	D1 = Math.floor(D)
	F = D - D1 - .5
	J = -1 * Math.floor(7 * (Math.floor((M + 9) / 12) + Y) / 4)
	if (G != 0) {S = (M - 9)
	   if (S < 0) {S = -1}
	   else if (S >= 0) {S = 1}
	   A = Math.abs(M - 9)
	   J3 = Math.floor(Y + S * Math.floor(A / 7))
	   J3 = -1 *Math.floor((Math.floor(J3 / 100) + 1) * 3 / 4)}
	J = J + Math.floor(275 * M / 9) + D1 + G * J3
	J = J + 1721027 + 2 * G + 367 * Y
	if (F < 0) {F = F + 1;  J = J - 1}
	return}

//=========================================================	
function convertTime(H3, M3)
	{if (H3 < 10) {H3 = "0" + H3}
	if (M3 < 10) {M3 = "0" + M3}
	timestring = H3 + ":" + M3
	return timestring}
	
//=========================================================
//
// Compute current phase and % illumination of the moon
//
//=========================================================
function calcMoonPhase(moon_year, moon_month, moon_day, moon_hour)
	{moondate = new Date(moon_year, moon_month - 1, moon_day, moon_hour, 00)
	moonmsec = moondate.getTime()
	GMT_time = moonmsec + (moondate.getTimezoneOffset() * 60 * 1000)
	startDate = new Date(1989, 11, 31, 00, 00)
	startMsec = startDate.getTime()
	dmsec = GMT_time - startMsec
	Dmoon  = ((((dmsec /1000) /60) /60) /24)
	Nmoon = Dmoon * (360 / 365.249)
	if (Nmoon > 0) {Nmoon = Nmoon - Math.floor(Math.abs(Nmoon / 360)) * 360} else {Nmoon = Nmoon + (360 + Math.floor(Math.abs(Nmoon / 360)) * 360)}
	Mo = Nmoon + 279.403303 - 282.768422
	if(Mo < 0) {Mo = Mo + 360}
	Ec = 360 * .016713 * Math.sin(Mo * degrees_to_radians) / Math.PI
	lamda = Nmoon + Ec + 279.403303
	if (lamda > 360) {lamda = lamda - 360}
	Lmoon = 13.1763966 * Dmoon + 318.351648
	if (Lmoon > 0) {Lmoon = Lmoon - Math.floor(Math.abs(Lmoon / 360)) * 360} else {Lmoon = Lmoon + (360 + Math.floor(Math.abs(Lmoon / 360)) * 360)};
	Mm = Lmoon - .1114041 * Dmoon - 36.34041
	if (Mm > 0) {Mm = Mm - Math.floor(Math.abs(Mm / 360)) * 360} else {Mm = Mm + (360 + Math.floor(Math.abs(Mm / 360)) * 360)}
	N65 = 318.510107 - .0529539 * Dmoon
	if (N65 > 0) {N65 = N65 - Math.floor(Math.abs(N65 / 360)) * 360} else {N65 = N65 + (360 + Math.floor(Math.abs(N65 / 360)) * 360)}
	Ev = 1.2739 * Math.sin((2 * (Lmoon - lamda) - Mm) * degrees_to_radians)
	Ae = .1858 * Math.sin(Mo * degrees_to_radians)
	A3 = .37 * Math.sin(Mo * degrees_to_radians)
	Mmp = Mm + Ev - Ae - A3
	Ec = 6.2886 * Math.sin(Mmp * degrees_to_radians)
	A4 = .214 * Math.sin((2 * Mmp) * degrees_to_radians)
	lp = Lmoon + Ev + Ec - Ae + A4
	Vmoon = .6583 * Math.sin((2 * (lp - lamda)) * degrees_to_radians)
	lpp = lp + Vmoon
	D67 = lpp - lamda
	float_percent_visible = .5 * (1 - Math.cos(D67 * degrees_to_radians)) * 100
	percent_visible = Math.round(float_percent_visible)
	trend = (Math.sin(D67 * degrees_to_radians))
	if(percent_visible == 0) {MoonPhase = "New Moon"}
	if(percent_visible == 100) {MoonPhase = "Full Moon"}
	if((percent_visible > 40) && (percent_visible < 60) && (trend > 0)) {MoonPhase = "First Quarter"}
	if((percent_visible > 40) && (percent_visible < 60) && (trend < 0)) {MoonPhase = "Last Quarter"}             
	if((percent_visible >= 1) && (percent_visible <= 40) && (trend > 0)) {MoonPhase = "Waxing Crescent"}
	if((percent_visible >= 1) && (percent_visible <= 40) && (trend < 0)) {MoonPhase = "Waning Crescent"}
	if((percent_visible >= 60) && (percent_visible <= 99) && (trend > 0)) {MoonPhase = "Waxing Gibbous"}
	if((percent_visible >= 60) && (percent_visible <= 99) && (trend < 0)) {MoonPhase = "Waning Gibbous"}
	return MoonPhase}

//=========================================================
//
// Computes sunrise and sunset for a given date
//
//=========================================================
function sun_rise_set(Sun_Day, Sun_Month, Sun_Year, Event) 
{
	newJD = calcJD(Sun_Year, Sun_Month+1, Sun_Day)
	K = degrees_to_radians
	sh = Math.sin(-K*0.8333)
	RISE = false
	SET = false
	if (Event == "Rise") {Start_Hour = 11} // earliest UTC sunrise of year
	if (Event == "Set") {Start_Hour = 22} // earliest UTC sunset of year
	Sun_Hour = Start_Hour
	while (Sun_Hour <= Start_Hour + 12) // Max diff between solstices for rise or set
		{jd=JulDay (Sun_Day, Sun_Month, Sun_Year, Sun_Hour)
		dec = sunDec(jd)
		gha = computeGHA (Sun_Day, Sun_Month, Sun_Year, Sun_Hour)	
		Y0 = Math.sin(K*computeHeight(dec, latitude, longitude, gha)) - sh
		gha = computeGHA (Sun_Day, Sun_Month, Sun_Year, Sun_Hour + 1.0)
		yPlus = Math.sin(K*computeHeight(dec, latitude, longitude, gha)) - sh
		gha = computeGHA (Sun_Day, Sun_Month, Sun_Year, Sun_Hour - 1.0)
		yMinus = Math.sin(K*computeHeight(dec, latitude, longitude, gha)) - sh
		QUAD(yMinus,yPlus)
		switch (NZ){
			case 1:	if (yMinus < 0.0) {UTRISE = Sun_Hour + zero1; RISE = true}
				else {UTSET = Sun_Hour + zero1; SET = true}
				break
	
			case 2:	if (YE < 0.0) {UTRISE = Sun_Hour + zero2; UTSET = Sun_Hour + zero1}
				else {UTRISE = Sun_Hour + zero1; UTSET = Sun_Hour + zero2}
				RISE = true
				SET = true
				break}
	if (Event == "Rise" && RISE == true) {return}
	if (Event == "Set" && SET == true) {return}	
	Sun_Hour++}}

//=========================================================
function QUAD(yMinus, yPlus)
	{NZ = 0
	A = 0.5 * (yMinus + yPlus) - Y0
	B = 0.5 * (yPlus - yMinus)
	C = Y0
	XE = -B / (2 * A)
	YE = (A * XE + B)* XE + C
	DIS = B * B - 4.0 * A * C
	if (DIS>=0) 
		{DX = 0.5 * Math.sqrt(DIS) / Math.abs(A)
		zero1 = XE - DX
		zero2 = XE + DX
		if (Math.abs(zero1) <= 1.0) NZ = NZ + 1
		if (Math.abs(zero2) <= 1.0) NZ = NZ + 1
		if (zero1 < -1.0) zero1 = zero2}}

//=========================================================	 
function computeHeight(de, la, lo, gh) 
	{lat_K = la * (degrees_to_radians)
	dec_K = de * (degrees_to_radians)
	x = Number(gh) + Number(lo)
	sinHeight = Math.sin(dec_K) * Math.sin(lat_K) + Math.cos(dec_K) * Math.cos(lat_K) * Math.cos(K*x)	
	return Math.asin(sinHeight) / K}

//=========================================================	 
function computeGHA(T, M, J, STD) 
	{N = 365 * J + T + 31 * M - 46	 
	if (M < 3) {N = N + Math.floor((J-1)/4)} else {N = N - Math.floor(0.4 * M + 2.3) + Math.floor(J/4)}		 
	P = STD / 24.0
	X = (P + N - 7.22449E5) * 0.98564734 + 279.306
	X = X * (degrees_to_radians)
	XX = -104.55 * Math.sin(X) - 429.266 * Math.cos(X) + 595.63 * Math.sin(2.0 * X) - 2.283 * Math.cos(2.0 * X)
	XX = XX + 4.6 * Math.sin(3.0 * X) + 18.7333 * Math.cos(3.0 * X)
	XX = XX - 13.2 * Math.sin(4.0 * X) - Math.cos(5.0 * X) - Math.sin(5.0 * X) / 3.0 + 0.5 * Math.sin(6.0 * X) + 0.231
	XX = XX / 240.0 + 360.0 * (P + 0.5)
	if (XX > 360.0) XX = XX - 360.0
	return XX}

//=========================================================	 
function JulDay(date, month, year, UT)
	{
	if (month <= 2) {month = month + 12, year = year - 1}
	B = Math.floor(year / 400.0) - Math.floor(year / 100.0)  + Math.floor(year / 4.0)
	A = 365.0 * year - 679004.0
	jd = A + B + Math.floor(30.6001 * (month + 1)) + date + UT / 24.0
	jd = jd + 2400000.5
	return jd}

//=========================================================	 
function sunDec(jd) 
	{cos_eps = 0.917482
	sin_eps = 0.397778				
	T = (jd - 2451545.0) / 36525.0
	M = PI_2 * frac(0.993133 + 99.997361 * T)
	DL = 6893.0 * Math.sin(M) + 72.0 * Math.sin(2.0 * M)
	L = PI_2 * frac(0.7859453 + M / PI_2 + (6191.2 * T + DL) / 1296000)
	SL = Math.sin(L)
	X = Math.cos(L)
	Y = cos_eps * SL
	Z = sin_eps * SL
	R = Math.sqrt(1.0 - Z * Z)
	dec = (360.0 / PI_2) * Math.atan(Z / R)
	return dec}

//=========================================================	 
function frac(X) 
	{X = X - Math.floor(X)
	if (X < 0) X = X + 1.0
	return X}

//=========================================================
//
// Function to display popup windows for individual images
//
//=========================================================
	function popUp(URL) {
		URL = "http://gretnawx.net/" + URL
		today = new Date()
		id = today.getTime()
		eval("page"+id+"=window.open(URL,'"+id+"','toolbar=0,scrollbars=0,location=0,statusbar=0,menubar=0,resizable=0,width=500,height=420,top=50,left=50')")}


	// ===================================================================
// Author: Matt Kruse <matt@mattkruse.com>
// WWW: http://www.mattkruse.com/
//
// NOTICE: You may use this code for any purpose, commercial or
// private, without any further permission from the author. You may
// remove this notice from your final code if you wish, however it is
// appreciated by the author if at least my web site address is kept.
//
// You may *NOT* re-distribute this code in any way except through its
// use. That means, you can include it in your product, or your web
// site, or any other form where the code is actually being used. You
// may not put the plain javascript up on your site for download or
// include it in your javascript libraries for download. 
// If you wish to share this code with others, please just point them
// to the URL instead.
// Please DO NOT link directly to my .js files from your site. Copy
// the files to your server and use them there. Thank you.
// ===================================================================

// HISTORY
// ------------------------------------------------------------------
// May 17, 2003: Fixed bug in parseDate() for dates <1970
// March 11, 2003: Added parseDate() function
// March 11, 2003: Added "NNN" formatting option. Doesn't match up
//                 perfectly with SimpleDateFormat formats, but 
//                 backwards-compatability was required.

// ------------------------------------------------------------------
// These functions use the same 'format' strings as the 
// java.text.SimpleDateFormat class, with minor exceptions.
// The format string consists of the following abbreviations:
// 
// Field        | Full Form          | Short Form
// -------------+--------------------+-----------------------
// Year         | yyyy (4 digits)    | yy (2 digits), y (2 or 4 digits)
// Month        | MMM (name or abbr.)| MM (2 digits), M (1 or 2 digits)
//              | NNN (abbr.)        |
// Day of Month | dd (2 digits)      | d (1 or 2 digits)
// Day of Week  | EE (name)          | E (abbr)
// Hour (1-12)  | hh (2 digits)      | h (1 or 2 digits)
// Hour (0-23)  | HH (2 digits)      | H (1 or 2 digits)
// Hour (0-11)  | KK (2 digits)      | K (1 or 2 digits)
// Hour (1-24)  | kk (2 digits)      | k (1 or 2 digits)
// Minute       | mm (2 digits)      | m (1 or 2 digits)
// Second       | ss (2 digits)      | s (1 or 2 digits)
// AM/PM        | a                  |
//
// NOTE THE DIFFERENCE BETWEEN MM and mm! Month=MM, not mm!
// Examples:
//  "MMM d, y" matches: January 01, 2000
//                      Dec 1, 1900
//                      Nov 20, 00
//  "M/d/yy"   matches: 01/20/00
//                      9/2/00
//  "MMM dd, yyyy hh:mm:ssa" matches: "January 01, 2000 12:30:45AM"
// ------------------------------------------------------------------

var MONTH_NAMES=new Array('January','February','March','April','May','June','July','August','September','October','November','December','Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec');
var DAY_NAMES=new Array('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sun','Mon','Tue','Wed','Thu','Fri','Sat');
function LZ(x) {return(x<0||x>9?"":"0")+x}

// ------------------------------------------------------------------
// isDate ( date_string, format_string )
// Returns true if date string matches format of format string and
// is a valid date. Else returns false.
// It is recommended that you trim whitespace around the value before
// passing it to this function, as whitespace is NOT ignored!
// ------------------------------------------------------------------
function isDate(val,format) {
	var date=getDateFromFormat(val,format);
	if (date==0) { return false; }
	return true;
	}

// -------------------------------------------------------------------
// compareDates(date1,date1format,date2,date2format)
//   Compare two date strings to see which is greater.
//   Returns:
//   1 if date1 is greater than date2
//   0 if date2 is greater than date1 of if they are the same
//  -1 if either of the dates is in an invalid format
// -------------------------------------------------------------------
function compareDates(date1,dateformat1,date2,dateformat2) {
	var d1=getDateFromFormat(date1,dateformat1);
	var d2=getDateFromFormat(date2,dateformat2);
	if (d1==0 || d2==0) {
		return -1;
		}
	else if (d1 > d2) {
		return 1;
		}
	return 0;
	}

// ------------------------------------------------------------------
// formatDate (date_object, format)
// Returns a date in the output format specified.
// The format string uses the same abbreviations as in getDateFromFormat()
// ------------------------------------------------------------------
function formatDate(date,format) {
	format=format+"";
	var result="";
	var i_format=0;
	var c="";
	var token="";
	var y=date.getYear()+"";
	var M=date.getMonth()+1;
	var d=date.getDate();
	var E=date.getDay();
	var H=date.getHours();
	var m=date.getMinutes();
	var s=date.getSeconds();
	var yyyy,yy,MMM,MM,dd,hh,h,mm,ss,ampm,HH,H,KK,K,kk,k;
	// Convert real date parts into formatted versions
	var value=new Object();
	if (y.length < 4) {y=""+(y-0+1900);}
	value["y"]=""+y;
	value["yyyy"]=y;
	value["yy"]=y.substring(2,4);
	value["M"]=M;
	value["MM"]=LZ(M);
	value["MMM"]=MONTH_NAMES[M-1];
	value["NNN"]=MONTH_NAMES[M+11];
	value["d"]=d;
	value["dd"]=LZ(d);
	value["E"]=DAY_NAMES[E+7];
	value["EE"]=DAY_NAMES[E];
	value["H"]=H;
	value["HH"]=LZ(H);
	if (H==0){value["h"]=12;}
	else if (H>12){value["h"]=H-12;}
	else {value["h"]=H;}
	value["hh"]=LZ(value["h"]);
	if (H>11){value["K"]=H-12;} else {value["K"]=H;}
	value["k"]=H+1;
	value["KK"]=LZ(value["K"]);
	value["kk"]=LZ(value["k"]);
	if (H > 11) { value["a"]="pm"; }
	else { value["a"]="am"; }
	value["m"]=m;
	value["mm"]=LZ(m);
	value["s"]=s;
	value["ss"]=LZ(s);
	while (i_format < format.length) {
		c=format.charAt(i_format);
		token="";
		while ((format.charAt(i_format)==c) && (i_format < format.length)) {
			token += format.charAt(i_format++);
			}
		if (value[token] != null) { result=result + value[token]; }
		else { result=result + token; }
		}
	return result;
	}
	
// ------------------------------------------------------------------
// Utility functions for parsing in getDateFromFormat()
// ------------------------------------------------------------------
function _isInteger(val) {
	var digits="1234567890";
	for (var i=0; i < val.length; i++) {
		if (digits.indexOf(val.charAt(i))==-1) { return false; }
		}
	return true;
	}
function _getInt(str,i,minlength,maxlength) {
	for (var x=maxlength; x>=minlength; x--) {
		var token=str.substring(i,i+x);
		if (token.length < minlength) { return null; }
		if (_isInteger(token)) { return token; }
		}
	return null;
	}
	
// ------------------------------------------------------------------
// getDateFromFormat( date_string , format_string )
//
// This function takes a date string and a format string. It matches
// If the date string matches the format string, it returns the 
// getTime() of the date. If it does not match, it returns 0.
// ------------------------------------------------------------------
function getDateFromFormat(val,format) {
	val=val+"";
	format=format+"";
	var i_val=0;
	var i_format=0;
	var c="";
	var token="";
	var token2="";
	var x,y;
	var now=new Date();
	var year=now.getYear();
	var month=now.getMonth()+1;
	var date=1;
	var hh=now.getHours();
	var mm=now.getMinutes();
	var ss=now.getSeconds();
	var ampm="";
	
	while (i_format < format.length) {
		// Get next token from format string
		c=format.charAt(i_format);
		token="";
		while ((format.charAt(i_format)==c) && (i_format < format.length)) {
			token += format.charAt(i_format++);
			}
		// Extract contents of value based on format token
		if (token=="yyyy" || token=="yy" || token=="y") {
			if (token=="yyyy") { x=4;y=4; }
			if (token=="yy")   { x=2;y=2; }
			if (token=="y")    { x=2;y=4; }
			year=_getInt(val,i_val,x,y);
			if (year==null) { return 0; }
			i_val += year.length;
			if (year.length==2) {
				if (year > 70) { year=1900+(year-0); }
				else { year=2000+(year-0); }
				}
			}
		else if (token=="MMM"||token=="NNN"){
			month=0;
			for (var i=0; i<MONTH_NAMES.length; i++) {
				var month_name=MONTH_NAMES[i];
				if (val.substring(i_val,i_val+month_name.length).toLowerCase()==month_name.toLowerCase()) {
					if (token=="MMM"||(token=="NNN"&&i>11)) {
						month=i+1;
						if (month>12) { month -= 12; }
						i_val += month_name.length;
						break;
						}
					}
				}
			if ((month < 1)||(month>12)){return 0;}
			}
		else if (token=="EE"||token=="E"){
			for (var i=0; i<DAY_NAMES.length; i++) {
				var day_name=DAY_NAMES[i];
				if (val.substring(i_val,i_val+day_name.length).toLowerCase()==day_name.toLowerCase()) {
					i_val += day_name.length;
					break;
					}
				}
			}
		else if (token=="MM"||token=="M") {
			month=_getInt(val,i_val,token.length,2);
			if(month==null||(month<1)||(month>12)){return 0;}
			i_val+=month.length;}
		else if (token=="dd"||token=="d") {
			date=_getInt(val,i_val,token.length,2);
			if(date==null||(date<1)||(date>31)){return 0;}
			i_val+=date.length;}
		else if (token=="hh"||token=="h") {
			hh=_getInt(val,i_val,token.length,2);
			if(hh==null||(hh<1)||(hh>12)){return 0;}
			i_val+=hh.length;}
		else if (token=="HH"||token=="H") {
			hh=_getInt(val,i_val,token.length,2);
			if(hh==null||(hh<0)||(hh>23)){return 0;}
			i_val+=hh.length;}
		else if (token=="KK"||token=="K") {
			hh=_getInt(val,i_val,token.length,2);
			if(hh==null||(hh<0)||(hh>11)){return 0;}
			i_val+=hh.length;}
		else if (token=="kk"||token=="k") {
			hh=_getInt(val,i_val,token.length,2);
			if(hh==null||(hh<1)||(hh>24)){return 0;}
			i_val+=hh.length;hh--;}
		else if (token=="mm"||token=="m") {
			mm=_getInt(val,i_val,token.length,2);
			if(mm==null||(mm<0)||(mm>59)){return 0;}
			i_val+=mm.length;}
		else if (token=="ss"||token=="s") {
			ss=_getInt(val,i_val,token.length,2);
			if(ss==null||(ss<0)||(ss>59)){return 0;}
			i_val+=ss.length;}
		else if (token=="a") {
			if (val.substring(i_val,i_val+2).toLowerCase()=="am") {ampm="AM";}
			else if (val.substring(i_val,i_val+2).toLowerCase()=="pm") {ampm="PM";}
			else {return 0;}
			i_val+=2;}
		else {
			if (val.substring(i_val,i_val+token.length)!=token) {return 0;}
			else {i_val+=token.length;}
			}
		}
	// If there are any trailing characters left in the value, it doesn't match
	if (i_val != val.length) { return 0; }
	// Is date valid for month?
	if (month==2) {
		// Check for leap year
		if ( ( (year%4==0)&&(year%100 != 0) ) || (year%400==0) ) { // leap year
			if (date > 29){ return 0; }
			}
		else { if (date > 28) { return 0; } }
		}
	if ((month==4)||(month==6)||(month==9)||(month==11)) {
		if (date > 30) { return 0; }
		}
	// Correct hours value
	if (hh<12 && ampm=="PM") { hh=hh-0+12; }
	else if (hh>11 && ampm=="AM") { hh-=12; }
	
	var newdate=new Date(year,month-1,date,hh,mm,ss);

//	return newdate.getTime();
//	alert(newdate.getHours())
	return newdate;
	}

