// gst3.js Main script for GoogleSatTrack var 3
// Copyright:: Copyright (C) Isana Kashiwai<isana at lizard-tail.com>
// License::  GPL

/*
history
development release for 3.6.0 (20091101): 
- always full screen
- movable data window
development release for 3.6.0 (20091102): 
- IE support
development release for 3.6.0 (20091202): 
-periodical retrieving of default settings & satellites list
-changed or added functions
  *delete "Defaults"
  *delete "Satellite"
  *change "long_updator"
  *change "set_defaults"
  *add "SatelliteListLoader"
3.6.0 (20091221): 
  first release ver 3.6.0
  
3.6.1 (20091223): 
- "glued" cursor problem 
  *change "onMouseMove"
  
3.6.2 (20100103)
- fixed a bug that the satellte dose not appear on the ground track.
 *change Clock.prototype.GMST on "sgp4.js"
 
3.6.3 (20100121)
- "mile" to "sm" 
- "ml/s" to "mph"
- "km/s" to "km/h"

3.7.0 (20100821)
- time to sunset/sunrise
*change "CalcSat", "Ephemeris.Sun" on terminator.js
*add "SatelliteEclips", "search_rise_set"
*change files : base.css, index.html

3.7.1 (20100823)
- atmospheric refraction in sunset/sunrise calculation
*change "SatelliteEclips"

3.8.0 (20110124)
- integrated "config panel"

3.9.0 (20110707)
- new tle loading method from local text files
* add "TLESourceLoader", "TLESourceDecoder"
* change "DataLoader", "sat_loader", "set_defaults"

3.10.0 (20110930)
- groundtrack is now calclated on the brawser.
* add "GroundTrackMaker"
* "DataLoader(GroundTrackLoader() ...)" was replaced to "GrondTrackMaker()"
-- to be done?
- There is a report groundtrack is not working on IE9. But it is not reproducible. - 2011.09.30

3.10.1 (20111003)
- proper DTD Definition was given
  the document was checked on the W3C validator and passed as XHTML 1.1
  http://validator.w3.org/check?uri=http%3A%2F%2Fwww.lizard-tail.com%2Fisana%2Ftracking%2F;verbose=1
  
- compatible with IE9/FF native mode;

3.10.2 (20111006)
- rename "gst.js" to "gst3.js" (privent version mixture)
- sgp4.js & terminator.js are merged with gst3.js (reduce client requests)

3.10.3 (20111020)
- prevent user text selection on IE
* change "window.onload"

---
versioning schemes:  
  "major.minor.revision (update)"
  The major number is increased when there are significant jumps in functionality, 
  the minor number is incremented when only minor features or significant fixes have been added, 
  and the revision number is incremented when minor bugs are fixed.
  
compatibility:
  Windows:
    Firfox 7
    Safari 5
    Chorome 14
    Internet Explorer 9 native mode
    Opera 11

  MacOS:
    Firfox 7
    Safari 5
    Firfox 7
    Chorome 14
    Opera 11
   
*/


function Pref(){
  this.release = "20111020";
  this.version = "3.10.3" ;
  this.decay_list_by_catalog_number = ["21701"];
  this.decay_list_by_name = ["UARS"];
  this.path = {
    fullpath: "http://www.lizard-tail.com/isana/tracking/",
    tle:"../tle/data/",
    image:"./image/"
  };
}

function now_sec(){
  var d = new Date();
  var year=d.getUTCFullYear();
  var month=d.getUTCMonth();
  var day=d.getUTCDate();
  var hours=d.getUTCHours();
  var minutes=d.getUTCMinutes();
  var seconds=d.getUTCSeconds();
  var now_sec=Date.UTC(year, month-1, day, hours, minutes, seconds);
  return now_sec;
}

function createXMLhttpObject(){
  XMLhttpObject = false;
  if(window.XMLHttpRequest) {
    XMLhttpObject = new XMLHttpRequest();
  }else if(window.ActiveXObject) {
    try {
      XMLhttpObject = new ActiveXObject("Msxml2.XMLHTTP");
    }catch(e){
      XMLhttpObject = new ActiveXObject("Microsoft.XMLHTTP");
    }
  }
  return XMLhttpObject;
}

function DataLoader(callback,data,resp,async,id) {

  XMLhttpObject=createXMLhttpObject();
  if (!XMLhttpObject){return;}
  XMLhttpObject.open("GET", data, async);
  XMLhttpObject.send(null);
  if(async==false){
    try{
      if(resp == "xml"){
      var data = XMLhttpObject.responseXML;
      }else{
      var data = XMLhttpObject.responseText;
      }
      callback(data,id);
    }catch(e){
      var pref = new Pref();
      if(pref.status == "startup" && id!="ground_track"){
        var str = '<div style="line-height:1.5em;font-size:x-large;margin-top:5em;text-align:center"><strong>GoogleSatTrack is temporary unavailable due to heavy traffic.<br>Please try again later.</strong><br><br><img src="image/iss.png"></div>';
        document.getElementById("map").innerHTML = str;
      }else{
        return;
      }
    }
  }else{
    try{
      XMLhttpObject.onreadystatechange = function() {
        if(XMLhttpObject.readyState == 4){
          if(XMLhttpObject.status == 200){
            if(resp == "xml"){
            var data = XMLhttpObject.responseXML;
            }else{
            var data = XMLhttpObject.responseText;
            }
            callback(data,id);
          }
        }else{
          return;
        }
      }
    }catch(e){
      var pref = new Pref();
      if(pref.status == "startup" && id!="ground_track"){
        var str = '<div style="line-height:1.5em;font-size:x-large;margin-top:5em;text-align:center"><strong>GoogleSatTrack is temporarily unavailable due to heavy traffic.<br>Please try again later.</strong><br><br><img src="image/iss.png"></div>';
        document.getElementById("map").innerHTML = str;
      }else{
        return;
      }
    }
  }
}

//from local
TLESourceLoader = function(TextData,id){
  var tle_array = TLESourceDecoder(TextData);
  if(id=="iss" || id=="sts"){
    var tle_array_length = tle_array.length;
    var now = new Date()
    var d0 = new Date(Date.UTC(now.getFullYear(),0,0,0,0));
    var now_in_days = (now - d0)/86400000;
    for (var i = 0; i < tle_array_length; i ++) {
      var sat_name = tle_array[i]["sat_name"];
      var first_line = tle_array[i]["first_line"];
      var second_line = tle_array[i]["second_line"];
      var epoch = tle_array[i]["epoch"];
      if(now_in_days>epoch){
         var tmp_array = tle_array[i];
      }
    }
    var source_array = tmp_array;
    Pref.prototype.tle_source.push(source_array);
  }else{
    Pref.prototype.tle_source = tle_array;
  }
}


var  TLESourceDecoder = function(data){
  var source_array = data.split("\n");
  var source_array_length = source_array.length;
  var tle_array=[];
  for(i=0; i<source_array_length; i=i+3){
    if(source_array[i]){
      var tmp_array=[];
      var sat_name =  source_array[i];
      var line1 =  source_array[i+1];
      var line2 =  source_array[i+2];
      tmp_array["sat_name"] = sat_name;
      tmp_array["catalog_number"] = Number(line1.slice(2,7));
      tmp_array["epoch"] = Number(line1.substring(20,32));
      tmp_array["first_line"] =line1
      tmp_array["second_line"] =line2
      tle_array.push(tmp_array);
    }
  }
return tle_array;
}

//from local


//callback methods for DataLoader
XMLLoader = function(xmlData,id){
  var data_type = xmlData.getElementsByTagName('data_type')[0].childNodes[0].nodeValue;
  if (data_type == "TLE"){
  var sat_name = xmlData.getElementsByTagName('sat_name')[0].childNodes[0].nodeValue;
  var first_line = xmlData.getElementsByTagName('first_line')[0].childNodes[0].nodeValue;
  var second_line = xmlData.getElementsByTagName('second_line')[0].childNodes[0].nodeValue;
  Pref.prototype.tmp_first_line=first_line;
  Pref.prototype.tmp_second_line=second_line;
      }
}

DefaultSettingLoader = function(jsonData,id){
  Default = eval("("+jsonData+")");
  return;
}

SatelliteListLoader = function(jsonData,id){
  Satellite = eval("("+jsonData+")");
  return;
}

GroundTrackLoader=function(jsonData,id){
  Pref.prototype.gt = eval("("+jsonData+")");
  return;
}

function setStaticData(){
  var pref = new Pref();
  if(!pref.sat2_name){
  document.title = "GoogleSatTrack - " + pref.sat1_name;
  }else{
  document.title = "GoogleSatTrack - " + pref.sat1_name + " & " + pref.sat2_name;
  }
  delete pref;
}

//initialization of the map
var map;
var SmallZoomControl;
var MapTypeControl;
var OverviewMapControl;
var ScaleControl;

function InitMap(){
  var pref = new Pref();
  var date = new Date();
  var position = pref.sat1_orbit.calc(date);  
  var default_position = position.latlng();
  if (GBrowserIsCompatible()) {
    map = new GMap2(document.getElementById("map"));
    map.disableDragging();
    SmallZoomControl = new GSmallZoomControl();
    MapTypeControl = new GMapTypeControl();
    OverviewMapControl = new GOverviewMapControl();
    ScaleControl = new GScaleControl();
    InitMask();
    showMask();

    GEvent.addListener(map, "zoomend", function(oldLevel,newLevel){
      map_zoomed(oldLevel,newLevel);
    })
    if(pref.zoom<=pref.minimum_zoom){
      map.setCenter(new GLatLng(0,0),pref.zoom,G_SATELLITE_MAP);
      Pref.prototype.move_mode = "static";  
    }else{
      map.setCenter(new GLatLng(default_position.latitude,default_position.longitude), pref.zoom,G_SATELLITE_MAP);
      Pref.prototype.move_mode = "dynamic";  
    }
  }
  delete pref;
}

function map_zoomed(oldLevel,newLevel){
  var pref = new Pref();
  if(pref.status!="startup"){
    setMoveMode(false)
  }
  delete pref;
};

function setMoveMode(recenter){
  var zoom = map.getZoom();
  var pref = new Pref
  var prev_move_mode = pref.move_mode;
  var move_mode = pref.move_mode;
  if(zoom<=pref.minimum_zoom){
    move_mode = "static";
    if(prev_move_mode=="dynamic"||recenter==true){
      map.setCenter(new GLatLng(0,0),zoom,map.getCurrentMapType());
    }
  }else{
    move_mode = "dynamic";  
    if(prev_move_mode=="static"||recenter==true){
      map.setCenter(new GLatLng(pref.sat_lat,pref.sat_lng),zoom,map.getCurrentMapType());
   }
  }
  Pref.prototype.move_mode = move_mode;
  setIndicator()
delete pref;
}

RightMask = function (image,width,height) {
  this.image_ = image;
  this.width_ = width;
  this.height_ = height;
 
}
RightMask.prototype = new GControl()

RightMask.prototype.initialize = function(map) {
  var container = document.createElement("div");
  container.style.zIndex = 1;  
  var RightMaskDiv = document.createElement("div");
  RightMaskDiv.setAttribute('id','right_mask');
  RightMaskDiv.width = this.width_ + "px";
  RightMaskDiv.height = this.height_ + "px";
  RightMaskDiv.innerHTML="<img src='./image/gray.png' width='"+this.width_+"' height='"+this.height_+"'>";
  container.appendChild(RightMaskDiv);
  map.getContainer().appendChild(container);
  return container;
}
RightMask.prototype.getDefaultPosition = function() {
  return new GControlPosition(G_ANCHOR_TOP_RIGHT, new GSize(0, 0));
}


LeftMask = function (image,width,height) {
  this.image_ = image;
  this.width_ = width;
  this.height_ = height;
}

LeftMask.prototype = new GControl()

LeftMask.prototype.initialize = function(map) {
  var container = document.createElement("div");
  container.style.zIndex = 1;  
  
  var LeftMaskDiv = document.createElement("div");
  LeftMaskDiv.setAttribute('id','left_mask');
  LeftMaskDiv.width = this.width_ + "px";
  LeftMaskDiv.height = this.height_ + "px";
  LeftMaskDiv.innerHTML="<img src='./image/gray.png' width='"+this.width_+"' height='"+this.height_+"'>";
  container.appendChild(LeftMaskDiv);
  map.getContainer().appendChild(container);
  return container;
}
LeftMask.prototype.getDefaultPosition = function() {
  return new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(0, 0));
}

function InitMask(){
  var map_area = document.getElementById("map");
  if (map_area.hasChildNodes()) {
    var children = map_area.childNodes;
    var zindex=0
    for (var i = 0; i < children.length; i++){
      var prev_zindex = zindex;
      if(children[i].style.zIndex){
        zindex = children[i].style.zIndex;
      }else{
        zindex = 0;
      }
      children[i].style.zIndex = zindex+100;
      if(prev_zindex>=zindex){
        var smallest_zindex=zindex;
      }
    }
  }
  var map_pane = map.getPane(G_MAP_FLOAT_PANE).parentNode.parentNode;
  map_pane.style.zIndex="0";

  return
}

function removeMask(){
  if(left_mask){
    map.removeControl(left_mask)
  }
  if(right_mask){
    map.removeControl(right_mask)
  }
}

