Bhikkhu-Kosalla 5 rokov pred
rodič
commit
6aab70798d
41 zmenil súbory, kde vykonal 11862 pridanie a 9 odobranie
  1. 79 0
      app/calendar/Gruntfile.js
  2. 200 3
      app/calendar/index1.html
  3. 17 0
      app/calendar/js/example.js
  4. 2856 0
      app/calendar/js/planet-positions.js
  5. 3 0
      app/calendar/js/planet-positions.min.js
  6. 79 0
      app/calendar/planet_position/Gruntfile.js
  7. 28 0
      app/calendar/planet_position/index.html
  8. 17 0
      app/calendar/planet_position/js/example.js
  9. 2856 0
      app/calendar/planet_position/js/planet-positions.js
  10. 3 0
      app/calendar/planet_position/js/planet-positions.min.js
  11. 27 0
      app/calendar/planet_position/package.json
  12. 31 0
      app/calendar/planet_position/readme.md
  13. 12 0
      app/calendar/planet_position/src/App.js
  14. 93 0
      app/calendar/planet_position/src/CelestialBody.js
  15. 146 0
      app/calendar/planet_position/src/Definitions.js
  16. 14 0
      app/calendar/planet_position/src/Math.js
  17. 516 0
      app/calendar/planet_position/src/MoonRealOrbit.js
  18. 31 0
      app/calendar/planet_position/src/NameSpace.js
  19. 247 0
      app/calendar/planet_position/src/OrbitalElements.js
  20. 44 0
      app/calendar/planet_position/src/SolarSystem.js
  21. 10 0
      app/calendar/planet_position/src/Three.shim.js
  22. 19 0
      app/calendar/planet_position/src/Utils.js
  23. 326 0
      app/calendar/planet_position/vendor/three/math/Euler.js
  24. 522 0
      app/calendar/planet_position/vendor/three/math/Quaternion.js
  25. 850 0
      app/calendar/planet_position/vendor/three/math/Vector3.js
  26. 12 0
      app/calendar/src/App.js
  27. 93 0
      app/calendar/src/CelestialBody.js
  28. 146 0
      app/calendar/src/Definitions.js
  29. 14 0
      app/calendar/src/Math.js
  30. 516 0
      app/calendar/src/MoonRealOrbit.js
  31. 31 0
      app/calendar/src/NameSpace.js
  32. 247 0
      app/calendar/src/OrbitalElements.js
  33. 44 0
      app/calendar/src/SolarSystem.js
  34. 10 0
      app/calendar/src/Three.shim.js
  35. 19 0
      app/calendar/src/Utils.js
  36. 326 0
      app/calendar/vendor/three/math/Euler.js
  37. 522 0
      app/calendar/vendor/three/math/Quaternion.js
  38. 850 0
      app/calendar/vendor/three/math/Vector3.js
  39. 1 1
      app/course/my_course_list.php
  40. 3 3
      app/pcdl/head_bar.php
  41. 2 2
      app/studio/index_tool_bar.php

+ 79 - 0
app/calendar/Gruntfile.js

@@ -0,0 +1,79 @@
+'use strict';
+
+module.exports = function(grunt) {
+
+	require('jit-grunt')(grunt);
+	require('time-grunt')(grunt);
+	// Project configuration.
+	grunt.initConfig({
+		// Metadata.
+		pkg: grunt.file.readJSON('package.json'),
+		banner: '/*! <%= pkg.title || pkg.name %> - v<%= pkg.version %> - ' +
+			'<%= grunt.template.today("yyyy-mm-dd") %>\n' +
+			'<%= pkg.homepage ? "* " + pkg.homepage + "\\n" : "" %>' +
+			'* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;'+
+			'*/\n\n',
+		
+		uglify: {
+			options: {
+				banner:  '<%= banner %>'
+			},
+			
+			build: {
+				src: 'js/planet-positions.js',
+				dest: 'js/planet-positions.min.js'
+			}			
+		},
+		
+		browserify : {
+			options : {
+				external: [],
+				browserifyOptions : {
+					debug: true
+				},
+				//
+			},
+			build : {
+				files: {'js/planet-positions.js' : './src/App.js'},
+				options : {
+					transform: [],
+					browserifyOptions : {
+						debug: true
+					},
+				}
+			}
+		},
+		
+		watch: {
+			js: {
+				files: 'src/**/*.js',
+				tasks: ['browserify:build'/*, 'uglify:prod'*/]
+			},			
+			scss: {
+				files: '**/*.scss',
+			
+				tasks: ['sass'],
+				options: {
+					spawn: false,
+					interrupt: true
+				}
+			
+			},
+		},
+
+		sass: {
+			development: {
+				options: {
+					style : 'compressed'
+				},
+				files: {
+					"css/main.css": "scss/main.scss",
+					"modules/views/email/css/main.css": "modules/views/email/scss/main.scss"
+				}
+			},
+		},	
+	});
+
+	grunt.registerTask('default', ['browserify:build', 'uglify:build']);	
+	
+};

+ 200 - 3
app/calendar/index1.html

@@ -16,6 +16,8 @@
     <script src="julian.js"></script>
     <script src="lune.js"></script>
     <script src="suncalc.js"></script>
+    <script src="./planet_position/js/planet-positions.js"></script>
+
     <script src="../studio/js/fixedsticky.js"></script>
     <script src="../guide/guide.js"></script>
     <link type="text/css" rel="stylesheet" href="../guide/guide.css" />
@@ -366,7 +368,64 @@
             "years": " සංවච්ඡ‍රා(නි) ",
             "yes_string": "can "
         };
+        var pali_month_name = [
+            { "id": "1", "value": "jeṭṭha", "season": "gimhāna", "season_icon": "☀" },//5.X-四-十五-心
+            { "id": "2", "value": "asāḷha", "season": "gimhāna", "season_icon": "☀" },//6.X-五-十五、十六-箕、斗
+            { "id": "3", "value": "sāvana", "season": "vassāna", "season_icon": "☔" },//7.X-六-十五-女
+            { "id": "4", "value": "poṭṭhapāda", "season": "vassāna", "season_icon": "☔" },//8.x-七-十五、十六-室、壁
+            { "id": "5", "value": "assajuja", "season": "vassāna", "season_icon": "☔" },//9.X-八-十五-樓
+            { "id": "6", "value": "kattika", "season": "vassāna", "season_icon": "☔" },//10.X-九-十五-昂
+            { "id": "7", "value": "māgasira", "season": "hemanta", "season_icon": "❄" },//11.X-十-十五-觜
+            { "id": "8", "value": "phussa", "season": "hemanta", "season_icon": "❄" },//12.X-十一-十五-鬼
+            { "id": "9", "value": "māgha", "season": "hemanta", "season_icon": "❄" },//1.X-十二-十五-星
+            { "id": "10", "value": "phagguna", "season": "hemanta", "season_icon": "❄" },//2.X-正月-十四、十五-張、異
+            { "id": "11", "value": "citta", "season": "gimhāna", "season_icon": "☀" },//3.X-二月-十五-角
+            { "id": "12", "value": "vesākha", "season": "gimhāna", "season_icon": "☀" }//4.X-三月-十五-氐
+        ]
+        var pali_nakkhatta_name = [
+            { "id": "0", "value": "assayuja", "name_zh": "娄宿" },
+            { "id": "1", "value": "bharaṇī", "name_zh": "胃宿" },
+            { "id": "2", "value": "Kattikā", "name_zh": "昂宿" },
+            { "id": "3", "value": "rohiṇī", "name_zh": "毕宿" },
+            { "id": "4", "value": "magasira", "name_zh": "觜宿" },
+            { "id": "5", "value": "Addā", "name_zh": "参宿" },
+            { "id": "6", "value": "punabbasu", "name_zh": "井宿" },
+            { "id": "7", "value": "phussa", "name_zh": "鬼宿" },
+            { "id": "8", "value": "Asilesā", "name_zh": "柳宿" },
+            { "id": "9", "value": "maghā", "name_zh": "星宿" },
+            { "id": "10", "value": "pubbaphagguṇī", "name_zh": "张宿" },
+            { "id": "11", "value": "uttaraphagguṇī", "name_zh": "翼宿" },
+            { "id": "12", "value": "hattha", "name_zh": "轸宿" },
+            { "id": "13", "value": "cittā", "name_zh": "角宿" },
+            { "id": "14", "value": "sāti", "name_zh": "亢宿" },
+            { "id": "15", "value": "visākhā", "name_zh": "氐宿" },
+            { "id": "16", "value": "anurādhā", "name_zh": "房宿" },
+            { "id": "17", "value": "jeṭṭha", "name_zh": "心宿" },
+            { "id": "18", "value": "mūlā", "name_zh": "尾宿" },
+            { "id": "19", "value": "pubbāsāḷha", "name_zh": "箕宿" },
+            { "id": "20", "value": "uttarāsāḷha", "name_zh": "斗宿" },
+            { "id": "21", "value": "savaṇa", "name_zh": "女宿" },
+            { "id": "22", "value": "dhaniṭṭhā", "name_zh": "虚宿" },
+            { "id": "23", "value": "satabhisaja", "name_zh": "危宿" },
+            { "id": "24", "value": "pubbabhaddapadā", "name_zh": "室宿" },
+            { "id": "25", "value": "uttarabhaddapadā", "name_zh": "壁宿" },
+            { "id": "26", "value": "revatī", "name_zh": "奎宿" }
+        ]
+        var horoscope_name = [
+            { "id": "0", "value": "Aries", "name_zh": "白羊", "icon": "♈" },
+            { "id": "1", "value": "Taurus", "name_zh": "金牛", "icon": "♉" },
+            { "id": "2", "value": "Gemini", "name_zh": "双子", "icon": "♊" },
+            { "id": "3", "value": "Cancer", "name_zh": "巨蟹", "icon": "♋" },
+            { "id": "4", "value": "Leo", "name_zh": "狮子", "icon": "♌" },
+            { "id": "5", "value": "Virgo", "name_zh": "处女", "icon": "♍" },
+            { "id": "6", "value": "Libra", "name_zh": "天秤", "icon": "♎" },
+            { "id": "7", "value": "Scorpio", "name_zh": "天蝎", "icon": "♏" },
+            { "id": "8", "value": "Sagittarius", "name_zh": "射手", "icon": "♐" },
+            { "id": "9", "value": "Capricornus", "name_zh": "摩羯", "icon": "♑" },
+            { "id": "10", "value": "Aquarius", "name_zh": "水瓶", "icon": "♒" },
+            { "id": "11", "value": "Pisces", "name_zh": "双鱼", "icon": "♓" }
 
+        ]
 
     </script>
     <style>
@@ -449,9 +508,13 @@
         <div>当前时间<span id="curr_time"></span></div>
         <div>现在时间<span id="now_time"></span></div>
         <div>当前時間戳<span id="curr_time_unix"></span></div>
+        <div>地球角度<span id="earth_angle"></span></div>
+        <div>月亮角度<span id="moon_angle"></span></div>
+        <div>月亮角度2<span id="moon_angle2"></span></div>
+
         <div>
-            <span>精准月相(强化戒德之日)</span>
-            <table id="lunar_phase_list" style="min-width: 40vw;">
+            <span>精准月相时间及星宿(强化戒德之日)</span>
+            <table id="lunar_phase_list" style="max-width: 70vw;width: -webkit-fill-available;">
             </table>
         </div>
 
@@ -465,12 +528,18 @@
         var first_list = new Array()//上弦月列表
         var full_list = new Array()//满月列表
         var last_list = new Array()//下弦月列表
+        var planets = new Array()//
+        var lunar_position = new Object
+
         var g_coordinate_this = new Object();
         var g_now_date = new Date();
         var today = new Date()
         var start_day = new Date()
         var next_year = new Date();
         var sun_times = new Object();
