// JScript File

//requires vector.js
//requires iss.js
//requires math.js


/* Flow control flag definitions */
var ALL_FLAGS = -1;
var SGP_INITIALIZED_FLAG  = 0x000001;	/* not used */
var SGP4_INITIALIZED_FLAG = 0x000002;
var SDP4_INITIALIZED_FLAG = 0x000004;
var SGP8_INITIALIZED_FLAG = 0x000008;	/* not used */
var SDP8_INITIALIZED_FLAG = 0x000010;	/* not used */
var SIMPLE_FLAG       		= 0x000020;
var DEEP_SPACE_EPHEM_FLAG = 0x000040;
var LUNAR_TERMS_DONE_FLAG = 0x000080;
var NEW_EPHEMERIS_FLAG    = 0x000100;	/* not used */
var DO_LOOP_FLAG          = 0x000200;
var RESONANCE_FLAG        = 0x000400;
var SYNCHRONOUS_FLAG      = 0x000800;
var EPOCH_RESTART_FLAG    = 0x001000;
var VISIBLE_FLAG          = 0x002000;
var SAT_ECLIPSED_FLAG     = 0x004000;

var Flags = 0;

/* Two-line-element satellite orbital data
   structure used directly by the SGP4/SDP4 code. */
function tle_t() {
	this.epoch=0;
	this.xndt2o=0;
	this.xndd6o=0;
	this.bstar=0;
	this.xincl=0;
	this.xnodeo=0;
	this.eo=0;
	this.omegao=0;
	this.xmo=0;
	this.xno=0;
	this.catnr=0;
	this.elset=0;
	this.revnum=0;
	this.sat_name = new String;
	this.idesg = new String;
	
	this.select_ephemeris = function ()
	{
		/* Selects the apropriate ephemeris type to be used */
		/* for predictions according to the data in the TLE */
		/* It also processes values in the tle set so that  */
		/* they are apropriate for the sgp4/sdp4 routines   */
	
		var ao, xnodp, dd1, dd2, delo, temp, a1, del1, r1;
	
		/* Preprocess tle set */
		this.xnodeo *= deg2rad;
		this.omegao *= deg2rad;
		this.xmo *= deg2rad;
		this.xincl *= deg2rad;
		temp = twopi / xmnpda / xmnpda;
		this.xno = this.xno * temp * xmnpda;
		this.xndt2o *= temp;
		this.xndd6o = this.xndd6o * temp / xmnpda;
		this.bstar /= ae;
	
		/* Period > 225 minutes is deep space */
		dd1 = (xke / this.xno);
		dd2 = tothrd;
		a1 = Math.pow(dd1,dd2);
		r1 = Math.cos(this.xincl);
		dd1 = (1.0 - this.eo * this.eo);
		temp = ck2 * 1.5 *(r1 * r1 * 3.0 - 1.0) / Math.pow(dd1,1.5);
		del1 = temp / (a1 * a1);
		ao = a1 * (1.0 - del1 * (tothrd * 0.5 + del1 * (del1 * 1.654320987654321 + 1.0) ) );
		delo = temp / (ao * ao);
		xnodp = this.xno / (delo + 1.0);

		/* Select a deep-space/near-earth ephemeris */
		if(twopi/xnodp/xmnpda >= 0.15625)
			SetFlag(DEEP_SPACE_EPHEM_FLAG);
		else
			ClearFlag(DEEP_SPACE_EPHEM_FLAG);
	}
}

/* Geodetic position structure used by SGP4/SDP4 code. */
function geodetic_t(that)
{
	if(that){
		this.lat = that.lat;
		this.lon = that.lon;
		this.alt = that.alt;
		this.theta = that.theta; /* double */
	}
	else {
		this.lat = 0;
		this.lon = 0;
		this.alt = 0;
		this.theta = 0; /* double */
	}
}