function showMask(){
  var pref = new Pref();
  var area = map.getSize();
  var zoom = map.getZoom();
  if(zoom<=pref.minimum_zoom){
    switch(zoom){
      case 0:
      var width = Math.floor((area.width-256)/2);
      break;
      case 1:
      var width = Math.floor((area.width-512)/2);
      break;
      case 2:
      var width = Math.floor((area.width-1024)/2);
      break;
      case 3:
      var width = Math.floor((area.width-2048)/2);
      break;
      case 4:
      var width = Math.floor((area.width-4096)/2);
      break;
      default:
      var width = "0";
    }
  }else{
    switch(zoom){
      case 0:
      var width = area.width - (256-13);
      break;
      case 1:
      var width = area.width - (512-25);
      break;
      case 2:
      var width = area.width - (1024-50);
      break;
      case 3:
      var width = area.width - (2048-100);
      break;
      case 4:
      var width = area.width - (4096-200);
      break;
      default:
      var width = "0";
    }
  }
  if(width<0){width = 0}
    left_mask = new LeftMask("./image/gray.png",width+1,area.height)
    right_mask = new RightMask("./image/gray.png",width,area.height)
    
    map.addControl(left_mask);
    map.addControl(right_mask);
   return;
}


createMarker = function(point,icon_image,icon_shadow,icon_size) {
  var sat_icon = new GIcon();
  sat_icon.image = icon_image;
  sat_icon.shadow = icon_shadow;
  sat_icon.iconSize = new GSize(icon_size, icon_size);
  sat_icon.shadowSize = new GSize(icon_size, icon_size);
  sat_icon.iconAnchor = new GPoint(icon_size/2, icon_size/2);
  this.create = new GMarker(point, sat_icon);
}

PostionString = function(latitude,longitude,altitude,velocity){
  var lat_integer = Math.floor(latitude);
  var long_integer = Math.floor(longitude);
  if (lat_integer>0){
    var lat_decimal = Math.floor((latitude-lat_integer)*60*100)/100;
    var lat = Math.abs(lat_integer)+"&deg; " + Math.abs(lat_decimal) + "&prime; N";
  }else{
    var lat_decimal = Math.floor(6000-(latitude-lat_integer)*60*100)/100;
    var lat = Math.abs(lat_integer+1)+"&deg; " + Math.abs(lat_decimal) + "&prime; S";
  }
  if (long_integer>0){
    var long_decimal = Math.floor((longitude-long_integer)*60*100)/100;
    var long = Math.abs(long_integer)+"&deg; " + Math.abs(long_decimal) + "&prime; E";
  }else{
    var long_decimal = Math.floor(6000-(longitude-long_integer)*60*100)/100;
    var long = Math.abs(long_integer+1)+"&deg; " + Math.abs(long_decimal) + "&prime; W";
  }
  var pref = new Pref();

  if(pref.unit=="mile"){
    var v_unit = "mph";
    var d_unit = "sm";
    var u = 0.621371192;
  }else{
    var v_unit = "km/h";
    var d_unit = "km";
    var u = 1;
  }
  
  var alt = Math.floor(Number(altitude)*u*1000)/1000 + " " + d_unit;
  var v = Math.floor(Number(velocity)*u*1000*3600)/1000 + " " + v_unit;;
  
  delete pref;
  
  this.latitude = lat;
  this.longitude = long;
  this.altitude = alt;
  this.velocity = v;
  return this;
}

CalcSat = function(){
  var pref = new Pref();
  var zoom = map.getZoom();
  var mode = pref.mode;
  var move_mode = pref.move_mode;
  var date = new Date();

  var sat1_icon_image = pref.sat1_icon_image;
  var sat1_icon_shadow = pref.sat1_icon_shadow;
  var sat1_icon_size = pref.sat1_icon_size;

  var position = pref.sat1_orbit.calc(date);
  var sat1_position = position.latlng();
  Pref.prototype.sat_lat = sat1_position.latitude;
  Pref.prototype.sat_lng = sat1_position.longitude;

  
  if(mode == "double" || mode == "triple"){
    var sat2_icon_image = pref.sat2_icon_image;
    var sat2_icon_shadow = pref.sat2_icon_shadow;
    var sat2_icon_size = pref.sat2_icon_size;
    var position = pref.sat2_orbit.calc(date);
    var sat2_position = position.latlng();
    var marker2 = new createMarker(new GLatLng(Number(sat2_position.latitude),Number(sat2_position.longitude)),sat2_icon_image,sat2_icon_shadow);
    map.removeOverlay(sat_marker2);
    var m2 = new createMarker(new GLatLng(Number(sat2_position.latitude),Number(sat2_position.longitude)),sat2_icon_image,sat2_icon_shadow,sat2_icon_size);
    sat_marker2 = m2.create;
    map.addOverlay(sat_marker2);

    var position_str2 = new PostionString(sat2_position.latitude,sat2_position.longitude,sat2_position.altitude,sat2_position.velocity);
    var doc = document;
    doc.getElementById("sat2_name").innerHTML = pref.sat2_name; 
    doc.getElementById("sat2_lat").innerHTML = position_str2.latitude;
    doc.getElementById("sat2_long").innerHTML = position_str2.longitude;
    doc.getElementById("sat2_alt").innerHTML = position_str2.altitude;
    doc.getElementById("sat2_v").innerHTML = position_str2.velocity;
   }
   
  if(mode == "double"){
    if(pref.unit=="mile"){
      var d_unit = "sm";
      var u = 0.621371192;
    }else{
      var d_unit = "km";
      var u = 1;
    }

    var distance = Math.sqrt((sat1_position.x-sat2_position.x)*(sat1_position.x-sat2_position.x)+(sat1_position.y-sat2_position.y)*(sat1_position.y-sat2_position.y)+(sat1_position.z-sat2_position.z)*(sat1_position.z-sat2_position.z))
    if (distance<50){
      distance = "less than 50";
    }else{
      distance = Math.floor(distance*u*100)/100;
    }

    doc.getElementById("distance").innerHTML = "Distance  : " + distance + " " + d_unit; 

  }
  if(mode=="triple"){
    var sat3_icon_image = pref.sat3_icon_image;
    var sat3_icon_shadow = pref.sat3_icon_shadow;
    var sat3_icon_size = pref.sat3_icon_size;
    var position = pref.sat3_orbit.calc(date);
    var sat3_position = position.latlng();
    var marker3 = new createMarker(new GLatLng(Number(sat3_position.latitude),Number(sat3_position.longitude)),sat3_icon_image,sat3_icon_shadow);
    map.removeOverlay(sat_marker3);
    var m3 = new createMarker(new GLatLng(Number(sat3_position.latitude),Number(sat3_position.longitude)),sat3_icon_image,sat3_icon_shadow,sat3_icon_size);
    sat_marker3 = m3.create;
    map.addOverlay(sat_marker3);  
  }

  map.removeOverlay(sat_marker1);
  var m1 = new createMarker(new GLatLng(Number(sat1_position.latitude),Number(sat1_position.longitude)),sat1_icon_image,sat1_icon_shadow,sat1_icon_size);
  sat_marker1 = m1.create;
  map.addOverlay(sat_marker1);

  if(move_mode == "dynamic"){
    map.panTo(new GLatLng(Number(sat1_position.latitude), Number(sat1_position.longitude)), zoom);
  }
  var position_str1 = new PostionString(sat1_position.latitude,sat1_position.longitude,sat1_position.altitude,sat1_position.velocity);
  var doc = document;
  doc.getElementById("sat1_name").innerHTML = pref.sat1_name; 
  doc.getElementById("sat1_lat").innerHTML = position_str1.latitude;
  doc.getElementById("sat1_long").innerHTML = position_str1.longitude;
  doc.getElementById("sat1_alt").innerHTML = position_str1.altitude;
  doc.getElementById("sat1_v").innerHTML = position_str1.velocity;


 if(pref.status == "startup"){
    var rise_set = GetSunriseSunset(date,pref.sat1_orbit);
    Pref.prototype.rise_set = rise_set;  
  }
  delete pref;
  var pref = new Pref();
  var time_to_sun_rise_set = Math.floor((pref.rise_set.time - date)/1000);
  var ttsrs_min = Math.floor(time_to_sun_rise_set/60);
  var ttsrs_sec = Math.floor(time_to_sun_rise_set - ttsrs_min*60);
  var ttsrs_str = ttsrs_min + " min " + ttsrs_sec + " sec";
  if(time_to_sun_rise_set<=0){
    var rise_set = GetSunriseSunset(date,pref.sat1_orbit);
    Pref.prototype.rise_set = rise_set;  
  }
 
  doc.getElementById("sat1_time_to_sun_rise_set").innerHTML = ttsrs_str + " to " + pref.rise_set.status;

  delete pref;
    window.setTimeout("CalcSat();",1000);
}

GetSunriseSunset = function(now,orbit){
  var pref = new Pref();
    var eclipse = SatelliteEclips(now,orbit);
    var rise_set = new search_rise_set(now,orbit, eclipse.daylight);
    return rise_set;
}
SatelliteEclips = function(now,orbit){
  var pref = new Pref();
  var sat_eci = orbit.calc(now);
  var rad=Math.PI/180;
  var ephem = new Ephemeris();
  var sun = ephem.Sun(now);
  var earth_radius =6378.137;
  var sun_radius = 696000;
  var sat_to_earth = {
    x:-sat_eci.x,
    y:-sat_eci.y,
    z:-sat_eci.z,
    radius:Math.sqrt(sat_eci.x*sat_eci.x+sat_eci.y*sat_eci.y+sat_eci.z*sat_eci.z)
  }
  var sat_to_sun = {
    x:sun.x-sat_eci.x,
    y:sun.y-sat_eci.y,
    z:sun.z-sat_eci.z,
    radius:Math.sqrt((sun.x-sat_eci.x)*(sun.x-sat_eci.x)+(sun.y-sat_eci.y)*(sun.y-sat_eci.y)+(sun.z-sat_eci.z)*(sun.z-sat_eci.z))
  }
  var ad_earth = Math.asin(earth_radius/sat_to_earth.radius)/rad;
  var ad_sun = Math.asin(sun_radius/sat_to_sun.radius)/rad;
  var vector_dot = sun.x*sat_to_earth.x+sun.y*sat_to_earth.y+sun.z*sat_to_earth.z;
  var sun_to_earth_radius = Math.sqrt(sun.x*sun.x+sun.y*sun.y + sun.z*sun.z);
  var angle_of_sepalation =Math.acos(vector_dot/(sun_to_earth_radius*sat_to_earth.radius))/rad;
  var depth = ad_earth-ad_sun-angle_of_sepalation - 0.572*2;

  if(ad_earth> ad_sun){
     if(0<=depth){
       var eclips = "umbral";
       var daylight = false;
     }else if(0>depth && depth<ad_sun * 2){
       var eclips = "penumbral";
       var daylight = true;
     }else{
       var eclips = "none";
       var daylight = true;
     }
  }else if(ad_earth< ad_sun ){
     if(0<=depth){
       var eclips = "annular";
       var daylight = true;
     }else{
       var eclips = "none";
       var daylight = true;
     }
  }
  
  delete pref;
  
  this.ad_sun = ad_sun;
  this.ad_earth = ad_earth;
  this.angle_of_sepalation = angle_of_sepalation;
  this.eclips = eclips;
  this.depth = depth;
  this.daylight = daylight;
  return this;
}

search_rise_set =  function(time,orbit,daylight){
  var pref = new Pref();
  var unit = 60*1000;
  var new_time = time;
  if(daylight==true){
    var status = "sunset";
  }else{
    var status = "sunrise";
  }
  var sign = 1;
  do{
    var t = new Date();
    t.setTime(new_time.getTime()+unit*sign);
    var e = new SatelliteEclips(t,orbit);
    if(e.daylight!=daylight){
      unit = unit/2;
      sign = sign*(-1);
    }
    daylight = e.daylight;
    new_time = t;
    }while(unit>1000);
  
  var t2 = new Date();
  t2.setTime(t.getTime());
  delete pref;

  this.time = t2;
  this.status = status;
  return 
}


function GTStaticMode(){
  var pref = new Pref();
  if(pref.gt){
    var gt = pref.gt.data;
    var data_length = gt.length-1;
    var orbit = 0;
    var start_lng = gt[0].lng;
    if(start_lng>0){
      var prev_sign="+";
    }else{
      var prev_sign="-";
    }
    var gt_array = []
  
    for(i=0; i<data_length; i++){  
      if(gt[i].lng<0){
        var sign = "-";
      }else if(gt[i].lng>0){
        var sign = "+";
      }
      if(prev_sign != sign && prev_sign != "-"){
        orbit++
      }
      if(!gt_array[orbit]){
        gt_array[orbit]=[]
      }
      gt_array[orbit].push(new GLatLng(Number(gt[i].lat),Number(gt[i].lng)));
      var prev_sign = sign;
    }
    var gt_array_length = gt_array.length;
    for (i=0;i<gt_array_length;i++){
        var gt_polyline = new GPolyline(gt_array[i].reverse(),"#ff0000",1,1)
        map.addOverlay(gt_polyline);
    }
  }else{
    alert("Ground track is temporarily unsavailable.\n Sorry for any inconvenient.");
    document.forms[0].elements[0].checked=false
    Pref.prototype.low_load = true;
    Pref.prototype.ground_track_flag=false;
  }
  delete pref;
  return;
}