+
+
+
         var curr_position = localStorage.getItem("local_position");
         if (curr_position) {
             g_coordinate_this.AT = curr_position.split("#")[0];
@@ -524,6 +593,11 @@
             console.log(first_list)//输出到控制台
             console.log(full_list)//输出到控制台
             lunar_phase_list_refresh()
+            get_position(today)
+
+
+            let d_earth_to_moon = (lunar_position.position.x ^ 2 + lunar_position.position.y ^ 2 + lunar_position.position.z ^ 2) ^ 0.5
+            let d_earth_to_moon_0 = phase(today).distance
 
             sun_times = SunCalc.getTimes(today, g_coordinate_this.AT, g_coordinate_this.LT, g_coordinate_this.height / 1000);
             sun_position = SunCalc.getPosition(today, g_coordinate_this.AT, g_coordinate_this.LT);
@@ -542,8 +616,97 @@
             $("#now_time").html(g_now_date.toLocaleTimeString());//现在
             $("#curr_time_unix").html(today.getTime());//時間戳
 
+            let earth_angle_string = ""
+            earth_angle_string += get_position(today).solar_position_angle + "——"
+            earth_angle_string += get_position(today).solar_position_angle_round + "——"
+            earth_angle_string += get_position(today).solar_station + "——"
+            earth_angle_string += get_station_name(today).solar.icon
+            $("#earth_angle").html(earth_angle_string);//地球角度
+
+            let moon_angle_string = ""
+            moon_angle_string += get_position(today).lunar_position_angle + "——"
+            moon_angle_string += get_position(today).lunar_position_angle_round + "——"
+            moon_angle_string += get_position(today).lunar_station + "——"
+            moon_angle_string += get_station_name(today).lunar.value
+            $("#moon_angle").html(moon_angle_string);//月亮角度——角度差算法
+
+            let moon_angle_string2 = ""
+            moon_angle_string2 += get_position(today).lunar_position_angle2 + "——"
+            moon_angle_string2 += get_position(today).lunar_position_angle_round2 + "——"
+            moon_angle_string2 += get_position(today).lunar_station2 + "——"
+            moon_angle_string2 += get_station_name(today).lunar.value
+            $("#moon_angle2").html(moon_angle_string2);//月亮角度——向量差算法
+
 
 
+        }
+        function get_position(date_time) {
+            let planets_position = new Object
+            planets = window.lagrange.planet_positions.getPositions(date_time);
+            //planets = global.planet_positions.getPositions(today);
+            //console.log(planets)//输出到控制台
+            earth_position = window.lagrange.planet_positions.getPositions(date_time)[3]
+            lunar_position = window.lagrange.planet_positions.getPositions(date_time)[11]
+            let lunar_position_angle = 0
+            let lunar_station = 0
+            let earth_position_angle = 0
+            let earth_station = 0
+            let earth_position_angle_round = 0
+            let lunar_position_angle_round = 0
+            //太阳相对地球的黄道偏角
+            if (earth_position.position.y >= 0) {
+                earth_position_angle = Math.atan2(earth_position.position.y, earth_position.position.x)
+            }
+            else {
+                earth_position_angle = Math.PI * 2 + Math.atan2(earth_position.position.y, earth_position.position.x)
+            }
+            earth_position_angle_round = earth_position_angle / Math.PI / 2 + 0.5
+            earth_position_angle_round = earth_position_angle_round - Math.floor(earth_position_angle_round)
+            earth_station = earth_position_angle_round * 12
+            planets_position.solar_station = earth_station
+            planets_position.solar_position_angle = earth_position_angle_round * Math.PI * 2
+            planets_position.solar_position_angle_round = earth_position_angle_round
+            //月球相对地球的黄道偏角——角度差算法
+            lunar_position_angle_round = earth_position_angle_round + phase(date_time).phase
+            lunar_position_angle_round = lunar_position_angle_round - Math.floor(lunar_position_angle_round)
+            lunar_position_angle = lunar_position_angle_round * Math.PI * 2
+            lunar_station = lunar_position_angle_round * 27
+            //月球相对地球的黄道偏角算法——向量差算法
+            let lunar_to_earth = new Object
+            lunar_to_earth.y = lunar_position.position.y - earth_position.position.y
+            lunar_to_earth.x = lunar_position.position.x - earth_position.position.x
+            if (lunar_to_earth.y >= 0) {
+                lunar_position_angle2 = Math.atan2(lunar_to_earth.y, lunar_to_earth.x)
+            }
+            else {
+                lunar_position_angle2 = Math.PI * 2 + Math.atan2(lunar_to_earth.y, lunar_to_earth.x)
+            }
+            lunar_position_angle_round2 = lunar_position_angle2 / Math.PI / 2
+            //lunar_position_angle_round = lunar_position_angle_round - Math.floor(lunar_position_angle_round)
+            lunar_position_angle2 = lunar_position_angle_round2 * Math.PI * 2
+
+            lunar_station2 = lunar_position_angle_round2 * 27
+
+            planets_position.lunar_station = lunar_station
+            planets_position.lunar_position_angle = lunar_position_angle
+            planets_position.lunar_position_angle_round = lunar_position_angle_round
+            planets_position.lunar_station2 = lunar_station2
+            planets_position.lunar_position_angle2 = lunar_position_angle2
+            planets_position.lunar_position_angle_round2 = lunar_position_angle_round2
+            return (planets_position)
+        }
+        function get_station_name(data_time) {//获取星象信息
+            let solar_num = 0
+            let lunar_num = 0
+            solar_num = get_position(data_time).solar_station
+            solar_num = Math.floor(solar_num)
+            lunar_num = get_position(data_time).lunar_station
+            lunar_num = Math.floor(lunar_num)
+
+            let result = new Object
+            result.solar = horoscope_name[solar_num]
+            result.lunar = pali_nakkhatta_name[lunar_num]
+            return (result)
         }
         function lunar_phase_list_refresh() {
             let output = ""
@@ -560,11 +723,21 @@
             for (let i_month = 0; i_month < month_num; i_month++) {
                 output += "<tr class='table_line'>"
                 output += "<td class='table_column'>"
-                output += i_month + 1
+                output += Math.round(get_position(full_list[i_month]).solar_station * 100) / 100
+                //output += "—"
+                //output += get_station_name(full_list[i_month]).lunar.value
+                //output += "—"
+                //output += get_station_name(full_list[i_month]).solar.name_zh
+                //output += "—"
+                //output += get_station_name(full_list[i_month]).solar.icon
                 output += "</td>"
+                //下弦月
                 if (SunCalc.getTimes(last_list[i_month], g_coordinate_this.AT, g_coordinate_this.LT, g_coordinate_this.height / 1000).dawn - last_list[i_month] <= 0) {//如果在破晓之后,不修正
                     output += "<td class='table_column' title='" + last_list[i_month].toLocaleTimeString() + "'>"
                     output += last_list[i_month].toLocaleDateString()
+                    output += "<br />"
+                    output += get_station_name(last_list[i_month]).lunar.value
+                    //output += Math.round(get_position(last_list[i_month]).lunar_station * 100) / 100
                     output += "</td>"
                 }
                 else {//如果在破晓之前,修正提前一天
@@ -572,11 +745,18 @@
                     let temp_date = last_list[i_month]
                     temp_date.setDate(temp_date.getDate() - 1)
                     output += temp_date.toLocaleDateString()
+                    output += "<br />"
+                    output += get_station_name(last_list[i_month]).lunar.value
+                    //output += Math.round(get_position(last_list[i_month]).lunar_station * 100) / 100
                     output += "</td>"
                 }
+                //新月
                 if (SunCalc.getTimes(new_list[i_month], g_coordinate_this.AT, g_coordinate_this.LT, g_coordinate_this.height / 1000).dawn - new_list[i_month] <= 0) {//如果在破晓之后,不修正
                     output += "<td class='table_column' title='" + new_list[i_month].toLocaleTimeString() + "'>"
                     output += new_list[i_month].toLocaleDateString()
+                    output += "<br />"
+                    output += get_station_name(new_list[i_month]).lunar.value
+                    //output += Math.round(get_position(new_list[i_month]).lunar_station * 100) / 100
                     output += "</td>"
                 }
                 else {//如果在破晓之前,修正提前一天
@@ -584,11 +764,18 @@
                     let temp_date = new_list[i_month]
                     temp_date.setDate(temp_date.getDate() - 1)
                     output += temp_date.toLocaleDateString()
+                    output += "<br />"
+                    output += get_station_name(new_list[i_month]).lunar.value
+                    //output += Math.round(get_position(new_list[i_month]).lunar_station * 100) / 100
                     output += "</td>"
                 }
+                //上弦月
                 if (SunCalc.getTimes(first_list[i_month], g_coordinate_this.AT, g_coordinate_this.LT, g_coordinate_this.height / 1000).dawn - first_list[i_month] <= 0) {//如果在破晓之后,不修正
                     output += "<td class='table_column' title='" + first_list[i_month].toLocaleTimeString() + "'>"
                     output += first_list[i_month].toLocaleDateString()
+                    output += "<br />"
+                    output += get_station_name(first_list[i_month]).lunar.value
+                    //output += Math.round(get_position(first_list[i_month]).lunar_station * 100) / 100
                     output += "</td>"
                 }
                 else {//如果在破晓之前,修正提前一天
@@ -596,11 +783,18 @@
                     let temp_date = first_list[i_month]
                     temp_date.setDate(temp_date.getDate() - 1)
                     output += temp_date.toLocaleDateString()
+                    output += "<br />"
+                    output += get_station_name(first_list[i_month]).lunar.value
+                    //output += Math.round(get_position(first_list[i_month]).lunar_station * 100) / 100
                     output += "</td>"
                 }
+                //满月
                 if (SunCalc.getTimes(full_list[i_month], g_coordinate_this.AT, g_coordinate_this.LT, g_coordinate_this.height / 1000).dawn - full_list[i_month] <= 0) {//如果在破晓之后,不修正
                     output += "<td class='table_column' title='" + full_list[i_month].toLocaleTimeString() + "'>"
                     output += full_list[i_month].toLocaleDateString()
+                    output += "<br />"
+                    output += get_station_name(full_list[i_month]).lunar.value
+                    //output += Math.round(get_position(full_list[i_month]).lunar_station * 100) / 100
                     output += "</td>"
                 }
                 else {//如果在破晓之前,修正提前一天
@@ -608,6 +802,9 @@
                     let temp_date = full_list[i_month]
                     temp_date.setDate(temp_date.getDate() - 1)
                     output += temp_date.toLocaleDateString()
+                    output += "<br />"
+                    output += get_station_name(full_list[i_month]).lunar.value
+                    //output += Math.round(get_position(full_list[i_month]).lunar_station * 100) / 100
                     output += "</td>"
                 }
                 output += "</tr>"

+ 17 - 0
app/calendar/js/example.js

@@ -0,0 +1,17 @@
+
+(function(ns){
+'use strict';
+
+	var pp = ns.planet_positions;
+
+	var planets = pp.getPositions(new Date('1977-12-21T12:00:00Z'), true);
+	console.log(planets);
+	planets.forEach(function(pos){
+		var div = document.createElement('div');
+		div.className = 'planet';
+		div.innerHTML = pos.name;
+		div.style.top = ((-pos.position.y / 2000000000)+(window.innerHeight/2))+'px';
+		div.style.left = ((pos.position.x / 2000000000)+(window.innerWidth/2))+'px';
+		document.body.appendChild(div); 
+	});
+}(window.lagrange));

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 2856 - 0
app/calendar/js/planet-positions.js


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 3 - 0
app/calendar/js/planet-positions.min.js


+ 79 - 0
app/calendar/planet_position/Gruntfile.js

@@ -0,0 +1,79 @@
+'use strict';
+
+module.exports = function(grunt) {
+
+	require('jit-grunt')(grunt);
+	require('time-grunt')(grunt);
+	// Project configuration.
+	grunt.initConfig({
+		// Metadata.
+		pkg: grunt.file.readJSON('package.json'),
+		banner: '/*! <%= pkg.title || pkg.name %> - v<%= pkg.version %> - ' +
+			'<%= grunt.template.today("yyyy-mm-dd") %>\n' +
+			'<%= pkg.homepage ? "* " + pkg.homepage + "\\n" : "" %>' +
+			'* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;'+
+			'*/\n\n',
+		
+		uglify: {
+			options: {
+				banner:  '<%= banner %>'
+			},
+			
+			build: {
+				src: 'js/planet-positions.js',
+				dest: 'js/planet-positions.min.js'
+			}			
+		},
+		
+		browserify : {
+			options : {
+				external: [],
+				browserifyOptions : {
+					debug: true
+				},
+				//
+			},
+			build : {
+				files: {'js/planet-positions.js' : './src/App.js'},
+				options : {
+					transform: [],
+					browserifyOptions : {
+						debug: true
+					},
+				}
+			}
+		},
+		
+		watch: {
+			js: {
+				files: 'src/**/*.js',
+				tasks: ['browserify:build'/*, 'uglify:prod'*/]
+			},			
+			scss: {
+				files: '**/*.scss',
+			
+				tasks: ['sass'],
+				options: {
+					spawn: false,
+					interrupt: true
+				}
+			
+			},
+		},
+
+		sass: {
+			development: {
+				options: {
+					style : 'compressed'
+				},
+				files: {
+					"css/main.css": "scss/main.scss",
+					"modules/views/email/css/main.css": "modules/views/email/scss/main.scss"
+				}
+			},
+		},	
+	});
+
+	grunt.registerTask('default', ['browserify:build', 'uglify:build']);	
+	
+};

+ 28 - 0
app/calendar/planet_position/index.html

@@ -0,0 +1,28 @@
+<!doctype html>
+<html xmlns:fb="http://ogp.me/ns/fb#">
+	<head>	
+		<meta charset="utf-8">
+		<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+		<meta name="author" content="Martin Vézina, La Grange">
+		<title>jsOrrery - Javascript Solar System Simulator</title>
+
+		<meta property="og:title" content="jsOrrery - Solar System Simulator" /> 
+		<style>
+			.planet{
+				position:absolute;
+				width:4px;
+				height:4px;
+				margin-top:-2px;
+				margin-left:-2px;
+				border-radius: 2px;
+				background:red;
+			}
+		</style>
+	</head>
+	<body>
+
+		<script src="./js/planet-positions.js"></script>
+		<script src="./js/example.js"></script>
+
+	</body>
+</html>

+ 17 - 0
app/calendar/planet_position/js/example.js

@@ -0,0 +1,17 @@
+
+(function(ns){
+'use strict';
+
+	var pp = ns.planet_positions;
+
+	var planets = pp.getPositions(new Date('1977-12-21T12:00:00Z'), true);
+	console.log(planets);
+	planets.forEach(function(pos){
+		var div = document.createElement('div');
+		div.className = 'planet';
+		div.innerHTML = pos.name;
+		div.style.top = ((-pos.position.y / 2000000000)+(window.innerHeight/2))+'px';
+		div.style.left = ((pos.position.x / 2000000000)+(window.innerWidth/2))+'px';
+		document.body.appendChild(div); 
+	});
+}(window.lagrange));

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 2856 - 0
app/calendar/planet_position/js/planet-positions.js


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 3 - 0
app/calendar/planet_position/js/planet-positions.min.js


+ 27 - 0
app/calendar/planet_position/package.json

@@ -0,0 +1,27 @@
+{
+	"name": "planet-positions.js",
+	"title": "Planet positions calculator",
+	"version": "0.0.1",
+	"homepage": "",
+	"author": {
+		"name": "Martin Vézina",
+		"email": "m.vezina@la-grange.ca"
+	},
+	"devDependencies": {
+		"grunt-contrib-watch": "~0.4.4",
+		"grunt": "~0.4.4",
+		"grunt-contrib-sass": "latest",
+		"grunt-contrib-uglify": "latest",
+		"grunt-contrib-concat": "latest",
+	   	"browserify-shim" : "~3.4.1",
+   		"grunt-browserify": "latest",
+    	"time-grunt": "latest",
+    	"jit-grunt": "latest"
+	},
+	"dependencies" : {
+	},
+	"browser": {
+		"ns": "./src/NameSpace.js"
+	},
+	"keywords": []
+}

+ 31 - 0
app/calendar/planet_position/readme.md

@@ -0,0 +1,31 @@
+#Planet positions
+
+Computes planet positions, plus the Earth's Moon, on any given UTC time.
+
+##Usage
+
+Include planet-positions.js (or planet-positions.min.js), then call 
+
+```javascript
+var planets = window.lagrange.planet_positions.getPositions(new Date());
+```
+
+An array of objects will be returned, one for each planet, with a Three.js Vector3 as the planet's position. If you also want to receive the planet's velocity as a Vector3, specify a second parameter set to true.
+
+```
+{
+	name: 'earth',
+	position: Three.Vector3,
+	velocity: Three.Vector3
+}
+```
+
+
+Credits
+-------
+
+* Planets orbital elements were taken from Nasa's [Jet Propulsion Laboratory](http://ssd.jpl.nasa.gov/?planet_pos).
+* I learned about calculating positions from orbital elements by reading these documents by [Keith Burnett](http://www.stargazing.net/kepler/ellipse.html), [Paul Schlyter](http://www.stjarnhimlen.se/comp/tutorial.html) and [E M Standish (JPL)](http://ssd.jpl.nasa.gov/txt/aprx_pos_planets.pdf).
+* David Eagle for orbital calculations of the moon, based on "Lunar Tables and Programs From 4000 B.C. TO A.D. 8000" by Michelle Chapront-Touze and Jean Chapront. See [mathworks.com](http://www.mathworks.com/matlabcentral/fileexchange/39130-orbital-elements-of-the-moon).
+
+More details on La Grange's blog at <a href="http://lab.la-grange.ca/en/jsorrery">http://lab.la-grange.ca/en/jsorrery</a>

+ 12 - 0
app/calendar/planet_position/src/App.js

@@ -0,0 +1,12 @@
+
+'use strict';
+var SolarSystem = require('./SolarSystem');
+
+
+var global = window.lagrange = window.lagrange || {};
+
+global.planet_positions = module.exports = {
+	getPositions: function(userDate){
+		return SolarSystem.getPositions(userDate);
+	}
+};

+ 93 - 0
app/calendar/planet_position/src/CelestialBody.js

@@ -0,0 +1,93 @@
+
+'use strict';
+
+var OrbitalElements = require('./OrbitalElements');
+var ns = require('ns');
+var THREE = require('./Three.shim');
+
+var CelestialBody = {
+
+	init : function() {
+		this.reset();
+		this.movement = new THREE.Vector3();
+		this.invMass = 1 / this.mass;
+
+		this.orbitalElements = Object.create(OrbitalElements);
+		this.orbitalElements.setName(this.name);
+		this.orbitalElements.setDefaultOrbit(this.orbit, this.orbitCalculator);
+		//console.log(this.name, this.position, this.velocity);
+
+	},
+
+	reset : function(){
+		this.angle = 0;
+		this.force = new THREE.Vector3();
+		this.movement = new THREE.Vector3();
+		this.previousPosition = null;
+	},
+
+	//if epoch start is not j2000, get epoch time from j2000 epoch time
+	getEpochTime : function(epochTime) {
+		if(this.epoch) {
+			epochTime = epochTime - ((this.epoch.getTime() - ns.J2000) / 1000);
+		}
+		return epochTime;
+	},
+
+	setPositionFromDate : function(epochTime, calculateVelocity) {
+
+		epochTime = this.getEpochTime(epochTime);
+		this.position = this.isCentral ? new THREE.Vector3() : this.orbitalElements.getPositionFromElements(this.orbitalElements.calculateElements(epochTime));
+		this.relativePosition = new THREE.Vector3();
+		if(calculateVelocity) {
+			this.velocity = this.isCentral ? new THREE.Vector3() : this.orbitalElements.calculateVelocity(epochTime, this.relativeTo, this.calculateFromElements);
+		}
+		this.positionRelativeTo();		
+	},
+	
+	getAngleTo : function(bodyName){
+		var ref = require('./SolarSystem').getBody(bodyName);
+		if(ref) {
+			
+			var eclPos = this.position.clone().sub(ref.getPosition()).normalize();
+			eclPos.z = 0;
+			var angleX = eclPos.angleTo(new THREE.Vector3(1, 0, 0));
+			var angleY = eclPos.angleTo(new THREE.Vector3(0, 1, 0));
+			//console.log(angleX, angleY);
+			var angle = angleX;
+			var q = Math.PI / 2;
+			if(angleY > q) angle = -angleX;
+			return angle;
+		}
+		return 0;
+	},
+
+	positionRelativeTo : function(){
+		if(this.relativeTo) {
+			var central = require('./SolarSystem').getBody(this.relativeTo);
+			if(central && central!==require('./SolarSystem').getBody()/**/) {
+				this.position.add(central.position);
+				//console.log(this.name+' pos rel to ' + this.relativeTo);
+				this.velocity && central.velocity && this.velocity.add(central.velocity);
+			}
+		}
+	},
+
+	calculatePosition : function(t) {
+		return this.orbitalElements.calculatePosition(t);
+	},
+
+	getPosition : function(){
+		return this.position.clone();
+	},
+
+	getVelocity : function(){
+		return this.velocity && this.velocity.clone();
+	},
+	//return true/false if this body is orbiting the requested body
+	isOrbitAround : function(celestial){
+		return celestial.name === this.relativeTo;
+	}
+};
+
+module.exports = CelestialBody;

+ 146 - 0
app/calendar/planet_position/src/Definitions.js

@@ -0,0 +1,146 @@
+'use strict';
+var ns = require('ns');
+var MoonRealOrbit = require('./MoonRealOrbit');
+
+module.exports = [
+	{
+		name: 'sun',
+		title : 'The Sun',
+		mass : 1.9891e30,
+		radius : 6.96342e5,
+		k : 0.01720209895 //gravitational constant (μ)
+	},
+	{
+	 	name: 'mercury',
+		title : 'Mercury',
+		mass : 3.3022e23,
+		radius:2439,
+		orbit : { 
+			base : {a : 0.38709927 * ns.AU ,  e : 0.20563593, i: 7.00497902, l : 252.25032350, lp : 77.45779628, o : 48.33076593},
+			cy : {a : 0.00000037 * ns.AU ,  e : 0.00001906, i: -0.00594749, l : 149472.67411175, lp : 0.16047689, o : -0.12534081}
+		}
+	},
+	{
+		name: 'venus',
+		title : 'Venus',
+		mass : 4.868e24,
+		radius : 6051,
+		orbit : {
+			base : {a : 0.72333566 * ns.AU ,  e : 0.00677672, i: 3.39467605, l : 181.97909950, lp : 131.60246718, o : 76.67984255},
+			cy : {a : 0.00000390 * ns.AU ,  e : -0.00004107, i: -0.00078890, l : 58517.81538729, lp : 0.00268329, o : -0.27769418}
+		}
+	},
+	{
+		name:'earth',
+		title : 'The Earth',
+		mass : 5.9736e24,
+		radius : 3443.9307 * ns.NM_TO_KM,
+		sideralDay : ns.SIDERAL_DAY,
+		tilt : 23+(26/60)+(21/3600) ,
+		orbit : {
+			base : {a : 1.00000261 * ns.AU, e : 0.01671123, i : -0.00001531, l : 100.46457166, lp : 102.93768193, o : 0.0},
+			cy : {a : 0.00000562 * ns.AU, e : -0.00004392, i : -0.01294668, l : 35999.37244981, lp : 0.32327364, o : 0.0}
+		}
+	},
+	{
+		name:'mars',
+		title : 'Mars',
+		mass : 6.4185e23,
+		radius : 3376,
+		sideralDay : 1.025957 * ns.DAY,
+		orbit : {
+			base : {a : 1.52371034 * ns.AU ,  e : 0.09339410, i: 1.84969142, l : -4.55343205, lp : -23.94362959, o : 49.55953891},
+			cy : {a : 0.00001847 * ns.AU ,  e : 0.00007882, i: -0.00813131, l : 19140.30268499, lp : 0.44441088, o : -0.29257343}
+		}
+	},
+	{
+	 	name:'jupiter',
+		title : 'Jupiter',
+		mass : 1.8986e27,
+		radius : 71492,
+		orbit : {
+			base : {a : 5.20288700 * ns.AU ,  e : 0.04838624, i: 1.30439695, l : 34.39644051, lp : 14.72847983, o : 100.47390909},
+			cy : {a : -0.00011607 * ns.AU ,  e : -0.00013253, i: -0.00183714, l : 3034.74612775, lp : 0.21252668, o : 0.20469106}
+		}
+	},
+	{
+		name:'saturn',
+		title : 'Saturn',
+		mass : 5.6846e26,
+		radius : 58232,
+		tilt : 26.7,
+		orbit : {
+			base : {a : 9.53667594 * ns.AU ,  e : 0.05386179, i: 2.48599187, l : 49.95424423, lp : 92.59887831, o : 113.66242448},
+			cy : {a : -0.00125060 * ns.AU ,  e : -0.00050991, i: 0.00193609, l : 1222.49362201, lp : -0.41897216, o : -0.28867794}
+		}
+	},
+	{
+		name: 'uranus',
+		title : 'Uranus',
+		mass : 8.6810e25,
+		radius : 25559,
+		orbit : {
+			base : {a : 19.18916464 * ns.AU ,  e : 0.04725744, i: 0.77263783, l : 313.23810451, lp : 170.95427630, o : 74.01692503},
+			cy : {a : -0.00196176 * ns.AU ,  e : -0.00004397, i: -0.00242939, l : 428.48202785, lp : 0.40805281, o : 0.04240589}
+		}
+	},
+	{
+		name:'neptune',
+		title : 'Neptune',
+		mass : 1.0243e26,
+		radius : 24764,
+		orbit : {
+			base : {a : 30.06992276  * ns.AU,  e : 0.00859048, i: 1.77004347, l : -55.12002969, lp : 44.96476227, o : 131.78422574},
+			cy : {a : 0.00026291  * ns.AU,  e : 0.00005105, i: 0.00035372, l : 218.45945325, lp : -0.32241464, o : -0.00508664}
+		}
+	},
+	{
+		name: 'pluto',
+		title : 'Pluto',
+		mass : 1.305e22+1.52e21,
+		radius : 1153,
+		orbit : {
+			base : {a : 39.48211675 * ns.AU ,  e : 0.24882730, i: 17.14001206, l : 238.92903833, lp : 224.06891629, o : 110.30393684},
+			cy : {a : -0.00031596 * ns.AU ,  e : 0.00005170, i: 0.00004818, l : 145.20780515, lp : -0.04062942, o : -0.01183482}
+		}
+	},
+	{
+		name: 'halley',
+		title : 'Halley\'s Comet',
+		mass : 2.2e14,
+		radius : 50,
+		orbit : {
+			base : {a : 17.83414429 * ns.AU ,  e : 0.967142908, i: 162.262691, M : 360 * (438393600 / (75.1 * ns.YEAR * ns.DAY)), w : 111.332485, o : 58.420081},
+			day : {a : 0 ,  e : 0, i: 0, M : (360 / (75.1 * 365.25) ), w : 0, o : 0}
+		}
+	},
+	{
+		name: 'moon',
+		title : 'The Moon',
+		mass : 7.3477e22,
+		radius : 1738.1,
+		sideralDay : (27.3215782 * ns.DAY) ,
+		tilt : 1.5424,
+		fov : 1,
+		relativeTo : 'earth',
+		orbitCalculator : MoonRealOrbit,
+		orbit: {
+			base : {
+				a : 384400,
+				e : 0.0554,
+				w : 318.15,
+				M : 135.27,
+				i : 5.16,
+				o : 125.08
+			},
+			day : {
+				a : 0,
+				e : 0,
+				i : 0,
+				M : 13.176358,//360 / 27.321582,
+				w : (360 / 5.997) / 365.25,
+				o : (360 / 18.600) / 365.25
+			}	
+		}
+	}
+];

+ 14 - 0
app/calendar/planet_position/src/Math.js

@@ -0,0 +1,14 @@
+'use strict';
+module.exports = {
+	sinh : function(a) {
+		return (Math.exp(a) - Math.exp(-a)) / 2;
+	},
+
+	cosh : function(a) {
+		return (Math.pow(Math.E, a) + Math.pow(Math.E, -a)) / 2;
+	},
+
+	sign : function(a) {
+		return (a >= 0.0) ? 1 : -1;
+	}
+};

+ 516 - 0
app/calendar/planet_position/src/MoonRealOrbit.js

@@ -0,0 +1,516 @@
+'use strict';
+
+var ns = require('ns');
+
+var DEG_TO_RAD = ns.DEG_TO_RAD;
+var RAD_TO_DEG = ns.RAD_TO_DEG;
+
+module.exports = function(t){
+
+	var t2 = t * t;
+	var t3 = t * t2;
+	var t4 = t * t3;
+	var t5 = t * t4;
+
+	var t2e4 = t2 * 1e-4;
+	var t3e6 = t3 * 1e-6;
+	var t4e8 = t4 * 1e-8;
+
+	//% semimajor axis
+
+	var sa = 3400.4 * Math.cos(DEG_TO_RAD * (235.7004 + 890534.2230 * t - 32.601 * t2e4 
+	+ 3.664 * t3e6 - 1.769 * t4e8)) 
+	- 635.6 * Math.cos(DEG_TO_RAD * (100.7370 + 413335.3554 * t - 122.571 * t2e4 
+	- 10.684 * t3e6 + 5.028 * t4e8)) 
+	- 235.6 * Math.cos(DEG_TO_RAD * (134.9634 + 477198.8676 * t + 89.970 * t2e4 
+	+ 14.348 * t3e6 - 6.797 * t4e8)) 
+	+ 218.1 * Math.cos(DEG_TO_RAD * (238.1713 +  854535.1727 * t - 31.065 * t2e4 
+	+ 3.623 * t3e6  - 1.769 * t4e8)) 
+	+ 181.0 * Math.cos(DEG_TO_RAD * (10.6638 + 1367733.0907 * t + 57.370 * t2e4 
+	+ 18.011 * t3e6 - 8.566 * t4e8)) 
+	- 39.9 * Math.cos(DEG_TO_RAD * (103.2079 + 377336.3051 * t - 121.035 * t2e4 
+	- 10.724 * t3e6 + 5.028 * t4e8)) 
+	- 38.4 * Math.cos(DEG_TO_RAD * (233.2295 + 926533.2733 * t - 34.136 * t2e4 
+	+ 3.705 * t3e6 - 1.769 * t4e8)) 
+	+ 33.8 * Math.cos(DEG_TO_RAD * (336.4374 + 1303869.5784 * t - 155.171 * t2e4 
+	- 7.020 * t3e6 + 3.259 * t4e8)) 
+	+ 28.8 * Math.cos(DEG_TO_RAD * (111.4008 + 1781068.4461 * t - 65.201 * t2e4 
+	+ 7.328 * t3e6 - 3.538 * t4e8)) 
+	+ 12.6 * Math.cos(DEG_TO_RAD * (13.1347 + 1331734.0404 * t + 58.906 * t2e4 
+	+ 17.971 * t3e6 - 8.566 * t4e8)) 
+	+ 11.4 * Math.cos(DEG_TO_RAD * (186.5442 + 966404.0351 * t - 68.058 * t2e4 
+	- 0.567 * t3e6 + 0.232 * t4e8)) 
+	- 11.1 * Math.cos(DEG_TO_RAD * (222.5657 - 441199.8173 * t - 91.506 * t2e4 
+	- 14.307 * t3e6 + 6.797 * t4e8)) 
+	- 10.2 * Math.cos(DEG_TO_RAD * (269.9268 + 954397.7353 * t + 179.941 * t2e4 
+	+ 28.695 * t3e6 - 13.594 * t4e8)) 
+	+ 9.7 * Math.cos(DEG_TO_RAD * (145.6272 + 1844931.9583 * t + 147.340 * t2e4 
+	+ 32.359 * t3e6 - 15.363 * t4e8)) 
+	+ 9.6 * Math.cos(DEG_TO_RAD * (240.6422 + 818536.1225 * t - 29.529 * t2e4 
+	+ 3.582 * t3e6 - 1.769 * t4e8)) 
+	+ 8.0 * Math.cos(DEG_TO_RAD * (297.8502 + 445267.1115 * t - 16.300 * t2e4 
+	+ 1.832 * t3e6 - 0.884 * t4e8)) 
+	- 6.2 * Math.cos(DEG_TO_RAD * (132.4925 + 513197.9179 * t + 88.434 * t2e4 
+	+ 14.388 * t3e6 - 6.797 * t4e8)) 
+	+ 6.0 * Math.cos(DEG_TO_RAD * (173.5506 + 1335801.3346 * t - 48.901 * t2e4 
+	+ 5.496 * t3e6 - 2.653 * t4e8)) 
+	+ 3.7 * Math.cos(DEG_TO_RAD * (113.8717 + 1745069.3958 * t - 63.665 * t2e4 
+	+ 7.287 * t3e6 - 3.538 * t4e8)) 
+	+ 3.6 * Math.cos(DEG_TO_RAD * (338.9083 + 1267870.5281 * t - 153.636 * t2e4 
+	- 7.061 * t3e6 + 3.259 * t4e8)) 
+	+ 3.2 * Math.cos(DEG_TO_RAD * (246.3642 + 2258267.3137 * t + 24.769 * t2e4 
+	+ 21.675 * t3e6 - 10.335 * t4e8)) 
+	- 3.0 * Math.cos(DEG_TO_RAD * (8.1929 + 1403732.1410 * t + 55.834 * t2e4 
+	+ 18.052 * t3e6 - 8.566 * t4e8)) 
+	+ 2.3 * Math.cos(DEG_TO_RAD * (98.2661 + 449334.4057 * t - 124.107 * t2e4 
+	- 10.643 * t3e6 + 5.028 * t4e8)) 
+	- 2.2 * Math.cos(DEG_TO_RAD * (357.5291 + 35999.0503 * t - 1.536 * t2e4 
+	+ 0.041 * t3e6 + 0.000 * t4e8)) 
+	- 2.0 * Math.cos(DEG_TO_RAD * (38.5872 + 858602.4669 * t - 138.871 * t2e4 
+	- 8.852 * t3e6 + 4.144 * t4e8)) 
+	- 1.8 * Math.cos(DEG_TO_RAD * (105.6788 + 341337.2548 * t - 119.499 * t2e4 
+	- 10.765 * t3e6 + 5.028 * t4e8)) 
+	- 1.7 * Math.cos(DEG_TO_RAD * (201.4740 + 826670.7108 * t - 245.142 * t2e4 
+	- 21.367 * t3e6 + 10.057 * t4e8)) 
+	+ 1.6 * Math.cos(DEG_TO_RAD * (184.1196 + 401329.0556 * t + 125.428 * t2e4 
+	+ 18.579 * t3e6 - 8.798 * t4e8)) 
+	- 1.4 * Math.cos(DEG_TO_RAD * (308.4192 - 489205.1674 * t + 158.029 * t2e4 
+	+ 14.915 * t3e6 - 7.029 * t4e8)) 
+	+ 1.3 * Math.cos(DEG_TO_RAD * (325.7736 - 63863.5122 * t - 212.541 * t2e4 
+	- 25.031 * t3e6 + 11.826 * t4e8));
+
+	var sapp = - 0.55 * Math.cos(DEG_TO_RAD * (238.2 + 854535.2 * t)) 
+		+ 0.10 * Math.cos(DEG_TO_RAD * (103.2 + 377336.3 * t)) 
+		+ 0.10 * Math.cos(DEG_TO_RAD * (233.2 + 926533.3 * t));
+
+	var sma = 383397.6 + sa + sapp * t;
+
+	//% orbital eccentricity
+
+	var se = 0.014217 * Math.cos(DEG_TO_RAD * (100.7370 + 413335.3554 * t - 122.571 * t2e4 
+	- 10.684 * t3e6 + 5.028 * t4e8)) 
+	+ 0.008551 * Math.cos(DEG_TO_RAD * (325.7736 - 63863.5122 * t - 212.541 * t2e4 
+	- 25.031 * t3e6 + 11.826 * t4e8)) 
+	- 0.001383 * Math.cos(DEG_TO_RAD * (134.9634 + 477198.8676 * t + 89.970 * t2e4 
+	+ 14.348 * t3e6 - 6.797 * t4e8)) 
+	+ 0.001353 * Math.cos(DEG_TO_RAD * (10.6638 + 1367733.0907 * t + 57.370 * t2e4 
+	+ 18.011 * t3e6 - 8.566 * t4e8)) 
+	- 0.001146 * Math.cos(DEG_TO_RAD * (66.5106 + 349471.8432 * t - 335.112 * t2e4 
+	- 35.715 * t3e6 + 16.854 * t4e8)) 
+	- 0.000915 * Math.cos(DEG_TO_RAD * (201.4740 + 826670.7108 * t - 245.142 * t2e4 
+	- 21.367 * t3e6 + 10.057 * t4e8)) 
+	+ 0.000869 * Math.cos(DEG_TO_RAD * (103.2079 + 377336.3051 * t - 121.035 * t2e4 
+	- 10.724 * t3e6 + 5.028 * t4e8)) 
+	- 0.000628 * Math.cos(DEG_TO_RAD * (235.7004 + 890534.2230 * t - 32.601 * t2e4 
+	+ 3.664 * t3e6  - 1.769 * t4e8)) 
+	- 0.000393 * Math.cos(DEG_TO_RAD * (291.5472 - 127727.0245 * t - 425.082 * t2e4 
+	- 50.062 * t3e6 + 23.651 * t4e8)) 
+	+ 0.000284 * Math.cos(DEG_TO_RAD * (328.2445 - 99862.5625 * t - 211.005 * t2e4 
+	- 25.072 * t3e6 + 11.826 * t4e8)) 
+	- 0.000278 * Math.cos(DEG_TO_RAD * (162.8868 - 31931.7561 * t - 106.271 * t2e4 
+	- 12.516 * t3e6 + 5.913 * t4e8)) 
+	- 0.000240 * Math.cos(DEG_TO_RAD * (269.9268 + 954397.7353 * t + 179.941 * t2e4 
+	+ 28.695 * t3e6 - 13.594 * t4e8)) 
+	+ 0.000230 * Math.cos(DEG_TO_RAD * (111.4008 + 1781068.4461 * t - 65.201 * t2e4 
+	+ 7.328 * t3e6  - 3.538 * t4e8)) 
+	+ 0.000229 * Math.cos(DEG_TO_RAD * (167.2476 + 762807.1986 * t - 457.683 * t2e4 
+	- 46.398 * t3e6 + 21.882 * t4e8)) 
+	- 0.000202 * Math.cos(DEG_TO_RAD * ( 83.3826 - 12006.2998 * t + 247.999 * t2e4 
+	+ 29.262 * t3e6 - 13.826 * t4e8)) 
+	+ 0.000190 * Math.cos(DEG_TO_RAD * (190.8102 - 541062.3799 * t - 302.511 * t2e4 
+	- 39.379 * t3e6 + 18.623 * t4e8)) 
+	+ 0.000177 * Math.cos(DEG_TO_RAD * (357.5291 + 35999.0503 * t - 1.536 * t2e4 
+	+ 0.041 * t3e6 + 0.000 * t4e8)) 
+	+ 0.000153 * Math.cos(DEG_TO_RAD * (32.2842 + 285608.3309 * t - 547.653 * t2e4 
+	- 60.746 * t3e6 + 28.679 * t4e8)) 
+	- 0.000137 * Math.cos(DEG_TO_RAD * (44.8902 + 1431596.6029 * t + 269.911 * t2e4 
+	+ 43.043 * t3e6 - 20.392 * t4e8)) 
+	+ 0.000122 * Math.cos(DEG_TO_RAD * (145.6272 + 1844931.9583 * t + 147.340 * t2e4 
+	+ 32.359 * t3e6 - 15.363 * t4e8)) 
+	+ 0.000116 * Math.cos(DEG_TO_RAD * (302.2110 + 1240006.0662 * t - 367.713 * t2e4 
+	- 32.051 * t3e6 + 15.085 * t4e8)) 
+	- 0.000111 * Math.cos(DEG_TO_RAD * (203.9449 + 790671.6605 * t - 243.606 * t2e4 
+	- 21.408 * t3e6 + 10.057 * t4e8)) 
+	- 0.000108 * Math.cos(DEG_TO_RAD * (68.9815 + 313472.7929 * t - 333.576 * t2e4 
+	- 35.756 * t3e6 + 16.854 * t4e8)) 
+	+ 0.000096 * Math.cos(DEG_TO_RAD * (336.4374 + 1303869.5784 * t - 155.171 * t2e4 
+	- 7.020 * t3e6 + 3.259 * t4e8)) 
+	- 0.000090 * Math.cos(DEG_TO_RAD * (98.2661 + 449334.4057 * t - 124.107 * t2e4 
+	- 10.643 * t3e6 + 5.028 * t4e8)) 
+	+ 0.000090 * Math.cos(DEG_TO_RAD * (13.1347 + 1331734.0404 * t + 58.906 * t2e4 
+	+ 17.971 * t3e6 - 8.566 * t4e8)) 
+	+ 0.000056 * Math.cos(DEG_TO_RAD * (55.8468 - 1018261.2475 * t - 392.482 * t2e4 
+	- 53.726 * t3e6 + 25.420 * t4e8)) 
+	- 0.000056 * Math.cos(DEG_TO_RAD * (238.1713 + 854535.1727 * t - 31.065 * t2e4 
+	+ 3.623 * t3e6 - 1.769 * t4e8)) 
+	+ 0.000052 * Math.cos(DEG_TO_RAD * (308.4192 - 489205.1674 * t + 158.029 * t2e4 
+	+ 14.915 * t3e6 - 7.029 * t4e8)) 
+	- 0.000050 * Math.cos(DEG_TO_RAD * (133.0212 + 698943.6863 * t - 670.224 * t2e4 
+	- 71.429 * t3e6 + 33.708 * t4e8)) 
+	- 0.000049 * Math.cos(DEG_TO_RAD * (267.9846 + 1176142.5540 * t - 580.254 * t2e4 
+	- 57.082 * t3e6 + 26.911 * t4e8)) 
+	- 0.000049 * Math.cos(DEG_TO_RAD * (184.1196 + 401329.0556 * t + 125.428 * t2e4 
+	+ 18.579 * t3e6 - 8.798 * t4e8)) 
+	- 0.000045 * Math.cos(DEG_TO_RAD * (49.1562 - 75869.8120 * t + 35.458 * t2e4 
+	+ 4.231 * t3e6 - 2.001 * t4e8)) 
+	+ 0.000044 * Math.cos(DEG_TO_RAD * (257.3208 - 191590.5367 * t - 637.623 * t2e4 
+	- 75.093 * t3e6 + 35.477 * t4e8)) 
+	+ 0.000042 * Math.cos(DEG_TO_RAD * (105.6788 + 341337.2548 * t - 119.499 * t2e4 
+	- 10.765 * t3e6 + 5.028 * t4e8)) 
+	+ 0.000042 * Math.cos(DEG_TO_RAD * (160.4159 + 4067.2942 * t - 107.806 * t2e4 
+	- 12.475 * t3e6 + 5.913 * t4e8)) 
+	+ 0.000040 * Math.cos(DEG_TO_RAD * (246.3642 + 2258267.3137 * t + 24.769 * t2e4 
+	+ 21.675 * t3e6 - 10.335 * t4e8)) 
+	- 0.000040 * Math.cos(DEG_TO_RAD * (156.5838 - 604925.8921 * t - 515.053 * t2e4 
+	- 64.410 * t3e6 + 30.448 * t4e8)) 
+	+ 0.000036 * Math.cos(DEG_TO_RAD * (169.7185 + 726808.1483 * t - 456.147 * t2e4 
+	- 46.439 * t3e6 + 21.882 * t4e8)) 
+	+ 0.000029 * Math.cos(DEG_TO_RAD * (113.8717 + 1745069.3958 * t - 63.665 * t2e4 
+	+ 7.287 * t3e6 - 3.538 * t4e8)) 
+	- 0.000029 * Math.cos(DEG_TO_RAD * (297.8502 + 445267.1115 * t - 16.300 * t2e4 
+	+ 1.832 * t3e6 - 0.884 * t4e8)) 
+	- 0.000028 * Math.cos(DEG_TO_RAD * (294.0181 - 163726.0747 * t - 423.546 * t2e4 
+	- 50.103 * t3e6 + 23.651 * t4e8)) 
+	+ 0.000027 * Math.cos(DEG_TO_RAD * (263.6238 + 381403.5993 * t - 228.841 * t2e4 
+	- 23.199 * t3e6 + 10.941 * t4e8)) 
+	- 0.000026 * Math.cos(DEG_TO_RAD * (358.0578 + 221744.8187 * t - 760.194 * t2e4 
+	- 85.777 * t3e6 + 40.505 * t4e8)) 
+	- 0.000026 * Math.cos(DEG_TO_RAD * (8.1929 + 1403732.1410 * t + 55.834 * t2e4 
+	+ 18.052 * t3e6 - 8.566 * t4e8));
+
+	var sedp = -0.0022 * Math.cos(DEG_TO_RAD * (103.2 + 377336.3 * t));
+
+	var ecc = 0.055544 + se + 1e-3 * t * sedp;
+
+	//% sine of half the inclination
+
+var sg = 0.0011776 * Math.cos(DEG_TO_RAD * (49.1562 - 75869.8120 * t + 35.458 * t2e4 
+	+ 4.231 * t3e6 - 2.001 * t4e8)) 
+	- 0.0000971 * Math.cos(DEG_TO_RAD * (235.7004 + 890534.2230 * t - 32.601 * t2e4 
+	+ 3.664 * t3e6 - 1.769 * t4e8)) 
+	+ 0.0000908 * Math.cos(DEG_TO_RAD * (186.5442 + 966404.0351 * t - 68.058 * t2e4 
+	- 0.567 * t3e6 + 0.232 * t4e8)) 
+	+ 0.0000623 * Math.cos(DEG_TO_RAD * (83.3826 - 12006.2998 * t + 247.999 * t2e4 
+	+ 29.262 * t3e6 - 13.826 * t4e8)) 
+	+ 0.0000483 * Math.cos(DEG_TO_RAD * (51.6271 - 111868.8623 * t + 36.994 * t2e4 
+	+ 4.190 * t3e6 - 2.001 * t4e8)) 
+	+ 0.0000348 * Math.cos(DEG_TO_RAD * (100.7370 + 413335.3554 * t - 122.571 * t2e4 
+	- 10.684 * t3e6 + 5.028 * t4e8)) 
+	- 0.0000316 * Math.cos(DEG_TO_RAD * (308.4192 - 489205.1674 * t + 158.029 * t2e4 
+	+ 14.915 * t3e6 - 7.029 * t4e8)) 
+	- 0.0000253 * Math.cos(DEG_TO_RAD * (46.6853 - 39870.7617 * t + 33.922 * t2e4 
+	+ 4.272 * t3e6 - 2.001 * t4e8)) 
+	- 0.0000141 * Math.cos(DEG_TO_RAD * (274.1928 - 553068.6797 * t - 54.513 * t2e4 
+	- 10.116 * t3e6 + 4.797 * t4e8)) 
+	+ 0.0000127 * Math.cos(DEG_TO_RAD * (325.7736 - 63863.5122 * t - 212.541 * t2e4 
+	- 25.031 * t3e6 + 11.826 * t4e8)) 
+	+ 0.0000117 * Math.cos(DEG_TO_RAD * (184.1196 + 401329.0556 * t + 125.428 * t2e4 
+	+ 18.579 * t3e6 - 8.798 * t4e8)) 
+	- 0.0000078 * Math.cos(DEG_TO_RAD * (98.3124 - 151739.6240 * t + 70.916 * t2e4 
+	+ 8.462 * t3e6 - 4.001 * t4e8)) 
+	- 0.0000063 * Math.cos(DEG_TO_RAD * (238.1713 + 854535.1727 * t - 31.065 * t2e4 
+	+ 3.623 * t3e6 - 1.769 * t4e8)) 
+	+ 0.0000063 * Math.cos(DEG_TO_RAD * (134.9634 + 477198.8676 * t + 89.970 * t2e4 
+	+ 14.348 * t3e6 - 6.797 * t4e8)) 
+	+ 0.0000036 * Math.cos(DEG_TO_RAD * (321.5076 + 1443602.9027 * t + 21.912 * t2e4 
+	+ 13.780 * t3e6 - 6.566 * t4e8)) 
+	- 0.0000035 * Math.cos(DEG_TO_RAD * (10.6638 + 1367733.0907 * t + 57.370 * t2e4 
+	+ 18.011 * t3e6 - 8.566 * t4e8)) 
+	+ 0.0000024 * Math.cos(DEG_TO_RAD * (149.8932 + 337465.5434 * t - 87.113 * t2e4 
+	- 6.453 * t3e6 + 3.028 * t4e8)) 
+	+ 0.0000024 * Math.cos(DEG_TO_RAD * (170.9849 - 930404.9848 * t + 66.523 * t2e4 
+	+ 0.608 * t3e6 - 0.232 * t4e8));
+
+	var sgp = - 0.0203 * Math.cos(DEG_TO_RAD * (125.0 - 1934.1 * t)) 
+		+ 0.0034 * Math.cos(DEG_TO_RAD * (220.2 - 1935.5 * t));
+
+	var gamma = 0.0449858 + sg + 1e-3 * sgp;
+
+	//% longitude of perigee
+
+	var sp = - 15.448 * Math.sin(DEG_TO_RAD * (100.7370 + 413335.3554 * t - 122.571 * t2e4 
+	- 10.684 * t3e6 + 5.028 * t4e8))
+	- 9.642 * Math.sin(DEG_TO_RAD * (325.7736 - 63863.5122 * t - 212.541 * t2e4 
+	- 25.031 * t3e6 + 11.826 * t4e8)) 
+	- 2.721 * Math.sin(DEG_TO_RAD * (134.9634 + 477198.8676 * t + 89.970 * t2e4 
+	+ 14.348 * t3e6 - 6.797 * t4e8)) 
+	+ 2.607 * Math.sin(DEG_TO_RAD * (66.5106 + 349471.8432 * t - 335.112 * t2e4 
+	- 35.715 * t3e6 + 16.854 * t4e8)) 
+	+ 2.085 * Math.sin(DEG_TO_RAD * (201.4740 + 826670.7108 * t - 245.142 * t2e4 
+	- 21.367 * t3e6 + 10.057 * t4e8)) 
+	+ 1.477 * Math.sin(DEG_TO_RAD * (10.6638 + 1367733.0907 * t + 57.370 * t2e4 
+	+ 18.011 * t3e6 - 8.566 * t4e8)) 
+	+ 0.968 * Math.sin(DEG_TO_RAD * (291.5472 - 127727.0245 * t - 425.082 * t2e4 
+	- 50.062 * t3e6 + 23.651 * t4e8)) 
+	- 0.949 * Math.sin(DEG_TO_RAD * (103.2079 + 377336.3051 * t - 121.035 * t2e4 
+	- 10.724 * t3e6 + 5.028 * t4e8)) 
+	- 0.703 * Math.sin(DEG_TO_RAD * (167.2476 + 762807.1986 * t - 457.683 * t2e4 
+	- 46.398 * t3e6 + 21.882 * t4e8)) 
+	- 0.660 * Math.sin(DEG_TO_RAD * (235.7004 + 890534.2230 * t - 32.601 * t2e4 
+	+ 3.664 * t3e6 - 1.769 * t4e8)) 
+	- 0.577 * Math.sin(DEG_TO_RAD * (190.8102 - 541062.3799 * t - 302.511 * t2e4 
+	- 39.379 * t3e6 + 18.623 * t4e8)) 
+	- 0.524 * Math.sin(DEG_TO_RAD * (269.9268 + 954397.7353 * t + 179.941 * t2e4 
+	+ 28.695 * t3e6 - 13.594 * t4e8)) 
+	- 0.482 * Math.sin(DEG_TO_RAD * (32.2842 + 285608.3309 * t - 547.653 * t2e4 
+	- 60.746 * t3e6 + 28.679 * t4e8)) 
+	+ 0.452 * Math.sin(DEG_TO_RAD * (357.5291 + 35999.0503 * t - 1.536 * t2e4 
+	+ 0.041 * t3e6 + 0.000 * t4e8)) 
+	- 0.381 * Math.sin(DEG_TO_RAD * (302.2110 + 1240006.0662 * t - 367.713 * t2e4 
+	- 32.051 * t3e6 + 15.085 * t4e8)) 
+	- 0.342 * Math.sin(DEG_TO_RAD * (328.2445 - 99862.5625 * t - 211.005 * t2e4 
+	- 25.072 * t3e6 + 11.826 * t4e8)) 
+	- 0.312 * Math.sin(DEG_TO_RAD * (44.8902 + 1431596.6029 * t + 269.911 * t2e4 
+	+ 43.043 * t3e6 - 20.392 * t4e8)) 
+	+ 0.282 * Math.sin(DEG_TO_RAD * (162.8868 - 31931.7561 * t - 106.271 * t2e4 
+	- 12.516 * t3e6 + 5.913 * t4e8)) 
+	+ 0.255 * Math.sin(DEG_TO_RAD * (203.9449 + 790671.6605 * t - 243.606 * t2e4 
+	- 21.408 * t3e6 + 10.057 * t4e8)) 
+	+ 0.252 * Math.sin(DEG_TO_RAD * (68.9815 + 313472.7929 * t - 333.576 * t2e4 
+	- 35.756 * t3e6 + 16.854 * t4e8)) 
+	- 0.211 * Math.sin(DEG_TO_RAD * (83.3826 - 12006.2998 * t + 247.999 * t2e4 
+	+ 29.262 * t3e6 - 13.826 * t4e8)) 
+	+ 0.193 * Math.sin(DEG_TO_RAD * (267.9846 + 1176142.5540 * t - 580.254 * t2e4 
+	- 57.082 * t3e6 + 26.911 * t4e8)) 
+	+ 0.191 * Math.sin(DEG_TO_RAD * (133.0212 + 698943.6863 * t - 670.224 * t2e4 
+	- 71.429 * t3e6 + 33.708 * t4e8)) 
+	- 0.184 * Math.sin(DEG_TO_RAD * (55.8468 - 1018261.2475 * t - 392.482 * t2e4 
+	- 53.726 * t3e6 + 25.420 * t4e8)) 
+	+ 0.182 * Math.sin(DEG_TO_RAD * (145.6272 + 1844931.9583 * t + 147.340 * t2e4 
+	+ 32.359 * t3e6 - 15.363 * t4e8)) 
+	- 0.158 * Math.sin(DEG_TO_RAD * (257.3208 - 191590.5367 * t - 637.623 * t2e4 
+	- 75.093 * t3e6 + 35.477 * t4e8)) 
+	+ 0.148 * Math.sin(DEG_TO_RAD * (156.5838 - 604925.8921 * t - 515.053 * t2e4 
+	- 64.410 * t3e6 + 30.448 * t4e8)) 
+	- 0.111 * Math.sin(DEG_TO_RAD * (169.7185 + 726808.1483 * t - 456.147 * t2e4 
+	- 46.439 * t3e6 + 21.882 * t4e8)) 
+	+ 0.101 * Math.sin(DEG_TO_RAD * (13.1347 + 1331734.0404 * t + 58.906 * t2e4 
+	+ 17.971 * t3e6 - 8.566 * t4e8)) 
+	+ 0.100 * Math.sin(DEG_TO_RAD * (358.0578 + 221744.8187 * t - 760.194 * t2e4 
+	- 85.777 * t3e6 + 40.505 * t4e8)) 
+	+ 0.087 * Math.sin(DEG_TO_RAD * (98.2661 + 449334.4057 * t - 124.107 * t2e4 
+	- 10.643 * t3e6 + 5.028 * t4e8)) 
+	+ 0.080 * Math.sin(DEG_TO_RAD * (42.9480 + 1653341.4216 * t - 490.283 * t2e4 
+	- 42.734 * t3e6 + 20.113 * t4e8)) 
+	+ 0.080 * Math.sin(DEG_TO_RAD * (222.5657 - 441199.8173 * t - 91.506 * t2e4 
+	- 14.307 * t3e6 + 6.797 * t4e8)) 
+	+ 0.077 * Math.sin(DEG_TO_RAD * (294.0181 - 163726.0747 * t - 423.546 * t2e4 
+	- 50.103 * t3e6 + 23.651 * t4e8)) 
+	- 0.073 * Math.sin(DEG_TO_RAD * (280.8834 - 1495460.1151 * t - 482.452 * t2e4 
+	- 68.074 * t3e6 + 32.217 * t4e8)) 
+	- 0.071 * Math.sin(DEG_TO_RAD * (304.6819 + 1204007.0159 * t - 366.177 * t2e4 
+	- 32.092 * t3e6 + 15.085 * t4e8)) 
+	- 0.069 * Math.sin(DEG_TO_RAD * (233.7582 + 1112279.0417 * t - 792.795 * t2e4 
+	- 82.113 * t3e6 + 38.736 * t4e8)) 
+	- 0.067 * Math.sin(DEG_TO_RAD * (34.7551 + 249609.2807 * t - 546.117 * t2e4 
+	- 60.787 * t3e6 + 28.679 * t4e8)) 
+	- 0.067 * Math.sin(DEG_TO_RAD * (263.6238 + 381403.5993 * t - 228.841 * t2e4 
+	- 23.199 * t3e6 + 10.941 * t4e8)) 
+	+ 0.055 * Math.sin(DEG_TO_RAD * (21.6203 - 1082124.7597 * t - 605.023 * t2e4 
+	- 78.757 * t3e6 + 37.246 * t4e8)) 
+	+ 0.055 * Math.sin(DEG_TO_RAD * (308.4192 - 489205.1674 * t + 158.029 * t2e4 
+	+ 14.915 * t3e6 -7.029 * t4e8)) 
+	- 0.054 * Math.sin(DEG_TO_RAD * (8.7216 + 1589477.9094 * t - 702.824 * t2e4 
+	- 67.766 * t3e6 + 31.939 * t4e8)) 
+	- 0.052 * Math.sin(DEG_TO_RAD * (179.8536 + 1908795.4705 * t + 359.881 * t2e4 
+	+ 57.390 * t3e6 - 27.189 * t4e8)) 
+	- 0.050 * Math.sin(DEG_TO_RAD * (98.7948 + 635080.1741 * t - 882.765 * t2e4 
+	- 96.461 * t3e6 + 45.533 * t4e8)) 
+	- 0.049 * Math.sin(DEG_TO_RAD * (128.6604 - 95795.2683 * t - 318.812 * t2e4 
+	- 37.547 * t3e6 + 17.738 * t4e8)) 
+	- 0.047 * Math.sin(DEG_TO_RAD * (17.3544 + 425341.6552 * t - 370.570 * t2e4 
+	- 39.946 * t3e6 + 18.854 * t4e8)) 
+	- 0.044 * Math.sin(DEG_TO_RAD * (160.4159 + 4067.2942 * t - 107.806 * t2e4 
+	- 12.475 * t3e6 + 5.913 * t4e8)) 
+	- 0.043 * Math.sin(DEG_TO_RAD * (238.1713 + 854535.1727 * t - 31.065 * t2e4 
+	+ 3.623 * t3e6 - 1.769 * t4e8)) 
+	+ 0.042 * Math.sin(DEG_TO_RAD * (270.4555 + 1140143.5037 * t - 578.718 * t2e4 
+	- 57.123 * t3e6 + 26.911 * t4e8)) 
+	- 0.042 * Math.sin(DEG_TO_RAD * (132.4925 + 513197.9179 * t + 88.434 * t2e4 
+	+ 14.388 * t3e6 - 6.797 * t4e8)) 
+	- 0.041 * Math.sin(DEG_TO_RAD * (122.3573 - 668789.4043 * t - 727.594 * t2e4 
+	- 89.441 * t3e6 + 42.274 * t4e8)) 
+	- 0.040 * Math.sin(DEG_TO_RAD * (105.6788 + 341337.2548 * t - 119.499 * t2e4 
+	- 10.765 * t3e6 + 5.028 * t4e8)) 
+	+ 0.038 * Math.sin(DEG_TO_RAD * (135.4921 + 662944.6361 * t - 668.688 * t2e4 
+	- 71.470 * t3e6 + 33.708 * t4e8)) 
+	- 0.037 * Math.sin(DEG_TO_RAD * (242.3910 - 51857.2124 * t - 460.540 * t2e4 
+	- 54.293 * t3e6 + 25.652 * t4e8)) 
+	+ 0.036 * Math.sin(DEG_TO_RAD * (336.4374 +  1303869.5784 * t - 155.171 * t2e4 
+	- 7.020 * t3e6 + 3.259 * t4e8)) 
+	+ 0.035 * Math.sin(DEG_TO_RAD * (223.0943 - 255454.0489 * t - 850.164 * t2e4 
+	- 100.124 * t3e6 + 47.302 * t4e8)) 
+	- 0.034 * Math.sin(DEG_TO_RAD * (193.2811 - 577061.4302 * t - 300.976 * t2e4 
+	- 39.419 * t3e6 + 18.623 * t4e8)) 
+	+ 0.031 * Math.sin(DEG_TO_RAD * (87.6023 - 918398.6850 * t - 181.476 * t2e4 
+	- 28.654 * t3e6 + 13.594 * t4e8));
+
+	var spp = 2.4 * Math.sin(DEG_TO_RAD * (103.2 + 377336.3 * t));
+
+	var lp = 83.353 + 4069.0137 * t - 103.238 * t2e4 
+	- 12.492 * t3e6 + 5.263 * t4e8 + sp + 1e-3 * t * spp;
+
+	//% longitude of the ascending node
+
+	var sr = - 1.4979 * Math.sin(DEG_TO_RAD * (49.1562 - 75869.8120 * t + 35.458 * t2e4 
+	+ 4.231 * t3e6 - 2.001 * t4e8)) 
+	- 0.1500 * Math.sin(DEG_TO_RAD * (357.5291 + 35999.0503 * t - 1.536 * t2e4 
+	+ 0.041 * t3e6 + 0.000 * t4e8)) 
+	- 0.1226 * Math.sin(DEG_TO_RAD * (235.7004 + 890534.2230 * t - 32.601 * t2e4 
+	+ 3.664 * t3e6 - 1.769 * t4e8)) 
+	+ 0.1176 * Math.sin(DEG_TO_RAD * (186.5442 + 966404.0351 * t - 68.058 * t2e4 
+	- 0.567 * t3e6 + 0.232 * t4e8)) 
+	- 0.0801 * Math.sin(DEG_TO_RAD * (83.3826 - 12006.2998 * t + 247.999 * t2e4 
+	+ 29.262 * t3e6 - 13.826 * t4e8)) 
+	- 0.0616 * Math.sin(DEG_TO_RAD * (51.6271 - 111868.8623 * t + 36.994 * t2e4 
+	+ 4.190 * t3e6 - 2.001 * t4e8)) 
+	+ 0.0490 * Math.sin(DEG_TO_RAD * (100.7370 + 413335.3554 * t - 122.571 * t2e4 
+	- 10.684 * t3e6 + 5.028 * t4e8)) 
+	+ 0.0409 * Math.sin(DEG_TO_RAD * (308.4192 - 489205.1674 * t + 158.029 * t2e4 
+	+ 14.915 * t3e6 - 7.029 * t4e8)) 
+	+ 0.0327 * Math.sin(DEG_TO_RAD * (134.9634 + 477198.8676 * t + 89.970 * t2e4 
+	+ 14.348 * t3e6 - 6.797 * t4e8)) 
+	+ 0.0324 * Math.sin(DEG_TO_RAD * (46.6853 - 39870.7617 * t + 33.922 * t2e4 
+	+ 4.272 * t3e6 - 2.001 * t4e8)) 
+	+ 0.0196 * Math.sin(DEG_TO_RAD * (98.3124 - 151739.6240 * t + 70.916 * t2e4 
+	+ 8.462 * t3e6 - 4.001 * t4e8)) 
+	+ 0.0180 * Math.sin(DEG_TO_RAD * (274.1928 - 553068.6797 * t - 54.513 * t2e4 
+	- 10.116 * t3e6 + 4.797 * t4e8)) 
+	+ 0.0150 * Math.sin(DEG_TO_RAD * (325.7736 - 63863.5122 * t - 212.541 * t2e4 
+	- 25.031 * t3e6 + 11.826 * t4e8)) 
+	- 0.0150 * Math.sin(DEG_TO_RAD * (184.1196 + 401329.0556 * t + 125.428 * t2e4 
+	+ 18.579 * t3e6 - 8.798 * t4e8)) 
+	- 0.0078 * Math.sin(DEG_TO_RAD * (238.1713 + 854535.1727 * t - 31.065 * t2e4 
+	+ 3.623 * t3e6 - 1.769 * t4e8)) 
+	- 0.0045 * Math.sin(DEG_TO_RAD * (10.6638 + 1367733.0907 * t + 57.370 * t2e4 
+	+ 18.011 * t3e6 - 8.566 * t4e8)) 
+	+ 0.0044 * Math.sin(DEG_TO_RAD * (321.5076 + 1443602.9027 * t + 21.912 * t2e4 
+	+ 13.780 * t3e6 - 6.566 * t4e8)) 
+	- 0.0042 * Math.sin(DEG_TO_RAD * (162.8868 - 31931.7561 * t - 106.271 * t2e4 
+	- 12.516 * t3e6 + 5.913 * t4e8)) 
+	- 0.0031 * Math.sin(DEG_TO_RAD * (170.9849 - 930404.9848 * t + 66.523 * t2e4 
+	+ 0.608 * t3e6 - 0.232 * t4e8)) 
+	+ 0.0031 * Math.sin(DEG_TO_RAD * (103.2079 + 377336.3051 * t - 121.035 * t2e4 
+	- 10.724 * t3e6 + 5.028 * t4e8)) 
+	+ 0.0029 * Math.sin(DEG_TO_RAD * (222.6120 - 1042273.8471 * t + 103.516 * t2e4 
+	+ 4.798 * t3e6 - 2.232 * t4e8)) 
+	+ 0.0028 * Math.sin(DEG_TO_RAD * (184.0733 + 1002403.0853 * t - 69.594 * t2e4 
+	- 0.526 * t3e6 + 0.232 * t4e8));
+
+	var srp = 25.9 * Math.sin(DEG_TO_RAD * (125.0 - 1934.1 * t)) 
+		- 4.3 * Math.sin(DEG_TO_RAD * (220.2 - 1935.5 * t));
+
+	var srpp = 0.38 * Math.sin(DEG_TO_RAD * (357.5 + 35999.1 * t));
+
+	var raan = 125.0446 - 1934.13618 * t + 20.762 * t2e4 
+		+ 2.139 * t3e6 - 1.650 * t4e8 + sr 
+		+ 1e-3 * (srp + srpp * t);
+
+	//% mean longitude
+
+	var sl = - 0.92581 * Math.sin(DEG_TO_RAD * (235.7004 + 890534.2230 * t - 32.601 * t2e4 
+	+ 3.664 * t3e6 - 1.769 * t4e8)) 
+	+ 0.33262 * Math.sin(DEG_TO_RAD * (100.7370 + 413335.3554 * t - 122.571 * t2e4 
+	- 10.684 * t3e6 + 5.028 * t4e8)) 
+	- 0.18402 * Math.sin(DEG_TO_RAD * (357.5291 + 35999.0503 * t - 1.536 * t2e4 
+	+ 0.041 * t3e6 + 0.000 * t4e8)) 
+	+ 0.11007 * Math.sin(DEG_TO_RAD * (134.9634 + 477198.8676 * t + 89.970 * t2e4 
+	+ 14.348 * t3e6 - 6.797 * t4e8)) 
+	- 0.06055 * Math.sin(DEG_TO_RAD * (238.1713 + 854535.1727 * t - 31.065 * t2e4 
+	+ 3.623 * t3e6 - 1.769 * t4e8)) 
+	+ 0.04741 * Math.sin(DEG_TO_RAD * (325.7736 - 63863.5122 * t - 212.541 * t2e4 
+	- 25.031 * t3e6 + 11.826 * t4e8)) 
+	- 0.03086 * Math.sin(DEG_TO_RAD * (10.6638 + 1367733.0907 * t + 57.370 * t2e4 
+	+ 18.011 * t3e6 - 8.566 * t4e8)) 
+	+ 0.02184 * Math.sin(DEG_TO_RAD * (103.2079 + 377336.3051 * t - 121.035 * t2e4 
+	- 10.724 * t3e6 + 5.028 * t4e8)) 
+	+ 0.01645 * Math.sin(DEG_TO_RAD * (49.1562 - 75869.8120 * t + 35.458 * t2e4 
+	+ 4.231 * t3e6 - 2.001 * t4e8)) 
+	+ 0.01022 * Math.sin(DEG_TO_RAD * (233.2295 + 926533.2733 * t - 34.136 * t2e4 
+	+ 3.705 * t3e6 - 1.769 * t4e8)) 
+	- 0.00756 * Math.sin(DEG_TO_RAD * (336.4374 + 1303869.5784 * t - 155.171 * t2e4 
+	- 7.020 * t3e6 + 3.259 * t4e8)) 
+	- 0.00530 * Math.sin(DEG_TO_RAD * (222.5657 - 441199.8173 * t - 91.506 * t2e4 
+	- 14.307 * t3e6 + 6.797 * t4e8)) 
+	- 0.00496 * Math.sin(DEG_TO_RAD * (162.8868 - 31931.7561 * t - 106.271 * t2e4 
+	- 12.516 * t3e6 + 5.913 * t4e8)) 
+	- 0.00472 * Math.sin(DEG_TO_RAD * (297.8502 + 445267.1115 * t - 16.300 * t2e4 
+	+ 1.832 * t3e6 - 0.884 * t4e8)) 
+	- 0.00271 * Math.sin(DEG_TO_RAD * (240.6422 + 818536.1225 * t - 29.529 * t2e4 
+	+ 3.582 * t3e6 - 1.769 * t4e8)) 
+	+ 0.00264 * Math.sin(DEG_TO_RAD * (132.4925 + 513197.9179 * t + 88.434 * t2e4 
+	+ 14.388 * t3e6 - 6.797 * t4e8)) 
+	- 0.00254 * Math.sin(DEG_TO_RAD * (186.5442 + 966404.0351 * t - 68.058 * t2e4 
+	- 0.567 * t3e6 + 0.232 * t4e8)) 
+	+ 0.00234 * Math.sin(DEG_TO_RAD * (269.9268 + 954397.7353 * t + 179.941 * t2e4 
+	+ 28.695 * t3e6 - 13.594 * t4e8)) 
+	- 0.00220 * Math.sin(DEG_TO_RAD * (13.1347 + 1331734.0404 * t + 58.906 * t2e4 
+	+ 17.971 * t3e6 - 8.566 * t4e8)) 
+	- 0.00202 * Math.sin(DEG_TO_RAD * (355.0582 + 71998.1006 * t - 3.072 * t2e4 
+	+ 0.082 * t3e6 + 0.000 * t4e8)) 
+	+ 0.00167 * Math.sin(DEG_TO_RAD * (328.2445 - 99862.5625 * t - 211.005 * t2e4 
+	- 25.072 * t3e6 + 11.826 * t4e8)) 
+	- 0.00143 * Math.sin(DEG_TO_RAD * (173.5506 + 1335801.3346 * t - 48.901 * t2e4 
+	+ 5.496 * t3e6 - 2.653 * t4e8)) 
+	- 0.00121 * Math.sin(DEG_TO_RAD * (98.2661 + 449334.4057 * t - 124.107 * t2e4 
+	- 10.643 * t3e6 + 5.028 * t4e8)) 
+	- 0.00116 * Math.sin(DEG_TO_RAD * (145.6272 + 1844931.9583 * t + 147.340 * t2e4 
+	+ 32.359 * t3e6 - 15.363 * t4e8)) 
+	+ 0.00102 * Math.sin(DEG_TO_RAD * (105.6788 + 341337.2548 * t - 119.499 * t2e4 
+	- 10.765 * t3e6 + 5.028 * t4e8)) 
+	- 0.00090 * Math.sin(DEG_TO_RAD * (184.1196 + 401329.0556 * t + 125.428 * t2e4 
+	+ 18.579 * t3e6 - 8.798 * t4e8)) 
+	- 0.00086 * Math.sin(DEG_TO_RAD * (338.9083 + 1267870.5281 * t - 153.636 * t2e4 
+	- 7.061 * t3e6 + 3.259 * t4e8)) 
+	- 0.00078 * Math.sin(DEG_TO_RAD * (111.4008 + 1781068.4461 * t - 65.201 * t2e4 
+	+ 7.328 * t3e6 - 3.538 * t4e8)) 
+	+ 0.00069 * Math.sin(DEG_TO_RAD * (323.3027 - 27864.4619 * t - 214.077 * t2e4 
+	- 24.990 * t3e6 + 11.826 * t4e8)) 
+	+ 0.00066 * Math.sin(DEG_TO_RAD * (51.6271 - 111868.8623 * t + 36.994 * t2e4 
+	+ 4.190 * t3e6 - 2.001 * t4e8)) 
+	+ 0.00065 * Math.sin(DEG_TO_RAD * (38.5872 + 858602.4669 * t - 138.871 * t2e4 
+	- 8.852 * t3e6 + 4.144 * t4e8)) 
+	- 0.00060 * Math.sin(DEG_TO_RAD * (83.3826 - 12006.2998 * t + 247.999 * t2e4 
+	+ 29.262 * t3e6 - 13.826 * t4e8)) 
+	+ 0.00054 * Math.sin(DEG_TO_RAD * (201.4740 + 826670.7108 * t - 245.142 * t2e4 
+	- 21.367 * t3e6 + 10.057 * t4e8)) 
+	- 0.00052 * Math.sin(DEG_TO_RAD * (308.4192 - 489205.1674 * t + 158.029 * t2e4 
+	+ 14.915 * t3e6 - 7.029 * t4e8)) 
+	+ 0.00048 * Math.sin(DEG_TO_RAD * (8.1929 + 1403732.1410 * t + 55.834 * t2e4 
+	+ 18.052 * t3e6 - 8.566 * t4e8)) 
+	- 0.00041 * Math.sin(DEG_TO_RAD * (46.6853 - 39870.7617 * t + 33.922 * t2e4 
+	+ 4.272 * t3e6 - 2.001 * t4e8)) 
+	- 0.00033 * Math.sin(DEG_TO_RAD * (274.1928 - 553068.6797 * t - 54.513 * t2e4 
+	- 10.116 * t3e6 + 4.797 * t4e8)) 
+	+ 0.00030 * Math.sin(DEG_TO_RAD * (160.4159 + 4067.2942 * t - 107.806 * t2e4 
+	- 12.475 * t3e6 + 5.913 * t4e8));
+
+	var slp = 3.96 * Math.sin(DEG_TO_RAD * (119.7 + 131.8 * t)) 
+		+ 1.96 * Math.sin(DEG_TO_RAD * (125.0 - 1934.1 * t));
+
+	var slpp = 0.463 * Math.sin(DEG_TO_RAD * (357.5 + 35999.1 * t)) 
+		+ 0.152 * Math.sin(DEG_TO_RAD * (238.2 + 854535.2 * t)) 
+		- 0.071 * Math.sin(DEG_TO_RAD * (27.8 + 131.8 * t)) 
+		- 0.055 * Math.sin(DEG_TO_RAD * (103.2 + 377336.3 * t)) 
+		- 0.026 * Math.sin(DEG_TO_RAD * (233.2 + 926533.3 * t));
+
+	var slppp = 14 * Math.sin(DEG_TO_RAD * (357.5 + 35999.1 * t)) 
+		+ 5 * Math.sin(DEG_TO_RAD * (238.2 + 854535.2 * t));
+
+	var lambda = 218.31665 + 481267.88134 * t - 13.268 * t2e4 
+		+ 1.856 * t3e6 - 1.534 * t4e8 + sl 
+		+ 1e-3 * (slp + slpp * t + slppp * t2e4);
+
+	var computed = {
+		a : sma * 1000,
+		e : ecc,
+		i : 2.0 * Math.asin(gamma) * RAD_TO_DEG,
+		w : ( (lp - raan)) % 360,
+		o : ( raan) % 360,
+		M : ( (lambda - lp)) %  360
+	};
+	
+	return computed;
+
+
+};

+ 31 - 0
app/calendar/planet_position/src/NameSpace.js

@@ -0,0 +1,31 @@
+/*
+	Global vars
+*/
+
+'use strict';
+module.exports = {
+	//gravitational constant to measure the force with masses in kg and radii in meters N(m/kg)^2
+	G : 6.6742e-11,
+	//astronomical unit in km
+	AU : 149597870,
+	CIRCLE : 2 * Math.PI,
+	KM : 1000,
+	DEG_TO_RAD : Math.PI/180,
+	RAD_TO_DEG : 180/Math.PI,
+	NM_TO_KM : 1.852,
+	LB_TO_KG : 0.453592,
+	LBF_TO_NEWTON : 4.44822162,
+	FT_TO_M : 0.3048,
+	//duration in seconds
+	DAY : 60 * 60 * 24,
+	//duration in days
+	YEAR : 365.25,
+	//duration in days
+	CENTURY : 100 * 365.25,
+	SIDERAL_DAY : 3600 * 23.9344696,
+	J2000 : new Date('2000-01-01T12:00:00-00:00'),
+	getEpochTime : function(userDate) {
+		userDate = userDate || new Date();
+		return ((userDate - this.J2000) / 1000) ;
+	}
+};

+ 247 - 0
app/calendar/planet_position/src/OrbitalElements.js

@@ -0,0 +1,247 @@
+
+'use strict';
+
+var ns = require('ns');
+var Utils = require('./Utils');
+var THREE = require('./Three.shim');
+var CMath = require('./Math');
+
+var maxIterationsForEccentricAnomaly = 10;
+var maxDE = 1e-15;
+
+var solveEccentricAnomaly = function(f, x0, maxIter) {
+		
+	var x = 0;
+	var x2 = x0;
+	
+	for (var i = 0; i < maxIter; i++) {
+		x = x2;
+		x2 = f(x);
+	}
+	
+	return x2;
+}
+
+var solveKepler = function(e, M) {
+	return function(x) {
+		return x + (M + e * Math.sin(x) - x) / (1 - e * Math.cos(x));
+	};
+};
+
+var solveKeplerLaguerreConway = function(e, M) {
+	return function(x) {
+		var s = e * Math.sin(x);
+		var c = e * Math.cos(x);
+		var f = x - s - M;
+		var f1 = 1 - c;
+		var f2 = s;
+
+		x += -5 * f / (f1 + CMath.sign(f1) * Math.sqrt(Math.abs(16 * f1 * f1 - 20 * f * f2)));
+		return x;
+	};
+};
+
+var solveKeplerLaguerreConwayHyp = function(e, M) {
+	return function(x) {
+		var s = e * CMath.sinh(x);
+		var c = e * CMath.cosh(x);
+		var f = x - s - M;
+		var f1 = c - 1;
+		var f2 = s;
+
+		x += -5 * f / (f1 + CMath.sign(f1) * Math.sqrt(Math.abs(16 * f1 * f1 - 20 * f * f2)));
+		return x;
+	};
+};
+
+module.exports = {
+	setDefaultOrbit : function(orbitalElements, calculator) {
+		this.orbitalElements = orbitalElements;
+		if(orbitalElements && orbitalElements.epoch) {
+			this.epochCorrection = ns.getEpochTime(orbitalElements.epoch);
+		}
+		this.calculator = calculator;
+	},
+
+	setName : function(name){
+		this.name = name;
+	},
+
+	calculateVelocity : function(timeEpoch, relativeTo, isFromDelta) {
+		if(!this.orbitalElements) return new THREE.Vector3(0,0,0);
+
+		var eclipticVelocity;
+		
+		if ( isFromDelta ) {
+			var pos1 = this.calculatePosition(timeEpoch);
+			var pos2 = this.calculatePosition(timeEpoch + 60);
+			eclipticVelocity = pos2.sub(pos1).multiplyScalar(1/60);
+		} else {
+			//vis viva to calculate speed (not velocity, i.e not a vector)
+			var el = this.calculateElements(timeEpoch);
+			var speed = Math.sqrt(ns.G * require('./SolarSystem').getBody(relativeTo).mass * ((2 / (el.r)) - (1 / (el.a))));
+
+			//now calculate velocity orientation, that is, a vector tangent to the orbital ellipse
+			var k = el.r / el.a;
+			var o = ((2 - (2 * el.e * el.e)) / (k * (2-k)))-1;
+			//floating point imprecision
+			o = o > 1 ? 1 : o;
+			var alpha = Math.PI - Math.acos(o);
+			alpha = el.v < 0 ? (2 * Math.PI) - alpha  : alpha;
+			var velocityAngle = el.v + (alpha / 2);
+			//velocity vector in the plane of the orbit
+			var orbitalVelocity = new THREE.Vector3(Math.cos(velocityAngle), Math.sin(velocityAngle)).setLength(speed);
+			var velocityEls = Utils.extend({}, el, {pos:orbitalVelocity, v:null, r:null});
+			eclipticVelocity = this.getPositionFromElements(velocityEls);
+		}
+
+		//var diff = eclipticVelocityFromDelta.sub(eclipticVelocity);console.log(diff.length());
+		return eclipticVelocity;
+		
+	},
+
+	calculatePosition : function(timeEpoch) {
+		if(!this.orbitalElements) return new THREE.Vector3(0,0,0);
+		var computed = this.calculateElements(timeEpoch);
+		var pos =  this.getPositionFromElements(computed);
+		return pos;
+	},
+
+	solveEccentricAnomaly : function(e, M){
+		if (e == 0.0) {
+			return M;
+		}  else if (e < 0.9) {
+			var sol = solveEccentricAnomaly(solveKepler(e, M), M, 6);
+			return sol;
+		} else if (e < 1.0) {
+			var E = M + 0.85 * e * ((Math.sin(M) >= 0.0) ? 1 : -1);
+			var sol = solveEccentricAnomaly(solveKeplerLaguerreConway(e, M), E, 8);
+			return sol;
+		} else if (e == 1.0) {
+			return M;
+		} else {
+			var E = Math.log(2 * M / e + 1.85);
+			var sol = solveEccentricAnomaly(solveKeplerLaguerreConwayHyp(e, M), E, 30);
+			return sol;
+		}
+	},
+
+	calculateElements : function(timeEpoch, forcedOrbitalElements) {
+		if(!forcedOrbitalElements && !this.orbitalElements) return null;
+
+		var orbitalElements = forcedOrbitalElements || this.orbitalElements;
+
+		/*
+
+		Epoch : J2000
+
+		a 	Semi-major axis
+	    e 	Eccentricity
+	    i 	Inclination
+	    o 	Longitude of Ascending Node (Ω)
+	    w 	Argument of periapsis (ω)
+		E 	Eccentric Anomaly
+	    T 	Time at perihelion
+	    M	Mean anomaly
+	    l 	Mean Longitude
+	    lp	longitude of periapsis
+	    r	distance du centre
+	    v	true anomaly
+
+	    P	Sidereal period (mean value)
+		Pw	Argument of periapsis precession period (mean value)
+		Pn	Longitude of the ascending node precession period (mean value)
+
+	    */
+	    if (this.epochCorrection) {
+	    	timeEpoch -= this.epochCorrection;
+	    }
+		var tDays = timeEpoch / ns.DAY;
+		var T = tDays / ns.CENTURY ;
+		//console.log(T);
+		var computed = {
+			t : timeEpoch
+		};
+
+		if(this.calculator && !forcedOrbitalElements) {
+			var realorbit = this.calculator(T);
+			Utils.extend(computed, realorbit);
+		} else {
+
+			if (orbitalElements.base) {
+				var variation;
+				for(var el in orbitalElements.base) {
+					//cy : variation by century.
+					//day : variation by day.
+					variation = orbitalElements.cy ? orbitalElements.cy[el] : (orbitalElements.day[el] * ns.CENTURY);
+					variation = variation || 0;
+					computed[el] = orbitalElements.base[el] + (variation * T);
+				}
+			} else {
+				computed = Utils.extend({}, orbitalElements);
+			}
+
+			if (undefined === computed.w) {
+				computed.w = computed.lp - computed.o;
+			}
+
+			if (undefined === computed.M) {
+				computed.M = computed.l - computed.lp;
+			}
+
+			computed.a = computed.a * ns.KM;//was in km, set it in m
+		}
+
+
+		computed.i = ns.DEG_TO_RAD * computed.i;
+		computed.o = ns.DEG_TO_RAD * computed.o;
+		computed.w = ns.DEG_TO_RAD * computed.w;
+		computed.M = ns.DEG_TO_RAD * computed.M;
+
+		computed.E = this.solveEccentricAnomaly(computed.e, computed.M);
+
+		computed.E = computed.E % ns.CIRCLE;
+		computed.i = computed.i % ns.CIRCLE;
+		computed.o = computed.o % ns.CIRCLE;
+		computed.w = computed.w % ns.CIRCLE;
+		computed.M = computed.M % ns.CIRCLE;
+
+		//in the plane of the orbit
+		computed.pos = new THREE.Vector3(computed.a * (Math.cos(computed.E) - computed.e), computed.a * (Math.sqrt(1 - (computed.e*computed.e))) * Math.sin(computed.E));
+
+		computed.r = computed.pos.length();
+		computed.v = Math.atan2(computed.pos.y, computed.pos.x);
+		if(orbitalElements.relativeTo) {
+			var relativeTo = require('./SolarSystem').getBody(orbitalElements.relativeTo);
+			if(relativeTo.tilt) {
+				computed.tilt = -relativeTo.tilt * ns.DEG_TO_RAD;
+			}
+		};
+		return computed;
+	},
+
+	getPositionFromElements : function(computed) {
+
+		if(!computed) return new THREE.Vector3(0,0,0);
+
+		var a1 = new THREE.Euler(computed.tilt || 0, 0, computed.o, 'XYZ');
+		var q1 = new THREE.Quaternion().setFromEuler(a1);
+		var a2 = new THREE.Euler(computed.i, 0, computed.w, 'XYZ');
+		var q2 = new THREE.Quaternion().setFromEuler(a2);
+
+		var planeQuat = new THREE.Quaternion().multiplyQuaternions(q1, q2);
+		computed.pos.applyQuaternion(planeQuat);
+		return computed.pos;
+	},
+
+	calculatePeriod : function(elements, relativeTo) {
+		var period;
+		if(this.orbitalElements && this.orbitalElements.day && this.orbitalElements.day.M) {
+			period = 360 / this.orbitalElements.day.M ;
+		}else if(require('./SolarSystem').getBody(relativeTo) && require('./SolarSystem').getBody(relativeTo).k && elements) {
+			period = 2 * Math.PI * Math.sqrt(Math.pow(elements.a/(ns.AU*1000), 3)) / require('./SolarSystem').getBody(relativeTo).k;
+		}
+		period *= ns.DAY;//in seconds
+		return period;
+	}
+};

+ 44 - 0
app/calendar/planet_position/src/SolarSystem.js

@@ -0,0 +1,44 @@
+'use strict';
+
+var ns = require('ns');
+var Utils = require('./Utils');
+var definitions = require('./Definitions');
+var CelestialBody = require('./CelestialBody');
+
+
+var bodies = definitions.map(function(def){
+	var body = Object.create(CelestialBody);
+	Utils.extend(body, def);
+	body.init();
+	return body;
+});
+
+var names = bodies.reduce(function(carry, body){
+	carry[body.name] = body;
+	return carry;
+}, {});
+
+var central = bodies.reduce(function(carry, body){
+	carry = carry && carry.mass > body.mass ? carry : body;
+	return carry;
+}, null);
+
+
+console.log(bodies);
+
+module.exports = {
+	getBody: function(name){
+		return names[name] || central;
+	},
+	getPositions: function(userDate, calculateVelocity){
+		var epochTime = ns.getEpochTime(userDate);
+		return bodies.map(function(body){
+			body.setPositionFromDate(epochTime, calculateVelocity);
+			return {
+				name: body.name,
+				position: body.getPosition(),
+				velocity: body.getVelocity()
+			};
+		});
+	}
+};

+ 10 - 0
app/calendar/planet_position/src/Three.shim.js

@@ -0,0 +1,10 @@
+
+'use strict';
+
+var THREE = global.THREE = {};
+
+require('../vendor/three/math/Vector3');
+require('../vendor/three/math/Quaternion');
+require('../vendor/three/math/Euler');
+
+module.exports = THREE;

+ 19 - 0
app/calendar/planet_position/src/Utils.js

@@ -0,0 +1,19 @@
+/*
+	Global vars
+*/
+
+'use strict';
+
+var extend = function(){
+	if(arguments.length === 1) return arguments[0];
+	var source = Array.prototype.splice.call(arguments, 1, 1)[0];
+	arguments[0] = Object.keys(source).reduce(function(carry, key){
+		carry[key] = source[key];
+		return carry;
+	}, arguments[0]);
+	return extend.apply(null, arguments);
+};
+
+module.exports = {
+	extend: extend
+};

+ 326 - 0
app/calendar/planet_position/vendor/three/math/Euler.js

@@ -0,0 +1,326 @@
+/**
+ * @author mrdoob / http://mrdoob.com/
+ * @author WestLangley / http://github.com/WestLangley
+ * @author bhouston / http://exocortex.com
+ */
+
+THREE.Euler = function ( x, y, z, order ) {
+
+	this._x = x || 0;
+	this._y = y || 0;
+	this._z = z || 0;
+	this._order = order || THREE.Euler.DefaultOrder;
+
+};
+
+THREE.Euler.RotationOrders = [ 'XYZ', 'YZX', 'ZXY', 'XZY', 'YXZ', 'ZYX' ];
+
+THREE.Euler.DefaultOrder = 'XYZ';
+
+THREE.Euler.prototype = {
+
+	constructor: THREE.Euler,
+
+	_x: 0, _y: 0, _z: 0, _order: THREE.Euler.DefaultOrder,
+
+	get x () {
+
+		return this._x;
+
+	},
+
+	set x ( value ) {
+
+		this._x = value;
+		this.onChangeCallback();
+
+	},
+
+	get y () {
+
+		return this._y;
+
+	},
+
+	set y ( value ) {
+
+		this._y = value;
+		this.onChangeCallback();
+
+	},
+
+	get z () {
+
+		return this._z;
+
+	},
+
+	set z ( value ) {
+
+		this._z = value;
+		this.onChangeCallback();
+
+	},
+
+	get order () {
+
+		return this._order;
+
+	},
+
+	set order ( value ) {
+
+		this._order = value;
+		this.onChangeCallback();
+
+	},
+
+	set: function ( x, y, z, order ) {
+
+		this._x = x;
+		this._y = y;
+		this._z = z;
+		this._order = order || this._order;
+
+		this.onChangeCallback();
+
+		return this;
+
+	},
+
+	copy: function ( euler ) {
+
+		this._x = euler._x;
+		this._y = euler._y;
+		this._z = euler._z;
+		this._order = euler._order;
+
+		this.onChangeCallback();
+
+		return this;
+
+	},
+
+	setFromRotationMatrix: function ( m, order, update ) {
+
+		var clamp = THREE.Math.clamp;
+
+		// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
+
+		var te = m.elements;
+		var m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ];
+		var m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ];
+		var m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ];
+
+		order = order || this._order;
+
+		if ( order === 'XYZ' ) {
+
+			this._y = Math.asin( clamp( m13, - 1, 1 ) );
+
+			if ( Math.abs( m13 ) < 0.99999 ) {
+
+				this._x = Math.atan2( - m23, m33 );
+				this._z = Math.atan2( - m12, m11 );
+
+			} else {
+
+				this._x = Math.atan2( m32, m22 );
+				this._z = 0;
+
+			}
+
+		} else if ( order === 'YXZ' ) {
+
+			this._x = Math.asin( - clamp( m23, - 1, 1 ) );
+
+			if ( Math.abs( m23 ) < 0.99999 ) {
+
+				this._y = Math.atan2( m13, m33 );
+				this._z = Math.atan2( m21, m22 );
+
+			} else {
+
+				this._y = Math.atan2( - m31, m11 );
+				this._z = 0;
+
+			}
+
+		} else if ( order === 'ZXY' ) {
+
+			this._x = Math.asin( clamp( m32, - 1, 1 ) );
+
+			if ( Math.abs( m32 ) < 0.99999 ) {
+
+				this._y = Math.atan2( - m31, m33 );
+				this._z = Math.atan2( - m12, m22 );
+
+			} else {
+
+				this._y = 0;
+				this._z = Math.atan2( m21, m11 );
+
+			}
+
+		} else if ( order === 'ZYX' ) {
+
+			this._y = Math.asin( - clamp( m31, - 1, 1 ) );
+
+			if ( Math.abs( m31 ) < 0.99999 ) {
+
+				this._x = Math.atan2( m32, m33 );
+				this._z = Math.atan2( m21, m11 );
+
+			} else {
+
+				this._x = 0;
+				this._z = Math.atan2( - m12, m22 );
+
+			}
+
+		} else if ( order === 'YZX' ) {
+
+			this._z = Math.asin( clamp( m21, - 1, 1 ) );
+
+			if ( Math.abs( m21 ) < 0.99999 ) {
+
+				this._x = Math.atan2( - m23, m22 );
+				this._y = Math.atan2( - m31, m11 );
+
+			} else {
+
+				this._x = 0;
+				this._y = Math.atan2( m13, m33 );
+
+			}
+
+		} else if ( order === 'XZY' ) {
+
+			this._z = Math.asin( - clamp( m12, - 1, 1 ) );
+
+			if ( Math.abs( m12 ) < 0.99999 ) {
+
+				this._x = Math.atan2( m32, m22 );
+				this._y = Math.atan2( m13, m11 );
+
+			} else {
+
+				this._x = Math.atan2( - m23, m33 );
+				this._y = 0;
+
+			}
+
+		} else {
+
+			THREE.warn( 'THREE.Euler: .setFromRotationMatrix() given unsupported order: ' + order )
+
+		}
+
+		this._order = order;
+
+		if ( update !== false ) this.onChangeCallback();
+
+		return this;
+
+	},
+
+	setFromQuaternion: function () {
+
+		var matrix;
+
+		return function ( q, order, update ) {
+
+			if ( matrix === undefined ) matrix = new THREE.Matrix4();
+			matrix.makeRotationFromQuaternion( q );
+			this.setFromRotationMatrix( matrix, order, update );
+
+			return this;
+
+		};
+
+	}(),
+
+	setFromVector3: function ( v, order ) {
+
+		return this.set( v.x, v.y, v.z, order || this._order );
+
+	},
+
+	reorder: function () {
+
+		// WARNING: this discards revolution information -bhouston
+
+		var q = new THREE.Quaternion();
+
+		return function ( newOrder ) {
+
+			q.setFromEuler( this );
+			this.setFromQuaternion( q, newOrder );
+
+		};
+
+	}(),
+
+	equals: function ( euler ) {
+
+		return ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order );
+
+	},
+
+	fromArray: function ( array ) {
+
+		this._x = array[ 0 ];
+		this._y = array[ 1 ];
+		this._z = array[ 2 ];
+		if ( array[ 3 ] !== undefined ) this._order = array[ 3 ];
+
+		this.onChangeCallback();
+
+		return this;
+
+	},
+
+	toArray: function ( array, offset ) {
+
+		if ( array === undefined ) array = [];
+		if ( offset === undefined ) offset = 0;
+
+		array[ offset ] = this._x;
+		array[ offset + 1 ] = this._y;
+		array[ offset + 2 ] = this._z;
+		array[ offset + 3 ] = this._order;
+
+		return array;
+	},
+
+	toVector3: function ( optionalResult ) {
+
+		if ( optionalResult ) {
+
+			return optionalResult.set( this._x, this._y, this._z );
+
+		} else {
+
+			return new THREE.Vector3( this._x, this._y, this._z );
+
+		}
+
+	},
+
+	onChange: function ( callback ) {
+
+		this.onChangeCallback = callback;
+
+		return this;
+
+	},
+
+	onChangeCallback: function () {},
+
+	clone: function () {
+
+		return new THREE.Euler( this._x, this._y, this._z, this._order );
+
+	}
+
+};