function sat_t()
{
	this.name = new String; /* String */
	this.catnum; /* long */
	this.setnum; /* long */
	this.designator = new String; /* String */
	this.year; /* int */
	this.refepoch; /* double */
	this.incl; /* double */
	this.raan; /* double */
	this.eccn; /* double */
	this.argper; /* double */
	this.meanan; /* double */
	this.meanmo; /* double */
	this.drag; /* double */
	this.nddot6; /* double */
	this.bstar; /* double */
	this.orbitnum; /* long */
	
	this.loadTLE = function (string) {
		var temp = new Array();
		var i, cur, tempnum;

		temp = string.split("\n");
		this.name = temp[0];

		this.catnum = Number(temp[1].substring(2,7) );
		this.designator = temp[1].substring(9,17);
		this.year = Number(temp[1].substring(18,20) );
		this.refepoch = Number(temp[1].substring(20,32) );
		this.drag = Number(temp[1].substring(33,43) );
		tempnum = 1.0e-5 * Number(temp[1].substring(44,50) );
		this.nddot6 = tempnum / Math.pow(10.0,(temp[1].substring(51, 52)-'0'));

		tempnum = 1.0e-5 * Number(temp[1].substring(53,59) );
		this.bstar = tempnum / Math.pow(10.0,(temp[1].substring(60, 61)-'0') );
		this.setnum = Number(temp[1].substring(64,68) );

		this.incl = Number(temp[2].substring(8,16) );
		this.raan = Number(temp[2].substring(17,25) );
		this.eccn = 1.0e-07 * Number(temp[2].substring(26,33) );
		this.argper = Number(temp[2].substring(34,42) );
		this.meanan = Number(temp[2].substring(43,51) );
		this.meanmo = Number(temp[2].substring(52,63) );
		this.orbitnum = Number(temp[2].substring(63,68) );
	}
}