function GTDynamicMode(){
  var pref = new Pref();
  if(pref.gt){
    var gt = pref.gt.data;
    var data_length = gt.length-1;
    var gt_array1=[],gt_array2=[],gt_array3=[],gt_array4=[],gt_array5=[],gt_array6=[];
    for(i=0; i<data_length; i++){
      if(i<=60){
        gt_array1.push(new GLatLng(Number(gt[i].lat),Number(gt[i].lng)));
      }
      if(i>=60&&i<=120){
        gt_array2.push(new GLatLng(Number(gt[i].lat),Number(gt[i].lng)));
      }
      if(i>=90&&i<=150){
        gt_array3.push(new GLatLng(Number(gt[i].lat),Number(gt[i].lng)));
      }
      if(i>=150&&i<=210){
        gt_array4.push(new GLatLng(Number(gt[i].lat),Number(gt[i].lng)));
      }
      if(i>=180&&i<=240){
        gt_array5.push(new GLatLng(Number(gt[i].lat),Number(gt[i].lng)));
      }
      if(i>=240){
        gt_array6.push(new GLatLng(Number(gt[i].lat),Number(gt[i].lng)));
      }
    }
    gt_polyline1 = new GPolyline(gt_array1,"#ff0000",1,1);
    gt_polyline2 = new GPolyline(gt_array2.reverse(),"#ff0000",1,1);
    gt_polyline3 = new GPolyline(gt_array3,"#ff0000",1,1);
    gt_polyline4 = new GPolyline(gt_array4.reverse(),"#ff0000",1,1);
    gt_polyline5 = new GPolyline(gt_array5,"#ff0000",1,1);
    gt_polyline6 = new GPolyline(gt_array6.reverse(),"#ff0000",1,1);
    
    map.addOverlay(gt_polyline1);
    map.addOverlay(gt_polyline2);
    map.addOverlay(gt_polyline3);
    map.addOverlay(gt_polyline4);
    map.addOverlay(gt_polyline5);
    map.addOverlay(gt_polyline6);  
  }else{
    alert("Ground track is temporary unsavailable.\n Sorry for any inconvenient.");
    Pref.prototype.low_load = true;
    Pref.prototype.ground_track_flag=false;
  }
  delete pref;
  return;

}

function showGroundTrack(){
  var pref = new Pref();
  if(pref.move_mode=="static"){
    GTStaticMode();
  }else{
    GTDynamicMode();  
  }
  delete pref;
}

function GroundTrackMaker(){
  var pref = new Pref();
  var date = new Date();
  var data_array = []
  var orbital_period = pref.sat1_orbit.orbital_period;
  var unit = orbital_period/360;
  var d = date;
  for(var i=0; i<360*3; i++){
    d.setTime(d.getTime()+ unit*60*1000);
    var p = pref.sat1_orbit.calc(d);
    var position = p.latlng();
    data_array[i] = {"lat":position.latitude,"lng":position.longitude}
  }
  return {"data": data_array}
}

function showLatLngLines(){
  for (i = 0; i < 12; i++) {
    var lat = (i-9)*30;
    var center= map.getCenter();
    var center_lng = center.lng() 
    if(center_lng>0){
      lng_polyline1 = new GPolyline([new GLatLng(lat,0),new GLatLng(lat,-179)],"#777777",1,0.5);
      lng_polyline2 = new GPolyline([new GLatLng(lat,center_lng),new GLatLng(lat,0)],"#777777",1,0.5);
      lng_polyline3 = new GPolyline([new GLatLng(lat,center_lng),new GLatLng(lat,179)],"#777777",1,0.5);
      lng_polyline4 = new GPolyline([new GLatLng(lat,-179),new GLatLng(lat,-30)],"#777777",1,0.5);
    }else{
      lng_polyline1 = new GPolyline([new GLatLng(lat,180),new GLatLng(lat,30)],"#777777",1,0.5);
      lng_polyline2 = new GPolyline([new GLatLng(lat,center_lng),new GLatLng(lat,-179)],"#777777",1,0.5);
      lng_polyline3 = new GPolyline([new GLatLng(lat,center_lng),new GLatLng(lat,0)],"#777777",1,0.5);
      lng_polyline4 = new GPolyline([new GLatLng(lat,0),new GLatLng(lat,179)],"#777777",1,0.5);
    }
      map.addOverlay(lng_polyline1);
      map.addOverlay(lng_polyline2);
      map.addOverlay(lng_polyline3);
      map.addOverlay(lng_polyline4);
  }
  for (i = 0; i < 12; i++) {
    var lng = i*30;
    lat_polyline = new GPolyline([new GLatLng(-85,lng),new GLatLng(85,lng)],"#777777",1,0.5);
    map.addOverlay(lat_polyline);
  }
}


function short_updator(){
  var pref = new Pref();
  if(pref.status != "startup"){
    setIndicator()
  }
  delete pref;
  window.setTimeout("short_updator();",300000);
}

function mid_updator(){
  var pref = new Pref();
  if(pref.status != "startup"){
    if(pref.ground_track_flag){
      //DataLoader(GroundTrackLoader,pref.gt_query1,"text",false,"ground_track");
      Pref.prototype.gt = GroundTrackMaker();
       var now = now_sec();
       Pref.prototype.gt_loaded = now;
   }
  }
    delete pref;
    window.setTimeout("mid_updator();",1200000);
}

function long_updator(){
  var pref = new Pref();
  if(pref.status != "startup"){
    var nocache = "?nocache=" +(new Date()).getTime();
    DataLoader(DefaultSettingLoader,"./default.json"+nocache,"text",false,"default_settings");
    DataLoader(SatelliteListLoader,"./satellites.json"+nocache,"text",false,"satellite_list");
    sat_loader(pref.target);
    setIndicator()
  }
    delete pref;
    window.setTimeout("long_updator();",3600000);
}

function setIndicator(){
  var pref = new Pref();
  map.clearOverlays();
  removeMask()
  if(pref.latlngline_flag == true){
    showLatLngLines();
  }
  if((pref.night_shade_flag == true) || (pref.terminator_flag == true)){
    if(pref.night_shade_flag == true){
      night_shade = true;
    }else{
      night_shade = false    
    }
    if(pref.terminator_flag == true){
      boundary = true;
    }else{
      boundary = false;
    }
  var date = new Date();
  var terminator = new Terminator(date);
  terminator.show(map,boundary,night_shade);
  }
  if(pref.ground_track_flag == true){
    var ground_track = showGroundTrack();
  }
  showMask()
  delete pref;
}

function scanIndicator(){
  var pref = new Pref();
  if (document.forms[0].elements[0].checked){
      var now = now_sec();
      var e = now - pref.gt_loaded; 
 if(pref.ground_track_flag == true && e > 600000){
      //DataLoader(GroundTrackLoader,pref.gt_query1,"text",false,"ground_track");
      Pref.prototype.gt = GroundTrackMaker();
      Pref.prototype.gt_loaded = now;
    }
    Pref.prototype.ground_track_flag=true;
  }else{
    Pref.prototype.ground_track_flag=false;
  }
  if (document.forms[0].elements[1].checked){
    Pref.prototype.latlngline_flag=true;
  }else{
    Pref.prototype.latlngline_flag=false;
  }
  if (document.forms[0].elements[2].checked){
    if(document.forms[0].elements[3].options[0].selected){
      Pref.prototype.night_shade_flag=true;
      Pref.prototype.terminator_flag=false;
    }else if(document.forms[0].elements[3].options[1].selected){
      Pref.prototype.night_shade_flag=false;
      Pref.prototype.terminator_flag=true;
    }
  }else{
     Pref.prototype.night_shade_flag=false;
     Pref.prototype.terminator_flag=false;
  }
  if(document.forms[0].elements[4].options[0].selected){
    Pref.prototype.unit="km";
  }else if(document.forms[0].elements[4].options[1].selected){
    Pref.prototype.unit="mile";
  }
  setIndicator()
}

function showMessagePanel(){
  var pref = new Pref();
  if(pref.message_panel==false){
  var element = document.createElement('div'); 
  element.setAttribute('id', "message_panel");

  var estyle = element.style;
  estyle.cssText  = 'filter: alpha(opacity=60); -moz-opacity:0.60; opacity:0.60;';
  estyle.backgroundColor = 'black';
  estyle.color='#bbb';
  //estyle.fontSize = 'small';
  estyle.fontWeight='bold';
  estyle.width = '400px';
  estyle.height = 'auto';
  estyle.top = '200px';
  estyle.left = String(pref.map_width*0.5 - 200) + "px";
  estyle.padding = '10px';
  estyle.position = 'absolute';
  estyle.zIndex = '150';

    var mp_str = "";
    mp_str += '<div id="message_panel">';
    mp_str += '<div id="message_panel_body" style="margin-bottom:1em">';
    mp_str += pref.sat1_message;
    mp_str += '</div>';
    
    mp_str += '<div style="text-align:center;width:100%">';
    //mp_str += '<a href="javascript:void(0)" onclick="showMessagePanel()" style="text-decoration:none;">close</a>';
    mp_str += '<form><input type="button" name="string" value="OK" onclick="showMessagePanel()" style="background-color:#000;border-top: 1px solid #ccc; border-right: 1px solid #999; border-bottom: 1px solid #999; border-left: 1px solid #ccc; padding: 2px 10px; font-weight: bold; cursor: pointer; color: #bbb; "></form>';
    mp_str += '</div>';
    mp_str += '</div>';
    element.innerHTML = mp_str;
    var map_area = document.getElementById("map");
    map_area.appendChild(element);

    Pref.prototype.message_panel=true;
  }else{
    var map_area = document.getElementById("map"); 
    map_area.removeChild(document.getElementById("message_panel"));
    Pref.prototype.message_panel=false;  
  }
}

function showConfig(){
  var pref = new Pref();

  if (pref.config_window==false){
  var element = document.createElement('div'); 
  element.setAttribute('id', "config_panel_bk");

  var estyle = element.style;
  estyle.cssText  = 'filter: alpha(opacity=60); -moz-opacity:0.60; opacity:0.60;';
  estyle.backgroundColor = 'black';
  estyle.width = '768px';
  estyle.height = '512px';
  estyle.position = 'absolute';
  estyle.zIndex = '100';

  var element2 = document.createElement('div'); 
  element2.setAttribute('id', "config_panel");
  
  var estyle2 = element2.style;
  estyle2.cssText  = 'filter: alpha(opacity=100); -moz-opacity:1.0; opacity:1.0;';
  estyle2.width = '768px';
  estyle2.height = '512px';
  estyle2.position = 'absolute';
  estyle2.zIndex = '101';


  var satnum = Satellite.sat_list.length;
  var cp_str = "";
  cp_str += '<div style="text-align:center;">';
  cp_str += '<div style="width:600px;margin:1em auto auto auto;color:#ffffff;line-height:1.2em;text-align:left;">';
  cp_str += '<p style="margin:0 0 0 0;border-bottom:1px solid #fff;color:#ffffff;"><strong>select satellite from pre-set list</strong></p>';
  cp_str += '<form name="sat_selector" style="margin:0 0 0 0">';
  cp_str += '<span id="caption">preset satellites : </span><br>';
  cp_str += '<select name="sat_list" >';
  for(i=0; i<satnum; i++){
    var id = Satellite.sat_list[i];
    if(Satellite[id].label){
      var label = Satellite[id].label;
    }else{
      var label = Satellite[id].name;    
    }
    if(id == pref.default_target){
      cp_str += '<option value="index.html">' + label + " (default)</option>";
    }else{
      cp_str += '<option value="index.html?&target=' + Satellite[id].id +'">' + label + '</option>';
    }
  }
  cp_str += '</select>    ';
  cp_str += '<input type="button" value="apply selection" onclick="setPreset()">';
  cp_str += '</form>';
  cp_str += '<p style="margin:2em 0 0 0;border-bottom:1px solid #fff;color:#ffffff;"><strong>define satellite by name & two line elements</strong></p>';
  cp_str += '<form name="user_defined" style="margin:0 0 0 0" onSubmit="setUserDefined();return false;">';
  cp_str += '<span id="caption">satellite name : </span><br>';
  cp_str += '<input type ="text" name="sat_name" style="width:600px;" value="' + pref.sat1_label + '"/><br>';
  cp_str += '<span id="caption">two line elements : <span><br>';
  cp_str += '<textarea name="tle" style="width:600px; height:50px" cols = "2">'+pref.sat1_first_line+"\n"+pref.sat1_second_line+'</textarea>';  
  cp_str += '<div style="margin:1em auto auto auto;text-align:center;"><input type="button" value="apply definition" onclick="setUserDefined()"></div>';
  cp_str += ' </form>';
  cp_str += '<p style="font-size:small;">Due to the limitation of algorithms, the high altitude satellites whose orbital period is longer than 225 minutes (altitude higher than 5800km in circular orbit) may not show proper position yet.</p>';
  cp_str += ' </div></div>';
  element2.innerHTML = cp_str;

      var map_area = document.getElementById("map");
      map_area.appendChild(element);
      map_area.appendChild(element2);
      if(pref.data_panel==true){
        showData();
      }
      document.forms["config"].elements[5].checked = true;          
      Pref.prototype.config_window = true;
  }else{
      var map_area = document.getElementById("map"); 
      map_area.removeChild(document.getElementById("config_panel_bk"));
      map_area.removeChild(document.getElementById("config_panel"));
      document.forms["config"].elements[5].checked = false;          
      Pref.prototype.config_window = false;
  }
  delete pref;

}
function setPreset(){
   var url = document.forms["sat_selector"].elements["sat_list"].value
  location.href=url;

}
function setUserDefined(){
   var sat_name = document.forms["user_defined"].elements["sat_name"].value
   var tle = document.forms["user_defined"].elements["tle"].value
   var tle_array = tle.split("\n");
   var first_line = tle_array[0];
   var second_line = tle_array[1];   
   location.href="index.html?&target=custom&sat_name=" + sat_name + "&1st=" + first_line + "&2nd=" + second_line;

}
QueryDecoder = function(){
  var query=[];
  var q = location.search.replace(/^\?/, '&').split("&");
  var l = q.length;
  for(i=0; i<l;i++){
   var tmp_array = q[i].split("=");
      var name = tmp_array[0];
      var value = tmp_array[1];
      query[name] = value;
  }
  return query;
}