+ 522 - 0
app/calendar/planet_position/vendor/three/math/Quaternion.js

@@ -0,0 +1,522 @@
+/**
+ * @author mikael emtinger / http://gomo.se/
+ * @author alteredq / http://alteredqualia.com/
+ * @author WestLangley / http://github.com/WestLangley
+ * @author bhouston / http://exocortex.com
+ */
+
+THREE.Quaternion = function ( x, y, z, w ) {
+
+	this._x = x || 0;
+	this._y = y || 0;
+	this._z = z || 0;
+	this._w = ( w !== undefined ) ? w : 1;
+
+};
+
+THREE.Quaternion.prototype = {
+
+	constructor: THREE.Quaternion,
+
+	_x: 0,_y: 0, _z: 0, _w: 0,
+
+	get x () {
+
+		return this._x;
+
+	},
+
+	set x ( value ) {
+
+		this._x = value;
+		this.onChangeCallback();
+
+	},
+
+	get y () {
+
+		return this._y;
+
+	},
+
+	set y ( value ) {
+
+		this._y = value;
+		this.onChangeCallback();
+
+	},
+
+	get z () {
+
+		return this._z;
+
+	},
+
+	set z ( value ) {
+
+		this._z = value;
+		this.onChangeCallback();
+
+	},
+
+	get w () {
+
+		return this._w;
+
+	},
+
+	set w ( value ) {
+
+		this._w = value;
+		this.onChangeCallback();
+
+	},
+
+	set: function ( x, y, z, w ) {
+
+		this._x = x;
+		this._y = y;
+		this._z = z;
+		this._w = w;
+
+		this.onChangeCallback();
+
+		return this;
+
+	},
+
+	copy: function ( quaternion ) {
+
+		this._x = quaternion.x;
+		this._y = quaternion.y;
+		this._z = quaternion.z;
+		this._w = quaternion.w;
+
+		this.onChangeCallback();
+
+		return this;
+
+	},
+
+	setFromEuler: function ( euler, update ) {
+
+		if ( euler instanceof THREE.Euler === false ) {
+
+			throw new Error( 'THREE.Quaternion: .setFromEuler() now expects a Euler rotation rather than a Vector3 and order.' );
+		}
+
+		// http://www.mathworks.com/matlabcentral/fileexchange/
+		// 	20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/
+		//	content/SpinCalc.m
+
+		var c1 = Math.cos( euler._x / 2 );
+		var c2 = Math.cos( euler._y / 2 );
+		var c3 = Math.cos( euler._z / 2 );
+		var s1 = Math.sin( euler._x / 2 );
+		var s2 = Math.sin( euler._y / 2 );
+		var s3 = Math.sin( euler._z / 2 );
+
+		if ( euler.order === 'XYZ' ) {
+
+			this._x = s1 * c2 * c3 + c1 * s2 * s3;
+			this._y = c1 * s2 * c3 - s1 * c2 * s3;
+			this._z = c1 * c2 * s3 + s1 * s2 * c3;
+			this._w = c1 * c2 * c3 - s1 * s2 * s3;
+
+		} else if ( euler.order === 'YXZ' ) {
+
+			this._x = s1 * c2 * c3 + c1 * s2 * s3;
+			this._y = c1 * s2 * c3 - s1 * c2 * s3;
+			this._z = c1 * c2 * s3 - s1 * s2 * c3;
+			this._w = c1 * c2 * c3 + s1 * s2 * s3;
+
+		} else if ( euler.order === 'ZXY' ) {
+
+			this._x = s1 * c2 * c3 - c1 * s2 * s3;
+			this._y = c1 * s2 * c3 + s1 * c2 * s3;
+			this._z = c1 * c2 * s3 + s1 * s2 * c3;
+			this._w = c1 * c2 * c3 - s1 * s2 * s3;
+
+		} else if ( euler.order === 'ZYX' ) {
+
+			this._x = s1 * c2 * c3 - c1 * s2 * s3;
+			this._y = c1 * s2 * c3 + s1 * c2 * s3;
+			this._z = c1 * c2 * s3 - s1 * s2 * c3;
+			this._w = c1 * c2 * c3 + s1 * s2 * s3;
+
+		} else if ( euler.order === 'YZX' ) {
+
+			this._x = s1 * c2 * c3 + c1 * s2 * s3;
+			this._y = c1 * s2 * c3 + s1 * c2 * s3;
+			this._z = c1 * c2 * s3 - s1 * s2 * c3;
+			this._w = c1 * c2 * c3 - s1 * s2 * s3;
+
+		} else if ( euler.order === 'XZY' ) {
+
+			this._x = s1 * c2 * c3 - c1 * s2 * s3;
+			this._y = c1 * s2 * c3 - s1 * c2 * s3;
+			this._z = c1 * c2 * s3 + s1 * s2 * c3;
+			this._w = c1 * c2 * c3 + s1 * s2 * s3;
+
+		}
+
+		if ( update !== false ) this.onChangeCallback();
+
+		return this;
+
+	},
+
+	setFromAxisAngle: function ( axis, angle ) {
+
+		// http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm
+
+		// assumes axis is normalized
+
+		var halfAngle = angle / 2, s = Math.sin( halfAngle );
+
+		this._x = axis.x * s;
+		this._y = axis.y * s;
+		this._z = axis.z * s;
+		this._w = Math.cos( halfAngle );
+
+		this.onChangeCallback();
+
+		return this;
+
+	},
+
+	setFromRotationMatrix: function ( m ) {
+
+		// http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
+
+		// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
+
+		var te = m.elements,
+
+			m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ],
+			m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ],
+			m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ],
+
+			trace = m11 + m22 + m33,
+			s;
+
+		if ( trace > 0 ) {
+
+			s = 0.5 / Math.sqrt( trace + 1.0 );
+
+			this._w = 0.25 / s;
+			this._x = ( m32 - m23 ) * s;
+			this._y = ( m13 - m31 ) * s;
+			this._z = ( m21 - m12 ) * s;
+
+		} else if ( m11 > m22 && m11 > m33 ) {
+
+			s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 );
+
+			this._w = ( m32 - m23 ) / s;
+			this._x = 0.25 * s;
+			this._y = ( m12 + m21 ) / s;
+			this._z = ( m13 + m31 ) / s;
+
+		} else if ( m22 > m33 ) {
+
+			s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 );
+
+			this._w = ( m13 - m31 ) / s;
+			this._x = ( m12 + m21 ) / s;
+			this._y = 0.25 * s;
+			this._z = ( m23 + m32 ) / s;
+
+		} else {
+
+			s = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 );
+
+			this._w = ( m21 - m12 ) / s;
+			this._x = ( m13 + m31 ) / s;
+			this._y = ( m23 + m32 ) / s;
+			this._z = 0.25 * s;
+
+		}
+
+		this.onChangeCallback();
+
+		return this;
+
+	},
+
+	setFromUnitVectors: function () {
+
+		// http://lolengine.net/blog/2014/02/24/quaternion-from-two-vectors-final
+
+		// assumes direction vectors vFrom and vTo are normalized
+
+		var v1, r;
+
+		var EPS = 0.000001;
+
+		return function ( vFrom, vTo ) {
+
+			if ( v1 === undefined ) v1 = new THREE.Vector3();
+
+			r = vFrom.dot( vTo ) + 1;
+
+			if ( r < EPS ) {
+
+				r = 0;
+
+				if ( Math.abs( vFrom.x ) > Math.abs( vFrom.z ) ) {
+
+					v1.set( - vFrom.y, vFrom.x, 0 );
+
+				} else {
+
+					v1.set( 0, - vFrom.z, vFrom.y );
+
+				}
+
+			} else {
+
+				v1.crossVectors( vFrom, vTo );
+
+			}
+
+			this._x = v1.x;
+			this._y = v1.y;
+			this._z = v1.z;
+			this._w = r;
+
+			this.normalize();
+
+			return this;
+
+		}
+
+	}(),
+
+	inverse: function () {
+
+		this.conjugate().normalize();
+
+		return this;
+
+	},
+
+	conjugate: function () {
+
+		this._x *= - 1;
+		this._y *= - 1;
+		this._z *= - 1;
+
+		this.onChangeCallback();
+
+		return this;
+
+	},
+
+	dot: function ( v ) {
+
+		return this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w;
+
+	},
+
+	lengthSq: function () {
+
+		return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w;
+
+	},
+
+	length: function () {
+
+		return Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w );
+
+	},
+
+	normalize: function () {
+
+		var l = this.length();
+
+		if ( l === 0 ) {
+
+			this._x = 0;
+			this._y = 0;
+			this._z = 0;
+			this._w = 1;
+
+		} else {
+
+			l = 1 / l;
+
+			this._x = this._x * l;
+			this._y = this._y * l;
+			this._z = this._z * l;
+			this._w = this._w * l;
+
+		}
+
+		this.onChangeCallback();
+
+		return this;
+
+	},
+
+	multiply: function ( q, p ) {
+
+		if ( p !== undefined ) {
+
+			THREE.warn( 'THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead.' );
+			return this.multiplyQuaternions( q, p );
+
+		}
+
+		return this.multiplyQuaternions( this, q );
+
+	},
+
+	multiplyQuaternions: function ( a, b ) {
+
+		// from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm
+
+		var qax = a._x, qay = a._y, qaz = a._z, qaw = a._w;
+		var qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w;
+
+		this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby;
+		this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz;
+		this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx;
+		this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz;
+
+		this.onChangeCallback();
+
+		return this;
+
+	},
+
+	multiplyVector3: function ( vector ) {
+
+		THREE.warn( 'THREE.Quaternion: .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead.' );
+		return vector.applyQuaternion( this );
+
+	},
+
+	slerp: function ( qb, t ) {
+
+		if ( t === 0 ) return this;
+		if ( t === 1 ) return this.copy( qb );
+
+		var x = this._x, y = this._y, z = this._z, w = this._w;
+
+		// http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/
+
+		var cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z;
+
+		if ( cosHalfTheta < 0 ) {
+
+			this._w = - qb._w;
+			this._x = - qb._x;
+			this._y = - qb._y;
+			this._z = - qb._z;
+
+			cosHalfTheta = - cosHalfTheta;
+
+		} else {
+
+			this.copy( qb );
+
+		}
+
+		if ( cosHalfTheta >= 1.0 ) {
+
+			this._w = w;
+			this._x = x;
+			this._y = y;
+			this._z = z;
+
+			return this;
+
+		}
+
+		var halfTheta = Math.acos( cosHalfTheta );
+		var sinHalfTheta = Math.sqrt( 1.0 - cosHalfTheta * cosHalfTheta );
+
+		if ( Math.abs( sinHalfTheta ) < 0.001 ) {
+
+			this._w = 0.5 * ( w + this._w );
+			this._x = 0.5 * ( x + this._x );
+			this._y = 0.5 * ( y + this._y );
+			this._z = 0.5 * ( z + this._z );
+
+			return this;
+
+		}
+
+		var ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta,
+		ratioB = Math.sin( t * halfTheta ) / sinHalfTheta;
+
+		this._w = ( w * ratioA + this._w * ratioB );
+		this._x = ( x * ratioA + this._x * ratioB );
+		this._y = ( y * ratioA + this._y * ratioB );
+		this._z = ( z * ratioA + this._z * ratioB );
+
+		this.onChangeCallback();
+
+		return this;
+
+	},
+
+	equals: function ( quaternion ) {
+
+		return ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w );
+
+	},
+
+	fromArray: function ( array, offset ) {
+
+		if ( offset === undefined ) offset = 0;
+
+		this._x = array[ offset ];
+		this._y = array[ offset + 1 ];
+		this._z = array[ offset + 2 ];
+		this._w = array[ offset + 3 ];
+
+		this.onChangeCallback();
+
+		return this;
+
+	},
+
+	toArray: function ( array, offset ) {
+
+		if ( array === undefined ) array = [];
+		if ( offset === undefined ) offset = 0;
+
+		array[ offset ] = this._x;
+		array[ offset + 1 ] = this._y;
+		array[ offset + 2 ] = this._z;
+		array[ offset + 3 ] = this._w;
+
+		return array;
+
+	},
+
+	onChange: function ( callback ) {
+
+		this.onChangeCallback = callback;
+
+		return this;
+
+	},
+
+	onChangeCallback: function () {},
+
+	clone: function () {
+
+		return new THREE.Quaternion( this._x, this._y, this._z, this._w );
+
+	}
+
+};
+
+THREE.Quaternion.slerp = function ( qa, qb, qm, t ) {
+
+	return qm.copy( qa ).slerp( qb, t );
+
+}