function Satellite() {
	this.sat = new sat_t();

	this.tle = new tle_t(); //2-line Element
	this.sat_geodetic = new geodetic_t(); // location

	
	/* private data */
	/* Satellite position and velocity vectors */		
	this.vel = new vector_t();
	this.vel.name = "velocity";
	this.pos = new vector_t();
	this.pos.name = "position";
	
	/* Satellite Az, El, Range, Range rate */
//	this.obs_set = new vector_t();
//	this.obs_set.name = "obs_set";

	this.jul_utc =0;
	this.jul_epoch = 0;
	this.daynum = 0;
	this.tsince = 0;
	this.age = 0;
	this.ephem='';
	this.io_lat='N';
	this.io_lon='E';
	
	this.Locate = function (currentTime){
		//this function will need to be modified to fetch the passed in currentTime for daynum
		if(!currentTime)
			this.daynum = CurrentDaynum();
		else
			this.daynum = MakeDaynum(currentTime);

		this.PreCalc();
		this.Calc();
		return this.sat_geodetic;
	}
	
	this.LocateRange = function (startTime, endTime, inc){
//add input error checking

		var end = endTime.getTime();
		var increment = inc*1000;//convert to microseconds
		var count = 0;
		var holder = new Array();


		this.PreCalc();
		for(var current = startTime.getTime(); current <= end; current += increment)//1000 millisec * inc (in seconds)
		{	
			this.daynum = MakeDaynum(new Date(current) );
			this.Calc();
			
			holder.push(new geodetic_t(this.sat_geodetic) );
		}

//		for(var i=0; i<holder.length; i++)
//			alert(holder[i].lat+" "+holder[i].lon);
		
		return holder;//return an array of geodetic_t
	}
	
	this.PreCalc = function () {
	/* This function copies TLE data from PREDICT's sat structure
	   to the SGP4/SDP4's single dimensioned tle structure, and
	   prepares the tracking code for the update. */

		this.tle.sat_name = this.sat.name;
		this.tle.idesg = this.sat.designator;
		this.tle.catnr = this.sat.catnum;
		this.tle.epoch = (1000.0 * this.sat.year) + this.sat.refepoch;
		this.tle.xndt2o = this.sat.drag;
		this.tle.xndd6o = this.sat.nddot6;
		this.tle.bstar = this.sat.bstar;
		this.tle.xincl = this.sat.incl;
		this.tle.xnodeo = this.sat.raan;
		this.tle.eo = this.sat.eccn;
		this.tle.omegao = this.sat.argper;
		this.tle.xmo = this.sat.meanan;
		this.tle.xno = this.sat.meanmo;
		this.tle.revnum = this.sat.orbitnum;
		 
		/* Clear all flags */	
		ClearFlag(ALL_FLAGS);
		/* Select ephemeris type.  This function will set or clear the
			 DEEP_SPACE_EPHEM_FLAG depending on the TLE parameters of the
			 satellite.  It will also pre-process tle members for the
			 ephemeris functions SGP4 or SDP4, so this function must
			 be called each time a new tle set is used. */

		this.tle.select_ephemeris();
	}
	
	this.Calc = function ()
	{
		/* This is the stuff we need to do repetitively while tracking. */
	
		/* Solar ECI position vector  */
		var solar_vector = new vector_t();
	
		/* Solar observed azi and ele vector  */
		var solar_set = new vector_t();
	
		/* Satellite's predicted geodetic position */
		var sat_geodetic = new geodetic_t();

		this.jul_utc=this.daynum+2444238.5;

		/* Convert satellite's epoch time to Julian  */
		/* and calculate time since epoch in minutes */

		this.jul_epoch=Julian_Date_of_Epoch(this.tle.epoch);
		this.tsince=(this.jul_utc-this.jul_epoch)*xmnpda;
		this.age=this.jul_utc-this.jul_epoch;

		/* Copy the ephemeris type in use to ephem string. */
			if (isFlagSet(DEEP_SPACE_EPHEM_FLAG))
				this.ephem = "SDP4";	//Should never be this for a normal satellite
			else
				this.ephem = "SGP4";
		/* Call NORAD routines according to deep-space flag. */

		if (isFlagSet(DEEP_SPACE_EPHEM_FLAG))
			this.SDP4();
		else
			this.SGP4();
	
		/* Scale position and velocity vectors to km and km/sec */
	
		this.Convert_Sat_State();
		
//		alert("pos["+this.pos.x+", "+this.pos.y+", "+this.pos.z+"] vel["+this.vel.x+", "+this.vel.y+", "+this.vel.z+"]");
	
		/* Calculate velocity of satellite */
	
		this.vel.Magnitude();
		sat_vel=this.vel.w;
		/** All angles in rads. Distance in km. Velocity in km/s **/
		/* Calculate satellite Azi, Ele, Range and Range-rate */
	
		/* Calculate satellite Lat North, Lon East and Alt. */
	
		this.Calculate_LatLonAlt();//jul_utc, &pos, &sat_geodetic);

		//convert to degrees from radians
		this.sat_geodetic.lat = Degrees(this.sat_geodetic.lat);
		this.sat_geodetic.lon = Degrees(this.sat_geodetic.lon);

		ClearFlag(ALL_FLAGS);
	}
	
	this.SGP4 = function()
	{

		/* This function is used to calculate the position and velocity */
		/* of near-earth (period < 225 minutes) satellites. tsince is   */
		/* time since epoch in minutes, tle is a pointer to a tle_t     */
		/* structure with Keplerian orbital elements and pos and vel    */
		/* are vector_t structures returning ECI satellite position and */ 
		/* velocity. Use Convert_Sat_State() to convert to km and km/s. */
	
		var aodp, aycof, c1, c4, c5, cosio, d2, d3, d4, delmo,
		omgcof, eta, omgdot, sinio, xnodp, sinmo, t2cof, t3cof, t4cof,
		t5cof, x1mth2, x3thm1, x7thm1, xmcof, xmdot, xnodcf, xnodot, xlcof;
	
		var cosuk, sinuk, rfdotk, vx, vy, vz, ux, uy, uz, xmy, xmx, cosnok,
		sinnok, cosik, sinik, rdotk, xinck, xnodek, uk, rk, cos2u, sin2u,
		u, sinu, cosu, betal, rfdot, rdot, r, pl, elsq, esine, ecose, epw,
		cosepw, x1m5th, xhdot1, tfour, sinepw, capu, ayn, xlt, aynl, xll,
		axn, xn, beta, xl, e, a, tcube, delm, delomg, templ, tempe, tempa,
		xnode, tsq, xmp, omega, xnoddf, omgadf, xmdf, a1, a3ovk2, ao,
		betao, betao2, c1sq, c2, c3, coef, coef1, del1, delo, eeta, eosq,
		etasq, perigee, pinvsq, psisq, qoms24, s4, temp, temp1, temp2,
		temp3, temp4, temp5, temp6, theta2, theta4, tsi;
	
		var i;
	
		/* Initialization */
	
		if (isFlagClear(SGP4_INITIALIZED_FLAG))
		{
			SetFlag(SGP4_INITIALIZED_FLAG);
	
			/* Recover original mean motion (xnodp) and   */
			/* semimajor axis (aodp) from input elements. */
	
			a1=Math.pow(xke/this.tle.xno,tothrd);
			cosio=Math.cos(this.tle.xincl);
			theta2=cosio*cosio;
			x3thm1=3*theta2-1.0;
			eosq=this.tle.eo*this.tle.eo;
			betao2=1.0-eosq;
			betao=Math.sqrt(betao2);
			del1=1.5*ck2*x3thm1/(a1*a1*betao*betao2);
			ao=a1*(1.0-del1*(0.5*tothrd+del1*(1.0+134.0/81.0*del1)));
			delo=1.5*ck2*x3thm1/(ao*ao*betao*betao2);
			xnodp=this.tle.xno/(1.0+delo);
			aodp=ao/(1.0-delo);
	
			/* For perigee less than 220 kilometers, the "simple"     */
			/* flag is set and the equations are truncated to linear  */
			/* variation in sqrt a and quadratic variation in mean    */
			/* anomaly.  Also, the c3 term, the delta omega term, and */
			/* the delta m term are dropped.                          */
	
			if ((aodp*(1-this.tle.eo)/ae)<(220/xkmper+ae))
					SetFlag(SIMPLE_FLAG);
	
			else
					ClearFlag(SIMPLE_FLAG);
	
			/* For perigees below 156 km, the      */
			/* values of s and qoms2t are altered. */
	
			s4=s;
			qoms24=qoms2t;
			perigee=(aodp*(1-this.tle.eo)-ae)*xkmper;
	
			if (perigee<156.0)
			{
				if (perigee<=98.0)
						s4=20;
				else
					 s4=perigee-78.0;
	
				qoms24=Math.pow((120-s4)*ae/xkmper,4);
				s4=s4/xkmper+ae;
			}
	
			pinvsq=1/(aodp*aodp*betao2*betao2);
			tsi=1/(aodp-s4);
			eta=aodp*this.tle.eo*tsi;
			etasq=eta*eta;
			eeta=this.tle.eo*eta;
			psisq=Math.abs(1-etasq);
			coef=qoms24*Math.pow(tsi,4);
			coef1=coef/Math.pow(psisq,3.5);
			c2=coef1*xnodp*(aodp*(1+1.5*etasq+eeta*(4+etasq))+0.75*ck2*tsi/psisq*x3thm1*(8+3*etasq*(8+etasq)));
			c1=this.tle.bstar*c2;
			sinio=Math.sin(this.tle.xincl);
			a3ovk2=-xj3/ck2*Math.pow(ae,3);
			c3=coef*tsi*a3ovk2*xnodp*ae*sinio/this.tle.eo;
			x1mth2=1-theta2;
	
			c4=2*xnodp*coef1*aodp*betao2*(eta*(2+0.5*etasq)+this.tle.eo*(0.5+2*etasq)-2*ck2*tsi/(aodp*psisq)*(-3*x3thm1*(1-2*eeta+etasq*(1.5-0.5*eeta))+0.75*x1mth2*(2*etasq-eeta*(1+etasq))*Math.cos(2*this.tle.omegao)));
			c5=2*coef1*aodp*betao2*(1+2.75*(etasq+eeta)+eeta*etasq);
	
			theta4=theta2*theta2;
			temp1=3*ck2*pinvsq*xnodp;
			temp2=temp1*ck2*pinvsq;
			temp3=1.25*ck4*pinvsq*pinvsq*xnodp;
			xmdot=xnodp+0.5*temp1*betao*x3thm1+0.0625*temp2*betao*(13-78*theta2+137*theta4);
			x1m5th=1-5*theta2;
			omgdot=-0.5*temp1*x1m5th+0.0625*temp2*(7-114*theta2+395*theta4)+temp3*(3-36*theta2+49*theta4);
			xhdot1=-temp1*cosio;
			xnodot=xhdot1+(0.5*temp2*(4-19*theta2)+2*temp3*(3-7*theta2))*cosio;
			omgcof=this.tle.bstar*c3*Math.cos(this.tle.omegao);
			xmcof=-tothrd*coef*this.tle.bstar*ae/eeta;
			xnodcf=3.5*betao2*xhdot1*c1;
			t2cof=1.5*c1;
			xlcof=0.125*a3ovk2*sinio*(3+5*cosio)/(1+cosio);
			aycof=0.25*a3ovk2*sinio;
			delmo=Math.pow(1+eta*Math.cos(this.tle.xmo),3);
			sinmo=Math.sin(this.tle.xmo);
			x7thm1=7*theta2-1;
	
			if (isFlagClear(SIMPLE_FLAG))
			{
				c1sq=c1*c1;
				d2=4*aodp*tsi*c1sq;
				temp=d2*tsi*c1/3;
				d3=(17*aodp+s4)*temp;
				d4=0.5*temp*aodp*tsi*(221*aodp+31*s4)*c1;
				t3cof=d2+2*c1sq;
				t4cof=0.25*(3*d3+c1*(12*d2+10*c1sq));
				t5cof=0.2*(3*d4+12*c1*d3+6*d2*d2+15*c1sq*(2*d2+c1sq));
			}
		}
	
		/* Update for secular gravity and atmospheric drag. */
		xmdf=this.tle.xmo+xmdot*this.tsince;
		omgadf=this.tle.omegao+omgdot*this.tsince;
		xnoddf=this.tle.xnodeo+xnodot*this.tsince;
		omega=omgadf;
		xmp=xmdf;
		tsq=this.tsince*this.tsince;
		xnode=xnoddf+xnodcf*tsq;
		tempa=1-c1*this.tsince;
		tempe=this.tle.bstar*c4*this.tsince;
		templ=t2cof*tsq;
			
		if (isFlagClear(SIMPLE_FLAG))
		{
			delomg=omgcof*this.tsince;
			delm=xmcof*(Math.pow(1+eta*Math.cos(xmdf),3)-delmo);
			temp=delomg+delm;
			xmp=xmdf+temp;
			omega=omgadf-temp;
			tcube=tsq*this.tsince;
			tfour=this.tsince*tcube;
			tempa=tempa-d2*tsq-d3*tcube-d4*tfour;
			tempe=tempe+this.tle.bstar*c5*(Math.sin(xmp)-sinmo);
			templ=templ+t3cof*tcube+tfour*(t4cof+this.tsince*t5cof);
		}
	
		a=aodp*Math.pow(tempa,2);
		e=this.tle.eo-tempe;
		xl=xmp+omega+xnode+xnodp*templ;
		beta=Math.sqrt(1-e*e);
		xn=xke/Math.pow(a,1.5);
	
		/* Long period periodics */
		axn=e*Math.cos(omega);
		temp=1/(a*beta*beta);
		xll=temp*xlcof*axn;
		aynl=temp*aycof;
		xlt=xl+xll;
		ayn=e*Math.sin(omega)+aynl;
	
		/* Solve Kepler's Equation */
		capu=FMod2p(xlt-xnode);
		temp2=capu;
		i=0;

		do
		{
			sinepw=Math.sin(temp2);
			cosepw=Math.cos(temp2);
			temp3=axn*sinepw;
			temp4=ayn*cosepw;
			temp5=axn*cosepw;
			temp6=ayn*sinepw;
			epw=(capu-temp4+temp3-temp2)/(1-temp5-temp6)+temp2;
			
			if (Math.abs(epw-temp2)<= e6a)
				break;
					
			temp2=epw;
	
		} while (i++<10);
	
		/* Short period preliminary quantities */
//IE bugs in here 
		ecose=temp5+temp6;
		esine=temp3-temp4;
		elsq=axn*axn+ayn*ayn;
		temp=1-elsq;
		pl=a*temp;
		r=a*(1-ecose);
		temp1=1/r;
		rdot=xke*Math.sqrt(a)*esine*temp1;
		rfdot=xke*Math.sqrt(pl)*temp1;
		temp2=a*temp1;
		betal=Math.sqrt(temp);
		temp3=1/(1+betal);
		cosu=temp2*(cosepw-axn+ayn*esine*temp3);
		sinu=temp2*(sinepw-ayn-axn*esine*temp3);
		u=AcTan(sinu,cosu);
		sin2u=2*sinu*cosu;
		cos2u=2*cosu*cosu-1;
		temp=1/pl;
		temp1=ck2*temp;
		temp2=temp1*temp;
	
		/* Update for short periodics */
		rk=r*(1-1.5*temp2*betal*x3thm1)+0.5*temp1*x1mth2*cos2u;
		uk=u-0.25*temp2*x7thm1*sin2u;
		xnodek=xnode+1.5*temp2*cosio*sin2u;
		xinck=this.tle.xincl+1.5*temp2*cosio*sinio*cos2u;
		rdotk=rdot-xn*temp1*x1mth2*sin2u;
		rfdotk=rfdot+xn*temp1*(x1mth2*cos2u+1.5*x3thm1);
	
		/* Orientation vectors */
		sinuk=Math.sin(uk);
		cosuk=Math.cos(uk);
		sinik=Math.sin(xinck);
		cosik=Math.cos(xinck);
		sinnok=Math.sin(xnodek);
		cosnok=Math.cos(xnodek);
		xmx=-sinnok*cosik;
		xmy=cosnok*cosik;
		ux=xmx*sinuk+cosnok*cosuk;
		uy=xmy*sinuk+sinnok*cosuk;
		uz=sinik*sinuk;
		vx=xmx*cosuk-cosnok*sinuk;
		vy=xmy*cosuk-sinnok*sinuk;
		vz=sinik*cosuk;
	
		/* Position and velocity */
		this.pos.x=rk*ux;
		this.pos.y=rk*uy;
		this.pos.z=rk*uz;
		this.vel.x=rdotk*ux+rfdotk*vx;
		this.vel.y=rdotk*uy+rfdotk*vy;
		this.vel.z=rdotk*uz+rfdotk*vz;

		/* Phase in radians */
		phase=xlt-xnode-omgadf+twopi;
			
		if (phase<0.0)
			phase+=twopi;
	
		phase=FMod2p(phase);
	}
	
	this.SDP4 = function ()
	{
		alert("SDP4 functionality has not been converted for use in this application");		
	}
	
	this.Convert_Sat_State = function ()
	{
		/* Converts the satellite's position and velocity  */
		/* vectors from normalized values to km and km/sec */ 
		this.pos.Scale_Vector(xkmper);
		this.vel.Scale_Vector(xkmper*xmnpda/secday);
	}

	this.Calculate_LatLonAlt = function ()//double time, vector_t *pos,  geodetic_t *geodetic)
	{
		/* Procedure Calculate_LatLonAlt will calculate the geodetic  */
		/* position of an object given its ECI position pos and time. */
		/* It is intended to be used to determine the ground track of */
		/* a satellite.  The calculations  assume the earth to be an  */
		/* oblate spheroid as defined in WGS '72.                     */
	
		/* Reference:  The 1992 Astronomical Almanac, page K12. */
	
		var r, e2, phi, c;
	
		this.sat_geodetic.theta = AcTan(this.pos.y, this.pos.x); /* radians */
		this.sat_geodetic.lon = FMod2p(this.sat_geodetic.theta - ThetaG_JD(this.jul_utc)); /* radians */
		r = Math.sqrt(Sqr(this.pos.x)+Sqr(this.pos.y));
		e2 = f * (2-f);
		this.sat_geodetic.lat = AcTan(this.pos.z, r); /* radians */
	
		do
		{
			phi = this.sat_geodetic.lat;
			c = 1/Math.sqrt(1-e2*Sqr(Math.sin(phi)));
			this.sat_geodetic.lat = AcTan(this.pos.z+xkmper*c*e2*Math.sin(phi),r);
	
		} while (Math.abs(this.sat_geodetic.lat-phi)>=1E-10);
	
		this.sat_geodetic.alt = r/Math.cos(this.sat_geodetic.lat) - xkmper*c; /* kilometers */
	
		if (this.sat_geodetic.lat>pio2)
			this.sat_geodetic.lat-=twopi;
	}
}