function escapeHTML(str) {
  return str.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "<").replace(/>/g, ">"); //"
}

tle_loader = function(sat){
  var result=[];
  if(sat.target=="custom"){
    var first_line = sat.first_line;
    var second_line = sat.second_line;
  }else{
    if(sat.target=="iss"||sat.target=="sts"){
      var pref = new Pref();
      var nocache = "?nocache=" +(new Date()).getTime();
      DataLoader(TLESourceLoader,pref.path.tle + sat.target+".txt" + nocache,"text",false, sat.target)
      var array=pref.tle_source;
      Pref.prototype.tle_source = [];
      var first_line =  array[0]["first_line"];
      var second_line = array[0]["second_line"];
      delete pref;
    }else{
      var pref = new Pref();
      var nocache = "?nocache=" +(new Date()).getTime();
      DataLoader(TLESourceLoader,pref.path.tle + "gst.txt" + nocache,"text",false, sat.target)
      var target_catalog_number = sat.catalog_number;
      var source_array=pref.tle_source;
      Pref.prototype.tle_source = [];
      var source_array_length = source_array.length;
	  var tle_array=[];
      for(i=0; i<source_array_length; i++){
        if(source_array[i]){
          var tmp_array=[];
          var sat_name =  source_array[i]["sat_name"];
          var line1 =  source_array[i]["first_line"];
          var line2 =  source_array[i]["second_line"];
          var catalog_number = String(line1.slice(2,7));
          if(catalog_number==target_catalog_number){
            var first_line =line1
            var second_line =line2
            break;
          }
        }
      }
	}
  }
  var tle = new TLE();
  var orbital_elements
  result["orbital_elements"] = tle.decode(first_line,second_line);
  result["first_line"] = first_line;
  result["second_line"] = second_line;
  return result;
}


function sat_loader (target){
  var target = target.split(",");
  Pref.prototype.sat1=[];
  var pref = new Pref();
  var sat1 = Satellite[target[0]];
  Pref.prototype.mode = sat1.mode;
  Pref.prototype.target = target;
  Pref.prototype.sat1_name = sat1.name;
  Pref.prototype.sat1_catalog_number = sat1.catalog_number;
  var tle1=tle_loader(sat1);
  Pref.prototype.sat1_first_line = tle1.first_line;
  Pref.prototype.sat1_second_line = tle1.second_line;
  Pref.prototype.sat1_orbit = new SGP4(tle1.orbital_elements);
  Pref.prototype.sat1_icon_image = sat1.icon_image;
  Pref.prototype.sat1_icon_shadow = sat1.icon_shadow;
  Pref.prototype.sat1_icon_size = sat1.icon_size;
  if(sat1.message){
    Pref.prototype.sat1_message = sat1.message;
  }
    //var nocache = "?nocache=" +(new Date()).getTime();
    //var gt_query = "gstserver.rb?mode=gt&target=custom&1st="+ tle1.first_line + "&2nd=" + tle1.second_line + nocache;
    //Pref.prototype.gt_query1 = gt_query;
    //DataLoader(GroundTrackLoader,gt_query,"text",false, "ground_track");
    Pref.prototype.gt = GroundTrackMaker();

  if(target[1] || sat1.mode == "double" || sat1.mode == "triple"){
    if(target[1]){
      var sat2 = Satellite[target[1]];
      Pref.prototype.mode = "double";
    }else{
      var sat2 = Satellite[sat1.second_target];
    }
    var tle2=tle_loader(sat2);
    Pref.prototype.sat2_name = sat2.name;
    Pref.prototype.sat2_catalog_number = sat2.catalog_number;
    Pref.prototype.sat2_first_line = tle2.first_line;
    Pref.prototype.sat2_second_line = tle2.second_line;
    Pref.prototype.sat2_orbit = new SGP4(tle2.orbital_elements);
    Pref.prototype.sat2_icon_image = sat2.icon_image;
    Pref.prototype.sat2_icon_shadow = sat2.icon_shadow;
    Pref.prototype.sat2_icon_size = sat2.icon_size;
  }
  if(target[2] || sat1.mode == "triple"){
    if(target[2]){
      var sat3 = Satellite[target[2]];
      Pref.prototype.mode = "triple";
    }else{
      var sat3 = Satellite[sat1.theard_target];
    }
    Pref.prototype.sat3_name = sat3.name;
    Pref.prototype.sat3_catalog_number = sat3.catalog_number;
    var tle3=tle_loader(sat3);
    Pref.prototype.sat3_first_line = tle3.first_line;
    Pref.prototype.sat3_second_line = tle3.second_line;
    Pref.prototype.sat3_orbit = new SGP4(tle3.orbital_elements);
    Pref.prototype.sat3_icon_image = sat3.icon_image;
    Pref.prototype.sat3_icon_shadow = sat3.icon_shadow;
    Pref.prototype.sat3_icon_size = sat3.icon_size;
  }
  delete pref;
  var now = now_sec();
  Pref.prototype.gt_loaded = now;

}

function custom_sat_loader(sat_name,first_line,second_line){
    Pref.prototype.mode = "single"
    Pref.prototype.target = "custom";
    Pref.prototype.gt_query1 = "gstserver.rb?mode=gt&target=custom&1st="+ first_line + "&2nd=" + second_line;
    Pref.prototype.sat1_name = sat_name;
    var tle = new TLE();
    Pref.prototype.orbital_elements1 = tle.decode(first_line,second_line);
    var pref = new Pref();
    //var nocache = "?nocache=" +(new Date()).getTime();
    //DataLoader(GroundTrackLoader,pref.gt_query1+nocache,"text",false,"custom");
    Pref.prototype.sat1_orbit = new SGP4(pref.orbital_elements1);
    Pref.prototype.gt = GroundTrackMaker();
    if(String(pref.orbital_elements1.catalog_no_1).indexOf(pref.decay_list_by_catalog_number)>-1 || String(sat_name).indexOf(pref.decay_list_by_name)>-1){
      Pref.prototype.sat1_message = sat_name + " is already re-entered Earth's atomosphiere.<br>It is not current position.<br/><br/>" +sat_name + " は大気圏に突入しました。<br>これは現在の軌道を示すものではありません。<br/><br/><a href='./'>>>Top Page</a>";
    }
    delete pref;
    Pref.prototype.sat1_icon_image = "image/sat1.png";
    Pref.prototype.sat1_icon_shadow = "image/shadow.png";  
    Pref.prototype.sat1_icon_size = 45;  
    var now = now_sec();
    Pref.prototype.gt_loaded = now;
}

function setCookie(){
  var expire = new Date();
  expire.setTime(expire.getTime()+(14*24*60*60*1000));
  var pref = new Pref();

  document.cookie = "gst_ground_track=" + pref.ground_track_flag + "; expires=" + expire.toGMTString();  //for debug
  document.cookie = "gst_latlngline=" + pref.latlngline_flag + "; expires=" + expire.toGMTString();  //for debug
  document.cookie = "gst_night_shade=" + pref.night_shade_flag + "; expires=" + expire.toGMTString();  //for debug
  document.cookie = "gst_terminator=" + pref.terminator_flag + "; expires=" + expire.toGMTString(); //for debug
  document.cookie = "gst_data_panel=" + pref.data_panel + "; expires=" + expire.toGMTString(); //for debug
  document.cookie = "gst_zoom_control=" + pref.zoom_control + "; expires=" + expire.toGMTString(); //for debug
  document.cookie = "gst_map_type_control=" + pref.map_type_control + "; expires=" + expire.toGMTString(); //for debug
  document.cookie = "gst_over_view_map=" + pref.over_view_map + "; expires=" + expire.toGMTString(); //for debug
  document.cookie = "gst_scale_control=" + pref.scale_control + "; expires=" + expire.toGMTString(); //for debug
  document.cookie = "gst_unit=" + pref.unit + "; expires=" + expire.toGMTString(); //for debug
  document.cookie = "gst_zoom=" + map.getZoom() + "; expires=" + expire.toGMTString(); //for debug
  return;
}

function getCookie(){
  var cookie_str=document.cookie;
  if(cookie_str){
    var cookie_array = cookie_str.split(";");
    var cookie_length = cookie_array.length;
    var cookie_hash = []
    for (i=0; i<cookie_length; i++){
      var temp_array = cookie_array[i].split("=");
      if(temp_array[1]=="true"){
        var flag=true;
      }else if(temp_array[1]=="false"){
        var flag=false;
      }
//indicators 
      if(temp_array[0].match(/gst_ground_track/)){ //for debug
        Pref.prototype.ground_track_flag=flag;
      }else if(temp_array[0].match(/gst_latlngline/)){  //for debug
        Pref.prototype.latlngline_flag=flag;
      }else if(temp_array[0].match(/gst_night_shade/)){  //for debug
        Pref.prototype.night_shade_flag=flag;
      }else if(temp_array[0].match(/gst_terminator/)){  //for debug
        Pref.prototype.terminator_flag=flag;
      }else if(temp_array[0].match(/gst_data_panel/)){  //for debug
        Pref.prototype.data_panel=flag;
//map controls 
      }else if(temp_array[0].match(/gst_zoom_control/)){  //for debug
        Pref.prototype.zoom_control=flag;
      }else if(temp_array[0].match(/gst_map_type_control/)){  //for debug
        Pref.prototype.map_type_control=flag;
      }else if(temp_array[0].match(/gst_over_view_map/)){  //for debug
        Pref.prototype.over_view_map=flag;
      }else if(temp_array[0].match(/gst_scale_control/)){  //for debug
        Pref.prototype.scale_control=flag;
//unit
      }else if(temp_array[0].match(/gst_unit/)){  //for debug
        Pref.prototype.unit=temp_array[1];
//zoom
      }else if(temp_array[0].match(/gst_zoom/)){  //for debug
        Pref.prototype.zoom=Number(temp_array[1]);
      }
    }    
  }
}

function  set_defaults(){
  sat_marker1 ="";
  sat_marker2 ="";
  sat_marker3 ="";
  var nocache = "?nocache=" +(new Date()).getTime();
  DataLoader(DefaultSettingLoader,"./default.json"+nocache,"text",false,"default_setttings");
  DataLoader(SatelliteListLoader,"./satellites.json"+nocache,"text",false,"satellite_list");
  Pref.prototype.zoom=Number(Default["zoom"]);
  Pref.prototype.maximum_zoom=Number(Default["maximum_zoom"]);
  Pref.prototype.minimum_zoom=Number(Default["minimum_zoom"]);
  Pref.prototype.default_target=Default["target"];
  Pref.prototype.msg=Default["message"];
  Pref.prototype.startup_msg=Default["startup_message"];
  Pref.prototype.unit = Default["unit"];
  Pref.prototype.ground_track_flag=true;
  Pref.prototype.low_load=false;
  Pref.prototype.latlngline_flag=true;
  Pref.prototype.night_shade_flag=true
  Pref.prototype.terminator_flag=false;
  Pref.prototype.fullwindow_flag = false;
  Pref.prototype.data_panel = Default["data_panel"];
  Pref.prototype.message_panel = false;
  Pref.prototype.startup_message_window = false;
  Pref.prototype.config_window = false;
  Pref.prototype.config_screen = false;
  Pref.prototype.tle_source = [];
  Pref.prototype.zoom_control=true;
  Pref.prototype.map_type_control=false;
  Pref.prototype.over_view_map=false;
  Pref.prototype.scale_control=false;
  getCookie();
  var pref = new Pref();

  if(pref.unit == "km"){
    Pref.prototype.unit_factor = 1;        
  }else if(pref.unit == "mile"){
    Pref.prototype.unit_factor = 0.621371192;
  }
  delete pref;
}

getScreenSize = function() {
  if ( window.innerWidth ) {
    var width = window.innerWidth;
  }
  else if ( document.documentElement && document.documentElement.clientWidth != 0 ) {
    var width =  document.documentElement.clientWidth;
  }
  else if ( document.body ) {
    var width = document.body.clientWidth;
  }
  if ( window.innerHeight ) {
    var height = window.innerHeight;
  }
  else if ( document.documentElement && document.documentElement.clientHeight != 0 ) {
    var height =  document.documentElement.clientHeight;
  }
  else if ( document.body ) {
    var height =  document.body.clientHeight;
  }
  this.width = width;
  this.height = height;
  return this;
}

function FitToWindow(){
  var pref=new Pref();
  var screen = getScreenSize();
  var prev_width = screen.width;
  var prev_height = screen.height;
  var new_width  = prev_width;
  var new_height  = prev_height;
  Pref.prototype.map_width=new_width;
  Pref.prototype.map_height=new_height;
  var d = document.getElementById("map").style;
  d.width  = new_width + "px";  
  d.height  = new_height + "px";
  
  if(new_width>=4096){
    Pref.prototype.minimum_zoom=4;
  }else if(new_width>=2048){
    Pref.prototype.minimum_zoom=3;
  }else if(new_width>=1024){
    Pref.prototype.minimum_zoom=2;
  }else if(new_width>=512){
    Pref.prototype.minimum_zoom=1;
  }else if(new_width>=256){
    Pref.prototype.minimum_zoom=0;  
  }
  if(pref.status=="running"){
    map.checkResize();
    setMoveMode(true);
  }
  clearTimeout(WindowResizeTimer);
  WindowResizeTimer = false
}