+ 850 - 0
app/calendar/planet_position/vendor/three/math/Vector3.js

@@ -0,0 +1,850 @@
+/**
+ * @author mrdoob / http://mrdoob.com/
+ * @author *kile / http://kile.stravaganza.org/
+ * @author philogb / http://blog.thejit.org/
+ * @author mikael emtinger / http://gomo.se/
+ * @author egraether / http://egraether.com/
+ * @author WestLangley / http://github.com/WestLangley
+ */
+
+THREE.Vector3 = function ( x, y, z ) {
+
+	this.x = x || 0;
+	this.y = y || 0;
+	this.z = z || 0;
+
+};
+
+THREE.Vector3.prototype = {
+
+	constructor: THREE.Vector3,
+
+	set: function ( x, y, z ) {
+
+		this.x = x;
+		this.y = y;
+		this.z = z;
+
+		return this;
+
+	},
+
+	setX: function ( x ) {
+
+		this.x = x;
+
+		return this;
+
+	},
+
+	setY: function ( y ) {
+
+		this.y = y;
+
+		return this;
+
+	},
+
+	setZ: function ( z ) {
+
+		this.z = z;
+
+		return this;
+
+	},
+
+	setComponent: function ( index, value ) {
+
+		switch ( index ) {
+
+			case 0: this.x = value; break;
+			case 1: this.y = value; break;
+			case 2: this.z = value; break;
+			default: throw new Error( 'index is out of range: ' + index );
+
+		}
+
+	},
+
+	getComponent: function ( index ) {
+
+		switch ( index ) {
+
+			case 0: return this.x;
+			case 1: return this.y;
+			case 2: return this.z;
+			default: throw new Error( 'index is out of range: ' + index );
+
+		}
+
+	},
+
+	copy: function ( v ) {
+
+		this.x = v.x;
+		this.y = v.y;
+		this.z = v.z;
+
+		return this;
+
+	},
+
+	add: function ( v, w ) {
+
+		if ( w !== undefined ) {
+
+			THREE.warn( 'THREE.Vector3: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );
+			return this.addVectors( v, w );
+
+		}
+
+		this.x += v.x;
+		this.y += v.y;
+		this.z += v.z;
+
+		return this;
+
+	},
+
+	addScalar: function ( s ) {
+
+		this.x += s;
+		this.y += s;
+		this.z += s;
+
+		return this;
+
+	},
+
+	addVectors: function ( a, b ) {
+
+		this.x = a.x + b.x;
+		this.y = a.y + b.y;
+		this.z = a.z + b.z;
+
+		return this;
+
+	},
+
+	sub: function ( v, w ) {
+
+		if ( w !== undefined ) {
+
+			THREE.warn( 'THREE.Vector3: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );
+			return this.subVectors( v, w );
+
+		}
+
+		this.x -= v.x;
+		this.y -= v.y;
+		this.z -= v.z;
+
+		return this;
+
+	},
+	
+	subScalar: function ( s ) {
+
+		this.x -= s;
+		this.y -= s;
+		this.z -= s;
+
+		return this;
+
+	},
+
+	subVectors: function ( a, b ) {
+
+		this.x = a.x - b.x;
+		this.y = a.y - b.y;
+		this.z = a.z - b.z;
+
+		return this;
+
+	},
+
+	multiply: function ( v, w ) {
+
+		if ( w !== undefined ) {
+
+			THREE.warn( 'THREE.Vector3: .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead.' );
+			return this.multiplyVectors( v, w );
+
+		}
+
+		this.x *= v.x;
+		this.y *= v.y;
+		this.z *= v.z;
+
+		return this;
+
+	},
+
+	multiplyScalar: function ( scalar ) {
+
+		this.x *= scalar;
+		this.y *= scalar;
+		this.z *= scalar;
+
+		return this;
+
+	},
+
+	multiplyVectors: function ( a, b ) {
+
+		this.x = a.x * b.x;
+		this.y = a.y * b.y;
+		this.z = a.z * b.z;
+
+		return this;
+
+	},
+
+	applyEuler: function () {
+
+		var quaternion;
+
+		return function ( euler ) {
+
+			if ( euler instanceof THREE.Euler === false ) {
+
+				THREE.error( 'THREE.Vector3: .applyEuler() now expects a Euler rotation rather than a Vector3 and order.' );
+
+			}
+
+			if ( quaternion === undefined ) quaternion = new THREE.Quaternion();
+
+			this.applyQuaternion( quaternion.setFromEuler( euler ) );
+
+			return this;
+
+		};
+
+	}(),
+
+	applyAxisAngle: function () {
+
+		var quaternion;
+
+		return function ( axis, angle ) {
+
+			if ( quaternion === undefined ) quaternion = new THREE.Quaternion();
+
+			this.applyQuaternion( quaternion.setFromAxisAngle( axis, angle ) );
+
+			return this;
+
+		};
+
+	}(),
+
+	applyMatrix3: function ( m ) {
+
+		var x = this.x;
+		var y = this.y;
+		var z = this.z;
+
+		var e = m.elements;
+
+		this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ] * z;
+		this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ] * z;
+		this.z = e[ 2 ] * x + e[ 5 ] * y + e[ 8 ] * z;
+
+		return this;
+
+	},
+
+	applyMatrix4: function ( m ) {
+
+		// input: THREE.Matrix4 affine matrix
+
+		var x = this.x, y = this.y, z = this.z;
+
+		var e = m.elements;
+
+		this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ]  * z + e[ 12 ];
+		this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ]  * z + e[ 13 ];
+		this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ];
+
+		return this;
+
+	},
+
+	applyProjection: function ( m ) {
+
+		// input: THREE.Matrix4 projection matrix
+
+		var x = this.x, y = this.y, z = this.z;
+
+		var e = m.elements;
+		var d = 1 / ( e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] ); // perspective divide
+
+		this.x = ( e[ 0 ] * x + e[ 4 ] * y + e[ 8 ]  * z + e[ 12 ] ) * d;
+		this.y = ( e[ 1 ] * x + e[ 5 ] * y + e[ 9 ]  * z + e[ 13 ] ) * d;
+		this.z = ( e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] ) * d;
+
+		return this;
+
+	},
+
+	applyQuaternion: function ( q ) {
+
+		var x = this.x;
+		var y = this.y;
+		var z = this.z;
+
+		var qx = q.x;
+		var qy = q.y;
+		var qz = q.z;
+		var qw = q.w;
+
+		// calculate quat * vector
+
+		var ix =  qw * x + qy * z - qz * y;
+		var iy =  qw * y + qz * x - qx * z;
+		var iz =  qw * z + qx * y - qy * x;
+		var iw = - qx * x - qy * y - qz * z;
+
+		// calculate result * inverse quat
+
+		this.x = ix * qw + iw * - qx + iy * - qz - iz * - qy;
+		this.y = iy * qw + iw * - qy + iz * - qx - ix * - qz;
+		this.z = iz * qw + iw * - qz + ix * - qy - iy * - qx;
+
+		return this;
+
+	},
+
+	project: function () {
+
+		var matrix;
+
+		return function ( camera ) {
+
+			if ( matrix === undefined ) matrix = new THREE.Matrix4();
+
+			matrix.multiplyMatrices( camera.projectionMatrix, matrix.getInverse( camera.matrixWorld ) );
+			return this.applyProjection( matrix );
+
+		};
+
+	}(),
+
+	unproject: function () {
+
+		var matrix;
+
+		return function ( camera ) {
+
+			if ( matrix === undefined ) matrix = new THREE.Matrix4();
+
+			matrix.multiplyMatrices( camera.matrixWorld, matrix.getInverse( camera.projectionMatrix ) );
+			return this.applyProjection( matrix );
+
+		};
+
+	}(),
+
+	transformDirection: function ( m ) {
+
+		// input: THREE.Matrix4 affine matrix
+		// vector interpreted as a direction
+
+		var x = this.x, y = this.y, z = this.z;
+
+		var e = m.elements;
+
+		this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ]  * z;
+		this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ]  * z;
+		this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z;
+
+		this.normalize();
+
+		return this;
+
+	},
+
+	divide: function ( v ) {
+
+		this.x /= v.x;
+		this.y /= v.y;
+		this.z /= v.z;
+
+		return this;
+
+	},
+
+	divideScalar: function ( scalar ) {
+
+		if ( scalar !== 0 ) {
+
+			var invScalar = 1 / scalar;
+
+			this.x *= invScalar;
+			this.y *= invScalar;
+			this.z *= invScalar;
+
+		} else {
+
+			this.x = 0;
+			this.y = 0;
+			this.z = 0;
+
+		}
+
+		return this;
+
+	},
+
+	min: function ( v ) {
+
+		if ( this.x > v.x ) {
+
+			this.x = v.x;
+
+		}
+
+		if ( this.y > v.y ) {
+
+			this.y = v.y;
+
+		}
+
+		if ( this.z > v.z ) {
+
+			this.z = v.z;
+
+		}
+
+		return this;
+
+	},
+
+	max: function ( v ) {
+
+		if ( this.x < v.x ) {
+
+			this.x = v.x;
+
+		}
+
+		if ( this.y < v.y ) {
+
+			this.y = v.y;
+
+		}
+
+		if ( this.z < v.z ) {
+
+			this.z = v.z;
+
+		}
+
+		return this;
+
+	},
+
+	clamp: function ( min, max ) {
+
+		// This function assumes min < max, if this assumption isn't true it will not operate correctly
+
+		if ( this.x < min.x ) {
+
+			this.x = min.x;
+
+		} else if ( this.x > max.x ) {
+
+			this.x = max.x;
+
+		}
+
+		if ( this.y < min.y ) {
+
+			this.y = min.y;
+
+		} else if ( this.y > max.y ) {
+
+			this.y = max.y;
+
+		}
+
+		if ( this.z < min.z ) {
+
+			this.z = min.z;
+
+		} else if ( this.z > max.z ) {
+
+			this.z = max.z;
+
+		}
+
+		return this;
+
+	},
+
+	clampScalar: ( function () {
+
+		var min, max;
+
+		return function ( minVal, maxVal ) {
+
+			if ( min === undefined ) {
+
+				min = new THREE.Vector3();
+				max = new THREE.Vector3();
+
+			}
+
+			min.set( minVal, minVal, minVal );
+			max.set( maxVal, maxVal, maxVal );
+
+			return this.clamp( min, max );
+
+		};
+
+	} )(),
+
+	floor: function () {
+
+		this.x = Math.floor( this.x );
+		this.y = Math.floor( this.y );
+		this.z = Math.floor( this.z );
+
+		return this;
+
+	},
+
+	ceil: function () {
+
+		this.x = Math.ceil( this.x );
+		this.y = Math.ceil( this.y );
+		this.z = Math.ceil( this.z );
+
+		return this;
+
+	},
+
+	round: function () {
+
+		this.x = Math.round( this.x );
+		this.y = Math.round( this.y );
+		this.z = Math.round( this.z );
+
+		return this;
+
+	},
+
+	roundToZero: function () {
+
+		this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );
+		this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );
+		this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z );
+
+		return this;
+
+	},
+
+	negate: function () {
+
+		this.x = - this.x;
+		this.y = - this.y;
+		this.z = - this.z;
+
+		return this;
+
+	},
+
+	dot: function ( v ) {
+
+		return this.x * v.x + this.y * v.y + this.z * v.z;
+
+	},
+
+	lengthSq: function () {
+
+		return this.x * this.x + this.y * this.y + this.z * this.z;
+
+	},
+
+	length: function () {
+
+		return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z );
+
+	},
+
+	lengthManhattan: function () {
+
+		return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z );
+
+	},
+
+	normalize: function () {
+
+		return this.divideScalar( this.length() );
+
+	},
+
+	setLength: function ( l ) {
+
+		var oldLength = this.length();
+
+		if ( oldLength !== 0 && l !== oldLength  ) {
+
+			this.multiplyScalar( l / oldLength );
+		}
+
+		return this;
+
+	},
+
+	lerp: function ( v, alpha ) {
+
+		this.x += ( v.x - this.x ) * alpha;
+		this.y += ( v.y - this.y ) * alpha;
+		this.z += ( v.z - this.z ) * alpha;
+
+		return this;
+
+	},
+
+	lerpVectors: function ( v1, v2, alpha ) {
+
+		this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 );
+
+		return this;
+
+	},
+
+	cross: function ( v, w ) {
+
+		if ( w !== undefined ) {
+
+			THREE.warn( 'THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead.' );
+			return this.crossVectors( v, w );
+
+		}
+
+		var x = this.x, y = this.y, z = this.z;
+
+		this.x = y * v.z - z * v.y;
+		this.y = z * v.x - x * v.z;
+		this.z = x * v.y - y * v.x;
+
+		return this;
+
+	},
+
+	crossVectors: function ( a, b ) {
+
+		var ax = a.x, ay = a.y, az = a.z;
+		var bx = b.x, by = b.y, bz = b.z;
+
+		this.x = ay * bz - az * by;
+		this.y = az * bx - ax * bz;
+		this.z = ax * by - ay * bx;
+
+		return this;
+
+	},
+
+	projectOnVector: function () {
+
+		var v1, dot;
+
+		return function ( vector ) {
+
+			if ( v1 === undefined ) v1 = new THREE.Vector3();
+
+			v1.copy( vector ).normalize();
+
+			dot = this.dot( v1 );
+
+			return this.copy( v1 ).multiplyScalar( dot );
+
+		};
+
+	}(),
+
+	projectOnPlane: function () {
+
+		var v1;
+
+		return function ( planeNormal ) {
+
+			if ( v1 === undefined ) v1 = new THREE.Vector3();
+
+			v1.copy( this ).projectOnVector( planeNormal );
+
+			return this.sub( v1 );
+
+		}
+
+	}(),
+
+	reflect: function () {
+
+		// reflect incident vector off plane orthogonal to normal
+		// normal is assumed to have unit length
+
+		var v1;
+
+		return function ( normal ) {
+
+			if ( v1 === undefined ) v1 = new THREE.Vector3();
+
+			return this.sub( v1.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) );
+
+		}
+
+	}(),
+
+	angleTo: function ( v ) {
+
+		var theta = this.dot( v ) / ( this.length() * v.length() );
+
+		// clamp, to handle numerical problems
+
+		return Math.acos( THREE.Math.clamp( theta, - 1, 1 ) );
+
+	},
+
+	distanceTo: function ( v ) {
+
+		return Math.sqrt( this.distanceToSquared( v ) );
+
+	},
+
+	distanceToSquared: function ( v ) {
+
+		var dx = this.x - v.x;
+		var dy = this.y - v.y;
+		var dz = this.z - v.z;
+
+		return dx * dx + dy * dy + dz * dz;
+
+	},
+
+	setEulerFromRotationMatrix: function ( m, order ) {
+
+		THREE.error( 'THREE.Vector3: .setEulerFromRotationMatrix() has been removed. Use Euler.setFromRotationMatrix() instead.' );
+
+	},
+
+	setEulerFromQuaternion: function ( q, order ) {
+
+		THREE.error( 'THREE.Vector3: .setEulerFromQuaternion() has been removed. Use Euler.setFromQuaternion() instead.' );
+
+	},
+
+	getPositionFromMatrix: function ( m ) {
+
+		THREE.warn( 'THREE.Vector3: .getPositionFromMatrix() has been renamed to .setFromMatrixPosition().' );
+
+		return this.setFromMatrixPosition( m );
+
+	},
+
+	getScaleFromMatrix: function ( m ) {
+
+		THREE.warn( 'THREE.Vector3: .getScaleFromMatrix() has been renamed to .setFromMatrixScale().' );
+
+		return this.setFromMatrixScale( m );
+	},
+
+	getColumnFromMatrix: function ( index, matrix ) {
+
+		THREE.warn( 'THREE.Vector3: .getColumnFromMatrix() has been renamed to .setFromMatrixColumn().' );
+
+		return this.setFromMatrixColumn( index, matrix );
+
+	},
+
+	setFromMatrixPosition: function ( m ) {
+
+		this.x = m.elements[ 12 ];
+		this.y = m.elements[ 13 ];
+		this.z = m.elements[ 14 ];
+
+		return this;
+
+	},
+
+	setFromMatrixScale: function ( m ) {
+
+		var sx = this.set( m.elements[ 0 ], m.elements[ 1 ], m.elements[  2 ] ).length();
+		var sy = this.set( m.elements[ 4 ], m.elements[ 5 ], m.elements[  6 ] ).length();
+		var sz = this.set( m.elements[ 8 ], m.elements[ 9 ], m.elements[ 10 ] ).length();
+
+		this.x = sx;
+		this.y = sy;
+		this.z = sz;
+
+		return this;
+	},
+
+	setFromMatrixColumn: function ( index, matrix ) {
+		
+		var offset = index * 4;
+
+		var me = matrix.elements;
+
+		this.x = me[ offset ];
+		this.y = me[ offset + 1 ];
+		this.z = me[ offset + 2 ];
+
+		return this;
+
+	},
+
+	equals: function ( v ) {
+
+		return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) );
+
+	},
+
+	fromArray: function ( array, offset ) {
+
+		if ( offset === undefined ) offset = 0;
+
+		this.x = array[ offset ];
+		this.y = array[ offset + 1 ];
+		this.z = array[ offset + 2 ];
+
+		return this;
+
+	},
+
+	toArray: function ( array, offset ) {
+
+		if ( array === undefined ) array = [];
+		if ( offset === undefined ) offset = 0;
+
+		array[ offset ] = this.x;
+		array[ offset + 1 ] = this.y;
+		array[ offset + 2 ] = this.z;
+
+		return array;
+
+	},
+
+	fromAttribute: function ( attribute, index, offset ) {
+
+		if ( offset === undefined ) offset = 0;
+
+		index = index * attribute.itemSize + offset;
+
+		this.x = attribute.array[ index ];
+		this.y = attribute.array[ index + 1 ];
+		this.z = attribute.array[ index + 2 ];
+
+		return this;
+
+	},
+
+	clone: function () {
+
+		return new THREE.Vector3( this.x, this.y, this.z );
+
+	}
+
+};

