function setDecimal(value, places)
//*************************************************************************************************
//Does rounding of numbers to desired number of places after decimal point
//*************************************************************************************************
{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}

function Far2Cel(tFar)
//*************************************************************************************************
//Converts degrees F to degrees C
//*************************************************************************************************
{tCel = (tFar-32) * (5/9)
return tCel}

function Cel2Far (tCel)
//*************************************************************************************************
//Converts degrees C to degrees F
//*************************************************************************************************
{tFar = tCel * (9/5) + 32
return tFar}

function Inches2mm (inches)
//*************************************************************************************************
//Converts inches of precipitation to mm
//*************************************************************************************************
{mm = inches * 25.4
return mm}

function mph2kts (windmph)
//*************************************************************************************************
//Converts windspeed from mph to kilometers per hour
//*************************************************************************************************
{windkts = windmph * 0.8689762419
return windkts}

function mb2inches(pressMB)
//*************************************************************************************************
//Converts pressure from millibars to inches of mercury
//*************************************************************************************************
{pressIN = pressMB/33.865
return pressIN}

function calcMixRatio(pressure_mb, dewpoint_far, elevation_feet)
//*************************************************************************************************
//Computes mixing ratio (g/kg) from pressure (mb), temp (Far), dewPt (Far) and station elev (Ft)
//***********************************************************************************************
{dewpoint_celsius = Far2Cel(dewpoint_far)
elevation_kilometers = (elevation_feet/3.28) / 1000
station_pressure = pressure_mb * Math.pow(2.71828, -elevation_kilometers / 8.5)
vapor_pressure = 6.112 * Math.pow(10, (7.5 * dewpoint_celsius) / (237.7 + dewpoint_celsius))
mix_ratio = 621.97 * (vapor_pressure/(station_pressure - vapor_pressure))
return mix_ratio}

function calcWetbulb(pressure_mb, temp_far, dewpoint_far)
//*************************************************************************************************
//Computes wet bulb temperature (Far) from pressure (mb), temp (Far), and 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}

function monthlyDepart(monthprecip, dayofmonth, monthofyear) 
//*************************************************************************************************
//Calculates departure from monthly normal precip for any given day of the month
//*************************************************************************************************
{normaltodate = (monthly_avg_rain[monthofyear] / days_in_month[monthofyear]) * dayofmonth
departmonth = monthprecip - normaltodate
return departmonth}

function yearlyDepart(monthofyear, yearprecip, norm_month_to_date)
//*************************************************************************************************
//Calculates departure from yearly normal precip for any given day of the year
//*************************************************************************************************
{   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} 

function monthlySnowDepart(monthsnow, dayofmonth, monthofyear) 
//*************************************************************************************************
//Calculates departure from monthly normal snowfall for any given day of the month
//*************************************************************************************************
{normalsnowtodate = (monthly_avg_snow[monthofyear] / days_in_month[monthofyear]) * dayofmonth
departsnow = monthsnow - normalsnowtodate
return departsnow}

function seasonSnowDepart(monthofyear, seasonsnow, norm_month_to_date)
//*************************************************************************************************
//Calculates departure from yearly normal snowfall for any given day of the year
//*************************************************************************************************
{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} 

function textMonth(numeric_month)
//*************************************************************************************************
//Calculates text month from numeric month
//*************************************************************************************************
{return text_month[numeric_month]}

function LeapYear(current_year)
//*************************************************************************************************
//Calculates Julian day of the current year
//*************************************************************************************************
{a = current_year / 4
aa = Math.floor(a)
if (a != aa) {return}
b = current_year / 100
bb = Math.floor(b)
a = current_year / 400
aa = Math.floor(a)
if (b == bb) {if (a != aa) {return}}
b = current_year / 1000
bb = Math.floor(b)
a = current_year / 4000
aa = Math.floor(a)
if (b == bb) {if (a == aa) {return}}
days_in_month[2] = 29
return}

function calcJday(current_month, current_day, current_year)
//*************************************************************************************************
//Calculates Julian day of the current year
//*************************************************************************************************
{LeapYear (current_year)
i = 1
prior_days = 0
while (i < current_month) {prior_days = prior_days + days_in_month[i], i++}
Jday = prior_days + current_day
return Jday}



function sunTime(sunrise, sunset, time)
//*************************************************************************************************
//Calculates time relative to local solar noon
//*************************************************************************************************
{solar_noon = (sunrise + sunset)/2 
suntime = (solar_noon - time)/60
return suntime}

function solarAltitude(Julian_day, suntime, latitude)
//*************************************************************************************************
//Calculates solar elevation angle for given hour, minute, and day of the year
//*************************************************************************************************
{hour = (15 * suntime) * degrees_to_radians
decl = 23.45 * Math.sin((Julian_day + solar_zero_offset) * (360/365) * degrees_to_radians)
decl = decl * degrees_to_radians
lat = latitude * degrees_to_radians
sin_alt = (Math.cos(lat) * Math.cos(decl) * Math.cos(hour)) + (Math.sin(lat) * Math.sin(decl))
altitude_angle = Math.asin(sin_alt) * radians_to_degrees
return altitude_angle}

function solarAzimuth(Julian_day, suntime, latitude)
//*************************************************************************************************
//Calculates solar azimuth angle for given hour, minute, and day of the year
//*************************************************************************************************
{hour = (15 * suntime) * degrees_to_radians
decl = 23.5 * Math.sin((Julian_day + solar_zero_offset) * (360/365) * degrees_to_radians)
decl = decl * degrees_to_radians
lat = latitude * degrees_to_radians
y_azm = (-1 * (Math.cos(hour)) * Math.cos(decl) * Math.sin(lat)) + (Math.cos(lat) * Math.sin(decl))
x_azm = Math.sin(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}

function maxSolar(solar_elevation)
//*************************************************************************************************
//Calculates maximum expected solar radiation for given hour, minute, and day of the year
//*************************************************************************************************
{maxradpossible = solar_constant * Math.sin(solar_elevation * degrees_to_radians)
attenuation = maxradpossible * attenuation_factor * Math.cos(solar_elevation * degrees_to_radians)
maxradpossible = maxradpossible - attenuation
if (maxradpossible < 0) {maxradpossible = 0}
return maxradpossible}

//*************************************************************************************************
//Computes moonrise and moonset times for a given lat/lon/day/month/year
//*************************************************************************************************
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

function moontimes(B5, L5, Y, M, D)
{moonrise = "00:-1"
moonset = "00:-1"
H = 6
if (M > 4 && M < 10) {H = 5}
if (M == 4 && D >= DST_start[Y]) {H = 5}
if (M == 10 && D < DST_end[Y]) {H = 5}
rise = ""
set = ""
Day = D
Month = M
m[M] = days_in_month[M]
Year = Y
Lat = B5
Long = L5
mr = 13
B5 = parseFloat(B5)
L5 = parseFloat(L5)
H = parseFloat(H)
Y = parseFloat(Y)
M = parseFloat(M)
D = parseFloat(D)
P2 = 2*pi
DR = pi / 180
R1 = DR
K1 = 15 * DR * 1.0027379
P1 = 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(var 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 + 2 * pi}}
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 - Lat + 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)
{M4 = M3
H3 = String(H3)
M3 = String(M3)
if (H3 < 10) {H3 = "0" + H3}
if (M4 < 10) {M3 = "0" + M3}
timestring = H3 + ":" + M3
return timestring}