function showData(){
  var pref = new Pref();
    if(pref.data_panel==false){
        document.getElementById("data").style.display="block";
        if(document.addEventListener){
        document.getElementById("data").addEventListener("mousedown",onMouseDown,false);
        document.getElementById("data").addEventListener("mouseup",onMouseUp,false);
        }else{
        document.getElementById("data").attachEvent("onmousedown",onMouseDown);
        document.getElementById("data").attachEvent("onmouseup",onMouseUp);
        }
        Pref.prototype.data_panel=true;
    }else{
        if(document.removeEventListener){
        document.getElementById("data").removeEventListener("mousedown",onMouseDown,false);
        document.getElementById("data").removeEventListener("mouseup",onMouseUp,false);
        document.getElementById("data").style.display="none";
        }else{
        document.getElementById("data").detachEvent("onmousedown",onMouseDown);
        document.getElementById("data").detachEvent("onmouseup",onMouseUp);
        }
        document.getElementById("data").style.display="none";
        Pref.prototype.data_panel=false;  
    }

}

function showStartupMessage(){
  var pref = new Pref();
  var message=pref.startup_msg;
  var pref = new Pref();
  if(pref.startup_message_window==false){
    document.getElementById("startup_message").style.display="block";
    document.getElementById("startup_message_body").innerHTML=message;
    Pref.prototype.startup_message_window=true;
  }else{
    document.getElementById("startup_message").style.display="none";
    Pref.prototype.startup_message_window=false;  
  }

};

function StartUp(){
  if(window.top !== window.self){
    FitToWindow();
    var str = '<div style="line-height:1.5em;font-size:x-large;margin-top:5em;text-align:center"><strong>GoogleSatTrack is not designed to work in frames. <br> Please visit the original site <a href="http://www.lizard-tail.com/isana/tracking/" target="_top">http://www.lizard-tail.com/isana/tracking/</a> directly for satellite tracker.</strong><br><br><img src="image/iss.png"></div>';
    document.getElementById("map").innerHTML = str;
  }else{
    Pref.prototype.status = "startup"
    set_defaults()
    var pref = new Pref();
    var target = pref.default_target;
    delete pref;
    
    var q = new QueryDecoder();
    if(q["target"]){
      target = q["target"];
    }
    if(target=="custom"){
      var sat_name = escapeHTML(decodeURI(q["sat_name"]));
      var first_line = decodeURI(q["1st"]);
      var second_line = decodeURI(q["2nd"]);
      Pref.prototype.sat1_name=sat_name;
      Pref.prototype.sat1_first_line=first_line
      Pref.prototype.sat1_second_line=second_line
      custom_sat_loader(sat_name,first_line, second_line);
    }else{
      sat_loader(target);
    }

    FitToWindow();
    InitMap();
    long_updator();
    mid_updator();
    short_updator();
    setStaticData();
    map.checkResize();
    delete pref;
    var pref = new Pref();
    
    if(pref.mode=="double"){
      document.getElementById("sat1_data").style.display = "block"; 
      document.getElementById("sat2_data").style.display = "block"; 
      document.getElementById("distance_data").style.display = "block"; 
    }else{
      document.getElementById("sat1_data").style.display = "block"; 
    }
    CalcSat();
    setIndicator();
    if(pref.startup_msg){
      showStartupMessage()
    }
    document.getElementById("config_button").style.display = "block"; 
    if(pref.data_panel==true){
      Pref.prototype.data_panel=false;
      showData();
    }
    if(pref.zoom_control==true){
      Pref.prototype.zoom_control=false;
      ToggleZoomControl();
    }
    if(pref.map_type_control==true){
      Pref.prototype.map_type_control=false;
      ToggleMapTypeControl();
    }
    if(pref.over_view_map==true){
      Pref.prototype.over_view_map=false;
      ToggleOverViewMap();
    }
    if(pref.scale_control==true){
      Pref.prototype.scale_control=false;
      ToggleScaleControl();
    }
    if(pref.sat1_message){
    showMessagePanel(pref.sat1_message);
	}
	
    Pref.prototype.status = "running"
  }
  return;
}


function Unload(){
 var pref = new Pref();
 if(pref.low_load == false){
  setCookie();
 }
  GUnload();
  return;
}

window.onload = function(){
  if(document.attachEvent){
   document.getElementById('data').attachEvent('onselectstart', function(){return false}); 
  }
  StartUp()
}
window.onunload = function(){Unload()}
WindowResizeTimer = false;
window.onresize = function(){
  if(!WindowResizeTimer){
    window.setTimeout("FitToWindow()", 1000) 
    WindowResizeTimer = true;
  }
  return;
}

Pref.prototype.data_panel_left=50;
Pref.prototype.data_panel_top=5;

function onMouseDown(event){
  if(!event) {event = window.event}
  var pref = new Pref();
    if(document.addEventListener){
      document.addEventListener("mousemove",onMouseMove,false);
    }else{
      document.body.attachEvent("onmousemove",onMouseMove);
    }

  Pref.prototype.cursor_offset_x = event.clientX - pref.data_panel_left;
  Pref.prototype.cursor_offset_y = event.clientY - pref.data_panel_top;

  return;
  }

function onMouseUp(event){
  if(document.addEventListener){
    document.removeEventListener("mousemove",onMouseMove,false);
  }else{
    document.body.detachEvent("onmousemove",onMouseMove);
  }
  return;
}

function onMouseMove(event){
  if(!event) {event = window.event}
  var pref = new Pref();
  var top = Number(event.clientY-pref.cursor_offset_y);
  var left = Number(event.clientX-pref.cursor_offset_x);
  document.getElementById("data").style.top = top + 'px';
  document.getElementById("data").style.left =left + 'px';
  if(event.clientY>pref.map_height+5 || event.clientX>pref.map_width-5 || event.clientY<5 || event.clientX<5){
      if(document.addEventListener){
        document.removeEventListener("mousemove",onMouseMove,false);
      }else{
        document.body.detachEvent("onmousemove",onMouseMove);
      }
      return;  
  }

  Pref.prototype.data_panel_left=left;
  Pref.prototype.data_panel_top=top;
  return;
}



function ConfigScreen(panel){
    var pref = new Pref();
    var perent_obj = document.getElementsByTagName("body")[0]; 

    if (pref.config_screen==false){
      var cf_element = document.createElement('div'); 
      cf_element.id = "config_screen"; 
      cf_element.setAttribute('id', "config_screen");
      var cfstyle = cf_element.style;
      cfstyle.cssText = ""
      cfstyle.cssText  += 'filter: alpha(opacity=80); -moz-opacity:0.80; opacity:0.80;';
      cfstyle.cssText  += 'border:1px solid #0000ff;';
      cfstyle.backgroundColor = 'black';
      cfstyle.width = '640px';
      cfstyle.height = '480px';
      cfstyle.position = 'absolute';
      cfstyle.left = pref.map_width/2-320 + "px";
      cfstyle.top = pref.map_height/2-240 + "px";
      cfstyle.zIndex = '500';

      perent_obj.appendChild(cf_element);
      Pref.prototype.config_screen = true;
      SwitchConfigPanel(panel);
    }else{
      perent_obj.removeChild(document.getElementById("config_screen"));
      Pref.prototype.config_screen = false;
    }
  delete pref;
}

function SwitchConfigPanel(id){
    var pref = new Pref();
  var config_screen = document.getElementById("config_screen")
  config_screen.innerHTML = document.getElementById("config_screen_header").innerHTML;
  config_screen.innerHTML += document.getElementById(id).innerHTML;

  switch (id){
 case "config_about":
      var about_element = document.createElement('div'); 
      about_element.setAttribute('id', "about");
      var aboutstyle = about_element.style;
      aboutstyle.cssText = "margin:5px 20px 0 20px";

      var str =  '';
      str += "<p><strong>GoogleSatTrack " + pref.version + " (" + pref.release + ")</strong></p>";
      str += "<p>GoogleSatTrack (GST) shows the current position of the International Space Station (or various satellites in earth orbit) on Google Maps in real-time. </p>";
      str += "<p>Don't forget to set your computer clock accurately. </p>";
      str += "<p>Please note GoogleSatTrack is NOT a Google product.</p>";
      str += "<p>Author: KASHIWAI, Isana (isana.k [at] gmail.com)</p>";      
      str += "<p>---</p>";
      str += "<p>more infomation ... <a href='readme_en.html' target='_blank'>readme</a>.</p>";

      if(pref.msg){
         str += "<p>---</p>";
         str += "<strong>";
         str += "<p>" + pref.msg + "</p>";
         str += "</strong>";
      }

        about_element.innerHTML += str;

      config_screen.appendChild(about_element);
  break;

  case "config_view":
    var view_element = document.createElement('div'); 
    view_element.setAttribute('id', "view");
    view_element.style.cssText = "margin:5px 10px 0 10px";
    str = '';
    str += '<div id="indicator"><form name = "config">';
    str += '<p><input type="checkbox" name="indicatior" value="ground_track" onclick="scanIndicator()"/> Ground track</p>'
    str += '<p><input type="checkbox" name="indicatior" value="latlng_line"  onclick="scanIndicator()" /> Lat/Lon lines</p>';
    str += '<p><input type="checkbox" name="indicatior" value="night"  onclick="scanIndicator()" checked/> Night with <select onChange="scanIndicator()"><option value="shade"> shading </option><option value="line"> line </option></select></p>';
    str += '<p>Unit <select onChange="scanIndicator()"><option value="km"> km </option><option value="mile"> mile </option></select></p>';
    str += '<p><input type="checkbox" name="data_panel" value="show_data"  onclick="showData()"/>Data panel</p>';
    str += '<p>---</p>';
    str += '<p><input type="checkbox" name="zoom_control" value="zoom_control"  onclick="ToggleZoomControl()"/> zoom control</p>';
    str += '<p><input type="checkbox" name="map_type_control" value="map_type_control"  onclick="ToggleMapTypeControl()"/> map type control</p>';
    str += '<p><input type="checkbox" name="over_view_map" value="over_view_map"  onclick="ToggleOverViewMap()"/> over view map</p>';
    str += '<p><input type="checkbox" name="scale_control" value="scale_control"  onclick="ToggleScaleControl()"/> scale</p>';
    
    str += '</form></div>';
    
    view_element.innerHTML += str;
    config_screen.appendChild(view_element);

  if(pref.ground_track_flag == true){
    document.forms[0].elements[0].checked = true;
  }
  if(pref.latlngline_flag == true){
    document.forms[0].elements[1].checked = true;
  }

  if(pref.night_shade_flag == true || pref.terminator_flag == true){
    if(pref.night_shade_flag == true){
      document.forms[0].elements[2].checked = true;
      document.forms[0].elements[3].options[0].selected = true
    }else if(pref.terminator_flag == true){
      document.forms[0].elements[2].checked = true;
      document.forms[0].elements[3].options[1].selected = true;
    }
  }else{
    document.forms[0].elements[2].checked = false;
  }

  if(pref.unit == "km"){
    document.forms[0].elements[4].options[0].selected = true
  }else if(pref.unit == "mile"){
    document.forms[0].elements[4].options[1].selected = true
  }

  if(pref.data_panel==true){
    document.forms[0].elements["data_panel"].checked = true;
  }else{
    document.forms[0].elements["data_panel"].checked = false;
  }

  if(pref.zoom_control == true){
    document.forms[0].elements["zoom_control"].checked = true;
  }else{
    document.forms[0].elements["zoom_control"].checked = false;
  }

  if(pref.map_type_control == true){
    document.forms[0].elements["map_type_control"].checked = true;
  }else{
    document.forms[0].elements["map_type_control"].checked = false;
  }

  if(pref.over_view_map == true){
    document.forms[0].elements["over_view_map"].checked = true;
  }else{
    document.forms[0].elements["over_view_map"].checked = false;
  }

  if(pref.scale_control == true){
    document.forms[0].elements["scale_control"].checked = true;
  }else{
    document.forms[0].elements["scale_control"].checked = false;
  }


  break;

  case "config_satellites":
    var satellites_element = document.createElement('div'); 
    satellites_element.setAttribute('id', "satellites");
    satellites_element.style.cssText = "margin:5px 10px 0 10px";
  var satnum = Satellite.sat_list.length;
  var str = "";
  str += '<div style="text-align:center;">';
  str += '<div style="width:600px;margin:1em auto auto auto;color:#ffffff;line-height:1.2em;text-align:left;">';
  str += '<p style="margin:0 0 0 0;border-bottom:1px solid #fff;color:#ffffff;"><strong>select satellite from pre-set list</strong></p>';
  str += '<form name="sat_selector" style="margin:0 0 0 0;font-size:small">';
  str += '<span id="caption">preset satellites : </span><br>';
  str += '<select name="sat_list" style="font-size:small" >';
  for(i=0; i<satnum; i++){
    var id = Satellite.sat_list[i];
    var name = Satellite[id].name;    
    if(id == pref.default_target){
      str += '<option value="index.html">' + name + " (default)</option>";
    }else{
      str += '<option value="index.html?&target=' + Satellite[id].id +'">' + name + '</option>';
    }
  }
  str += '</select>    ';
  str += '<input type="button" value="apply selection" onclick="setPreset()">';
  str += '</form>';
  str += '<p style="margin:2em 0 0 0;border-bottom:1px solid #fff;color:#ffffff;"><strong>define satellite by name & two line elements</strong></p>';
  str += '<form name="user_defined" style="margin:0 0 0 0;font-size:small" onSubmit="setUserDefined();return false;">';
  str += '<span id="caption">satellite name : </span><br>';
  str += '<input type ="text" name="sat_name" style="width:600px;font-size:small" value="' + pref.sat1_name + '"/><br>';
  str += '<span id="caption">two line elements : <span><br>';
  str += '<textarea name="tle" style="width:600px; height:50px;font-size:small" cols = "2">'+pref.sat1_first_line+"\n"+pref.sat1_second_line+'</textarea>';  
  str += '<div style="margin:1em auto auto auto;text-align:center;"><input type="button" value="apply definition" onclick="setUserDefined()"></div>';
  str += ' </form>';
  str += '<p style="font-size:small;">Due to the limitation of algorithms, the high altitude satellites whose orbital period is longer than 225 minutes (altitude higher than 5800km in circular orbit) may not show proper position yet.</p>';
  str += ' </div></div>';

  satellites_element.innerHTML += str;
  config_screen.appendChild(satellites_element);

 break;

  }
  delete pref;
}