+ 12 - 0
app/calendar/src/App.js

@@ -0,0 +1,12 @@
+
+'use strict';
+var SolarSystem = require('./SolarSystem');
+
+
+var global = window.lagrange = window.lagrange || {};
+
+global.planet_positions = module.exports = {
+	getPositions: function(userDate){
+		return SolarSystem.getPositions(userDate);
+	}
+};

+ 93 - 0
app/calendar/src/CelestialBody.js

@@ -0,0 +1,93 @@
+
+'use strict';
+
+var OrbitalElements = require('./OrbitalElements');
+var ns = require('ns');
+var THREE = require('./Three.shim');
+
+var CelestialBody = {
+
+	init : function() {
+		this.reset();
+		this.movement = new THREE.Vector3();
+		this.invMass = 1 / this.mass;
+
+		this.orbitalElements = Object.create(OrbitalElements);
+		this.orbitalElements.setName(this.name);
+		this.orbitalElements.setDefaultOrbit(this.orbit, this.orbitCalculator);
+		//console.log(this.name, this.position, this.velocity);
+
+	},
+
+	reset : function(){
+		this.angle = 0;
+		this.force = new THREE.Vector3();
+		this.movement = new THREE.Vector3();
+		this.previousPosition = null;
+	},
+
+	//if epoch start is not j2000, get epoch time from j2000 epoch time
+	getEpochTime : function(epochTime) {
+		if(this.epoch) {
+			epochTime = epochTime - ((this.epoch.getTime() - ns.J2000) / 1000);
+		}
+		return epochTime;
+	},
+
+	setPositionFromDate : function(epochTime, calculateVelocity) {
+
+		epochTime = this.getEpochTime(epochTime);
+		this.position = this.isCentral ? new THREE.Vector3() : this.orbitalElements.getPositionFromElements(this.orbitalElements.calculateElements(epochTime));
+		this.relativePosition = new THREE.Vector3();
+		if(calculateVelocity) {
+			this.velocity = this.isCentral ? new THREE.Vector3() : this.orbitalElements.calculateVelocity(epochTime, this.relativeTo, this.calculateFromElements);
+		}
+		this.positionRelativeTo();		
+	},
+	
+	getAngleTo : function(bodyName){
+		var ref = require('./SolarSystem').getBody(bodyName);
+		if(ref) {
+			
+			var eclPos = this.position.clone().sub(ref.getPosition()).normalize();
+			eclPos.z = 0;
+			var angleX = eclPos.angleTo(new THREE.Vector3(1, 0, 0));
+			var angleY = eclPos.angleTo(new THREE.Vector3(0, 1, 0));
+			//console.log(angleX, angleY);
+			var angle = angleX;
+			var q = Math.PI / 2;
+			if(angleY > q) angle = -angleX;
+			return angle;
+		}
+		return 0;
+	},
+
+	positionRelativeTo : function(){
+		if(this.relativeTo) {
+			var central = require('./SolarSystem').getBody(this.relativeTo);
+			if(central && central!==require('./SolarSystem').getBody()/**/) {
+				this.position.add(central.position);
+				//console.log(this.name+' pos rel to ' + this.relativeTo);
+				this.velocity && central.velocity && this.velocity.add(central.velocity);
+			}
+		}
+	},
+
+	calculatePosition : function(t) {
+		return this.orbitalElements.calculatePosition(t);
+	},
+
+	getPosition : function(){
+		return this.position.clone();
+	},
+
+	getVelocity : function(){
+		return this.velocity && this.velocity.clone();
+	},
+	//return true/false if this body is orbiting the requested body
+	isOrbitAround : function(celestial){
+		return celestial.name === this.relativeTo;
+	}
+};
+
+module.exports = CelestialBody;

+ 146 - 0
app/calendar/src/Definitions.js

@@ -0,0 +1,146 @@
+'use strict';
+var ns = require('ns');
+var MoonRealOrbit = require('./MoonRealOrbit');
+
+module.exports = [
+	{
+		name: 'sun',
+		title : 'The Sun',
+		mass : 1.9891e30,
+		radius : 6.96342e5,
+		k : 0.01720209895 //gravitational constant (μ)
+	},
+	{
+	 	name: 'mercury',
+		title : 'Mercury',
+		mass : 3.3022e23,
+		radius:2439,
+		orbit : { 
+			base : {a : 0.38709927 * ns.AU ,  e : 0.20563593, i: 7.00497902, l : 252.25032350, lp : 77.45779628, o : 48.33076593},
+			cy : {a : 0.00000037 * ns.AU ,  e : 0.00001906, i: -0.00594749, l : 149472.67411175, lp : 0.16047689, o : -0.12534081}
+		}
+	},
+	{
+		name: 'venus',
+		title : 'Venus',
+		mass : 4.868e24,
+		radius : 6051,
+		orbit : {
+			base : {a : 0.72333566 * ns.AU ,  e : 0.00677672, i: 3.39467605, l : 181.97909950, lp : 131.60246718, o : 76.67984255},
+			cy : {a : 0.00000390 * ns.AU ,  e : -0.00004107, i: -0.00078890, l : 58517.81538729, lp : 0.00268329, o : -0.27769418}
+		}
+	},
+	{
+		name:'earth',
+		title : 'The Earth',
+		mass : 5.9736e24,
+		radius : 3443.9307 * ns.NM_TO_KM,
+		sideralDay : ns.SIDERAL_DAY,
+		tilt : 23+(26/60)+(21/3600) ,
+		orbit : {
+			base : {a : 1.00000261 * ns.AU, e : 0.01671123, i : -0.00001531, l : 100.46457166, lp : 102.93768193, o : 0.0},
+			cy : {a : 0.00000562 * ns.AU, e : -0.00004392, i : -0.01294668, l : 35999.37244981, lp : 0.32327364, o : 0.0}
+		}
+	},
+	{
+		name:'mars',
+		title : 'Mars',
+		mass : 6.4185e23,
+		radius : 3376,
+		sideralDay : 1.025957 * ns.DAY,
+		orbit : {
+			base : {a : 1.52371034 * ns.AU ,  e : 0.09339410, i: 1.84969142, l : -4.55343205, lp : -23.94362959, o : 49.55953891},
+			cy : {a : 0.00001847 * ns.AU ,  e : 0.00007882, i: -0.00813131, l : 19140.30268499, lp : 0.44441088, o : -0.29257343}
+		}
+	},
+	{
+	 	name:'jupiter',
+		title : 'Jupiter',
+		mass : 1.8986e27,
+		radius : 71492,
+		orbit : {
+			base : {a : 5.20288700 * ns.AU ,  e : 0.04838624, i: 1.30439695, l : 34.39644051, lp : 14.72847983, o : 100.47390909},
+			cy : {a : -0.00011607 * ns.AU ,  e : -0.00013253, i: -0.00183714, l : 3034.74612775, lp : 0.21252668, o : 0.20469106}
+		}
+	},
+	{
+		name:'saturn',
+		title : 'Saturn',
+		mass : 5.6846e26,
+		radius : 58232,
+		tilt : 26.7,
+		orbit : {
+			base : {a : 9.53667594 * ns.AU ,  e : 0.05386179, i: 2.48599187, l : 49.95424423, lp : 92.59887831, o : 113.66242448},
+			cy : {a : -0.00125060 * ns.AU ,  e : -0.00050991, i: 0.00193609, l : 1222.49362201, lp : -0.41897216, o : -0.28867794}
+		}
+	},
+	{
+		name: 'uranus',
+		title : 'Uranus',
+		mass : 8.6810e25,
+		radius : 25559,
+		orbit : {
+			base : {a : 19.18916464 * ns.AU ,  e : 0.04725744, i: 0.77263783, l : 313.23810451, lp : 170.95427630, o : 74.01692503},
+			cy : {a : -0.00196176 * ns.AU ,  e : -0.00004397, i: -0.00242939, l : 428.48202785, lp : 0.40805281, o : 0.04240589}
+		}
+	},
+	{
+		name:'neptune',
+		title : 'Neptune',
+		mass : 1.0243e26,
+		radius : 24764,
+		orbit : {
+			base : {a : 30.06992276  * ns.AU,  e : 0.00859048, i: 1.77004347, l : -55.12002969, lp : 44.96476227, o : 131.78422574},
+			cy : {a : 0.00026291  * ns.AU,  e : 0.00005105, i: 0.00035372, l : 218.45945325, lp : -0.32241464, o : -0.00508664}
+		}
+	},
+	{
+		name: 'pluto',
+		title : 'Pluto',
+		mass : 1.305e22+1.52e21,
+		radius : 1153,
+		orbit : {
+			base : {a : 39.48211675 * ns.AU ,  e : 0.24882730, i: 17.14001206, l : 238.92903833, lp : 224.06891629, o : 110.30393684},
+			cy : {a : -0.00031596 * ns.AU ,  e : 0.00005170, i: 0.00004818, l : 145.20780515, lp : -0.04062942, o : -0.01183482}
+		}
+	},
+	{
+		name: 'halley',
+		title : 'Halley\'s Comet',
+		mass : 2.2e14,
+		radius : 50,
+		orbit : {
+			base : {a : 17.83414429 * ns.AU ,  e : 0.967142908, i: 162.262691, M : 360 * (438393600 / (75.1 * ns.YEAR * ns.DAY)), w : 111.332485, o : 58.420081},
+			day : {a : 0 ,  e : 0, i: 0, M : (360 / (75.1 * 365.25) ), w : 0, o : 0}
+		}
+	},
+	{
+		name: 'moon',
+		title : 'The Moon',
+		mass : 7.3477e22,
+		radius : 1738.1,
+		sideralDay : (27.3215782 * ns.DAY) ,
+		tilt : 1.5424,
+		fov : 1,
+		relativeTo : 'earth',
+		orbitCalculator : MoonRealOrbit,
+		orbit: {
+			base : {
+				a : 384400,
+				e : 0.0554,
+				w : 318.15,
+				M : 135.27,
+				i : 5.16,
+				o : 125.08
+			},
+			day : {
+				a : 0,
+				e : 0,
+				i : 0,
+				M : 13.176358,//360 / 27.321582,
+				w : (360 / 5.997) / 365.25,
+				o : (360 / 18.600) / 365.25
+			}	
+		}
+	}
+];

+ 14 - 0
app/calendar/src/Math.js

@@ -0,0 +1,14 @@
+'use strict';
+module.exports = {
+	sinh : function(a) {
+		return (Math.exp(a) - Math.exp(-a)) / 2;
+	},
+
+	cosh : function(a) {
+		return (Math.pow(Math.E, a) + Math.pow(Math.E, -a)) / 2;
+	},
+
+	sign : function(a) {
+		return (a >= 0.0) ? 1 : -1;
+	}
+};

+ 516 - 0
app/calendar/src/MoonRealOrbit.js