function CurrentDaynum()
{
	/* Read the system clock and return the number
	   of days since 31Dec79 00:00:00 UTC (daynum 0) */
	var usecs, sec;
	var d = new Date();
	var t = d.getTime();
	sec = t/1000;
	usec = sec%1;

	return (((sec-usec)/86400.0)-3651.0);
}

function MakeDaynum(timestamp){
	var usecs, sec;
	var t = timestamp.getTime();
	sec = t/1000;
	usec = sec%1;

return (((sec-usec)/86400.0)-3651.0);
}

function Julian_Date_of_Epoch(epoch)
{ 
	/* The function Julian_Date_of_Epoch returns the Julian Date of     */
	/* an epoch specified in the format used in the NORAD two-line      */
	/* element sets. It has been modified to support dates beyond       */
	/* the year 1999 assuming that two-digit years in the range 00-56   */
	/* correspond to 2000-2056. Until the two-line element set format   */
	/* is changed, it is only valid for dates through 2056 December 31. */

	var year, day;

	/* Modification to support Y2K */
	/* Valid 1957 through 2056     */

//		day=modf(epoch*1E-3, &year)*1E3;
	day = (epoch*1E-3%1)*1E3;
	year = epoch*1E-3 - (epoch*1E-3%1)

	if (year<57)
		year=year+2000;
	else
		year=year+1900;
	return (Julian_Date_of_Year(year)+day);
}