function ToggleZoomControl(){
  removeMask()
  var pref = new Pref();
  if(pref.zoom_control==false){
      map.addControl(SmallZoomControl, new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(5,40)));
      Pref.prototype.zoom_control=true;
   }else{
      map.removeControl(SmallZoomControl);
      Pref.prototype.zoom_control=false;
   }
  InitMask()
  showMask()
}


function ToggleMapTypeControl(){
  removeMask()
  var pref = new Pref()
  if(pref.map_type_control==false){
      map.addControl(MapTypeControl);
      Pref.prototype.map_type_control=true;
   }else{
      map.removeControl(MapTypeControl);
      Pref.prototype.map_type_control=false;
   }
  InitMask()
  showMask()
}


function ToggleOverViewMap(){
  removeMask()
  var pref = new Pref()
  if(pref.over_view_map==false){
      map.addControl(OverviewMapControl);
      Pref.prototype.over_view_map=true;
   }else{
      map.removeControl(OverviewMapControl);
      Pref.prototype.over_view_map=false;
   }
  InitMask()
  showMask()
}

function ToggleScaleControl(){
  removeMask()
  var pref = new Pref()
  if(pref.scale_control==false){
      map.addControl(ScaleControl);
      Pref.prototype.scale_control=true;
   }else{
      map.removeControl(ScaleControl);
      Pref.prototype.scale_control=false;
   }
  InitMask()
  showMask()
}


// Sub script (terminator overlay) for GoogleSatTrack var 3
// Copyright:: Copyright (C) 2009 Isana Kashiwai<isana at lizard-tail.com>
// License::  GPL
// Update:: 2009.03.24

Ephemeris = function(){}

Ephemeris.prototype.JulianDay = function(date){
  d = new Date();
  d.setTime(date.getTime())
  var year=d.getUTCFullYear();
  var month=d.getUTCMonth()+1;
  var day=d.getUTCDate();
  var calender="";

  if(month <= 2){
    var year = year - 1;
    var month = month + 12;
  } 

  var julian_day = Math.floor(365.25*(year+4716))+Math.floor(30.6001*(month+1))+day-1524.5;
  
  if (calender == "julian"){ 
    var transition_offset=0;
  }else if(calender == "gregorian"){
    var tmp = Math.floor(year/100);
    var transition_offset=2-tmp+Math.floor(tmp/4);
  }else if(julian_day<2299160.5){
    var transition_offset=0;
  }else{
    var tmp = Math.floor(year/100);
    var transition_offset=2-tmp+Math.floor(tmp/4);
  }
    var jd=julian_day+transition_offset;
    this.jd = jd;
    return jd
}


Ephemeris.prototype.GMST = function(date){
//load default values
  d = new Date();
  d.setTime(date.getTime())
  var hours=d.getUTCHours();
  var minutes=d.getUTCMinutes();
  var seconds=d.getUTCSeconds();
  var time_in_sec=hours*3600+minutes*60+seconds;
  var ephemeris = new Ephemeris()
  var jd = ephemeris.JulianDay(date);
  var rad=Math.PI/180;
  var deg=180/Math.PI;
  
//gmst at 0:00
  var t = (jd-2451545.0)/36525;
  var gmst_at_zero = (24110.5484 + 8640184.812866*t+0.093104*t*t+0.0000062*t*t*t)/3600;
  if(gmst_at_zero>24){gmst_at_zero=gmst_at_zero%24;}
  this.gmst_at_zero=gmst_at_zero;

//gmst at target time
  var gmst=gmst_at_zero+(time_in_sec * 1.00273790925)/3600;

  //mean obliquity of the ecliptic
  e = 23+26.0/60+21.448/3600 -46.8150/3600*t -0.00059/3600*t*t +0.001813/3600*t*t*t;
  //nutation in longitude
  omega = 125.04452-1934.136261*t+0.0020708*t*t+t*t*t/450000;
  long1 = 280.4665 + 36000.7698*t;
  long2 = 218.3165 + 481267.8813*t;
  phai = -17.20*Math.sin(omega*rad)-(-1.32*Math.sin(2*long1*rad))-0.23*Math.sin(2*long2*rad) + 0.21*Math.sin(2*omega*rad);
  gmst =gmst + ((phai/15)*(Math.cos(e*rad)))/3600

  if(gmst<0){gmst=gmst%24+24;}
  if(gmst>24){gmst=gmst%24;}
  this.gmst=gmst
  return gmst
}

Ephemeris.prototype.Sun = function(date){
  //load default values
  d = new Date();
  d.setTime(date.getTime())
  var hours=d.getUTCHours();
  var minutes=d.getUTCMinutes();
  var seconds=d.getUTCSeconds();
  var time_in_day=hours/24+minutes/1440+seconds/86400;
  
  var jd = this.JulianDay(date);
  var rad=Math.PI/180;

  //ephemeris days from the epch J2000.0
  var t = (jd + time_in_day -2451545.0)/36525;

  //geometric_mean_longitude
  var mean_longitude = 280.46646 + 36000.76983*t + 0.0003032*t*t;
  if(mean_longitude<0){mean_longitude=mean_longitude%360+360;}
  if(mean_longitude>360){mean_longitude=mean_longitude%360;}

  //mean anomaly of the Sun
  var mean_anomaly =  357.52911+ 35999.05029*t - 0.0001537*t*t;
  if(mean_anomaly<0){mean_anomaly=mean_anomaly%360+360;}
  if(mean_anomaly>360){mean_anomaly=mean_anomaly%360;}

  //eccentricity of the Earth's orbit
  var eccentricity = 0.016708634 - 0.000042037*t - 0.0000001267*t*t;

  //Sun's equation of  the center
  var equation = (1.914602 - 0.004817*t - 0.000014*t*t)*Math.sin(mean_anomaly*rad);
  equation += (0.019993 - 0.000101*t)*Math.sin(2*mean_anomaly*rad);
  equation += 0.000289 *Math.sin(3*mean_anomaly*rad);

  //true longitude of the Sun
  var true_longitude = mean_longitude + equation;
  //for more accuracy
  //var year=d.getUTCFullYear();
  //true_longitude = true_longitude - 0.01397*(year - 2000);  
  
  //true anomary of the Sun
  var true_anomary = mean_anomaly + equation;

  //radius vector, distance between center of the Sun and the Earth
  var radius = (1.000001018*(1-eccentricity*eccentricity))/(1 + eccentricity*Math.cos(true_anomary*rad));
  this.radius=radius;
  var distance=radius*149597870
  this.distance = distance;
  //apparent longitude
  var w = 125.04 - 1934.136*t;
  var apparent_longitude = true_longitude - 0.00569 - 0.00478 * Math.sin(w*rad);
  var longitude = apparent_longitude;
  this.longitude = longitude;

  //obliquity of the ecliptic
  var obliquity = 23+26.0/60+21.448/3600 -(46.8150/3600)*t -(0.00059/3600)*t*t +(0.001813/3600)*t*t*t; 

  //correction for apperent position of the sun 
  obliquity = obliquity+0.00256*Math.cos(w*rad);

  //right asantion of the Sun
  var sun_ra = Math.atan2(Math.cos(obliquity*rad)*Math.sin(longitude*rad), Math.cos(longitude*rad))
  sun_ra = sun_ra/rad;
  if(sun_ra<0){sun_ra=sun_ra+360;}
  if(sun_ra>360){sun_ra=sun_ra%360;}
  this.ra=sun_ra/15;

  //declination of the Sun
  var sun_dec = Math.asin(Math.sin(obliquity*rad)*Math.sin(longitude*rad));
  this.dec=sun_dec/rad;

	this.x = distance*Math.cos(longitude*rad);
	this.y = distance*(Math.sin(longitude*rad)*Math.cos(obliquity*rad));
	this.z = distance*(Math.sin(longitude*rad)*Math.sin(obliquity*rad));
  return this;
}

Terminator=function(date){
 this.date = date;
}

Terminator.prototype.generate = function(){
  date = this.date;
  var rad=Math.PI/180;
  var ephem = new Ephemeris();
  var sun = ephem.Sun(date);
  var sun_ra = sun.ra;
  var sun_dec = sun.dec;
  var gmst = ephem.GMST(date);
  var sun_long = -(gmst*15 - sun_ra*15);
  if (sun_long>360){sun_long=sun_long%360};
  if (sun_long<0){sun_long=sun_long%360+360};
  var sun_lat = sun_dec;

  if(sun_lat>5){
    var polar_night_flag = "south";
  }else if(sun_lat<-5){
    var polar_night_flag = "north";    
  }else{
    var polar_night_flag = "none";
  }

  var NightCircle = function(start,end,rev){
    var lat_array=[];
    var lng_array=[];
    for (i=start; i<= end; i+=1){
      var delta_lat = Math.asin(Math.cos(sun_lat*rad)*Math.sin(i*rad))/rad;
      if(Math.abs(delta_lat)<85){
        var x = -Math.cos(sun_long*rad)*Math.sin(sun_lat*rad)*Math.sin(i*rad)-Math.sin(sun_long*rad)*Math.cos(i*rad);
        var y = -Math.sin(sun_long*rad)*Math.sin(sun_lat*rad)*Math.sin(i*rad)+Math.cos(sun_long*rad)*Math.cos(i*rad);
        var delta_long = Math.atan2(y,x)/rad;
        if(delta_long>360){delta_long=delta_long%360}
        if(delta_long<0){delta_long=delta_long%360+360}
        lat_array.push(delta_lat);
        lng_array.push(delta_long);
      }
    }
    if(rev==true){
      this.lat_array= lat_array.reverse();
      this.lng_array= lng_array.reverse();
    }else{
      this.lat_array= lat_array;
      this.lng_array= lng_array;
    }
    return this;
  }
  var qtr=NightCircle(0,90,true);
  var latitude_array_east = qtr.lat_array;
  var longitude_array_east = qtr.lng_array;
  
  var qtr=NightCircle(270,360,true);
  latitude_array_east = latitude_array_east.concat(qtr.lat_array);
  longitude_array_east = longitude_array_east.concat(qtr.lng_array);
  
  var qtr=NightCircle(90,180,false);
  var latitude_array_west = qtr.lat_array;
  var longitude_array_west = qtr.lng_array;
  
  var qtr=NightCircle(180,270,false);
  latitude_array_west = latitude_array_west.concat(qtr.lat_array);
  longitude_array_west = longitude_array_west.concat(qtr.lng_array);

  if(sun_lat < 0){
    latitude_array_west.reverse();
    longitude_array_west.reverse();
  }else if(sun_lat > 0){
    latitude_array_east.reverse();
    longitude_array_east.reverse();
  }
  var latitude_array=latitude_array_east.concat(latitude_array_west);
  var longitude_array=longitude_array_east.concat(longitude_array_west);

  this.latitude_array=latitude_array;
  this.longitude_array=longitude_array;
  this.polar_night_flag = polar_night_flag;  
  return this;
}