@@ -0,0 +1,516 @@
+'use strict';
+
+var ns = require('ns');
+
+var DEG_TO_RAD = ns.DEG_TO_RAD;
+var RAD_TO_DEG = ns.RAD_TO_DEG;
+
+module.exports = function(t){
+
+	var t2 = t * t;
+	var t3 = t * t2;
+	var t4 = t * t3;
+	var t5 = t * t4;
+
+	var t2e4 = t2 * 1e-4;
+	var t3e6 = t3 * 1e-6;
+	var t4e8 = t4 * 1e-8;
+
+	//% semimajor axis
+
+	var sa = 3400.4 * Math.cos(DEG_TO_RAD * (235.7004 + 890534.2230 * t - 32.601 * t2e4 
+	+ 3.664 * t3e6 - 1.769 * t4e8)) 
+	- 635.6 * Math.cos(DEG_TO_RAD * (100.7370 + 413335.3554 * t - 122.571 * t2e4 
+	- 10.684 * t3e6 + 5.028 * t4e8)) 
+	- 235.6 * Math.cos(DEG_TO_RAD * (134.9634 + 477198.8676 * t + 89.970 * t2e4 
+	+ 14.348 * t3e6 - 6.797 * t4e8)) 
+	+ 218.1 * Math.cos(DEG_TO_RAD * (238.1713 +  854535.1727 * t - 31.065 * t2e4 
+	+ 3.623 * t3e6  - 1.769 * t4e8)) 
+	+ 181.0 * Math.cos(DEG_TO_RAD * (10.6638 + 1367733.0907 * t + 57.370 * t2e4 
+	+ 18.011 * t3e6 - 8.566 * t4e8)) 
+	- 39.9 * Math.cos(DEG_TO_RAD * (103.2079 + 377336.3051 * t - 121.035 * t2e4 
+	- 10.724 * t3e6 + 5.028 * t4e8)) 
+	- 38.4 * Math.cos(DEG_TO_RAD * (233.2295 + 926533.2733 * t - 34.136 * t2e4 
+	+ 3.705 * t3e6 - 1.769 * t4e8)) 
+	+ 33.8 * Math.cos(DEG_TO_RAD * (336.4374 + 1303869.5784 * t - 155.171 * t2e4 
+	- 7.020 * t3e6 + 3.259 * t4e8)) 
+	+ 28.8 * Math.cos(DEG_TO_RAD * (111.4008 + 1781068.4461 * t - 65.201 * t2e4 
+	+ 7.328 * t3e6 - 3.538 * t4e8)) 
+	+ 12.6 * Math.cos(DEG_TO_RAD * (13.1347 + 1331734.0404 * t + 58.906 * t2e4 
+	+ 17.971 * t3e6 - 8.566 * t4e8)) 
+	+ 11.4 * Math.cos(DEG_TO_RAD * (186.5442 + 966404.0351 * t - 68.058 * t2e4 
+	- 0.567 * t3e6 + 0.232 * t4e8)) 
+	- 11.1 * Math.cos(DEG_TO_RAD * (222.5657 - 441199.8173 * t - 91.506 * t2e4 
+	- 14.307 * t3e6 + 6.797 * t4e8)) 
+	- 10.2 * Math.cos(DEG_TO_RAD * (269.9268 + 954397.7353 * t + 179.941 * t2e4 
+	+ 28.695 * t3e6 - 13.594 * t4e8)) 
+	+ 9.7 * Math.cos(DEG_TO_RAD * (145.6272 + 1844931.9583 * t + 147.340 * t2e4 
+	+ 32.359 * t3e6 - 15.363 * t4e8)) 
+	+ 9.6 * Math.cos(DEG_TO_RAD * (240.6422 + 818536.1225 * t - 29.529 * t2e4 
+	+ 3.582 * t3e6 - 1.769 * t4e8)) 
+	+ 8.0 * Math.cos(DEG_TO_RAD * (297.8502 + 445267.1115 * t - 16.300 * t2e4 
+	+ 1.832 * t3e6 - 0.884 * t4e8)) 
+	- 6.2 * Math.cos(DEG_TO_RAD * (132.4925 + 513197.9179 * t + 88.434 * t2e4 
+	+ 14.388 * t3e6 - 6.797 * t4e8)) 
+	+ 6.0 * Math.cos(DEG_TO_RAD * (173.5506 + 1335801.3346 * t - 48.901 * t2e4 
+	+ 5.496 * t3e6 - 2.653 * t4e8)) 
+	+ 3.7 * Math.cos(DEG_TO_RAD * (113.8717 + 1745069.3958 * t - 63.665 * t2e4 
+	+ 7.287 * t3e6 - 3.538 * t4e8)) 
+	+ 3.6 * Math.cos(DEG_TO_RAD * (338.9083 + 1267870.5281 * t - 153.636 * t2e4 
+	- 7.061 * t3e6 + 3.259 * t4e8)) 
+	+ 3.2 * Math.cos(DEG_TO_RAD * (246.3642 + 2258267.3137 * t + 24.769 * t2e4 
+	+ 21.675 * t3e6 - 10.335 * t4e8)) 
+	- 3.0 * Math.cos(DEG_TO_RAD * (8.1929 + 1403732.1410 * t + 55.834 * t2e4 
+	+ 18.052 * t3e6 - 8.566 * t4e8)) 
+	+ 2.3 * Math.cos(DEG_TO_RAD * (98.2661 + 449334.4057 * t - 124.107 * t2e4 
+	- 10.643 * t3e6 + 5.028 * t4e8)) 
+	- 2.2 * Math.cos(DEG_TO_RAD * (357.5291 + 35999.0503 * t - 1.536 * t2e4 
+	+ 0.041 * t3e6 + 0.000 * t4e8)) 
+	- 2.0 * Math.cos(DEG_TO_RAD * (38.5872 + 858602.4669 * t - 138.871 * t2e4 
+	- 8.852 * t3e6 + 4.144 * t4e8)) 
+	- 1.8 * Math.cos(DEG_TO_RAD * (105.6788 + 341337.2548 * t - 119.499 * t2e4 
+	- 10.765 * t3e6 + 5.028 * t4e8)) 
+	- 1.7 * Math.cos(DEG_TO_RAD * (201.4740 + 826670.7108 * t - 245.142 * t2e4 
+	- 21.367 * t3e6 + 10.057 * t4e8)) 
+	+ 1.6 * Math.cos(DEG_TO_RAD * (184.1196 + 401329.0556 * t + 125.428 * t2e4 
+	+ 18.579 * t3e6 - 8.798 * t4e8)) 
+	- 1.4 * Math.cos(DEG_TO_RAD * (308.4192 - 489205.1674 * t + 158.029 * t2e4 
+	+ 14.915 * t3e6 - 7.029 * t4e8)) 
+	+ 1.3 * Math.cos(DEG_TO_RAD * (325.7736 - 63863.5122 * t - 212.541 * t2e4 
+	- 25.031 * t3e6 + 11.826 * t4e8));
+
+	var sapp = - 0.55 * Math.cos(DEG_TO_RAD * (238.2 + 854535.2 * t)) 
+		+ 0.10 * Math.cos(DEG_TO_RAD * (103.2 + 377336.3 * t)) 
+		+ 0.10 * Math.cos(DEG_TO_RAD * (233.2 + 926533.3 * t));
+
+	var sma = 383397.6 + sa + sapp * t;
+
+	//% orbital eccentricity
+
+	var se = 0.014217 * Math.cos(DEG_TO_RAD * (100.7370 + 413335.3554 * t - 122.571 * t2e4 
+	- 10.684 * t3e6 + 5.028 * t4e8)) 
+	+ 0.008551 * Math.cos(DEG_TO_RAD * (325.7736 - 63863.5122 * t - 212.541 * t2e4 
+	- 25.031 * t3e6 + 11.826 * t4e8)) 
+	- 0.001383 * Math.cos(DEG_TO_RAD * (134.9634 + 477198.8676 * t + 89.970 * t2e4 
+	+ 14.348 * t3e6 - 6.797 * t4e8)) 
+	+ 0.001353 * Math.cos(DEG_TO_RAD * (10.6638 + 1367733.0907 * t + 57.370 * t2e4 
+	+ 18.011 * t3e6 - 8.566 * t4e8)) 
+	- 0.001146 * Math.cos(DEG_TO_RAD * (66.5106 + 349471.8432 * t - 335.112 * t2e4 
+	- 35.715 * t3e6 + 16.854 * t4e8)) 
+	- 0.000915 * Math.cos(DEG_TO_RAD * (201.4740 + 826670.7108 * t - 245.142 * t2e4 
+	- 21.367 * t3e6 + 10.057 * t4e8)) 
+	+ 0.000869 * Math.cos(DEG_TO_RAD * (103.2079 + 377336.3051 * t - 121.035 * t2e4 
+	- 10.724 * t3e6 + 5.028 * t4e8)) 
+	- 0.000628 * Math.cos(DEG_TO_RAD * (235.7004 + 890534.2230 * t - 32.601 * t2e4 
+	+ 3.664 * t3e6  - 1.769 * t4e8)) 
+	- 0.000393 * Math.cos(DEG_TO_RAD * (291.5472 - 127727.0245 * t - 425.082 * t2e4 
+	- 50.062 * t3e6 + 23.651 * t4e8)) 
+	+ 0.000284 * Math.cos(DEG_TO_RAD * (328.2445 - 99862.5625 * t - 211.005 * t2e4 
+	- 25.072 * t3e6 + 11.826 * t4e8)) 
+	- 0.000278 * Math.cos(DEG_TO_RAD * (162.8868 - 31931.7561 * t - 106.271 * t2e4 
+	- 12.516 * t3e6 + 5.913 * t4e8)) 
+	- 0.000240 * Math.cos(DEG_TO_RAD * (269.9268 + 954397.7353 * t + 179.941 * t2e4 
+	+ 28.695 * t3e6 - 13.594 * t4e8)) 
+	+ 0.000230 * Math.cos(DEG_TO_RAD * (111.4008 + 1781068.4461 * t - 65.201 * t2e4 
+	+ 7.328 * t3e6  - 3.538 * t4e8)) 
+	+ 0.000229 * Math.cos(DEG_TO_RAD * (167.2476 + 762807.1986 * t - 457.683 * t2e4 
+	- 46.398 * t3e6 + 21.882 * t4e8)) 
+	- 0.000202 * Math.cos(DEG_TO_RAD * ( 83.3826 - 12006.2998 * t + 247.999 * t2e4 
+	+ 29.262 * t3e6 - 13.826 * t4e8)) 
+	+ 0.000190 * Math.cos(DEG_TO_RAD * (190.8102 - 541062.3799 * t - 302.511 * t2e4 
+	- 39.379 * t3e6 + 18.623 * t4e8)) 
+	+ 0.000177 * Math.cos(DEG_TO_RAD * (357.5291 + 35999.0503 * t - 1.536 * t2e4 
+	+ 0.041 * t3e6 + 0.000 * t4e8)) 
+	+ 0.000153 * Math.cos(DEG_TO_RAD * (32.2842 + 285608.3309 * t - 547.653 * t2e4 
+	- 60.746 * t3e6 + 28.679 * t4e8)) 
+	- 0.000137 * Math.cos(DEG_TO_RAD * (44.8902 + 1431596.6029 * t + 269.911 * t2e4 
+	+ 43.043 * t3e6 - 20.392 * t4e8)) 
+	+ 0.000122 * Math.cos(DEG_TO_RAD * (145.6272 + 1844931.9583 * t + 147.340 * t2e4 
+	+ 32.359 * t3e6 - 15.363 * t4e8)) 
+	+ 0.000116 * Math.cos(DEG_TO_RAD * (302.2110 + 1240006.0662 * t - 367.713 * t2e4 
+	- 32.051 * t3e6 + 15.085 * t4e8)) 
+	- 0.000111 * Math.cos(DEG_TO_RAD * (203.9449 + 790671.6605 * t - 243.606 * t2e4 
+	- 21.408 * t3e6 + 10.057 * t4e8)) 
+	- 0.000108 * Math.cos(DEG_TO_RAD * (68.9815 + 313472.7929 * t - 333.576 * t2e4 
+	- 35.756 * t3e6 + 16.854 * t4e8)) 
+	+ 0.000096 * Math.cos(DEG_TO_RAD * (336.4374 + 1303869.5784 * t - 155.171 * t2e4 
+	- 7.020 * t3e6 + 3.259 * t4e8)) 
+	- 0.000090 * Math.cos(DEG_TO_RAD * (98.2661 + 449334.4057 * t - 124.107 * t2e4 
+	- 10.643 * t3e6 + 5.028 * t4e8)) 
+	+ 0.000090 * Math.cos(DEG_TO_RAD * (13.1347 + 1331734.0404 * t + 58.906 * t2e4 
+	+ 17.971 * t3e6 - 8.566 * t4e8)) 
+	+ 0.000056 * Math.cos(DEG_TO_RAD * (55.8468 - 1018261.2475 * t - 392.482 * t2e4 
+	- 53.726 * t3e6 + 25.420 * t4e8)) 
+	- 0.000056 * Math.cos(DEG_TO_RAD * (238.1713 + 854535.1727 * t - 31.065 * t2e4 
+	+ 3.623 * t3e6 - 1.769 * t4e8)) 
+	+ 0.000052 * Math.cos(DEG_TO_RAD * (308.4192 - 489205.1674 * t + 158.029 * t2e4 
+	+ 14.915 * t3e6 - 7.029 * t4e8)) 
+	- 0.000050 * Math.cos(DEG_TO_RAD * (133.0212 + 698943.6863 * t - 670.224 * t2e4 
+	- 71.429 * t3e6 + 33.708 * t4e8)) 
+	- 0.000049 * Math.cos(DEG_TO_RAD * (267.9846 + 1176142.5540 * t - 580.254 * t2e4 
+	- 57.082 * t3e6 + 26.911 * t4e8)) 
+	- 0.000049 * Math.cos(DEG_TO_RAD * (184.1196 + 401329.0556 * t + 125.428 * t2e4 
+	+ 18.579 * t3e6 - 8.798 * t4e8)) 
+	- 0.000045 * Math.cos(DEG_TO_RAD * (49.1562 - 75869.8120 * t + 35.458 * t2e4 
+	+ 4.231 * t3e6 - 2.001 * t4e8)) 
+	+ 0.000044 * Math.cos(DEG_TO_RAD * (257.3208 - 191590.5367 * t - 637.623 * t2e4 
+	- 75.093 * t3e6 + 35.477 * t4e8)) 
+	+ 0.000042 * Math.cos(DEG_TO_RAD * (105.6788 + 341337.2548 * t - 119.499 * t2e4 
+	- 10.765 * t3e6 + 5.028 * t4e8)) 
+	+ 0.000042 * Math.cos(DEG_TO_RAD * (160.4159 + 4067.2942 * t - 107.806 * t2e4 
+	- 12.475 * t3e6 + 5.913 * t4e8)) 
+	+ 0.000040 * Math.cos(DEG_TO_RAD * (246.3642 + 2258267.3137 * t + 24.769 * t2e4 
+	+ 21.675 * t3e6 - 10.335 * t4e8)) 
+	- 0.000040 * Math.cos(DEG_TO_RAD * (156.5838 - 604925.8921 * t - 515.053 * t2e4 
+	- 64.410 * t3e6 + 30.448 * t4e8)) 
+	+ 0.000036 * Math.cos(DEG_TO_RAD * (169.7185 + 726808.1483 * t - 456.147 * t2e4 
+	- 46.439 * t3e6 + 21.882 * t4e8)) 
+	+ 0.000029 * Math.cos(DEG_TO_RAD * (113.8717 + 1745069.3958 * t - 63.665 * t2e4 
+	+ 7.287 * t3e6 - 3.538 * t4e8)) 
+	- 0.000029 * Math.cos(DEG_TO_RAD * (297.8502 + 445267.1115 * t - 16.300 * t2e4 
+	+ 1.832 * t3e6 - 0.884 * t4e8)) 
+	- 0.000028 * Math.cos(DEG_TO_RAD * (294.0181 - 163726.0747 * t - 423.546 * t2e4 
+	- 50.103 * t3e6 + 23.651 * t4e8)) 
+	+ 0.000027 * Math.cos(DEG_TO_RAD * (263.6238 + 381403.5993 * t - 228.841 * t2e4 
+	- 23.199 * t3e6 + 10.941 * t4e8)) 
+	- 0.000026 * Math.cos(DEG_TO_RAD * (358.0578 + 221744.8187 * t - 760.194 * t2e4 
+	- 85.777 * t3e6 + 40.505 * t4e8)) 
+	- 0.000026 * Math.cos(DEG_TO_RAD * (8.1929 + 1403732.1410 * t + 55.834 * t2e4 
+	+ 18.052 * t3e6 - 8.566 * t4e8));
+
+	var sedp = -0.0022 * Math.cos(DEG_TO_RAD * (103.2 + 377336.3 * t));
+
+	var ecc = 0.055544 + se + 1e-3 * t * sedp;
+
+	//% sine of half the inclination
+
+var sg = 0.0011776 * Math.cos(DEG_TO_RAD * (49.1562 - 75869.8120 * t + 35.458 * t2e4 
+	+ 4.231 * t3e6 - 2.001 * t4e8)) 
+	- 0.0000971 * Math.cos(DEG_TO_RAD * (235.7004 + 890534.2230 * t - 32.601 * t2e4 
+	+ 3.664 * t3e6 - 1.769 * t4e8)) 
+	+ 0.0000908 * Math.cos(DEG_TO_RAD * (186.5442 + 966404.0351 * t - 68.058 * t2e4 
+	- 0.567 * t3e6 + 0.232 * t4e8)) 
+	+ 0.0000623 * Math.cos(DEG_TO_RAD * (83.3826 - 12006.2998 * t + 247.999 * t2e4 
+	+ 29.262 * t3e6 - 13.826 * t4e8)) 
+	+ 0.0000483 * Math.cos(DEG_TO_RAD * (51.6271 - 111868.8623 * t + 36.994 * t2e4 
+	+ 4.190 * t3e6 - 2.001 * t4e8)) 
+	+ 0.0000348 * Math.cos(DEG_TO_RAD * (100.7370 + 413335.3554 * t - 122.571 * t2e4 
+	- 10.684 * t3e6 + 5.028 * t4e8)) 
+	- 0.0000316 * Math.cos(DEG_TO_RAD * (308.4192 - 489205.1674 * t + 158.029 * t2e4 
+	+ 14.915 * t3e6 - 7.029 * t4e8)) 
+	- 0.0000253 * Math.cos(DEG_TO_RAD * (46.6853 - 39870.7617 * t + 33.922 * t2e4 
+	+ 4.272 * t3e6 - 2.001 * t4e8)) 
+	- 0.0000141 * Math.cos(DEG_TO_RAD * (274.1928 - 553068.6797 * t - 54.513 * t2e4 
+	- 10.116 * t3e6 + 4.797 * t4e8)) 
+	+ 0.0000127 * Math.cos(DEG_TO_RAD * (325.7736 - 63863.5122 * t - 212.541 * t2e4 
+	- 25.031 * t3e6 + 11.826 * t4e8)) 
+	+ 0.0000117 * Math.cos(DEG_TO_RAD * (184.1196 + 401329.0556 * t + 125.428 * t2e4 
+	+ 18.579 * t3e6 - 8.798 * t4e8)) 
+	- 0.0000078 * Math.cos(DEG_TO_RAD * (98.3124 - 151739.6240 * t + 70.916 * t2e4 
+	+ 8.462 * t3e6 - 4.001 * t4e8)) 
+	- 0.0000063 * Math.cos(DEG_TO_RAD * (238.1713 + 854535.1727 * t - 31.065 * t2e4 
+	+ 3.623 * t3e6 - 1.769 * t4e8)) 
+	+ 0.0000063 * Math.cos(DEG_TO_RAD * (134.9634 + 477198.8676 * t + 89.970 * t2e4 
+	+ 14.348 * t3e6 - 6.797 * t4e8)) 
+	+ 0.0000036 * Math.cos(DEG_TO_RAD * (321.5076 + 1443602.9027 * t + 21.912 * t2e4 
+	+ 13.780 * t3e6 - 6.566 * t4e8)) 
+	- 0.0000035 * Math.cos(DEG_TO_RAD * (10.6638 + 1367733.0907 * t + 57.370 * t2e4 
+	+ 18.011 * t3e6 - 8.566 * t4e8)) 
+	+ 0.0000024 * Math.cos(DEG_TO_RAD * (149.8932 + 337465.5434 * t - 87.113 * t2e4 
+	- 6.453 * t3e6 + 3.028 * t4e8)) 
+	+ 0.0000024 * Math.cos(DEG_TO_RAD * (170.9849 - 930404.9848 * t + 66.523 * t2e4 
+	+ 0.608 * t3e6 - 0.232 * t4e8));
+
+	var sgp = - 0.0203 * Math.cos(DEG_TO_RAD * (125.0 - 1934.1 * t)) 
+		+ 0.0034 * Math.cos(DEG_TO_RAD * (220.2 - 1935.5 * t));
+
+	var gamma = 0.0449858 + sg + 1e-3 * sgp;
+
+	//% longitude of perigee
+
+	var sp = - 15.448 * Math.sin(DEG_TO_RAD * (100.7370 + 413335.3554 * t - 122.571 * t2e4 
+	- 10.684 * t3e6 + 5.028 * t4e8))
+	- 9.642 * Math.sin(DEG_TO_RAD * (325.7736 - 63863.5122 * t - 212.541 * t2e4 
+	- 25.031 * t3e6 + 11.826 * t4e8)) 
+	- 2.721 * Math.sin(DEG_TO_RAD * (134.9634 + 477198.8676 * t + 89.970 * t2e4 
+	+ 14.348 * t3e6 - 6.797 * t4e8)) 
+	+ 2.607 * Math.sin(DEG_TO_RAD * (66.5106 + 349471.8432 * t - 335.112 * t2e4 
+	- 35.715 * t3e6 + 16.854 * t4e8)) 
+	+ 2.085 * Math.sin(DEG_TO_RAD * (201.4740 + 826670.7108 * t - 245.142 * t2e4 
+	- 21.367 * t3e6 + 10.057 * t4e8)) 
+	+ 1.477 * Math.sin(DEG_TO_RAD * (10.6638 + 1367733.0907 * t + 57.370 * t2e4 
+	+ 18.011 * t3e6 - 8.566 * t4e8)) 
+	+ 0.968 * Math.sin(DEG_TO_RAD * (291.5472 - 127727.0245 * t - 425.082 * t2e4 
+	- 50.062 * t3e6 + 23.651 * t4e8)) 
+	- 0.949 * Math.sin(DEG_TO_RAD * (103.2079 + 377336.3051 * t - 121.035 * t2e4 
+	- 10.724 * t3e6 + 5.028 * t4e8)) 
+	- 0.703 * Math.sin(DEG_TO_RAD * (167.2476 + 762807.1986 * t - 457.683 * t2e4 
+	- 46.398 * t3e6 + 21.882 * t4e8)) 
+	- 0.660 * Math.sin(DEG_TO_RAD * (235.7004 + 890534.2230 * t - 32.601 * t2e4 
+	+ 3.664 * t3e6 - 1.769 * t4e8)) 
+	- 0.577 * Math.sin(DEG_TO_RAD * (190.8102 - 541062.3799 * t - 302.511 * t2e4 
+	- 39.379 * t3e6 + 18.623 * t4e8)) 
+	- 0.524 * Math.sin(DEG_TO_RAD * (269.9268 + 954397.7353 * t + 179.941 * t2e4 
+	+ 28.695 * t3e6 - 13.594 * t4e8)) 
+	- 0.482 * Math.sin(DEG_TO_RAD * (32.2842 + 285608.3309 * t - 547.653 * t2e4 
+	- 60.746 * t3e6 + 28.679 * t4e8)) 
+	+ 0.452 * Math.sin(DEG_TO_RAD * (357.5291 + 35999.0503 * t - 1.536 * t2e4 
+	+ 0.041 * t3e6 + 0.000 * t4e8)) 
+	- 0.381 * Math.sin(DEG_TO_RAD * (302.2110 + 1240006.0662 * t - 367.713 * t2e4 
+	- 32.051 * t3e6 + 15.085 * t4e8)) 
+	- 0.342 * Math.sin(DEG_TO_RAD * (328.2445 - 99862.5625 * t - 211.005 * t2e4 
+	- 25.072 * t3e6 + 11.826 * t4e8)) 
+	- 0.312 * Math.sin(DEG_TO_RAD * (44.8902 + 1431596.6029 * t + 269.911 * t2e4 
+	+ 43.043 * t3e6 - 20.392 * t4e8)) 
+	+ 0.282 * Math.sin(DEG_TO_RAD * (162.8868 - 31931.7561 * t - 106.271 * t2e4 
+	- 12.516 * t3e6 + 5.913 * t4e8)) 
+	+ 0.255 * Math.sin(DEG_TO_RAD * (203.9449 + 790671.6605 * t - 243.606 * t2e4 
+	- 21.408 * t3e6 + 10.057 * t4e8)) 
+	+ 0.252 * Math.sin(DEG_TO_RAD * (68.9815 + 313472.7929 * t - 333.576 * t2e4 
+	- 35.756 * t3e6 + 16.854 * t4e8)) 
+	- 0.211 * Math.sin(DEG_TO_RAD * (83.3826 - 12006.2998 * t + 247.999 * t2e4 
+	+ 29.262 * t3e6 - 13.826 * t4e8)) 
+	+ 0.193 * Math.sin(DEG_TO_RAD * (267.9846 + 1176142.5540 * t - 580.254 * t2e4 
+	- 57.082 * t3e6 + 26.911 * t4e8)) 
+	+ 0.191 * Math.sin(DEG_TO_RAD * (133.0212 + 698943.6863 * t - 670.224 * t2e4 
+	- 71.429 * t3e6 + 33.708 * t4e8)) 
+	- 0.184 * Math.sin(DEG_TO_RAD * (55.8468 - 1018261.2475 * t - 392.482 * t2e4 
+	- 53.726 * t3e6 + 25.420 * t4e8)) 
+	+ 0.182 * Math.sin(DEG_TO_RAD * (145.6272 + 1844931.9583 * t + 147.340 * t2e4 
+	+ 32.359 * t3e6 - 15.363 * t4e8)) 
+	- 0.158 * Math.sin(DEG_TO_RAD * (257.3208 - 191590.5367 * t - 637.623 * t2e4 
+	- 75.093 * t3e6 + 35.477 * t4e8)) 
+	+ 0.148 * Math.sin(DEG_TO_RAD * (156.5838 - 604925.8921 * t - 515.053 * t2e4 
+	- 64.410 * t3e6 + 30.448 * t4e8)) 
+	- 0.111 * Math.sin(DEG_TO_RAD * (169.7185 + 726808.1483 * t - 456.147 * t2e4 
+	- 46.439 * t3e6 + 21.882 * t4e8)) 
+	+ 0.101 * Math.sin(DEG_TO_RAD * (13.1347 + 1331734.0404 * t + 58.906 * t2e4 
+	+ 17.971 * t3e6 - 8.566 * t4e8)) 
+	+ 0.100 * Math.sin(DEG_TO_RAD * (358.0578 + 221744.8187 * t - 760.194 * t2e4 
+	- 85.777 * t3e6 + 40.505 * t4e8)) 
+	+ 0.087 * Math.sin(DEG_TO_RAD * (98.2661 + 449334.4057 * t - 124.107 * t2e4 
+	- 10.643 * t3e6 + 5.028 * t4e8)) 
+	+ 0.080 * Math.sin(DEG_TO_RAD * (42.9480 + 1653341.4216 * t - 490.283 * t2e4 
+	- 42.734 * t3e6 + 20.113 * t4e8)) 
+	+ 0.080 * Math.sin(DEG_TO_RAD * (222.5657 - 441199.8173 * t - 91.506 * t2e4 
+	- 14.307 * t3e6 + 6.797 * t4e8)) 
+	+ 0.077 * Math.sin(DEG_TO_RAD * (294.0181 - 163726.0747 * t - 423.546 * t2e4 
+	- 50.103 * t3e6 + 23.651 * t4e8)) 
+	- 0.073 * Math.sin(DEG_TO_RAD * (280.8834 - 1495460.1151 * t - 482.452 * t2e4 
+	- 68.074 * t3e6 + 32.217 * t4e8)) 
+	- 0.071 * Math.sin(DEG_TO_RAD * (304.6819 + 1204007.0159 * t - 366.177 * t2e4 
+	- 32.092 * t3e6 + 15.085 * t4e8)) 
+	- 0.069 * Math.sin(DEG_TO_RAD * (233.7582 + 1112279.0417 * t - 792.795 * t2e4 
+	- 82.113 * t3e6 + 38.736 * t4e8)) 
+	- 0.067 * Math.sin(DEG_TO_RAD * (34.7551 + 249609.2807 * t - 546.117 * t2e4 
+	- 60.787 * t3e6 + 28.679 * t4e8)) 
+	- 0.067 * Math.sin(DEG_TO_RAD * (263.6238 + 381403.5993 * t - 228.841 * t2e4 
+	- 23.199 * t3e6 + 10.941 * t4e8)) 
+	+ 0.055 * Math.sin(DEG_TO_RAD * (21.6203 - 1082124.7597 * t - 605.023 * t2e4 
+	- 78.757 * t3e6 + 37.246 * t4e8)) 
+	+ 0.055 * Math.sin(DEG_TO_RAD * (308.4192 - 489205.1674 * t + 158.029 * t2e4 
+	+ 14.915 * t3e6 -7.029 * t4e8)) 
+	- 0.054 * Math.sin(DEG_TO_RAD * (8.7216 + 1589477.9094 * t - 702.824 * t2e4 
+	- 67.766 * t3e6 + 31.939 * t4e8)) 
+	- 0.052 * Math.sin(DEG_TO_RAD * (179.8536 + 1908795.4705 * t + 359.881 * t2e4 
+	+ 57.390 * t3e6 - 27.189 * t4e8)) 
+	- 0.050 * Math.sin(DEG_TO_RAD * (98.7948 + 635080.1741 * t - 882.765 * t2e4 
+	- 96.461 * t3e6 + 45.533 * t4e8)) 
+	- 0.049 * Math.sin(DEG_TO_RAD * (128.6604 - 95795.2683 * t - 318.812 * t2e4 
+	- 37.547 * t3e6 + 17.738 * t4e8)) 
+	- 0.047 * Math.sin(DEG_TO_RAD * (17.3544 + 425341.6552 * t - 370.570 * t2e4 
+	- 39.946 * t3e6 + 18.854 * t4e8)) 
+	- 0.044 * Math.sin(DEG_TO_RAD * (160.4159 + 4067.2942 * t - 107.806 * t2e4 
+	- 12.475 * t3e6 + 5.913 * t4e8)) 
+	- 0.043 * Math.sin(DEG_TO_RAD * (238.1713 + 854535.1727 * t - 31.065 * t2e4 
+	+ 3.623 * t3e6 - 1.769 * t4e8)) 
+	+ 0.042 * Math.sin(DEG_TO_RAD * (270.4555 + 1140143.5037 * t - 578.718 * t2e4 
+	- 57.123 * t3e6 + 26.911 * t4e8)) 
+	- 0.042 * Math.sin(DEG_TO_RAD * (132.4925 + 513197.9179 * t + 88.434 * t2e4 
+	+ 14.388 * t3e6 - 6.797 * t4e8)) 
+	- 0.041 * Math.sin(DEG_TO_RAD * (122.3573 - 668789.4043 * t - 727.594 * t2e4 
+	- 89.441 * t3e6 + 42.274 * t4e8)) 
+	- 0.040 * Math.sin(DEG_TO_RAD * (105.6788 + 341337.2548 * t - 119.499 * t2e4 
+	- 10.765 * t3e6 + 5.028 * t4e8)) 
+	+ 0.038 * Math.sin(DEG_TO_RAD * (135.4921 + 662944.6361 * t - 668.688 * t2e4 
+	- 71.470 * t3e6 + 33.708 * t4e8)) 
+	- 0.037 * Math.sin(DEG_TO_RAD * (242.3910 - 51857.2124 * t - 460.540 * t2e4 
+	- 54.293 * t3e6 + 25.652 * t4e8)) 
+	+ 0.036 * Math.sin(DEG_TO_RAD * (336.4374 +  1303869.5784 * t - 155.171 * t2e4 
+	- 7.020 * t3e6 + 3.259 * t4e8)) 
+	+ 0.035 * Math.sin(DEG_TO_RAD * (223.0943 - 255454.0489 * t - 850.164 * t2e4 
+	- 100.124 * t3e6 + 47.302 * t4e8)) 
+	- 0.034 * Math.sin(DEG_TO_RAD * (193.2811 - 577061.4302 * t - 300.976 * t2e4 
+	- 39.419 * t3e6 + 18.623 * t4e8)) 
+	+ 0.031 * Math.sin(DEG_TO_RAD * (87.6023 - 918398.6850 * t - 181.476 * t2e4 
+	- 28.654 * t3e6 + 13.594 * t4e8));
+
+	var spp = 2.4 * Math.sin(DEG_TO_RAD * (103.2 + 377336.3 * t));
+
+	var lp = 83.353 + 4069.0137 * t - 103.238 * t2e4 
+	- 12.492 * t3e6 + 5.263 * t4e8 + sp + 1e-3 * t * spp;
+
+	//% longitude of the ascending node
+
+	var sr = - 1.4979 * Math.sin(DEG_TO_RAD * (49.1562 - 75869.8120 * t + 35.458 * t2e4 
+	+ 4.231 * t3e6 - 2.001 * t4e8)) 
+	- 0.1500 * Math.sin(DEG_TO_RAD * (357.5291 + 35999.0503 * t - 1.536 * t2e4 
+	+ 0.041 * t3e6 + 0.000 * t4e8)) 
+	- 0.1226 * Math.sin(DEG_TO_RAD * (235.7004 + 890534.2230 * t - 32.601 * t2e4 
+	+ 3.664 * t3e6 - 1.769 * t4e8)) 
+	+ 0.1176 * Math.sin(DEG_TO_RAD * (186.5442 + 966404.0351 * t - 68.058 * t2e4 
+	- 0.567 * t3e6 + 0.232 * t4e8)) 
+	- 0.0801 * Math.sin(DEG_TO_RAD * (83.3826 - 12006.2998 * t + 247.999 * t2e4 
+	+ 29.262 * t3e6 - 13.826 * t4e8)) 
+	- 0.0616 * Math.sin(DEG_TO_RAD * (51.6271 - 111868.8623 * t + 36.994 * t2e4 
+	+ 4.190 * t3e6 - 2.001 * t4e8)) 
+	+ 0.0490 * Math.sin(DEG_TO_RAD * (100.7370 + 413335.3554 * t - 122.571 * t2e4 
+	- 10.684 * t3e6 + 5.028 * t4e8)) 
+	+ 0.0409 * Math.sin(DEG_TO_RAD * (308.4192 - 489205.1674 * t + 158.029 * t2e4 
+	+ 14.915 * t3e6 - 7.029 * t4e8)) 
+	+ 0.0327 * Math.sin(DEG_TO_RAD * (134.9634 + 477198.8676 * t + 89.970 * t2e4 
+	+ 14.348 * t3e6 - 6.797 * t4e8)) 
+	+ 0.0324 * Math.sin(DEG_TO_RAD * (46.6853 - 39870.7617 * t + 33.922 * t2e4 
+	+ 4.272 * t3e6 - 2.001 * t4e8)) 
+	+ 0.0196 * Math.sin(DEG_TO_RAD * (98.3124 - 151739.6240 * t + 70.916 * t2e4 
+	+ 8.462 * t3e6 - 4.001 * t4e8)) 
+	+ 0.0180 * Math.sin(DEG_TO_RAD * (274.1928 - 553068.6797 * t - 54.513 * t2e4 
+	- 10.116 * t3e6 + 4.797 * t4e8)) 
+	+ 0.0150 * Math.sin(DEG_TO_RAD * (325.7736 - 63863.5122 * t - 212.541 * t2e4 
+	- 25.031 * t3e6 + 11.826 * t4e8)) 
+	- 0.0150 * Math.sin(DEG_TO_RAD * (184.1196 + 401329.0556 * t + 125.428 * t2e4 
+	+ 18.579 * t3e6 - 8.798 * t4e8)) 
+	- 0.0078 * Math.sin(DEG_TO_RAD * (238.1713 + 854535.1727 * t - 31.065 * t2e4 
+	+ 3.623 * t3e6 - 1.769 * t4e8)) 
+	- 0.0045 * Math.sin(DEG_TO_RAD * (10.6638 + 1367733.0907 * t + 57.370 * t2e4 
+	+ 18.011 * t3e6 - 8.566 * t4e8)) 
+	+ 0.0044 * Math.sin(DEG_TO_RAD * (321.5076 + 1443602.9027 * t + 21.912 * t2e4 
+	+ 13.780 * t3e6 - 6.566 * t4e8)) 
+	- 0.0042 * Math.sin(DEG_TO_RAD * (162.8868 - 31931.7561 * t - 106.271 * t2e4 
+	- 12.516 * t3e6 + 5.913 * t4e8)) 
+	- 0.0031 * Math.sin(DEG_TO_RAD * (170.9849 - 930404.9848 * t + 66.523 * t2e4 
+	+ 0.608 * t3e6 - 0.232 * t4e8)) 
+	+ 0.0031 * Math.sin(DEG_TO_RAD * (103.2079 + 377336.3051 * t - 121.035 * t2e4 
+	- 10.724 * t3e6 + 5.028 * t4e8)) 
+	+ 0.0029 * Math.sin(DEG_TO_RAD * (222.6120 - 1042273.8471 * t + 103.516 * t2e4 
+	+ 4.798 * t3e6 - 2.232 * t4e8)) 
+	+ 0.0028 * Math.sin(DEG_TO_RAD * (184.0733 + 1002403.0853 * t - 69.594 * t2e4 
+	- 0.526 * t3e6 + 0.232 * t4e8));
+
+	var srp = 25.9 * Math.sin(DEG_TO_RAD * (125.0 - 1934.1 * t)) 
+		- 4.3 * Math.sin(DEG_TO_RAD * (220.2 - 1935.5 * t));
+
+	var srpp = 0.38 * Math.sin(DEG_TO_RAD * (357.5 + 35999.1 * t));
+
+	var raan = 125.0446 - 1934.13618 * t + 20.762 * t2e4 
+		+ 2.139 * t3e6 - 1.650 * t4e8 + sr 
+		+ 1e-3 * (srp + srpp * t);
+
+	//% mean longitude
+
+	var sl = - 0.92581 * Math.sin(DEG_TO_RAD * (235.7004 + 890534.2230 * t - 32.601 * t2e4 
+	+ 3.664 * t3e6 - 1.769 * t4e8)) 
+	+ 0.33262 * Math.sin(DEG_TO_RAD * (100.7370 + 413335.3554 * t - 122.571 * t2e4 
+	- 10.684 * t3e6 + 5.028 * t4e8)) 
+	- 0.18402 * Math.sin(DEG_TO_RAD * (357.5291 + 35999.0503 * t - 1.536 * t2e4 
+	+ 0.041 * t3e6 + 0.000 * t4e8)) 
+	+ 0.11007 * Math.sin(DEG_TO_RAD * (134.9634 + 477198.8676 * t + 89.970 * t2e4 
+	+ 14.348 * t3e6 - 6.797 * t4e8)) 
+	- 0.06055 * Math.sin(DEG_TO_RAD * (238.1713 + 854535.1727 * t - 31.065 * t2e4 
+	+ 3.623 * t3e6 - 1.769 * t4e8)) 
+	+ 0.04741 * Math.sin(DEG_TO_RAD * (325.7736 - 63863.5122 * t - 212.541 * t2e4 
+	- 25.031 * t3e6 + 11.826 * t4e8)) 
+	- 0.03086 * Math.sin(DEG_TO_RAD * (10.6638 + 1367733.0907 * t + 57.370 * t2e4 
+	+ 18.011 * t3e6 - 8.566 * t4e8)) 
+	+ 0.02184 * Math.sin(DEG_TO_RAD * (103.2079 + 377336.3051 * t - 121.035 * t2e4 
+	- 10.724 * t3e6 + 5.028 * t4e8)) 
+	+ 0.01645 * Math.sin(DEG_TO_RAD * (49.1562 - 75869.8120 * t + 35.458 * t2e4 
+	+ 4.231 * t3e6 - 2.001 * t4e8)) 
+	+ 0.01022 * Math.sin(DEG_TO_RAD * (233.2295 + 926533.2733 * t - 34.136 * t2e4 
+	+ 3.705 * t3e6 - 1.769 * t4e8)) 
+	- 0.00756 * Math.sin(DEG_TO_RAD * (336.4374 + 1303869.5784 * t - 155.171 * t2e4 
+	- 7.020 * t3e6 + 3.259 * t4e8)) 
+	- 0.00530 * Math.sin(DEG_TO_RAD * (222.5657 - 441199.8173 * t - 91.506 * t2e4 
+	- 14.307 * t3e6 + 6.797 * t4e8)) 
+	- 0.00496 * Math.sin(DEG_TO_RAD * (162.8868 - 31931.7561 * t - 106.271 * t2e4 
+	- 12.516 * t3e6 + 5.913 * t4e8)) 
+	- 0.00472 * Math.sin(DEG_TO_RAD * (297.8502 + 445267.1115 * t - 16.300 * t2e4 
+	+ 1.832 * t3e6 - 0.884 * t4e8)) 
+	- 0.00271 * Math.sin(DEG_TO_RAD * (240.6422 + 818536.1225 * t - 29.529 * t2e4 
+	+ 3.582 * t3e6 - 1.769 * t4e8)) 
+	+ 0.00264 * Math.sin(DEG_TO_RAD * (132.4925 + 513197.9179 * t + 88.434 * t2e4 
+	+ 14.388 * t3e6 - 6.797 * t4e8)) 
+	- 0.00254 * Math.sin(DEG_TO_RAD * (186.5442 + 966404.0351 * t - 68.058 * t2e4 
+	- 0.567 * t3e6 + 0.232 * t4e8)) 
+	+ 0.00234 * Math.sin(DEG_TO_RAD * (269.9268 + 954397.7353 * t + 179.941 * t2e4 
+	+ 28.695 * t3e6 - 13.594 * t4e8)) 
+	- 0.00220 * Math.sin(DEG_TO_RAD * (13.1347 + 1331734.0404 * t + 58.906 * t2e4 
+	+ 17.971 * t3e6 - 8.566 * t4e8)) 
+	- 0.00202 * Math.sin(DEG_TO_RAD * (355.0582 + 71998.1006 * t - 3.072 * t2e4 
+	+ 0.082 * t3e6 + 0.000 * t4e8)) 
+	+ 0.00167 * Math.sin(DEG_TO_RAD * (328.2445 - 99862.5625 * t - 211.005 * t2e4 
+	- 25.072 * t3e6 + 11.826 * t4e8)) 
+	- 0.00143 * Math.sin(DEG_TO_RAD * (173.5506 + 1335801.3346 * t - 48.901 * t2e4 
+	+ 5.496 * t3e6 - 2.653 * t4e8)) 
+	- 0.00121 * Math.sin(DEG_TO_RAD * (98.2661 + 449334.4057 * t - 124.107 * t2e4 
+	- 10.643 * t3e6 + 5.028 * t4e8)) 
+	- 0.00116 * Math.sin(DEG_TO_RAD * (145.6272 + 1844931.9583 * t + 147.340 * t2e4 
+	+ 32.359 * t3e6 - 15.363 * t4e8)) 
+	+ 0.00102 * Math.sin(DEG_TO_RAD * (105.6788 + 341337.2548 * t - 119.499 * t2e4 
+	- 10.765 * t3e6 + 5.028 * t4e8)) 
+	- 0.00090 * Math.sin(DEG_TO_RAD * (184.1196 + 401329.0556 * t + 125.428 * t2e4 
+	+ 18.579 * t3e6 - 8.798 * t4e8)) 
+	- 0.00086 * Math.sin(DEG_TO_RAD * (338.9083 + 1267870.5281 * t - 153.636 * t2e4 
+	- 7.061 * t3e6 + 3.259 * t4e8)) 
+	- 0.00078 * Math.sin(DEG_TO_RAD * (111.4008 + 1781068.4461 * t - 65.201 * t2e4 
+	+ 7.328 * t3e6 - 3.538 * t4e8)) 
+	+ 0.00069 * Math.sin(DEG_TO_RAD * (323.3027 - 27864.4619 * t - 214.077 * t2e4 
+	- 24.990 * t3e6 + 11.826 * t4e8)) 
+	+ 0.00066 * Math.sin(DEG_TO_RAD * (51.6271 - 111868.8623 * t + 36.994 * t2e4 
+	+ 4.190 * t3e6 - 2.001 * t4e8)) 
+	+ 0.00065 * Math.sin(DEG_TO_RAD * (38.5872 + 858602.4669 * t - 138.871 * t2e4 
+	- 8.852 * t3e6 + 4.144 * t4e8)) 
+	- 0.00060 * Math.sin(DEG_TO_RAD * (83.3826 - 12006.2998 * t + 247.999 * t2e4 
+	+ 29.262 * t3e6 - 13.826 * t4e8)) 
+	+ 0.00054 * Math.sin(DEG_TO_RAD * (201.4740 + 826670.7108 * t - 245.142 * t2e4 
+	- 21.367 * t3e6 + 10.057 * t4e8)) 
+	- 0.00052 * Math.sin(DEG_TO_RAD * (308.4192 - 489205.1674 * t + 158.029 * t2e4 
+	+ 14.915 * t3e6 - 7.029 * t4e8)) 
+	+ 0.00048 * Math.sin(DEG_TO_RAD * (8.1929 + 1403732.1410 * t + 55.834 * t2e4 
+	+ 18.052 * t3e6 - 8.566 * t4e8)) 
+	- 0.00041 * Math.sin(DEG_TO_RAD * (46.6853 - 39870.7617 * t + 33.922 * t2e4 
+	+ 4.272 * t3e6 - 2.001 * t4e8)) 
+	- 0.00033 * Math.sin(DEG_TO_RAD * (274.1928 - 553068.6797 * t - 54.513 * t2e4 
+	- 10.116 * t3e6 + 4.797 * t4e8)) 
+	+ 0.00030 * Math.sin(DEG_TO_RAD * (160.4159 + 4067.2942 * t - 107.806 * t2e4 
+	- 12.475 * t3e6 + 5.913 * t4e8));
+
+	var slp = 3.96 * Math.sin(DEG_TO_RAD * (119.7 + 131.8 * t)) 
+		+ 1.96 * Math.sin(DEG_TO_RAD * (125.0 - 1934.1 * t));
+
+	var slpp = 0.463 * Math.sin(DEG_TO_RAD * (357.5 + 35999.1 * t)) 
+		+ 0.152 * Math.sin(DEG_TO_RAD * (238.2 + 854535.2 * t)) 
+		- 0.071 * Math.sin(DEG_TO_RAD * (27.8 + 131.8 * t)) 
+		- 0.055 * Math.sin(DEG_TO_RAD * (103.2 + 377336.3 * t)) 
+		- 0.026 * Math.sin(DEG_TO_RAD * (233.2 + 926533.3 * t));
+
+	var slppp = 14 * Math.sin(DEG_TO_RAD * (357.5 + 35999.1 * t)) 
+		+ 5 * Math.sin(DEG_TO_RAD * (238.2 + 854535.2 * t));
+
+	var lambda = 218.31665 + 481267.88134 * t - 13.268 * t2e4 
+		+ 1.856 * t3e6 - 1.534 * t4e8 + sl 
+		+ 1e-3 * (slp + slpp * t + slppp * t2e4);
+
+	var computed = {
+		a : sma * 1000,
+		e : ecc,
+		i : 2.0 * Math.asin(gamma) * RAD_TO_DEG,
+		w : ( (lp - raan)) % 360,
+		o : ( raan) % 360,
+		M : ( (lambda - lp)) %  360
+	};
+	
+	return computed;
+
+
+};