function Julian_Date_of_Year(year)
{
	/* The function Julian_Date_of_Year calculates the Julian Date  */
	/* of Day 0.0 of {year}. This function is used to calculate the */
	/* Julian Date of any date by using Julian_Date_of_Year, DOY,   */
	/* and Fraction_of_Day. */

	/* Astronomical Formulae for Calculators, Jean Meeus, */
	/* pages 23-25. Calculate Julian Date of 0.0 Jan year */

//rounding is used for forcing integer values like the C code
	var A, B, i;
	var jdoy;

	year=year-1;
	i=Math.round( (year/100)-0.5); 
	A=i;
	i=Math.round( (A/4)-0.5);
	B= 2 - A + i;
	i=Math.round( (365.25*year)-0.5);
	i+=Math.round( (30.6001*14) -0.5);
	jdoy=i+1720994.5+B;

	return jdoy;
}

function ThetaG_JD(jd)
{
	/* Reference:  The 1992 Astronomical Almanac, page B6. */

	var UT, TU, GMST;

	UT=(jd+0.5)%1;
	jd=jd-UT;
	TU=(jd-2451545.0)/36525;
	GMST=24110.54841+TU*(8640184.812866+TU*(0.093104-TU*6.2E-6));
	var test = GMST;
	GMST = (GMST+secday*omega_E*UT) % secday;
	return (twopi*GMST/secday);
}

/* Functions for testing and setting/clearing flags used in SGP4 code */

function isFlagSet(flag) /* return int; input int */
{
	return (Flags&flag);
}

function isFlagClear(flag) /* return int; input int */
{
	return (~Flags&flag);
}

function SetFlag(flag) /* return void; input int */
{
	Flags|=flag;
}

function ClearFlag(flag) /* return void; input int */
{
	Flags&=~flag;
}