Terminator.prototype.split = function(){
  var trm =this.generate();
  var lng_array = trm.longitude_array;
  var lat_array = trm.latitude_array;
  var array_length=lng_array.length;
  var start_lng = lng_array[0];
  var last_lng = lng_array[array_length-1];

  //var split_size = 90; //4 parts
  //var split_size = 45; //8 parts
  //var split_size = 30; //12 parts
  //var split_size = 22.5; //16 parts
  var split_size = 15; //24 parts
  //var split_size = 11.25; //32 parts
  //var split_size = 10; //36 parts
  //var split_size = 5; //72 parts
  //var split_size = 3; //120 parts
  if(start_lng>split_size){
    var first_split_point = Math.floor(start_lng/split_size)*split_size+split_size;
    if(first_split_point<=0){first_split_point=360}
  }else{
    var first_split_point = split_size;
  }
   var last_split_point = Math.floor(last_lng/split_size)*split_size+split_size;

  var split_latitude = function(lat1,lng1,lat2,lng2,split_lng){
    if(split_lng==360){
      var offset = 360
    }else{
      var offset=0
    }
    var  split_lat = lat1 + (split_lng- lng1)*((lat2-lat1)/((lng2+offset - lng1)));
    return split_lat;
  }

  var splitted_lng_array = [];
  var splitted_lat_array = [];
  var split_latlng_array = function(start,end,split_count,next){

    for (sp = start;sp<=end;sp=sp+split_size){
      splitted_lng_array[split_count]=[];
      splitted_lat_array[split_count]=[];
      for (i = next; i < array_length; i++) {
        if(sp>lng_array[i]&&sp-split_size<lng_array[i]){
          splitted_lng_array[split_count].push(lng_array[i])
          splitted_lat_array[split_count].push(lat_array[i])
        }else{
          var spl_lat = split_latitude(lat_array[i-1],lng_array[i-1],lat_array[i],lng_array[i],sp);
          splitted_lng_array[split_count].push(sp);
          splitted_lat_array[split_count].push(spl_lat);
          next = i;
          split_count++;
          break;
        }
      }
    }
    this.splitted_lng_array = splitted_lng_array;
    this.splitted_lat_array = splitted_lat_array;
    this.split_point = sp;
    this.split_count = split_count;
    this.next = next;
  }

  if(start_lng<last_lng){
    var sp = new split_latlng_array(first_split_point,last_split_point,0,0);
  }else{
    var sp = new split_latlng_array(first_split_point,360,0,0);
    sp = new split_latlng_array(split_size,last_split_point,sp.split_count,sp.next);
  }


  var splitted_lng_array = sp.splitted_lng_array;
  var splitted_lat_array = sp.splitted_lat_array;
  
 var sp_length = splitted_lng_array.length
 for(i=1;i<sp_length;i++){
   var last_lng = splitted_lng_array[i-1][splitted_lng_array[i-1].length-1];
   var last_lat = splitted_lat_array[i-1][splitted_lat_array[i-1].length-1];
   if(last_lng == 360){last_lng=0}
   splitted_lng_array[i].unshift(last_lng)
   splitted_lat_array[i].unshift(last_lat)
 }
  this.splitted_lng_array = splitted_lng_array;
  this.splitted_lat_array = splitted_lat_array;
  return this;

}

Terminator.prototype.show = function(map,boundary,night_shade){
  var split = this.split();
  var splitted_lng_array = split.splitted_lng_array;
  var splitted_lat_array = split.splitted_lat_array;
  var polar_night_flag = this.polar_night_flag;  

//Generate Porygon Array
  if(polar_night_flag=="north"){
    var lat_limit = 85;
  }else if(polar_night_flag=="south"){
    var lat_limit = -85;
  }

  var PorigonMaker = function(lng_array,lat_array,start_lat){
    var polygon = []
    var polyline = []
    var lng_array_length =lng_array.length;
    var lat_array_length =lat_array.length;
    var pref=new Pref();
    if(lng_array[0]>180){
      var true_lng = lng_array[0]-360;
    }else{
      var true_lng = lng_array[0];    
    }
    if(pref.move_mode=="fixed" && true_lng<0){
      lat_array.reverse();
      lng_array.reverse();
    }
    delete pref;
    if (lng_array_length>0){
      if(polar_night_flag!="none"){polygon.push(new GLatLng(lat_limit,lng_array[0]));}
      polygon.push(new GLatLng(start_lat,lng_array[0]));
      for (var i = 0; i < lat_array_length; i++) {
        polygon.push(new GLatLng(lat_array[i],lng_array[i]));    
        polyline.push(new GLatLng(lat_array[i],lng_array[i]));    
      }
      polygon.push(new GLatLng(start_lat,lng_array[lng_array_length-1]));
     
      if(polar_night_flag!="none"){polygon.push(new GLatLng(lat_limit,lng_array[lng_array_length-1]));}
      polygon.push(polygon[0]);
  
      if((lat_array[lat_array_length-1]==lat_array[lat_array_length-2])&&(lng_array[lng_array_length-1]!=lng_array[lng_array_length-2])){
          polyline.pop();  
      }  
      if((lat_array[0]==lat_array[1])&&(lng_array[0]!=lng_array[1])){
          polyline.shift();  
      }
    }
    this.polygon=polygon;
    this.polyline=polyline;
    return this;
  }
  
  var night_polygon_array = [];
  var night_polyline_array = [];
  var start_lat = splitted_lat_array[0][0];
  var al = splitted_lng_array.length;
  for(var j=0;j<al;j++){
    var p = new PorigonMaker(splitted_lng_array[j],splitted_lat_array[j],start_lat);
    night_polygon_array[j] = p.polygon;
    night_polyline_array[j] = p.polyline;
  }

  if (night_shade){
  var npl1 = night_polygon_array.length;
   for(var k1=0;k1<npl1;k1++){
      map.addOverlay(new GPolygon(night_polygon_array[k1], "#000000",1, 0, "#000000", 0.35));
    }
  }

  if (boundary){
    var npl2 = night_polyline_array.length;
    for(var k2=0;k2<npl2;k2++){
      map.addOverlay(new GPolyline(night_polyline_array[k2], "#000000", 2, 0.5));
    }
  }

}

// Orbital Propagation Model 'SGP4' for NORAD mean element sets
// Felix R. Hoots, Ronald L. Roehrich, "Space Track Report No.3 : Models for Propagation of NORAD Elements Sets"
// JavaScript version by KASHIWAI, Isana (isana at lizard-tail dot com)
// License::  GPL
// Update:: 2010.03.03

Clock = function(){}

Clock.prototype.JulianDay = function(date){
  d = new Date();
  d.setTime(date.getTime())
  var year=d.getUTCFullYear();
  var month=d.getUTCMonth()+1;
  var day=d.getUTCDate();
  var calender="";

  if(month <= 2){
    var year = year - 1;
    var month = month + 12;
  } 

  var julian_day = Math.floor(365.25*(year+4716))+Math.floor(30.6001*(month+1))+day-1524.5;
  
  if (calender == "julian"){ 
    var transition_offset=0;
  }else if(calender == "gregorian"){
    var tmp = Math.floor(year/100);
    var transition_offset=2-tmp+Math.floor(tmp/4);
  }else if(julian_day<2299160.5){
    var transition_offset=0;
  }else{
    var tmp = Math.floor(year/100);
    var transition_offset=2-tmp+Math.floor(tmp/4);
  }
    var jd=julian_day+transition_offset;
    this.jd = jd;
    return jd
}


Clock.prototype.GMST = function(date){
//load default values
  d = new Date();
  d.setTime(date.getTime())
  var hours=d.getUTCHours();
  var minutes=d.getUTCMinutes();
  var seconds=d.getUTCSeconds();
  var time_in_sec=hours*3600+minutes*60+seconds;
  var clock = new Clock()
  var jd = clock.JulianDay(date);
  var rad=Math.PI/180;
  var deg=180/Math.PI;
  
  var t = (jd-2451545.0)/36525;
  var gmst_at_zero = (24110.5484 + 8640184.812866*t+0.093104*t*t+0.0000062*t*t*t)/3600;
  var gmst=gmst_at_zero+(time_in_sec * 1.00273790925)/3600;

  if(gmst<0){gmst=gmst%24+24;}
  if(gmst>24){gmst=gmst%24;}
  this.gmst=gmst
  return gmst
}

TLE = function(){}

TLE.prototype.decode = function(line1,line2){
  var orbital_elements={
    line_number_1 :   Number(line1.slice(0,0)),
    catalog_no_1 :  Number(line1.slice(2,7)),
    security_classification :  Number(line1.slice(7,7)),
    international_identification : String(line1.slice(9,17)),
    epoch_year : Number(line1.slice(18,20)),
    epoch : Number(line1.substring(20,32)),
    first_derivative_mean_motion : Number(line1.substring(33,43)),
    second_derivative_mean_motion : Number(line1.substring(44,52)),
    bstar_mantissa: Number(line1.substring(53,59)),
    bstar_exponent : Number(line1.substring(59,61)),
    ephemeris_type :  Number(line1.substring(62,63)),
    element_number :  Number(line1.substring(64,68)),
    check_sum_1 :   Number(line1.substring(69,69)),
    line_number_2 :   Number(line1.slice(0,0)),
    catalog_no_2 :  Number(line2.slice(2,7)),
    inclination : Number(line2.substring(8,16)),
    right_ascension : Number(line2.substring(17,25)),
    eccentricity : Number(line2.substring(26,33)),
    argument_of_perigee : Number(line2.substring(34,42)),
    mean_anomaly : Number(line2.substring(43,51)),
    mean_motion : Number(line2.substring(52,63)),
    rev_number_at_epoch : Number(line2.substring(64,68)),
    check_sum_2 :   Number(line1.substring(68,69))
   }
  return orbital_elements;
}

TLE.prototype.elapsedTime = function(epoch_year,epoch,date){
  var d = new Date();
  d.setTime(date.getTime())
  var year=d.getUTCFullYear();
  var month=d.getUTCMonth()+1;
  var day=d.getUTCDate();
  var hours=d.getUTCHours();
  var minutes=d.getUTCMinutes();
  var seconds=d.getUTCSeconds();
  var year2=epoch_year-1;
  var now_sec=Date.UTC(year, month-1, day, hours, minutes, seconds);
  var epoch_sec=Date.UTC(year2, 11, 31, 0, 0, 0)+(epoch*24*60*60*1000);
  var elapsed_time=(now_sec-epoch_sec)/(60*1000);
  return elapsed_time.toFixed(2);
}

SGP4 = function(orbital_elements){
  var torad = Math.PI/180;
  var e6a = 1.0e-6;
  var tothrd = 0.66666667;
  var xj2 = 1.082616e-3;
  var xj4 = -1.65597e-6;
  var xj3 = -0.253881e-5;
  var xke = 0.743669161e-1;
  var xkmper = 6378.135;
  var min_par_day = 1440.0;
  var ae = 1.0;
  var qo = ae +120.0/xkmper;
  var ck2 =5.413080e-4;
  var ck4 = 0.62098875e-6;
  var qoms2t = 1.88027916e-9;
  var s = 1.0+78.0/xkmper;
  var de2ra = 0.174532925e-1;
  var pi = 3.14159265;
  var pio2 = 1.57079633;
  var twopi = 6.2831853;
  var x3pio2 = 4.71238898;

  var epy = Number(orbital_elements["epoch_year"]);
  //epoch_year should be smaller than 2057.
  if(epy<57){var epoch_year=epy+2000}else{var epoch_year=epy+1900};
  var epoch = orbital_elements["epoch"];
  var bstar_mantissa = orbital_elements["bstar_mantissa"]*1e-5;
  var bstar_exponent = Number("1e" + orbital_elements["bstar_exponent"]);
  var xincl = orbital_elements["inclination"]*torad;
  var xnodeo = orbital_elements["right_ascension"]*torad;
  var eo = orbital_elements["eccentricity"]*1e-7;
  var omegao  = orbital_elements["argument_of_perigee"]*torad;
  var xmo = orbital_elements["mean_anomaly"]*torad;
  var xno  = orbital_elements["mean_motion"]*2.0*Math.PI/1440.0;
  var bstar = bstar_mantissa*bstar_exponent

  var a1 = Math.pow(xke/xno,(2.0/3.0));
  var cosio=Math.cos(xincl);
  var theta2=cosio*cosio;
  var x3thm1=3*theta2-1.0;
  var eosq=eo*eo;
  var betao2=1-eosq;
  var betao=Math.sqrt(betao2);
  var del1=1.5*ck2*x3thm1/(a1*a1*betao*betao2);
  var ao=a1*(1-del1*((1.0/3.0)+del1*(1.0+(134.0/81.0)*del1)));
  var delo=1.5*ck2*x3thm1/(ao*ao*betao*betao2);
  var xnodp=xno/(1.0+delo); //original_mean_motion
  var aodp=ao/(1.0-delo); //semi_major_axis

  var orbital_period= 1440.0/Number(orbital_elements["mean_motion"]);

  var isimp=0;
  if ((aodp*(1.0-eo)/ae) < (220.0/xkmper+ae)){
    isimp=1;
  }

  var s4=s;
  var qoms24=qoms2t;
  var perige=(aodp*(1.0-eo)-ae)*xkmper;
  var apoge=(aodp*(1.0+eo)-ae)*xkmper;
  if (perige < 156.0){
    s4 = perige-78.0;
    if (perige <= 98.0){
      s4 = 20.0;
    }else{
      var qoms24=Math.pow(((120.0-s4)*ae/xkmper),4);
      s4 = s4/xkmper+ae;
	}
  }
  var pinvsq=1.0/(aodp*aodp*betao2*betao2);
  var tsi=1.0/(aodp-s4);
  var eta=aodp*eo*tsi;
  var etasq=eta*eta;
  var eeta=eo*eta;
  var psisq=Math.abs(1.0-etasq);
  var coef=qoms24*Math.pow(tsi,4);
  var coef1=coef/Math.pow(psisq,3.5);
  
  var c2=coef1*xnodp*(aodp*(1.0+1.5*etasq+eeta*(4.0+etasq))+0.75*ck2*tsi/psisq*x3thm1*(8.0+3.*etasq*(8.0+etasq)));
  var c1=bstar*c2;
  var sinio=Math.sin(xincl);
  var a3ovk2=-xj3/ck2*Math.pow(ae,3);
  var c3=coef*tsi*a3ovk2*xnodp*ae*sinio/eo;
  var x1mth2=1.0-theta2;
  var c4=2.0*xnodp*coef1*aodp*betao2*(eta*(2.0+0.5*etasq)+eo*(0.5+2.0*etasq)-2.0*ck2*tsi/(aodp*psisq)*(-3.0*x3thm1*(1.0-2.0*eeta+etasq*(1.5-0.5*eeta))+0.75*x1mth2*(2.0*etasq-eeta*(1.0+etasq))*Math.cos((2.0*omegao))));
  var c5=2.0*coef1*aodp*betao2*(1.0+2.75*(etasq+eeta)+eeta*etasq);

  var theta4=theta2*theta2;
  var temp1=3.0*ck2*pinvsq*xnodp;
  var temp2=temp1*ck2*pinvsq;
  var temp3=1.25*ck4*pinvsq*pinvsq*xnodp;
  var xmdot=xnodp+0.5*temp1*betao*x3thm1+0.0625*temp2*betao*(13.0-78.0*theta2+137.0*theta4);

  var x1m5th=1.0-5.0*theta2;
  var omgdot=-0.5*temp1*x1m5th+0.0625*temp2*(7.0-114.0*theta2+395.0*theta4)+temp3*(3.0-36.0*theta2+49.0*theta4);
  var xhdot1=-temp1*cosio;
  var xnodot=xhdot1+(0.5*temp2*(4.0-19.0*theta2)+2.0*temp3*(3.0-7.0*theta2))*cosio;
  var omgcof=bstar*c3*Math.cos(omegao);
  var xmcof=-tothrd*coef*bstar*ae/eeta;
  var xnodcf=3.5*betao2*xhdot1*c1;
  var t2cof=1.5*c1;
  var xlcof=0.125*a3ovk2*sinio*(3.0+5.0*cosio)/(1.0+cosio);
  var aycof=0.25*a3ovk2*sinio;
  var delmo=Math.pow((1.0+eta*Math.cos(xmo)),3);
  var sinmo=Math.sin(xmo);
  var x7thm1=7.*theta2-1.0;

  if (isimp != 1){
    var c1sq=c1*c1;
    var d2=4.*aodp*tsi*c1sq;
    var temp=d2*tsi*c1/3.0;
    var d3=(17.0*aodp+s4)*temp;
    var d4=0.5*temp*aodp*tsi*(221.0*aodp+31.*s4)*c1;
    var t3cof=d2+2.0*c1sq;
    var t4cof=0.25*(3.0*d3+c1*(12.0*d2+10.0*c1sq));
    var t5cof=0.2*(3.0*d4+12.0*c1*d3+6.0*d2*d2+15.*c1sq*(2.0*d2+c1sq));
  }  

//set accesser

  this.apoge=apoge
  this.perige=perige
  this.orbital_period=orbital_period;
  this.epoch_year=epoch_year;
  this.epoch=epoch;
  this.xmo = xmo;
  this.xmdot = xmdot;
  this.omegao = omegao;
  this.omgdot = omgdot;
  this.xnodeo = xnodeo;
  this.xnodot = xnodot;
  this.xnodcf = xnodcf
  this.bstar = bstar;
  this.t2cof = t2cof;
  this.omgcof = omgcof;
  this.isimp = isimp;
  this.xmcof = xmcof;
  this.eta = eta;
  this.delmo = delmo;
  this.c1 = c1;
  this.c4 = c4;
  this.c5 = c5;
  this.d2 = d2;
  this.d3 = d3;
  this.d4 = d4;
  this.sinmo = sinmo;
  this.t3cof = t3cof;
  this.t4cof = t4cof;
  this.t5cof = t5cof;
  this.aodp = aodp;
  this.eo = eo;
  this.xnodp = xnodp;
  this.xke = xke;
  this.xlcof = xlcof;
  this.aycof = aycof;
  this.x3thm1 = x3thm1;
  this.x1mth2 = x1mth2;
  this.xincl = xincl;
  this.cosio = cosio;
  this.sinio = sinio;
  this.e6a = e6a;
  this.ck2 = ck2;
  this.x7thm1 = x7thm1;
  this.xkmper = xkmper;
}