+ 31 - 0
app/calendar/src/NameSpace.js

@@ -0,0 +1,31 @@
+/*
+	Global vars
+*/
+
+'use strict';
+module.exports = {
+	//gravitational constant to measure the force with masses in kg and radii in meters N(m/kg)^2
+	G : 6.6742e-11,
+	//astronomical unit in km
+	AU : 149597870,
+	CIRCLE : 2 * Math.PI,
+	KM : 1000,
+	DEG_TO_RAD : Math.PI/180,
+	RAD_TO_DEG : 180/Math.PI,
+	NM_TO_KM : 1.852,
+	LB_TO_KG : 0.453592,
+	LBF_TO_NEWTON : 4.44822162,
+	FT_TO_M : 0.3048,
+	//duration in seconds
+	DAY : 60 * 60 * 24,
+	//duration in days
+	YEAR : 365.25,
+	//duration in days
+	CENTURY : 100 * 365.25,
+	SIDERAL_DAY : 3600 * 23.9344696,
+	J2000 : new Date('2000-01-01T12:00:00-00:00'),
+	getEpochTime : function(userDate) {
+		userDate = userDate || new Date();
+		return ((userDate - this.J2000) / 1000) ;
+	}
+};

+ 247 - 0
app/calendar/src/OrbitalElements.js

@@ -0,0 +1,247 @@
+
+'use strict';
+
+var ns = require('ns');
+var Utils = require('./Utils');
+var THREE = require('./Three.shim');
+var CMath = require('./Math');
+
+var maxIterationsForEccentricAnomaly = 10;
+var maxDE = 1e-15;
+
+var solveEccentricAnomaly = function(f, x0, maxIter) {
+		
+	var x = 0;
+	var x2 = x0;
+	
+	for (var i = 0; i < maxIter; i++) {
+		x = x2;
+		x2 = f(x);
+	}
+	
+	return x2;
+}
+
+var solveKepler = function(e, M) {
+	return function(x) {
+		return x + (M + e * Math.sin(x) - x) / (1 - e * Math.cos(x));
+	};
+};
+
+var solveKeplerLaguerreConway = function(e, M) {
+	return function(x) {
+		var s = e * Math.sin(x);
+		var c = e * Math.cos(x);
+		var f = x - s - M;
+		var f1 = 1 - c;
+		var f2 = s;
+
+		x += -5 * f / (f1 + CMath.sign(f1) * Math.sqrt(Math.abs(16 * f1 * f1 - 20 * f * f2)));
+		return x;
+	};
+};
+
+var solveKeplerLaguerreConwayHyp = function(e, M) {
+	return function(x) {
+		var s = e * CMath.sinh(x);
+		var c = e * CMath.cosh(x);
+		var f = x - s - M;
+		var f1 = c - 1;
+		var f2 = s;
+
+		x += -5 * f / (f1 + CMath.sign(f1) * Math.sqrt(Math.abs(16 * f1 * f1 - 20 * f * f2)));
+		return x;
+	};
+};
+
+module.exports = {
+	setDefaultOrbit : function(orbitalElements, calculator) {
+		this.orbitalElements = orbitalElements;
+		if(orbitalElements && orbitalElements.epoch) {
+			this.epochCorrection = ns.getEpochTime(orbitalElements.epoch);
+		}
+		this.calculator = calculator;
+	},
+
+	setName : function(name){
+		this.name = name;
+	},
+
+	calculateVelocity : function(timeEpoch, relativeTo, isFromDelta) {
+		if(!this.orbitalElements) return new THREE.Vector3(0,0,0);
+
+		var eclipticVelocity;
+		
+		if ( isFromDelta ) {
+			var pos1 = this.calculatePosition(timeEpoch);
+			var pos2 = this.calculatePosition(timeEpoch + 60);
+			eclipticVelocity = pos2.sub(pos1).multiplyScalar(1/60);
+		} else {
+			//vis viva to calculate speed (not velocity, i.e not a vector)
+			var el = this.calculateElements(timeEpoch);
+			var speed = Math.sqrt(ns.G * require('./SolarSystem').getBody(relativeTo).mass * ((2 / (el.r)) - (1 / (el.a))));
+
+			//now calculate velocity orientation, that is, a vector tangent to the orbital ellipse
+			var k = el.r / el.a;
+			var o = ((2 - (2 * el.e * el.e)) / (k * (2-k)))-1;
+			//floating point imprecision
+			o = o > 1 ? 1 : o;
+			var alpha = Math.PI - Math.acos(o);
+			alpha = el.v < 0 ? (2 * Math.PI) - alpha  : alpha;
+			var velocityAngle = el.v + (alpha / 2);
+			//velocity vector in the plane of the orbit
+			var orbitalVelocity = new THREE.Vector3(Math.cos(velocityAngle), Math.sin(velocityAngle)).setLength(speed);
+			var velocityEls = Utils.extend({}, el, {pos:orbitalVelocity, v:null, r:null});
+			eclipticVelocity = this.getPositionFromElements(velocityEls);
+		}
+
+		//var diff = eclipticVelocityFromDelta.sub(eclipticVelocity);console.log(diff.length());
+		return eclipticVelocity;
+		
+	},
+
+	calculatePosition : function(timeEpoch) {
+		if(!this.orbitalElements) return new THREE.Vector3(0,0,0);
+		var computed = this.calculateElements(timeEpoch);
+		var pos =  this.getPositionFromElements(computed);
+		return pos;
+	},
+
+	solveEccentricAnomaly : function(e, M){
+		if (e == 0.0) {
+			return M;
+		}  else if (e < 0.9) {
+			var sol = solveEccentricAnomaly(solveKepler(e, M), M, 6);
+			return sol;
+		} else if (e < 1.0) {
+			var E = M + 0.85 * e * ((Math.sin(M) >= 0.0) ? 1 : -1);
+			var sol = solveEccentricAnomaly(solveKeplerLaguerreConway(e, M), E, 8);
+			return sol;
+		} else if (e == 1.0) {
+			return M;
+		} else {
+			var E = Math.log(2 * M / e + 1.85);
+			var sol = solveEccentricAnomaly(solveKeplerLaguerreConwayHyp(e, M), E, 30);
+			return sol;
+		}
+	},
+
+	calculateElements : function(timeEpoch, forcedOrbitalElements) {
+		if(!forcedOrbitalElements && !this.orbitalElements) return null;
+
+		var orbitalElements = forcedOrbitalElements || this.orbitalElements;
+
+		/*
+
+		Epoch : J2000
+
+		a 	Semi-major axis
+	    e 	Eccentricity
+	    i 	Inclination
+	    o 	Longitude of Ascending Node (Ω)
+	    w 	Argument of periapsis (ω)
+		E 	Eccentric Anomaly
+	    T 	Time at perihelion
+	    M	Mean anomaly
+	    l 	Mean Longitude
+	    lp	longitude of periapsis
+	    r	distance du centre
+	    v	true anomaly
+
+	    P	Sidereal period (mean value)
+		Pw	Argument of periapsis precession period (mean value)
+		Pn	Longitude of the ascending node precession period (mean value)
+
+	    */
+	    if (this.epochCorrection) {
+	    	timeEpoch -= this.epochCorrection;
+	    }
+		var tDays = timeEpoch / ns.DAY;
+		var T = tDays / ns.CENTURY ;
+		//console.log(T);
+		var computed = {
+			t : timeEpoch
+		};
+
+		if(this.calculator && !forcedOrbitalElements) {
+			var realorbit = this.calculator(T);
+			Utils.extend(computed, realorbit);
+		} else {
+
+			if (orbitalElements.base) {
+				var variation;
+				for(var el in orbitalElements.base) {
+					//cy : variation by century.
+					//day : variation by day.
+					variation = orbitalElements.cy ? orbitalElements.cy[el] : (orbitalElements.day[el] * ns.CENTURY);
+					variation = variation || 0;
+					computed[el] = orbitalElements.base[el] + (variation * T);
+				}
+			} else {
+				computed = Utils.extend({}, orbitalElements);
+			}
+
+			if (undefined === computed.w) {
+				computed.w = computed.lp - computed.o;
+			}
+
+			if (undefined === computed.M) {
+				computed.M = computed.l - computed.lp;
+			}
+
+			computed.a = computed.a * ns.KM;//was in km, set it in m
+		}
+
+
+		computed.i = ns.DEG_TO_RAD * computed.i;
+		computed.o = ns.DEG_TO_RAD * computed.o;
+		computed.w = ns.DEG_TO_RAD * computed.w;
+		computed.M = ns.DEG_TO_RAD * computed.M;
+
+		computed.E = this.solveEccentricAnomaly(computed.e, computed.M);
+
+		computed.E = computed.E % ns.CIRCLE;
+		computed.i = computed.i % ns.CIRCLE;
+		computed.o = computed.o % ns.CIRCLE;
+		computed.w = computed.w % ns.CIRCLE;
+		computed.M = computed.M % ns.CIRCLE;
+
+		//in the plane of the orbit
+		computed.pos = new THREE.Vector3(computed.a * (Math.cos(computed.E) - computed.e), computed.a * (Math.sqrt(1 - (computed.e*computed.e))) * Math.sin(computed.E));
+
+		computed.r = computed.pos.length();
+		computed.v = Math.atan2(computed.pos.y, computed.pos.x);
+		if(orbitalElements.relativeTo) {
+			var relativeTo = require('./SolarSystem').getBody(orbitalElements.relativeTo);
+			if(relativeTo.tilt) {
+				computed.tilt = -relativeTo.tilt * ns.DEG_TO_RAD;
+			}
+		};
+		return computed;
+	},
+
+	getPositionFromElements : function(computed) {
+
+		if(!computed) return new THREE.Vector3(0,0,0);
+
+		var a1 = new THREE.Euler(computed.tilt || 0, 0, computed.o, 'XYZ');
+		var q1 = new THREE.Quaternion().setFromEuler(a1);
+		var a2 = new THREE.Euler(computed.i, 0, computed.w, 'XYZ');
+		var q2 = new THREE.Quaternion().setFromEuler(a2);
+
+		var planeQuat = new THREE.Quaternion().multiplyQuaternions(q1, q2);
+		computed.pos.applyQuaternion(planeQuat);
+		return computed.pos;
+	},
+
+	calculatePeriod : function(elements, relativeTo) {
+		var period;
+		if(this.orbitalElements && this.orbitalElements.day && this.orbitalElements.day.M) {
+			period = 360 / this.orbitalElements.day.M ;
+		}else if(require('./SolarSystem').getBody(relativeTo) && require('./SolarSystem').getBody(relativeTo).k && elements) {
+			period = 2 * Math.PI * Math.sqrt(Math.pow(elements.a/(ns.AU*1000), 3)) / require('./SolarSystem').getBody(relativeTo).k;
+		}
+		period *= ns.DAY;//in seconds
+		return period;
+	}
+};

+ 44 - 0
app/calendar/src/SolarSystem.js

@@ -0,0 +1,44 @@
+'use strict';
+
+var ns = require('ns');
+var Utils = require('./Utils');
+var definitions = require('./Definitions');
+var CelestialBody = require('./CelestialBody');
+
+
+var bodies = definitions.map(function(def){
+	var body = Object.create(CelestialBody);
+	Utils.extend(body, def);
+	body.init();
+	return body;
+});
+
+var names = bodies.reduce(function(carry, body){
+	carry[body.name] = body;
+	return carry;
+}, {});
+
+var central = bodies.reduce(function(carry, body){
+	carry = carry && carry.mass > body.mass ? carry : body;
+	return carry;
+}, null);
+
+
+console.log(bodies);
+
+module.exports = {
+	getBody: function(name){
+		return names[name] || central;
+	},
+	getPositions: function(userDate, calculateVelocity){
+		var epochTime = ns.getEpochTime(userDate);
+		return bodies.map(function(body){
+			body.setPositionFromDate(epochTime, calculateVelocity);
+			return {
+				name: body.name,
+				position: body.getPosition(),
+				velocity: body.getVelocity()
+			};
+		});
+	}
+};

+ 10 - 0
app/calendar/src/Three.shim.js

@@ -0,0 +1,10 @@
+
+'use strict';
+
+var THREE = global.THREE = {};
+
+require('../vendor/three/math/Vector3');
+require('../vendor/three/math/Quaternion');
+require('../vendor/three/math/Euler');
+
+module.exports = THREE;

+ 19 - 0
app/calendar/src/Utils.js

@@ -0,0 +1,19 @@
+/*
+	Global vars
+*/
+
+'use strict';
+
+var extend = function(){
+	if(arguments.length === 1) return arguments[0];
+	var source = Array.prototype.splice.call(arguments, 1, 1)[0];
+	arguments[0] = Object.keys(source).reduce(function(carry, key){
+		carry[key] = source[key];
+		return carry;
+	}, arguments[0]);
+	return extend.apply(null, arguments);
+};
+
+module.exports = {
+	extend: extend
+};

+ 326 - 0
app/calendar/vendor/three/math/Euler.js

@@ -0,0 +1,326 @@
+/**
+ * @author mrdoob / http://mrdoob.com/
+ * @author WestLangley / http://github.com/WestLangley
+ * @author bhouston / http://exocortex.com
+ */
+
+THREE.Euler = function ( x, y, z, order ) {
+
+	this._x = x || 0;
+	this._y = y || 0;
+	this._z = z || 0;
+	this._order = order || THREE.Euler.DefaultOrder;
+
+};
+
+THREE.Euler.RotationOrders = [ 'XYZ', 'YZX', 'ZXY', 'XZY', 'YXZ', 'ZYX' ];
+
+THREE.Euler.DefaultOrder = 'XYZ';
+
+THREE.Euler.prototype = {
+
+	constructor: THREE.Euler,
+
+	_x: 0, _y: 0, _z: 0, _order: THREE.Euler.DefaultOrder,
+
+	get x () {
+
+		return this._x;
+
+	},
+
+	set x ( value ) {
+
+		this._x = value;
+		this.onChangeCallback();
+
+	},
+
+	get y () {
+
+		return this._y;
+
+	},
+
+	set y ( value ) {
+
+		this._y = value;
+		this.onChangeCallback();
+
+	},
+
+	get z () {
+
+		return this._z;
+
+	},
+
+	set z ( value ) {
+
+		this._z = value;
+		this.onChangeCallback();
+
+	},
+
+	get order () {
+
+		return this._order;
+
+	},
+
+	set order ( value ) {
+
+		this._order = value;
+		this.onChangeCallback();
+
+	},
+
+	set: function ( x, y, z, order ) {
+
+		this._x = x;
+		this._y = y;
+		this._z = z;
+		this._order = order || this._order;
+
+		this.onChangeCallback();
+
+		return this;
+
+	},
+
+	copy: function ( euler ) {
+
+		this._x = euler._x;
+		this._y = euler._y;
+		this._z = euler._z;
+		this._order = euler._order;
+
+		this.onChangeCallback();
+
+		return this;
+
+	},
+
+	setFromRotationMatrix: function ( m, order, update ) {
+
+		var clamp = THREE.Math.clamp;
+
+		// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
+
+		var te = m.elements;
+		var m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ];
+		var m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ];
+		var m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ];
+
+		order = order || this._order;
+
+		if ( order === 'XYZ' ) {
+
+			this._y = Math.asin( clamp( m13, - 1, 1 ) );
+
+			if ( Math.abs( m13 ) < 0.99999 ) {
+
+				this._x = Math.atan2( - m23, m33 );
+				this._z = Math.atan2( - m12, m11 );
+
+			} else {
+
+				this._x = Math.atan2( m32, m22 );
+				this._z = 0;
+
+			}
+
+		} else if ( order === 'YXZ' ) {
+
+			this._x = Math.asin( - clamp( m23, - 1, 1 ) );
+
+			if ( Math.abs( m23 ) < 0.99999 ) {
+
+				this._y = Math.atan2( m13, m33 );
+				this._z = Math.atan2( m21, m22 );
+
+			} else {
+
+				this._y = Math.atan2( - m31, m11 );
+				this._z = 0;
+
+			}
+
+		} else if ( order === 'ZXY' ) {
+
+			this._x = Math.asin( clamp( m32, - 1, 1 ) );
+
+			if ( Math.abs( m32 ) < 0.99999 ) {
+
+				this._y = Math.atan2( - m31, m33 );
+				this._z = Math.atan2( - m12, m22 );
+
+			} else {
+
+				this._y = 0;
+				this._z = Math.atan2( m21, m11 );
+
+			}
+
+		} else if ( order === 'ZYX' ) {
+
+			this._y = Math.asin( - clamp( m31, - 1, 1 ) );
+
+			if ( Math.abs( m31 ) < 0.99999 ) {
+
+				this._x = Math.atan2( m32, m33 );
+				this._z = Math.atan2( m21, m11 );
+
+			} else {
+
+				this._x = 0;
+				this._z = Math.atan2( - m12, m22 );
+
+			}
+
+		} else if ( order === 'YZX' ) {
+
+			this._z = Math.asin( clamp( m21, - 1, 1 ) );
+
+			if ( Math.abs( m21 ) < 0.99999 ) {
+
+				this._x = Math.atan2( - m23, m22 );
+				this._y = Math.atan2( - m31, m11 );
+
+			} else {
+
+				this._x = 0;
+				this._y = Math.atan2( m13, m33 );
+
+			}
+
+		} else if ( order === 'XZY' ) {
+
+			this._z = Math.asin( - clamp( m12, - 1, 1 ) );
+
+			if ( Math.abs( m12 ) < 0.99999 ) {
+
+				this._x = Math.atan2( m32, m22 );
+				this._y = Math.atan2( m13, m11 );
+
+			} else {
+
+				this._x = Math.atan2( - m23, m33 );
+				this._y = 0;
+
+			}
+
+		} else {
+
+			THREE.warn( 'THREE.Euler: .setFromRotationMatrix() given unsupported order: ' + order )
+
+		}
+
+		this._order = order;
+
+		if ( update !== false ) this.onChangeCallback();
+
+		return this;
+
+	},
+
+	setFromQuaternion: function () {
+
+		var matrix;
+
+		return function ( q, order, update ) {
+
+			if ( matrix === undefined ) matrix = new THREE.Matrix4();
+			matrix.makeRotationFromQuaternion( q );
+			this.setFromRotationMatrix( matrix, order, update );
+
+			return this;
+
+		};
+
+	}(),
+
+	setFromVector3: function ( v, order ) {
+
+		return this.set( v.x, v.y, v.z, order || this._order );
+
+	},
+
+	reorder: function () {
+
+		// WARNING: this discards revolution information -bhouston
+
+		var q = new THREE.Quaternion();
+
+		return function ( newOrder ) {
+
+			q.setFromEuler( this );
+			this.setFromQuaternion( q, newOrder );
+
+		};
+
+	}(),
+
+	equals: function ( euler ) {
+
+		return ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order );
+
+	},
+
+	fromArray: function ( array ) {
+
+		this._x = array[ 0 ];
+		this._y = array[ 1 ];
+		this._z = array[ 2 ];
+		if ( array[ 3 ] !== undefined ) this._order = array[ 3 ];
+
+		this.onChangeCallback();
+
+		return this;
+
+	},
+
+	toArray: function ( array, offset ) {
+
+		if ( array === undefined ) array = [];
+		if ( offset === undefined ) offset = 0;
+
+		array[ offset ] = this._x;
+		array[ offset + 1 ] = this._y;
+		array[ offset + 2 ] = this._z;
+		array[ offset + 3 ] = this._order;
+
+		return array;
+	},
+
+	toVector3: function ( optionalResult ) {
+
+		if ( optionalResult ) {
+
+			return optionalResult.set( this._x, this._y, this._z );
+
+		} else {
+
+			return new THREE.Vector3( this._x, this._y, this._z );
+
+		}
+
+	},
+
+	onChange: function ( callback ) {
+
+		this.onChangeCallback = callback;
+
+		return this;
+
+	},
+
+	onChangeCallback: function () {},
+
+	clone: function () {
+
+		return new THREE.Euler( this._x, this._y, this._z, this._order );
+
+	}
+
+};

+ 522 - 0
app/calendar/vendor/three/math/Quaternion.js