SGP4.prototype.calc = function(date){
  var d = new Date();
  d.setTime(date.getTime());
  var rad = Math.PI/180;

  //variable from SGP4.setConstant
  var xmo=this.xmo;
  var xmdot=this.xmdot;
  var omegao=this.omegao;
  var omgdot=this.omgdot;
  var xnodeo=this.xnodeo;
  var xnodot=this.xnodot;
  var xnodcf = this.xnodcf
  var bstar=this.bstar;
  var t2cof=this.t2cof;
  var omgcof=this.omgcof;
  var isimp=this.isimp;
  var xmcof=this.xmcof;
  var eta=this.eta;
  var delmo=this.delmo;
  var c1=this.c1;
  var c4=this.c4;
  var c5=this.c5;
  var d2=this.d2;
  var d3=this.d3;
  var d4=this.d4;
  var sinmo=this.sinmo;
  var t3cof=this.t3cof;
  var t4cof=this.t4cof;
  var t5cof=this.t5cof;
  var aodp=this.aodp;
  var eo=this.eo;
  var xnodp=this.xnodp;
  var xke=this.xke;
  var xlcof=this.xlcof;
  var aycof=this.aycof;
  var x3thm1=this.x3thm1;
  var x1mth2=this.x1mth2;
  var xincl=this.xincl;
  var cosio=this.cosio;
  var sinio=this.sinio;
  var e6a=this.e6a;
  var ck2=this.ck2;
  var x7thm1=this.x7thm1;
  var xkmper = this.xkmper;
  var epoch_year=this.epoch_year;
  var epoch=this.epoch;

  var tle = new TLE();
  var tsince = tle.elapsedTime(epoch_year,epoch,date);

  var xmdf=xmo+xmdot*tsince;
  var omgadf=omegao+omgdot*tsince;
  var xnoddf=xnodeo+xnodot*tsince;
  var omega=omgadf;
  var xmp=xmdf;
  var tsq=tsince*tsince;
  var xnode=xnoddf+xnodcf*tsq;
  var tempa=1.0-c1*tsince;
  var tempe=bstar*c4*tsince;
  var templ=t2cof*tsq;

  if (isimp != 1){
    var delomg=omgcof*tsince;
    var delm=xmcof*(Math.pow((1.0+eta*Math.cos(xmdf)),3)-delmo);
    var temp=delomg+delm;
    var xmp=xmdf+temp;
    var omega=omgadf-temp;
    var tcube=tsq*tsince;
    var tfour=tsince*tcube;
    var tempa=tempa-d2*tsq-d3*tcube-d4*tfour;
    var tempe=tempe+bstar*c5*(Math.sin(xmp)-sinmo);
    var templ=templ+t3cof*tcube+tfour*(t4cof+tsince*t5cof);
  }
  var a=aodp*tempa*tempa;
  var e=eo-tempe;
  var xl=xmp+omega+xnode+xnodp*templ;
  var beta=Math.sqrt(1.0-e*e);
  var xn=xke/Math.pow(a,1.5);

  // long period periodics
  var axn=e*Math.cos(omega);
  var temp=1.0/(a*beta*beta);
  var xll=temp*xlcof*axn;
  var aynl=temp*aycof;
  var xlt=xl+xll;
  var ayn=e*Math.sin(omega)+aynl;

  // solve keplers equation

  //var capu=Number(fmod2p(xlt-xnode));
  var capu = (xlt-xnode)%(2.0*Math.PI);
  var temp2=capu;
  for (i=1; i<=10; i++){
    var sinepw=Math.sin(temp2);
    var cosepw=Math.cos(temp2);
    var temp3=axn*sinepw;
    var temp4=ayn*cosepw;
    var temp5=axn*cosepw;
    var temp6=ayn*sinepw;
    var epw=(capu-temp4+temp3-temp2)/(1.0-temp5-temp6)+temp2;
  if (Math.abs(epw-temp2) <= e6a){
    break
  };
  temp2=epw;
}
     // short period preliminary quantities

  var ecose=temp5+temp6;
  var esine=temp3-temp4;
  var elsq=axn*axn+ayn*ayn;
  var temp=1.0-elsq;
  var pl=a*temp;
  var r=a*(1.0-ecose);
  var temp1=1.0/r;
  var rdot=xke*Math.sqrt(a)*esine*temp1;
  var rfdot=xke*Math.sqrt(pl)*temp1;
  var temp2=a*temp1;
  var betal=Math.sqrt(temp);
  var temp3=1.0/(1.0+betal);
  var cosu=temp2*(cosepw-axn+ayn*esine*temp3);
  var sinu=temp2*(sinepw-ayn-axn*esine*temp3);
  var u=Math.atan2(sinu,cosu);
  if (u<0){u+= 2* Math.PI;}
  var sin2u=2.0*sinu*cosu;
  var cos2u=2.0*cosu*cosu-1.;
  var temp=1.0/pl;
  var temp1=ck2*temp;
  var temp2=temp1*temp;

  // update for short periodics

  var rk=r*(1.0-1.5*temp2*betal*x3thm1)+0.5*temp1*x1mth2*cos2u;
  var uk=u-0.25*temp2*x7thm1*sin2u;
  var xnodek=xnode+1.5*temp2*cosio*sin2u;
  var xinck=xincl+1.5*temp2*cosio*sinio*cos2u;
  var rdotk=rdot-xn*temp1*x1mth2*sin2u;
  var rfdotk=rfdot+xn*temp1*(x1mth2*cos2u+1.5*x3thm1);

  // orientation vectors

  var sinuk=Math.sin(uk);
  var cosuk=Math.cos(uk);
  var sinik=Math.sin(xinck);
  var cosik=Math.cos(xinck);
  var sinnok=Math.sin(xnodek);
  var cosnok=Math.cos(xnodek);
  var xmx=-sinnok*cosik;
  var xmy=cosnok*cosik;
  var ux=xmx*sinuk+cosnok*cosuk;
  var uy=xmy*sinuk+sinnok*cosuk;
  var uz=sinik*sinuk;
  var vx=xmx*cosuk-cosnok*sinuk;
  var vy=xmy*cosuk-sinnok*sinuk;
  var vz=sinik*cosuk;
  var x=rk*ux;
  var y=rk*uy;
  var z=rk*uz;
  var xdot=rdotk*ux+rfdotk*vx;
  var ydot=rdotk*uy+rfdotk*vy;
  var zdot=rdotk*uz+rfdotk*vz;

  var xkm = (x*xkmper);
  var ykm = (y*xkmper);
  var zkm = (z*xkmper);
  var xdotkmps = (xdot*xkmper/60);
  var ydotkmps = (ydot*xkmper/60);
  var zdotkmps = (zdot*xkmper/60);

  
  this.x = xkm;
  this.y = ykm;
  this.z = zkm;
  

  this.xdot = xdotkmps;
  this.ydot = ydotkmps;
  this.zdot = zdotkmps;

  this.latlng = function(){
    var clock = new Clock()
    var gmst = clock.GMST(date);
    var lst = gmst*15;

    var f = 0.00335277945 //Earth's flattening term in WGS-72 (= 1/298.26)
    var a = 6378.135  //Earth's equational radius in WGS-72 (km)

    var r = Math.sqrt(xkm*xkm+ykm*ykm);
    var lng = Math.atan2(ykm,xkm)/rad - lst;
    if(lng>360){lng = lng%360;}
    if(lng<0){lng = lng%360+360;}    
    if(lng>180){lng=lng-360}
   
    var lat = Math.atan2(zkm,r);
    var e2 = f*(2-f);
    var tmp_lat = 0

    do{
      tmp_lat = lat;
      var sin_lat= Math.sin(tmp_lat)
      var c = 1/Math.sqrt(1-e2*sin_lat*sin_lat);
      lat= Math.atan2(zkm+a*c*e2*(Math.sin(tmp_lat)),r);
    }while(Math.abs(lat-tmp_lat)>0.0001);

    var alt = r/Math.cos(lat)-a*c;
    var v = Math.sqrt(xdotkmps*xdotkmps + ydotkmps*ydotkmps + zdotkmps*zdotkmps);

    this.longitude = lng
    this.latitude = lat/rad;
    this.altitude = alt;
    this.velocity = v;
    return this;
  }


  this.look = function(lat,lng,alt){
    var clock = new Clock()
    var gmst = clock.GMST(date);
    var lst = gmst*15 + lng;

    var a = 6378.135  //Earth's equational radius in WGS-72 (km)
    var f = 0.00335277945 //Earth's flattening term in WGS-72 (= 1/298.26)
    var sin_lat =Math.sin(lat*rad);
    var c = 1/Math.sqrt(1+f*(f-2)*sin_lat*sin_lat);
    var s = (1-f)*(1-f)*c;  
    var xo = a*c*Math.cos(lat*rad)*Math.cos(lst*rad);
    var yo = a*c*Math.cos(lat*rad)*Math.sin(lst*rad);
    var zo = a*s*Math.sin(lat*rad);


    var xs = xkm;
    var ys = ykm;
    var zs = zkm;

    var rx0= xs - xo;
    var ry0= ys - yo
    var rz0= zs - zo

    var rs = Math.sin(lat*rad)*Math.cos(lst*rad)*rx0 + Math.sin(lat*rad)*Math.sin(lst*rad)*ry0-Math.cos(lat*rad)*rz0;
    var re = -Math.sin(lst*rad)*rx0 + Math.cos(lst*rad)*ry0;
    var rz = Math.cos(lat*rad)*Math.cos(lst*rad)*rx0+Math.cos(lat*rad)*Math.sin(lst*rad)*ry0 + Math.sin(lat*rad)*rz0;
    var range = Math.sqrt(rs*rs+re*re+rz*rz);
    var elevation = Math.asin(rz/range);
    var azimuth  = Math.atan2(-re,rs);
    azimuth = azimuth/rad+180;
    if (azimuth>360){
    azimuth = azimuth%360;
    }
    
    this.range = range;
    this.elevation = elevation/rad;
    this.azimuth  = azimuth;
    return this;
  }
  return this;
}