@@ -0,0 +1,522 @@
+/**
+ * @author mikael emtinger / http://gomo.se/
+ * @author alteredq / http://alteredqualia.com/
+ * @author WestLangley / http://github.com/WestLangley
+ * @author bhouston / http://exocortex.com
+ */
+
+THREE.Quaternion = function ( x, y, z, w ) {
+
+	this._x = x || 0;
+	this._y = y || 0;
+	this._z = z || 0;
+	this._w = ( w !== undefined ) ? w : 1;
+
+};
+
+THREE.Quaternion.prototype = {
+
+	constructor: THREE.Quaternion,
+
+	_x: 0,_y: 0, _z: 0, _w: 0,
+
+	get x () {
+
+		return this._x;
+
+	},
+
+	set x ( value ) {
+
+		this._x = value;
+		this.onChangeCallback();
+
+	},
+
+	get y () {
+
+		return this._y;
+
+	},
+
+	set y ( value ) {
+
+		this._y = value;
+		this.onChangeCallback();
+
+	},
+
+	get z () {
+
+		return this._z;
+
+	},
+
+	set z ( value ) {
+
+		this._z = value;
+		this.onChangeCallback();
+
+	},
+
+	get w () {
+
+		return this._w;
+
+	},
+
+	set w ( value ) {
+
+		this._w = value;
+		this.onChangeCallback();
+
+	},
+
+	set: function ( x, y, z, w ) {
+
+		this._x = x;
+		this._y = y;
+		this._z = z;
+		this._w = w;
+
+		this.onChangeCallback();
+
+		return this;
+
+	},
+
+	copy: function ( quaternion ) {
+
+		this._x = quaternion.x;
+		this._y = quaternion.y;
+		this._z = quaternion.z;
+		this._w = quaternion.w;
+
+		this.onChangeCallback();
+
+		return this;
+
+	},
+
+	setFromEuler: function ( euler, update ) {
+
+		if ( euler instanceof THREE.Euler === false ) {
+
+			throw new Error( 'THREE.Quaternion: .setFromEuler() now expects a Euler rotation rather than a Vector3 and order.' );
+		}
+
+		// http://www.mathworks.com/matlabcentral/fileexchange/
+		// 	20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/
+		//	content/SpinCalc.m
+
+		var c1 = Math.cos( euler._x / 2 );
+		var c2 = Math.cos( euler._y / 2 );
+		var c3 = Math.cos( euler._z / 2 );
+		var s1 = Math.sin( euler._x / 2 );
+		var s2 = Math.sin( euler._y / 2 );
+		var s3 = Math.sin( euler._z / 2 );
+
+		if ( euler.order === 'XYZ' ) {
+
+			this._x = s1 * c2 * c3 + c1 * s2 * s3;
+			this._y = c1 * s2 * c3 - s1 * c2 * s3;
+			this._z = c1 * c2 * s3 + s1 * s2 * c3;
+			this._w = c1 * c2 * c3 - s1 * s2 * s3;
+
+		} else if ( euler.order === 'YXZ' ) {
+
+			this._x = s1 * c2 * c3 + c1 * s2 * s3;
+			this._y = c1 * s2 * c3 - s1 * c2 * s3;
+			this._z = c1 * c2 * s3 - s1 * s2 * c3;
+			this._w = c1 * c2 * c3 + s1 * s2 * s3;
+
+		} else if ( euler.order === 'ZXY' ) {
+
+			this._x = s1 * c2 * c3 - c1 * s2 * s3;
+			this._y = c1 * s2 * c3 + s1 * c2 * s3;
+			this._z = c1 * c2 * s3 + s1 * s2 * c3;
+			this._w = c1 * c2 * c3 - s1 * s2 * s3;
+
+		} else if ( euler.order === 'ZYX' ) {
+
+			this._x = s1 * c2 * c3 - c1 * s2 * s3;
+			this._y = c1 * s2 * c3 + s1 * c2 * s3;
+			this._z = c1 * c2 * s3 - s1 * s2 * c3;
+			this._w = c1 * c2 * c3 + s1 * s2 * s3;
+
+		} else if ( euler.order === 'YZX' ) {
+
+			this._x = s1 * c2 * c3 + c1 * s2 * s3;
+			this._y = c1 * s2 * c3 + s1 * c2 * s3;
+			this._z = c1 * c2 * s3 - s1 * s2 * c3;
+			this._w = c1 * c2 * c3 - s1 * s2 * s3;
+
+		} else if ( euler.order === 'XZY' ) {
+
+			this._x = s1 * c2 * c3 - c1 * s2 * s3;
+			this._y = c1 * s2 * c3 - s1 * c2 * s3;
+			this._z = c1 * c2 * s3 + s1 * s2 * c3;
+			this._w = c1 * c2 * c3 + s1 * s2 * s3;
+
+		}
+
+		if ( update !== false ) this.onChangeCallback();
+
+		return this;
+
+	},
+
+	setFromAxisAngle: function ( axis, angle ) {
+
+		// http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm
+
+		// assumes axis is normalized
+
+		var halfAngle = angle / 2, s = Math.sin( halfAngle );
+
+		this._x = axis.x * s;
+		this._y = axis.y * s;
+		this._z = axis.z * s;
+		this._w = Math.cos( halfAngle );
+
+		this.onChangeCallback();
+
+		return this;
+
+	},
+
+	setFromRotationMatrix: function ( m ) {
+
+		// http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
+
+		// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
+
+		var te = m.elements,
+
+			m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ],
+			m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ],
+			m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ],
+
+			trace = m11 + m22 + m33,
+			s;
+
+		if ( trace > 0 ) {
+
+			s = 0.5 / Math.sqrt( trace + 1.0 );
+
+			this._w = 0.25 / s;
+			this._x = ( m32 - m23 ) * s;
+			this._y = ( m13 - m31 ) * s;
+			this._z = ( m21 - m12 ) * s;
+
+		} else if ( m11 > m22 && m11 > m33 ) {
+
+			s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 );
+
+			this._w = ( m32 - m23 ) / s;
+			this._x = 0.25 * s;
+			this._y = ( m12 + m21 ) / s;
+			this._z = ( m13 + m31 ) / s;
+
+		} else if ( m22 > m33 ) {
+
+			s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 );
+
+			this._w = ( m13 - m31 ) / s;
+			this._x = ( m12 + m21 ) / s;
+			this._y = 0.25 * s;
+			this._z = ( m23 + m32 ) / s;
+
+		} else {
+
+			s = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 );
+
+			this._w = ( m21 - m12 ) / s;
+			this._x = ( m13 + m31 ) / s;
+			this._y = ( m23 + m32 ) / s;
+			this._z = 0.25 * s;
+
+		}
+
+		this.onChangeCallback();
+
+		return this;
+
+	},
+
+	setFromUnitVectors: function () {
+
+		// http://lolengine.net/blog/2014/02/24/quaternion-from-two-vectors-final
+
+		// assumes direction vectors vFrom and vTo are normalized
+
+		var v1, r;
+
+		var EPS = 0.000001;
+
+		return function ( vFrom, vTo ) {
+
+			if ( v1 === undefined ) v1 = new THREE.Vector3();
+
+			r = vFrom.dot( vTo ) + 1;
+
+			if ( r < EPS ) {
+
+				r = 0;
+
+				if ( Math.abs( vFrom.x ) > Math.abs( vFrom.z ) ) {
+
+					v1.set( - vFrom.y, vFrom.x, 0 );
+
+				} else {
+
+					v1.set( 0, - vFrom.z, vFrom.y );
+
+				}
+
+			} else {
+
+				v1.crossVectors( vFrom, vTo );
+
+			}
+
+			this._x = v1.x;
+			this._y = v1.y;
+			this._z = v1.z;
+			this._w = r;
+
+			this.normalize();
+
+			return this;
+
+		}
+
+	}(),
+
+	inverse: function () {
+
+		this.conjugate().normalize();
+
+		return this;
+
+	},
+
+	conjugate: function () {
+
+		this._x *= - 1;
+		this._y *= - 1;
+		this._z *= - 1;
+
+		this.onChangeCallback();
+
+		return this;
+
+	},
+
+	dot: function ( v ) {
+
+		return this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w;
+
+	},
+
+	lengthSq: function () {
+
+		return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w;
+
+	},
+
+	length: function () {
+
+		return Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w );
+
+	},
+
+	normalize: function () {
+
+		var l = this.length();
+
+		if ( l === 0 ) {
+
+			this._x = 0;
+			this._y = 0;
+			this._z = 0;
+			this._w = 1;
+
+		} else {
+
+			l = 1 / l;
+
+			this._x = this._x * l;
+			this._y = this._y * l;
+			this._z = this._z * l;
+			this._w = this._w * l;
+
+		}
+
+		this.onChangeCallback();
+
+		return this;
+
+	},
+
+	multiply: function ( q, p ) {
+
+		if ( p !== undefined ) {
+
+			THREE.warn( 'THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead.' );
+			return this.multiplyQuaternions( q, p );
+
+		}
+
+		return this.multiplyQuaternions( this, q );
+
+	},
+
+	multiplyQuaternions: function ( a, b ) {
+
+		// from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm
+
+		var qax = a._x, qay = a._y, qaz = a._z, qaw = a._w;
+		var qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w;
+
+		this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby;
+		this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz;
+		this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx;
+		this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz;
+
+		this.onChangeCallback();
+
+		return this;
+
+	},
+
+	multiplyVector3: function ( vector ) {
+
+		THREE.warn( 'THREE.Quaternion: .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead.' );
+		return vector.applyQuaternion( this );
+
+	},
+
+	slerp: function ( qb, t ) {
+
+		if ( t === 0 ) return this;
+		if ( t === 1 ) return this.copy( qb );
+
+		var x = this._x, y = this._y, z = this._z, w = this._w;
+
+		// http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/
+
+		var cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z;
+
+		if ( cosHalfTheta < 0 ) {
+
+			this._w = - qb._w;
+			this._x = - qb._x;
+			this._y = - qb._y;
+			this._z = - qb._z;
+
+			cosHalfTheta = - cosHalfTheta;
+
+		} else {
+
+			this.copy( qb );
+
+		}
+
+		if ( cosHalfTheta >= 1.0 ) {
+
+			this._w = w;
+			this._x = x;
+			this._y = y;
+			this._z = z;
+
+			return this;
+
+		}
+
+		var halfTheta = Math.acos( cosHalfTheta );
+		var sinHalfTheta = Math.sqrt( 1.0 - cosHalfTheta * cosHalfTheta );
+
+		if ( Math.abs( sinHalfTheta ) < 0.001 ) {
+
+			this._w = 0.5 * ( w + this._w );
+			this._x = 0.5 * ( x + this._x );
+			this._y = 0.5 * ( y + this._y );
+			this._z = 0.5 * ( z + this._z );
+
+			return this;
+
+		}
+
+		var ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta,
+		ratioB = Math.sin( t * halfTheta ) / sinHalfTheta;
+
+		this._w = ( w * ratioA + this._w * ratioB );
+		this._x = ( x * ratioA + this._x * ratioB );
+		this._y = ( y * ratioA + this._y * ratioB );
+		this._z = ( z * ratioA + this._z * ratioB );
+
+		this.onChangeCallback();
+
+		return this;
+
+	},
+
+	equals: function ( quaternion ) {
+
+		return ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w );
+
+	},
+
+	fromArray: function ( array, offset ) {
+
+		if ( offset === undefined ) offset = 0;
+
+		this._x = array[ offset ];
+		this._y = array[ offset + 1 ];
+		this._z = array[ offset + 2 ];
+		this._w = array[ offset + 3 ];
+
+		this.onChangeCallback();
+
+		return this;
+
+	},
+
+	toArray: function ( array, offset ) {
+
+		if ( array === undefined ) array = [];
+		if ( offset === undefined ) offset = 0;
+
+		array[ offset ] = this._x;
+		array[ offset + 1 ] = this._y;
+		array[ offset + 2 ] = this._z;
+		array[ offset + 3 ] = this._w;
+
+		return array;
+
+	},
+
+	onChange: function ( callback ) {
+
+		this.onChangeCallback = callback;
+
+		return this;
+
+	},
+
+	onChangeCallback: function () {},
+
+	clone: function () {
+
+		return new THREE.Quaternion( this._x, this._y, this._z, this._w );
+
+	}
+
+};
+
+THREE.Quaternion.slerp = function ( qa, qb, qm, t ) {
+
+	return qm.copy( qa ).slerp( qb, t );
+
+}

+ 850 - 0
app/calendar/vendor/three/math/Vector3.js

@@ -0,0 +1,850 @@
+/**
+ * @author mrdoob / http://mrdoob.com/
+ * @author *kile / http://kile.stravaganza.org/
+ * @author philogb / http://blog.thejit.org/
+ * @author mikael emtinger / http://gomo.se/
+ * @author egraether / http://egraether.com/
+ * @author WestLangley / http://github.com/WestLangley
+ */
+
+THREE.Vector3 = function ( x, y, z ) {
+
+	this.x = x || 0;
+	this.y = y || 0;
+	this.z = z || 0;
+
+};
+
+THREE.Vector3.prototype = {
+
+	constructor: THREE.Vector3,
+
+	set: function ( x, y, z ) {
+
+		this.x = x;
+		this.y = y;
+		this.z = z;
+
+		return this;
+
+	},
+
+	setX: function ( x ) {
+
+		this.x = x;
+
+		return this;
+
+	},
+
+	setY: function ( y ) {
+
+		this.y = y;
+
+		return this;
+
+	},
+
+	setZ: function ( z ) {
+
+		this.z = z;
+
+		return this;
+
+	},
+
+	setComponent: function ( index, value ) {
+
+		switch ( index ) {
+
+			case 0: this.x = value; break;
+			case 1: this.y = value; break;
+			case 2: this.z = value; break;
+			default: throw new Error( 'index is out of range: ' + index );
+
+		}
+
+	},
+
+	getComponent: function ( index ) {
+
+		switch ( index ) {
+
+			case 0: return this.x;
+			case 1: return this.y;
+			case 2: return this.z;
+			default: throw new Error( 'index is out of range: ' + index );
+
+		}
+
+	},
+
+	copy: function ( v ) {
+
+		this.x = v.x;
+		this.y = v.y;
+		this.z = v.z;
+
+		return this;
+
+	},
+
+	add: function ( v, w ) {
+
+		if ( w !== undefined ) {
+
+			THREE.warn( 'THREE.Vector3: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );
+			return this.addVectors( v, w );
+
+		}
+
+		this.x += v.x;
+		this.y += v.y;
+		this.z += v.z;
+
+		return this;
+
+	},
+
+	addScalar: function ( s ) {
+
+		this.x += s;
+		this.y += s;
+		this.z += s;
+
+		return this;
+
+	},
+
+	addVectors: function ( a, b ) {
+
+		this.x = a.x + b.x;
+		this.y = a.y + b.y;
+		this.z = a.z + b.z;
+
+		return this;
+
+	},
+
+	sub: function ( v, w ) {
+
+		if ( w !== undefined ) {
+
+			THREE.warn( 'THREE.Vector3: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );
+			return this.subVectors( v, w );
+
+		}
+
+		this.x -= v.x;
+		this.y -= v.y;
+		this.z -= v.z;
+
+		return this;
+
+	},
+	
+	subScalar: function ( s ) {
+
+		this.x -= s;
+		this.y -= s;
+		this.z -= s;
+
+		return this;
+
+	},
+
+	subVectors: function ( a, b ) {
+
+		this.x = a.x - b.x;
+		this.y = a.y - b.y;
+		this.z = a.z - b.z;
+
+		return this;
+
+	},
+
+	multiply: function ( v, w ) {
+
+		if ( w !== undefined ) {
+
+			THREE.warn( 'THREE.Vector3: .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead.' );
+			return this.multiplyVectors( v, w );
+
+		}
+
+		this.x *= v.x;
+		this.y *= v.y;
+		this.z *= v.z;
+
+		return this;
+
+	},
+
+	multiplyScalar: function ( scalar ) {
+
+		this.x *= scalar;
+		this.y *= scalar;
+		this.z *= scalar;
+
+		return this;
+
+	},
+
+	multiplyVectors: function ( a, b ) {
+
+		this.x = a.x * b.x;
+		this.y = a.y * b.y;
+		this.z = a.z * b.z;
+
+		return this;
+
+	},
+
+	applyEuler: function () {
+
+		var quaternion;
+
+		return function ( euler ) {
+
+			if ( euler instanceof THREE.Euler === false ) {
+
+				THREE.error( 'THREE.Vector3: .applyEuler() now expects a Euler rotation rather than a Vector3 and order.' );
+
+			}
+
+			if ( quaternion === undefined ) quaternion = new THREE.Quaternion();
+
+			this.applyQuaternion( quaternion.setFromEuler( euler ) );
+
+			return this;
+
+		};
+
+	}(),
+
+	applyAxisAngle: function () {
+
+		var quaternion;
+
+		return function ( axis, angle ) {
+
+			if ( quaternion === undefined ) quaternion = new THREE.Quaternion();
+
+			this.applyQuaternion( quaternion.setFromAxisAngle( axis, angle ) );
+
+			return this;
+
+		};
+
+	}(),
+
+	applyMatrix3: function ( m ) {
+
+		var x = this.x;
+		var y = this.y;
+		var z = this.z;
+
+		var e = m.elements;
+
+		this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ] * z;
+		this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ] * z;
+		this.z = e[ 2 ] * x + e[ 5 ] * y + e[ 8 ] * z;
+
+		return this;
+
+	},
+
+	applyMatrix4: function ( m ) {
+
+		// input: THREE.Matrix4 affine matrix
+
+		var x = this.x, y = this.y, z = this.z;
+
+		var e = m.elements;
+
+		this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ]  * z + e[ 12 ];
+		this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ]  * z + e[ 13 ];
+		this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ];
+
+		return this;
+
+	},
+
+	applyProjection: function ( m ) {
+
+		// input: THREE.Matrix4 projection matrix
+
+		var x = this.x, y = this.y, z = this.z;
+
+		var e = m.elements;
+		var d = 1 / ( e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] ); // perspective divide
+
+		this.x = ( e[ 0 ] * x + e[ 4 ] * y + e[ 8 ]  * z + e[ 12 ] ) * d;
+		this.y = ( e[ 1 ] * x + e[ 5 ] * y + e[ 9 ]  * z + e[ 13 ] ) * d;
+		this.z = ( e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] ) * d;
+
+		return this;
+
+	},
+
+	applyQuaternion: function ( q ) {
+
+		var x = this.x;
+		var y = this.y;
+		var z = this.z;
+
+		var qx = q.x;
+		var qy = q.y;
+		var qz = q.z;
+		var qw = q.w;
+
+		// calculate quat * vector
+
+		var ix =  qw * x + qy * z - qz * y;
+		var iy =  qw * y + qz * x - qx * z;
+		var iz =  qw * z + qx * y - qy * x;
+		var iw = - qx * x - qy * y - qz * z;
+
+		// calculate result * inverse quat
+
+		this.x = ix * qw + iw * - qx + iy * - qz - iz * - qy;
+		this.y = iy * qw + iw * - qy + iz * - qx - ix * - qz;
+		this.z = iz * qw + iw * - qz + ix * - qy - iy * - qx;
+
+		return this;
+
+	},
+
+	project: function () {
+
+		var matrix;
+
+		return function ( camera ) {
+
+			if ( matrix === undefined ) matrix = new THREE.Matrix4();
+
+			matrix.multiplyMatrices( camera.projectionMatrix, matrix.getInverse( camera.matrixWorld ) );
+			return this.applyProjection( matrix );
+
+		};
+
+	}(),
+
+	unproject: function () {
+
+		var matrix;
+
+		return function ( camera ) {
+
+			if ( matrix === undefined ) matrix = new THREE.Matrix4();
+
+			matrix.multiplyMatrices( camera.matrixWorld, matrix.getInverse( camera.projectionMatrix ) );
+			return this.applyProjection( matrix );
+
+		};
+
+	}(),
+
+	transformDirection: function ( m ) {
+
+		// input: THREE.Matrix4 affine matrix
+		// vector interpreted as a direction
+
+		var x = this.x, y = this.y, z = this.z;
+
+		var e = m.elements;
+
+		this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ]  * z;
+		this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ]  * z;
+		this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z;
+
+		this.normalize();
+
+		return this;
+
+	},
+
+	divide: function ( v ) {
+
+		this.x /= v.x;
+		this.y /= v.y;
+		this.z /= v.z;
+
+		return this;
+
+	},
+
+	divideScalar: function ( scalar ) {
+
+		if ( scalar !== 0 ) {
+
+			var invScalar = 1 / scalar;
+
+			this.x *= invScalar;
+			this.y *= invScalar;
+			this.z *= invScalar;
+
+		} else {
+
+			this.x = 0;
+			this.y = 0;
+			this.z = 0;
+
+		}
+
+		return this;
+
+	},
+
+	min: function ( v ) {
+
+		if ( this.x > v.x ) {
+
+			this.x = v.x;
+
+		}
+
+		if ( this.y > v.y ) {
+
+			this.y = v.y;
+
+		}
+
+		if ( this.z > v.z ) {
+
+			this.z = v.z;
+
+		}
+
+		return this;
+
+	},
+
+	max: function ( v ) {
+
+		if ( this.x < v.x ) {
+
+			this.x = v.x;
+
+		}
+
+		if ( this.y < v.y ) {
+
+			this.y = v.y;
+
+		}
+
+		if ( this.z < v.z ) {
+
+			this.z = v.z;
+
+		}
+
+		return this;
+
+	},
+
+	clamp: function ( min, max ) {
+
+		// This function assumes min < max, if this assumption isn't true it will not operate correctly
+
+		if ( this.x < min.x ) {
+
+			this.x = min.x;
+
+		} else if ( this.x > max.x ) {
+
+			this.x = max.x;
+
+		}
+
+		if ( this.y < min.y ) {
+
+			this.y = min.y;
+
+		} else if ( this.y > max.y ) {
+
+			this.y = max.y;
+
+		}
+
+		if ( this.z < min.z ) {
+
+			this.z = min.z;
+
+		} else if ( this.z > max.z ) {
+
+			this.z = max.z;
+
+		}
+
+		return this;
+
+	},
+
+	clampScalar: ( function () {
+
+		var min, max;
+
+		return function ( minVal, maxVal ) {
+
+			if ( min === undefined ) {
+
+				min = new THREE.Vector3();
+				max = new THREE.Vector3();
+
+			}
+
+			min.set( minVal, minVal, minVal );
+			max.set( maxVal, maxVal, maxVal );
+
+			return this.clamp( min, max );
+
+		};
+
+	} )(),
+
+	floor: function () {
+
+		this.x = Math.floor( this.x );
+		this.y = Math.floor( this.y );
+		this.z = Math.floor( this.z );
+
+		return this;
+
+	},
+
+	ceil: function () {
+
+		this.x = Math.ceil( this.x );
+		this.y = Math.ceil( this.y );
+		this.z = Math.ceil( this.z );
+
+		return this;
+
+	},
+
+	round: function () {
+
+		this.x = Math.round( this.x );
+		this.y = Math.round( this.y );
+		this.z = Math.round( this.z );
+
+		return this;
+
+	},
+
+	roundToZero: function () {
+
+		this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );
+		this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );
+		this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z );
+
+		return this;
+
+	},
+
+	negate: function () {
+
+		this.x = - this.x;
+		this.y = - this.y;
+		this.z = - this.z;
+
+		return this;
+
+	},
+
+	dot: function ( v ) {
+
+		return this.x * v.x + this.y * v.y + this.z * v.z;
+
+	},
+
+	lengthSq: function () {
+
+		return this.x * this.x + this.y * this.y + this.z * this.z;
+
+	},
+
+	length: function () {
+
+		return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z );
+
+	},
+
+	lengthManhattan: function () {
+
+		return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z );
+
+	},
+
+	normalize: function () {
+
+		return this.divideScalar( this.length() );
+
+	},
+
+	setLength: function ( l ) {
+
+		var oldLength = this.length();
+
+		if ( oldLength !== 0 && l !== oldLength  ) {
+
+			this.multiplyScalar( l / oldLength );
+		}
+
+		return this;
+
+	},
+
+	lerp: function ( v, alpha ) {
+
+		this.x += ( v.x - this.x ) * alpha;
+		this.y += ( v.y - this.y ) * alpha;
+		this.z += ( v.z - this.z ) * alpha;
+
+		return this;
+
+	},
+
+	lerpVectors: function ( v1, v2, alpha ) {
+
+		this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 );
+
+		return this;
+
+	},
+
+	cross: function ( v, w ) {
+
+		if ( w !== undefined ) {
+
+			THREE.warn( 'THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead.' );
+			return this.crossVectors( v, w );
+
+		}
+
+		var x = this.x, y = this.y, z = this.z;
+
+		this.x = y * v.z - z * v.y;
+		this.y = z * v.x - x * v.z;
+		this.z = x * v.y - y * v.x;
+
+		return this;
+
+	},
+
+	crossVectors: function ( a, b ) {
+
+		var ax = a.x, ay = a.y, az = a.z;
+		var bx = b.x, by = b.y, bz = b.z;
+
+		this.x = ay * bz - az * by;
+		this.y = az * bx - ax * bz;
+		this.z = ax * by - ay * bx;
+
+		return this;
+
+	},
+
+	projectOnVector: function () {
+
+		var v1, dot;
+
+		return function ( vector ) {
+
+			if ( v1 === undefined ) v1 = new THREE.Vector3();
+
+			v1.copy( vector ).normalize();
+
+			dot = this.dot( v1 );
+
+			return this.copy( v1 ).multiplyScalar( dot );
+
+		};
+
+	}(),
+
+	projectOnPlane: function () {
+
+		var v1;
+
+		return function ( planeNormal ) {
+
+			if ( v1 === undefined ) v1 = new THREE.Vector3();
+
+			v1.copy( this ).projectOnVector( planeNormal );
+
+			return this.sub( v1 );
+
+		}
+
+	}(),
+
+	reflect: function () {
+
+		// reflect incident vector off plane orthogonal to normal
+		// normal is assumed to have unit length
+
+		var v1;
+
+		return function ( normal ) {
+
+			if ( v1 === undefined ) v1 = new THREE.Vector3();
+
+			return this.sub( v1.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) );
+
+		}
+
+	}(),
+
+	angleTo: function ( v ) {
+
+		var theta = this.dot( v ) / ( this.length() * v.length() );
+
+		// clamp, to handle numerical problems
+
+		return Math.acos( THREE.Math.clamp( theta, - 1, 1 ) );
+
+	},
+
+	distanceTo: function ( v ) {
+
+		return Math.sqrt( this.distanceToSquared( v ) );
+
+	},
+
+	distanceToSquared: function ( v ) {
+
+		var dx = this.x - v.x;
+		var dy = this.y - v.y;
+		var dz = this.z - v.z;
+
+		return dx * dx + dy * dy + dz * dz;
+
+	},
+
+	setEulerFromRotationMatrix: function ( m, order ) {
+
+		THREE.error( 'THREE.Vector3: .setEulerFromRotationMatrix() has been removed. Use Euler.setFromRotationMatrix() instead.' );
+
+	},
+
+	setEulerFromQuaternion: function ( q, order ) {
+
+		THREE.error( 'THREE.Vector3: .setEulerFromQuaternion() has been removed. Use Euler.setFromQuaternion() instead.' );
+
+	},
+
+	getPositionFromMatrix: function ( m ) {
+
+		THREE.warn( 'THREE.Vector3: .getPositionFromMatrix() has been renamed to .setFromMatrixPosition().' );
+
+		return this.setFromMatrixPosition( m );
+
+	},
+
+	getScaleFromMatrix: function ( m ) {
+
+		THREE.warn( 'THREE.Vector3: .getScaleFromMatrix() has been renamed to .setFromMatrixScale().' );
+
+		return this.setFromMatrixScale( m );
+	},
+
+	getColumnFromMatrix: function ( index, matrix ) {
+
+		THREE.warn( 'THREE.Vector3: .getColumnFromMatrix() has been renamed to .setFromMatrixColumn().' );
+
+		return this.setFromMatrixColumn( index, matrix );
+
+	},
+
+	setFromMatrixPosition: function ( m ) {
+
+		this.x = m.elements[ 12 ];
+		this.y = m.elements[ 13 ];
+		this.z = m.elements[ 14 ];
+
+		return this;
+
+	},
+
+	setFromMatrixScale: function ( m ) {
+
+		var sx = this.set( m.elements[ 0 ], m.elements[ 1 ], m.elements[  2 ] ).length();
+		var sy = this.set( m.elements[ 4 ], m.elements[ 5 ], m.elements[  6 ] ).length();
+		var sz = this.set( m.elements[ 8 ], m.elements[ 9 ], m.elements[ 10 ] ).length();
+
+		this.x = sx;
+		this.y = sy;
+		this.z = sz;
+
+		return this;
+	},
+
+	setFromMatrixColumn: function ( index, matrix ) {
+		
+		var offset = index * 4;
+
+		var me = matrix.elements;
+
+		this.x = me[ offset ];
+		this.y = me[ offset + 1 ];
+		this.z = me[ offset + 2 ];
+
+		return this;
+
+	},
+
+	equals: function ( v ) {
+
+		return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) );
+
+	},
+
+	fromArray: function ( array, offset ) {
+
+		if ( offset === undefined ) offset = 0;
+
+		this.x = array[ offset ];
+		this.y = array[ offset + 1 ];
+		this.z = array[ offset + 2 ];
+
+		return this;
+
+	},
+
+	toArray: function ( array, offset ) {
+
+		if ( array === undefined ) array = [];
+		if ( offset === undefined ) offset = 0;
+
+		array[ offset ] = this.x;
+		array[ offset + 1 ] = this.y;
+		array[ offset + 2 ] = this.z;
+
+		return array;
+
+	},
+
+	fromAttribute: function ( attribute, index, offset ) {
+
+		if ( offset === undefined ) offset = 0;
+
+		index = index * attribute.itemSize + offset;
+
+		this.x = attribute.array[ index ];
+		this.y = attribute.array[ index + 1 ];
+		this.z = attribute.array[ index + 2 ];
+
+		return this;
+
+	},
+
+	clone: function () {
+
+		return new THREE.Vector3( this.x, this.y, this.z );
+
+	}
+
+};

+ 1 - 1
app/course/my_course_list.php

@@ -1,6 +1,6 @@
 <div class="tool_bar">
 	<div>
-	课程
+	<?php echo $_local->gui->add;?>
 	</div>
 
 	<div>

+ 3 - 3
app/pcdl/head_bar.php

@@ -215,9 +215,9 @@
 					<li><a class="nav_link" href="../dict"><?php echo $_local->gui->dictionary; ?></a></li>
 					<li class="nav_link head_nav_dropdown" >
 						<div><?php echo $_local->gui->more; ?></div>
-						<ul class="head_nav_dropdown_content">
-							<li><a class="nav_link" href="../pc"><?php echo $_local->gui->digest;//书摘?></a></li>
-							<li><a class="nav_link" href="../course"><?php echo $_local->gui->composition;//著作?></a></li>
+						<ul class="head_nav_dropdown_content" style="margin-top: 0em;top: 2em;margin-left:-0.5em;padding-bottom: 0.5em;">
+							<!--<li><a class="nav_link" href="../pc"><?php echo $_local->gui->digest;//书摘?></a></li>
+							<li><a class="nav_link" href="../course"><?php echo $_local->gui->composition;//著作?></a></li>-->
 							<li><a class="nav_link" href="../calendar"><?php echo $_local->gui->buddhist_calendar;?></a></li>
 							<li><a class="nav_link" href="../tools/unicode.html"><?php echo $_local->gui->code_convert;//巴利编码转换?></a></li>
 							<li><a class="nav_link" href="../statistics"><?php echo $_local->gui->corpus_statistics;?></a></li>

+ 2 - 2
app/studio/index_tool_bar.php

@@ -70,7 +70,7 @@
 						</svg>	
 					</span>	
 					<span class="navi_text">
-					<?php echo $_local->gui->lesson;?>
+					<?php echo $_local->gui->academy;?>
 					
 					</span>
 				</li>
@@ -114,7 +114,7 @@
 		<!-- tool bar begin-->
 		<div class='index_toolbar'>
 			<div id="index_nav">
-			<svg class="icon" style="height: 3.5em;width: 15em;padding-top: 15px;">
+			<svg class="icon" style="height: 3em;width: 15em;padding-top: 3px;">
 				<use xlink:href="../public/images/svg/wikipali_banner.svg#wikipali_banner"></use>
 			</svg>
 			</div>

Niektoré súbory nie sú zobrazené, pretože je v týchto rozdielových dátach zmenené mnoho súborov