Fixed issue where physically insignificant part mass was not being correctly cascaded down through parent parts.
Fixed issue where physically insignificant part mass was not being correctly cascaded down through parent parts.

--- a/Documents/CHANGES.txt
+++ b/Documents/CHANGES.txt
@@ -1,3 +1,43 @@
+1.0.18.0
+    Added: Orbital readouts - "Speed at Periapsis" and "Speed at Apoapsis". (Padishar)
+    Added: Manoeuvre readouts - "Post-burn Apoapsis" and "Post-burn Periapsis". (Padishar)
+    Fixed: Synched the minimum simulation time sliders and stopped them from snapping back after 999ms. (saybur)
+    Fixed: Added workaround for the bug in Vessel.horizontalSrfSpeed (Padishar)
+    Fixed: Physically insignificant part masses were not correctly being cascaded down through its parents.
+
+1.0.17.0
+    Added: 'Mach Number' readout under the 'Surface' category and included it on the default surface HUD.
+    Added: Stock sections in the Flight Engineer can now become HUDs.
+    Added 'Thermal' readouts category including:
+        Internal Flux
+        Convection Flux
+        Radiation Flux
+        Critical Part Name
+        Critical Part Temperature
+        Critical Part Skin Temperature
+        Critical Part Thermal Percentage of Max Temperature
+        Hottest Part Name
+        Hottest Part Temperature
+        Hottest Part Skin Temperature
+        Coldest Part Name
+        Coldest Part Temperature
+        Coldest Part Skin Temperature
+
+    Changed: Mach on the Build Engineer now accurate to 2 decimal places.
+    Changed: Max mach in the Build Engineer defaults to 1.00 even when no jet engines are present.
+    Changed: Increased eccentricity readout to 5 decimal places.
+    Changed: Implemented Sarbian's object pooling.
+    Changed: The default selected body is now assigned via 'Planitarium.Home'.
+    Changed: HUDs to clamp fully inside the screen instead of allowing them to run off the edge by a certain amount.
+    Fixed: Physically insignificant part mass is now associated with the parent part.
+    Fixed: Longitude and Latitude readouts now use a KER formatter instead of Squad's incorrect implementation.
+    Fixed: Possible null reference in the Rendezvous Processor.
+    Fixed: Fairing mass issues introduced with regards to simulation changes.
+    Fixed: Use of per-propellant fuel flow mode override.
+    Fixed: Burn times calculated for jet engines.
+    Fixed: Thrust issues introduced with Sarbian's simulation alterations.
+    Fixed: Issue where HUDs positioned close to the top/bottom of the screen could be pushed out of position.
+
 1.0.16.6, 02-05-15
     Fixed: Separately staged fairing mass jettisons are now calculated in the editor.
 
@@ -40,7 +80,7 @@
 
 1.0.15.1, 13-02-2015
     Rebuild
-    
+
 1.0.15.0, 08-02-2015
     Padishar's Fixes:
         Added: Support KIDS ISP thrust correction.
@@ -50,7 +90,7 @@
 
 1.0.14.1, 28-12-2014
     Fixed: Missing texture on the ER-7500 model.
-    
+
 1.0.14.0, 28-12-2014
     Added: Career mode that limits the Flight Engineer by:
         - Requiring an Engineer Kerbal of any level, or placement of an Engineer Chip or ER-7500 part.
@@ -170,7 +210,7 @@
     Added: New readout to the surface category:
         - Vertical Acceleration
         - Horizontal Acceleration
-    
+
     Changed: Atmospheric efficiency readout now shows as a percentage.
     Changed: Atmospheric settings (pressure/velocity) in the editor condensed onto a single line.
     Fixed: Bug where the overlays in the editor would stay open outside of parts screen.
@@ -327,6 +367,7 @@
     Added: Stock toolbar support in the Flight Engineer.
     Changed: Orbital Period has higher precision.
     Fixed: Various NullRefs in editor window and overlay.
-    
+
 1.0.0.0, 24-07-2014
     Initial release for public testing.
+

--- a/KerbalEngineer/CelestialBodies.cs
+++ b/KerbalEngineer/CelestialBodies.cs
@@ -37,7 +37,8 @@
             try
             {
                 SystemBody = new BodyInfo(PSystemManager.Instance.localBodies.Find(b => b.referenceBody == null || b.referenceBody == b));
-                if (!SetSelectedBody("Kerbin"))
+                String homeCBName = Planetarium.fetch.Home.bodyName;
+                if (!SetSelectedBody(homeCBName))
                 {
                     SelectedBody = SystemBody;
                     SelectedBody.SetSelected(true);

--- a/KerbalEngineer/Control/ControlCentre.cs
+++ b/KerbalEngineer/Control/ControlCentre.cs
@@ -142,7 +142,7 @@
             try
             {
                 GUI.skin = null;
-                this.position = GUILayout.Window(this.GetInstanceID(), this.position, this.Window, "KERBAL ENGINEER REDUX " + EngineerGlobals.AssemblyVersion + " - CONTROL CENTRE", HighLogic.Skin.window);
+                this.position = GUILayout.Window(this.GetInstanceID(), this.position, this.Window, "KERBAL ENGINEER REDUX " + EngineerGlobals.ASSEMBLY_VERSION + " - CONTROL CENTRE", HighLogic.Skin.window);
                 this.CentreWindow();
             }
             catch (Exception ex)

--- a/KerbalEngineer/Editor/BuildAdvanced.cs
+++ b/KerbalEngineer/Editor/BuildAdvanced.cs
@@ -215,7 +215,7 @@
                 }
 
                 // Change the window title based on whether in compact mode or not.
-                title = !compactMode ? "KERBAL ENGINEER REDUX " + EngineerGlobals.AssemblyVersion : "K.E.R. " + EngineerGlobals.AssemblyVersion;
+                title = !compactMode ? "KERBAL ENGINEER REDUX " + EngineerGlobals.ASSEMBLY_VERSION : "K.E.R. " + EngineerGlobals.ASSEMBLY_VERSION;
 
                 // Reset the window size when the staging or something else has changed.
                 stagesLength = stages.Length;
@@ -523,12 +523,12 @@
             GUILayout.EndHorizontal();
 
             GUILayout.BeginHorizontal();
-            GUILayout.Label("Simulate using vectored thrust values:");
+            GUILayout.Label("Simulate using vectored thrust values:", settingStyle);
             SimManager.vectoredThrust = GUILayout.Toggle(SimManager.vectoredThrust, "ENABLED", buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset));
             GUILayout.EndHorizontal();
 
             GUILayout.BeginHorizontal();
-            GUILayout.Label("Verbose Simulation Log:");
+            GUILayout.Label("Verbose Simulation Log:", settingStyle);
             SimManager.logOutput = GUILayout.Toggle(SimManager.logOutput, "ENABLED", buttonStyle, GUILayout.Width(100.0f * GuiDisplaySize.Offset));
             GUILayout.EndHorizontal();
 
@@ -563,9 +563,9 @@
             }
             GUILayout.EndHorizontal();
 
-            GUILayout.Label("Minimum delay between simulations: " + SimManager.minSimTime.Milliseconds + "ms", settingStyle);
+            GUILayout.Label("Minimum delay between simulations: " + SimManager.minSimTime.TotalMilliseconds + "ms", settingStyle);
             GUI.skin = HighLogic.Skin;
-            SimManager.minSimTime = new TimeSpan(0, 0, 0, 0, (int)GUILayout.HorizontalSlider(SimManager.minSimTime.Milliseconds, 0, 2000.0f));
+            SimManager.minSimTime = TimeSpan.FromMilliseconds(GUILayout.HorizontalSlider((float)SimManager.minSimTime.TotalMilliseconds, 0, 2000.0f));
             GUI.skin = null;
         }
 

--- a/KerbalEngineer/EngineerGlobals.cs
+++ b/KerbalEngineer/EngineerGlobals.cs
@@ -1,7 +1,5 @@
 // 
-//     Kerbal Engineer Redux
-// 
-//     Copyright (C) 2014 CYBUTEK
+//     Copyright (C) 2015 CYBUTEK
 // 
 //     This program is free software: you can redistribute it and/or modify
 //     it under the terms of the GNU General Public License as published by
@@ -17,42 +15,31 @@
 //     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 // 
 
-#region Using Directives
-
-using System.IO;
-using System.Reflection;
-
-#endregion
-
 namespace KerbalEngineer
 {
-    public class EngineerGlobals
+    using System.IO;
+    using System.Reflection;
+
+    public static class EngineerGlobals
     {
-        #region Constants
-
         /// <summary>
         ///     Current version of the Kerbal Engineer assembly.
         /// </summary>
-        public const string AssemblyVersion = "1.0.16.6";
-
-        #endregion
-
-        #region Fields
+        public const string ASSEMBLY_VERSION = "1.0.18.0";
 
         private static string assemblyFile;
         private static string assemblyName;
         private static string assemblyPath;
-
-        #endregion
-
-        #region Properties
 
         /// <summary>
         ///     Gets the Kerbal Engineer assembly's path including the file name.
         /// </summary>
         public static string AssemblyFile
         {
-            get { return assemblyFile ?? (assemblyFile = Assembly.GetExecutingAssembly().Location); }
+            get
+            {
+                return assemblyFile ?? (assemblyFile = Assembly.GetExecutingAssembly().Location);
+            }
         }
 
         /// <summary>
@@ -60,7 +47,10 @@
         /// </summary>
         public static string AssemblyName
         {
-            get { return assemblyName ?? (assemblyName = new FileInfo(AssemblyFile).Name); }
+            get
+            {
+                return assemblyName ?? (assemblyName = new FileInfo(AssemblyFile).Name);
+            }
         }
 
         /// <summary>
@@ -68,9 +58,10 @@
         /// </summary>
         public static string AssemblyPath
         {
-            get { return assemblyPath ?? (assemblyPath = AssemblyFile.Replace(new FileInfo(AssemblyFile).Name, "")); }
+            get
+            {
+                return assemblyPath ?? (assemblyPath = AssemblyFile.Replace(new FileInfo(AssemblyFile).Name, ""));
+            }
         }
-
-        #endregion
     }
 }

--- a/KerbalEngineer/Extensions/DoubleExtensions.cs
+++ b/KerbalEngineer/Extensions/DoubleExtensions.cs
@@ -1,7 +1,7 @@
 // 
 //     Kerbal Engineer Redux
 // 
-//     Copyright (C) 2014 CYBUTEK
+//     Copyright (C) 2015 CYBUTEK
 // 
 //     This program is free software: you can redistribute it and/or modify
 //     it under the terms of the GNU General Public License as published by
@@ -17,18 +17,12 @@
 //     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 // 
 
-#region Using Directives
-
-using KerbalEngineer.Helpers;
-
-#endregion
-
 namespace KerbalEngineer.Extensions
 {
+    using Helpers;
+
     public static class DoubleExtensions
     {
-        #region Methods: public
-
         public static double Clamp(this double value, double lower, double higher)
         {
             return value < lower ? lower : value > higher ? higher : value;
@@ -49,14 +43,19 @@
             return Units.ToDistance(value);
         }
 
-        public static string ToTorque(this double value)
+        public static string ToFlux(this double value)
         {
-            return Units.ToTorque(value);
+            return Units.ToFlux(value);
         }
 
         public static string ToForce(this double value)
         {
             return Units.ToForce(value);
+        }
+
+        public static string ToMach(this double value)
+        {
+            return Units.ToMach(value);
         }
 
         public static string ToMass(this double value)
@@ -79,6 +78,14 @@
             return Units.ToSpeed(value);
         }
 
-        #endregion
+        public static string ToTemperature(this double value)
+        {
+            return Units.ToTemperature(value);
+        }
+
+        public static string ToTorque(this double value)
+        {
+            return Units.ToTorque(value);
+        }
     }
 }

--- a/KerbalEngineer/Extensions/FloatExtensions.cs
+++ b/KerbalEngineer/Extensions/FloatExtensions.cs
@@ -1,7 +1,7 @@
 // 
 //     Kerbal Engineer Redux
 // 
-//     Copyright (C) 2014 CYBUTEK
+//     Copyright (C) 2015 CYBUTEK
 // 
 //     This program is free software: you can redistribute it and/or modify
 //     it under the terms of the GNU General Public License as published by
@@ -17,18 +17,12 @@
 //     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 // 
 
-#region Using Directives
-
-using KerbalEngineer.Helpers;
-
-#endregion
-
 namespace KerbalEngineer.Extensions
 {
+    using Helpers;
+
     public static class FloatExtensions
     {
-        #region Methods: public
-
         public static string ToAcceleration(this float value)
         {
             return Units.ToAcceleration(value);
@@ -44,14 +38,19 @@
             return Units.ToDistance(value);
         }
 
+        public static string ToFlux(this float value)
+        {
+            return Units.ToFlux(value);
+        }
+
         public static string ToForce(this float value)
         {
             return Units.ToForce(value);
         }
 
-        public static string ToTorque(this float value)
+        public static string ToMach(this float value)
         {
-            return Units.ToTorque(value);
+            return Units.ToMach(value);
         }
 
         public static string ToMass(this float value)
@@ -74,6 +73,14 @@
             return Units.ToSpeed(value);
         }
 
-        #endregion
+        public static string ToTemperature(this float value)
+        {
+            return Units.ToTemperature(value);
+        }
+
+        public static string ToTorque(this float value)
+        {
+            return Units.ToTorque(value);
+        }
     }
 }

--- a/KerbalEngineer/Extensions/PartExtensions.cs
+++ b/KerbalEngineer/Extensions/PartExtensions.cs
@@ -55,6 +55,7 @@
         /// <summary>
         ///     Gets whether the part has fuel.
         /// </summary>
+        /* not used
         public static bool EngineHasFuel(this Part part)
         {
             PartModule cachePartModule = GetModule<ModuleEngines>(part);
@@ -71,7 +72,7 @@
 
             return false;
         }
-
+        */
         /// <summary>
         ///     Gets the cost of the part excluding resources.
         /// </summary>
@@ -123,6 +124,7 @@
         /// <summary>
         ///     Gets the maximum thrust of the part if it's an engine.
         /// </summary>
+        /* not used
         public static double GetMaxThrust(this Part part)
         {
             PartModule cachePartModule = GetModule<ModuleEngines>(part);
@@ -139,6 +141,7 @@
 
             return 0.0;
         }
+        */
 
         /// <summary>
         ///     Gets the first typed PartModule in the part's module list.
@@ -194,10 +197,10 @@
             return GetModule<ModuleEngines>(part);
         }
 
-        public static ModuleEnginesFX GetModuleEnginesFx(this Part part)
+/*        public static ModuleEnginesFX GetModuleEnginesFx(this Part part)
         {
             return GetModule<ModuleEnginesFX>(part);
-        }
+        }*/
 
         /// <summary>
         ///     Gets a ModuleGenerator typed PartModule.
@@ -218,16 +221,20 @@
         /// <summary>
         ///     Gets the current selected ModuleEnginesFX.
         /// </summary>
-        public static ModuleEnginesFX GetModuleMultiModeEngine(this Part part)
-        {
-            ModuleEnginesFX moduleEngineFx;
-            string mode = GetModule<MultiModeEngine>(part).mode;
-            for (int i = 0; i < part.Modules.Count; ++i)
-            {
-                moduleEngineFx = part.Modules[i] as ModuleEnginesFX;
-                if (moduleEngineFx != null && moduleEngineFx.engineID == mode)
-                {
-                    return moduleEngineFx;
+        public static ModuleEngines GetModuleMultiModeEngine(this Part part)
+        {
+            ModuleEngines moduleEngines;
+            MultiModeEngine multiMod = GetModule<MultiModeEngine>(part);
+            if (multiMod != null)
+            {
+                string mode = multiMod.mode;
+                for (int i = 0; i < part.Modules.Count; ++i)
+                {
+                    moduleEngines = part.Modules[i] as ModuleEngines;
+                    if (moduleEngines != null && moduleEngines.engineID == mode)
+                    {
+                        return moduleEngines;
+                    }
                 }
             }
             return null;
@@ -343,6 +350,7 @@
         /// <summary>
         ///     Gets the current specific impulse for the engine.
         /// </summary>
+        /* not used
         public static double GetSpecificImpulse(this Part part, float atmosphere)
         {
             PartModule cachePartModule = GetModule<ModuleEngines>(part);
@@ -359,6 +367,7 @@
 
             return 0.0;
         }
+        */
 
         /// <summary>
         ///     Gets the total mass of the part including resources.
@@ -457,7 +466,7 @@
         /// </summary>
         public static bool IsEngine(this Part part)
         {
-            return HasModule<ModuleEngines>(part) || HasModule<ModuleEnginesFX>(part);
+            return HasModule<ModuleEngines>(part);
         }
 
         /// <summary>
@@ -540,7 +549,7 @@
         /// </summary>
         public static bool IsSolidRocket(this Part part)
         {
-            return (part.HasModule<ModuleEngines>() && part.GetModuleEngines().throttleLocked) || (part.HasModule<ModuleEnginesFX>() && part.GetModuleEnginesFx().throttleLocked);
+            return (part.HasModule<ModuleEngines>() && part.GetModuleEngines().throttleLocked);
         }
 
         public class ProtoModuleDecoupler
@@ -588,6 +597,12 @@
             }
         }
 
+        // This needs updating to handle multi-mode engines and engines with multiple ModuleEngines correctly.
+        // It currently just shows the stats of the currently active module for multi-mode engines and just 
+        // the first ModuleEngines for engines with multiple modules.
+        // It should really show all the modes for multi-mode engines as separate sections.
+        // For other engines with multiple ModuleEngines it should combine the separate modules into a single set of data
+        // The constructor should be changed to take the Part itself.  It can be called if HasModule<ModuleEngines>() is true.
         public class ProtoModuleEngine
         {
             private readonly PartModule module;
@@ -627,19 +642,6 @@
                 MinimumThrust = engine.minThrust;
                 Propellants = engine.propellants;
             }
-
-            private void SetModuleEnginesFx()
-            {
-                ModuleEnginesFX engine = module as ModuleEnginesFX;
-                if (engine == null)
-                {
-                    return;
-                }
-
-                MaximumThrust = engine.maxThrust * (engine.thrustPercentage * 0.01);
-                MinimumThrust = engine.minThrust;
-                Propellants = engine.propellants;
-            }
         }
     }
 }

--- /dev/null
+++ b/KerbalEngineer/Extensions/StringExtensions.cs
@@ -1,1 +1,33 @@
+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2015 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
 
+namespace KerbalEngineer.Extensions
+{
+    public static class StringExtensions
+    {
+        public static string ToLength(this string value, int length)
+        {
+            if (value != null && value.Length > length)
+            {
+                value = value.Substring(0, length) + "...";
+            }
+            return value;
+        }
+    }
+}

--- a/KerbalEngineer/Flight/DisplayStack.cs
+++ b/KerbalEngineer/Flight/DisplayStack.cs
@@ -214,7 +214,7 @@
         /// </summary>
         private void DrawControlBar()
         {
-            GUILayout.Label("FLIGHT ENGINEER " + EngineerGlobals.AssemblyVersion, this.titleStyle);
+            GUILayout.Label("FLIGHT ENGINEER " + EngineerGlobals.ASSEMBLY_VERSION, this.titleStyle);
 
             this.DrawControlBarButtons(SectionLibrary.StockSections);
             this.DrawControlBarButtons(SectionLibrary.CustomSections);

--- a/KerbalEngineer/Flight/Readouts/Miscellaneous/SimulationDelay.cs
+++ b/KerbalEngineer/Flight/Readouts/Miscellaneous/SimulationDelay.cs
@@ -51,7 +51,7 @@
             GUILayout.BeginHorizontal();
             GUILayout.Label("Sim Delay", this.NameStyle);
             GUI.skin = HighLogic.Skin;
-            SimManager.minSimTime = new TimeSpan(0, 0, 0, 0, (int)GUILayout.HorizontalSlider(SimManager.minSimTime.Milliseconds, 0, 1000.0f));
+            SimManager.minSimTime = TimeSpan.FromMilliseconds(GUILayout.HorizontalSlider((float)SimManager.minSimTime.TotalMilliseconds, 0, 2000.0f));
             GUI.skin = null;
             GUILayout.EndHorizontal();
         }

--- a/KerbalEngineer/Flight/Readouts/Orbital/ManoeuvreNode/ManoeuvreProcessor.cs
+++ b/KerbalEngineer/Flight/Readouts/Orbital/ManoeuvreNode/ManoeuvreProcessor.cs
@@ -30,6 +30,8 @@
 
 namespace KerbalEngineer.Flight.Readouts.Orbital.ManoeuvreNode
 {
+    using Helpers;
+
     public class ManoeuvreProcessor : IUpdatable, IUpdateRequest
     {
         #region Fields
@@ -60,6 +62,10 @@
         }
 
         public static double NormalDeltaV { get; private set; }
+
+        public static double PostBurnAp { get; private set; }
+
+        public static double PostBurnPe { get; private set; }
 
         public static double ProgradeDeltaV { get; private set; }
 
@@ -108,6 +114,8 @@
             NormalDeltaV = deltaV.y;
             RadialDeltaV = deltaV.x;
             TotalDeltaV = node.GetBurnVector(FlightGlobals.ship_orbit).magnitude;
+            PostBurnAp = node.nextPatch != null ? node.nextPatch.ApA : 0;
+            PostBurnPe = node.nextPatch != null ? node.nextPatch.PeA : 0;
 
             UniversalTime = FlightGlobals.ActiveVessel.patchedConicSolver.maneuverNodes[0].UT;
             AngleToPrograde = FlightGlobals.ActiveVessel.patchedConicSolver.maneuverNodes[0].patch.GetAngleToPrograde(UniversalTime);
@@ -163,7 +171,7 @@
                     deltaVDrain = deltaV.Clamp(0.0, stageDeltaV);
                 }
 
-                var exhaustVelocity = stage.isp * 9.82;
+                var exhaustVelocity = stage.isp * Units.GRAVITY;
                 var flowRate = stage.thrust / exhaustVelocity;
                 var endMass = Math.Exp(Math.Log(startMass) - deltaVDrain / exhaustVelocity);
                 var deltaMass = (startMass - endMass) * Math.Exp(-(deltaVDrain * 0.001) / exhaustVelocity);

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Orbital/ManoeuvreNode/PostBurnApoapsis.cs
@@ -1,1 +1,69 @@
+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2014 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
 
+#region Using Directives
+
+using System;
+
+using KerbalEngineer.Extensions;
+using KerbalEngineer.Flight.Sections;
+
+#endregion
+
+namespace KerbalEngineer.Flight.Readouts.Orbital.ManoeuvreNode
+{
+    public class PostBurnApoapsis : ReadoutModule
+    {
+        #region Constructors
+
+        public PostBurnApoapsis()
+        {
+            this.Name = "Post-burn Apoapsis";
+            this.Category = ReadoutCategory.GetCategory("Orbital");
+            this.HelpString = String.Empty;
+            this.IsDefault = false;
+        }
+
+        #endregion
+
+        #region Methods: public
+
+        public override void Draw(SectionModule section)
+        {
+            if (!ManoeuvreProcessor.ShowDetails)
+            {
+                return;
+            }
+
+            this.DrawLine("Post-burn Apoapsis", ManoeuvreProcessor.PostBurnAp.ToDistance(), section.IsHud);
+        }
+
+        public override void Reset()
+        {
+            ManoeuvreProcessor.Reset();
+        }
+
+        public override void Update()
+        {
+            ManoeuvreProcessor.RequestUpdate();
+        }
+
+        #endregion
+    }
+}

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Orbital/ManoeuvreNode/PostBurnPeriapsis.cs
@@ -1,1 +1,69 @@
+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2014 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
 
+#region Using Directives
+
+using System;
+
+using KerbalEngineer.Extensions;
+using KerbalEngineer.Flight.Sections;
+
+#endregion
+
+namespace KerbalEngineer.Flight.Readouts.Orbital.ManoeuvreNode
+{
+    public class PostBurnPeriapsis : ReadoutModule
+    {
+        #region Constructors
+
+        public PostBurnPeriapsis()
+        {
+            this.Name = "Post-burn Periapsis";
+            this.Category = ReadoutCategory.GetCategory("Orbital");
+            this.HelpString = String.Empty;
+            this.IsDefault = false;
+        }
+
+        #endregion
+
+        #region Methods: public
+
+        public override void Draw(SectionModule section)
+        {
+            if (!ManoeuvreProcessor.ShowDetails)
+            {
+                return;
+            }
+
+            this.DrawLine("Post-burn Periapsis", ManoeuvreProcessor.PostBurnPe.ToDistance(), section.IsHud);
+        }
+
+        public override void Reset()
+        {
+            ManoeuvreProcessor.Reset();
+        }
+
+        public override void Update()
+        {
+            ManoeuvreProcessor.RequestUpdate();
+        }
+
+        #endregion
+    }
+}

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Orbital/SpeedAtApoapsis.cs
@@ -1,1 +1,68 @@
+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2014 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
 
+#region Using Directives
+
+using System;
+using KerbalEngineer.Flight.Sections;
+using KerbalEngineer.Helpers;
+using KerbalEngineer.Extensions;
+
+#endregion
+
+namespace KerbalEngineer.Flight.Readouts.Orbital
+{
+    public class SpeedAtApoapsis : ReadoutModule
+    {
+        #region Constructors
+
+        public SpeedAtApoapsis()
+        {
+            this.Name = "Speed at Apoapsis";
+            this.Category = ReadoutCategory.GetCategory("Orbital");
+            this.HelpString = "Shows the orbital speed of the vessel when at apoapsis, the highest point of the orbit.";
+            this.IsDefault = false;
+        }
+
+        #endregion
+
+        #region Methods: public
+
+        public override void Draw(SectionModule section)
+        {
+            // Vis-viva: v^2 = GM(2/r - 1/a)
+            // All this is easily got from the ships orbit (and reference body)
+            String str;
+            Orbit orbit = FlightGlobals.ship_orbit;
+            if (orbit.eccentricity > 1.0)
+                str = "---m/s";
+            else
+            {
+                double speedsqr = orbit.referenceBody.gravParameter * ((2 / orbit.ApR) - (1 / orbit.semiMajorAxis));
+                if (Double.IsNaN(speedsqr) || speedsqr < 0)
+                    str = "---m/s";     // Don't think this is possible barring bugs in the Orbit class
+                else
+                    str = Math.Sqrt(speedsqr).ToSpeed();
+            }
+            this.DrawLine(str, section.IsHud);
+        }
+
+        #endregion
+    }
+}

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Orbital/SpeedAtPeriapsis.cs
@@ -1,1 +1,64 @@
+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2014 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
 
+#region Using Directives
+
+using System;
+using KerbalEngineer.Flight.Sections;
+using KerbalEngineer.Helpers;
+using KerbalEngineer.Extensions;
+
+#endregion
+
+namespace KerbalEngineer.Flight.Readouts.Orbital
+{
+    public class SpeedAtPeriapsis : ReadoutModule
+    {
+        #region Constructors
+
+        public SpeedAtPeriapsis()
+        {
+            this.Name = "Speed at Periapsis";
+            this.Category = ReadoutCategory.GetCategory("Orbital");
+            this.HelpString = "Shows the orbital speed of the vessel when at periapsis, the lowest point of the orbit.";
+            this.IsDefault = false;
+        }
+
+        #endregion
+
+        #region Methods: public
+
+        public override void Draw(SectionModule section)
+        {
+            // Vis-viva: v^2 = GM(2/r - 1/a)
+            // All this is easily got from the ships orbit (and reference body)
+            String str;
+            Orbit orbit = FlightGlobals.ship_orbit;
+            double oneovera = (orbit.eccentricity == 1) ? 0 : (1 / orbit.semiMajorAxis);
+            double speedsqr = orbit.referenceBody.gravParameter * ((2 / orbit.PeR) - oneovera);
+            if (Double.IsNaN(speedsqr) || speedsqr < 0)
+                str = "---m/s";
+            else
+                str = Math.Sqrt(speedsqr).ToSpeed();
+            this.DrawLine(str, section.IsHud);
+        }
+
+        #endregion
+    }
+}

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Orbital/TimeToAtmosphere.cs
@@ -1,1 +1,99 @@
+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2014 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
 
+#region Using Directives
+
+using System;
+using KerbalEngineer.Flight.Sections;
+using KerbalEngineer.Helpers;
+
+#endregion
+
+namespace KerbalEngineer.Flight.Readouts.Orbital
+{
+    public class TimeToAtmosphere : ReadoutModule
+    {
+        //private LogMsg log = new LogMsg();
+        
+        #region Constructors
+
+        public TimeToAtmosphere()
+        {
+            this.Name = "Time to Atmosphere";
+            this.Category = ReadoutCategory.GetCategory("Orbital");
+            this.HelpString = "Shows the time until the vessel enters or leaves atmosphere.";
+            this.IsDefault = false;
+        }
+
+        #endregion
+
+        #region Methods: public
+
+        public override void Draw(SectionModule section)
+        {
+            String str;
+            Orbit orbit = FlightGlobals.ship_orbit;
+
+            if (orbit.referenceBody.atmosphere && orbit.PeA < orbit.referenceBody.atmosphereDepth)
+            {
+                double tA = orbit.TrueAnomalyAtRadius(orbit.referenceBody.atmosphereDepth + orbit.referenceBody.Radius);
+                //log.buf.AppendFormat("tA = {0}\n", tA);
+                double utTime = Planetarium.GetUniversalTime();
+                //log.buf.AppendFormat("utTime = {0}\n", utTime);
+                double timeAtRad1 = orbit.GetUTforTrueAnomaly(tA, orbit.period * 0.5);
+                //log.buf.AppendFormat("timeAtRad1 = {0}\n", timeAtRad1);
+                if (timeAtRad1 < utTime)
+                {
+                    timeAtRad1 += orbit.period;
+                    //log.buf.AppendFormat("timeAtRad1 = {0}\n", timeAtRad1);
+                }
+                double timeAtRad2 = orbit.GetUTforTrueAnomaly(-tA, orbit.period * 0.5);
+                //log.buf.AppendFormat("timeAtRad2 = {0}\n", timeAtRad2);
+                if (timeAtRad2 < utTime)
+                {
+                    timeAtRad2 += orbit.period;
+                    //log.buf.AppendFormat("timeAtRad2 = {0}\n", timeAtRad2);
+                }
+                double time = Math.Min(timeAtRad1, timeAtRad2) - utTime;
+                //log.buf.AppendFormat("time = {0}\n", time);
+
+                if (Double.IsNaN(time))
+                {
+                    str = "---s";
+                    //log.buf.AppendLine("time is NaN");
+                }
+                else
+                {
+                    str = TimeFormatter.ConvertToString(time);
+                    //log.buf.AppendFormat("str = {0}\n", str);
+                }
+            }
+            else
+            {
+                str = "---s";
+                //log.buf.AppendLine("no atmosphere or pe > atmosphere");
+            }
+
+            //log.Flush();
+            this.DrawLine(str, section.IsHud);
+        }
+
+        #endregion
+    }
+}

--- a/KerbalEngineer/Flight/Readouts/ReadoutLibrary.cs
+++ b/KerbalEngineer/Flight/Readouts/ReadoutLibrary.cs
@@ -1,7 +1,5 @@
 // 
-//     Kerbal Engineer Redux
-// 
-//     Copyright (C) 2014 CYBUTEK
+//     Copyright (C) 2015 CYBUTEK
 // 
 //     This program is free software: you can redistribute it and/or modify
 //     it under the terms of the GNU General Public License as published by
@@ -19,8 +17,6 @@
 
 namespace KerbalEngineer.Flight.Readouts
 {
-    #region Using Directives
-
     using System;
     using System.Collections.Generic;
     using System.Linq;
@@ -30,6 +26,7 @@
     using Rendezvous;
     using Settings;
     using Surface;
+    using Thermal;
     using Vessel;
     using AltitudeSeaLevel = Surface.AltitudeSeaLevel;
     using ApoapsisHeight = Orbital.ApoapsisHeight;
@@ -40,17 +37,9 @@
     using TimeToApoapsis = Orbital.TimeToApoapsis;
     using TimeToPeriapsis = Orbital.TimeToPeriapsis;
 
-    #endregion
-
     public static class ReadoutLibrary
     {
-        #region Fields
-
         private static List<ReadoutModule> readouts = new List<ReadoutModule>();
-
-        #endregion
-
-        #region Constructors
 
         /// <summary>
         ///     Sets up and populates the readout library with the stock readouts.
@@ -63,6 +52,7 @@
                 ReadoutCategory.SetCategory("Surface", "Surface and atmospheric readouts.");
                 ReadoutCategory.SetCategory("Vessel", "Vessel performance statistics.");
                 ReadoutCategory.SetCategory("Rendezvous", "Readouts for rendezvous manovoeures.");
+                ReadoutCategory.SetCategory("Thermal", "Thermal characteristics readouts.");
                 ReadoutCategory.SetCategory("Miscellaneous", "Miscellaneous readouts.");
                 ReadoutCategory.Selected = ReadoutCategory.GetCategory("Orbital");
 
@@ -101,6 +91,11 @@
                 readouts.Add(new NodeTimeToHalfBurn());
                 readouts.Add(new NodeAngleToPrograde());
                 readouts.Add(new NodeAngleToRetrograde());
+                readouts.Add(new PostBurnApoapsis());
+                readouts.Add(new PostBurnPeriapsis());
+                readouts.Add(new SpeedAtApoapsis());
+                readouts.Add(new SpeedAtPeriapsis());
+                readouts.Add(new TimeToAtmosphere());
 
                 // Surface
                 readouts.Add(new AltitudeSeaLevel());
@@ -109,6 +104,7 @@
                 readouts.Add(new VerticalAcceleration());
                 readouts.Add(new HorizontalSpeed());
                 readouts.Add(new HorizontalAcceleration());
+                readouts.Add(new MachNumber());
                 readouts.Add(new Latitude());
                 readouts.Add(new Longitude());
                 readouts.Add(new GeeForce());
@@ -171,7 +167,22 @@
                 readouts.Add(new Rendezvous.OrbitalPeriod());
                 readouts.Add(new Rendezvous.SemiMajorAxis());
                 readouts.Add(new Rendezvous.SemiMinorAxis());
-                
+
+                // Thermal
+                readouts.Add(new InternalFlux());
+                readouts.Add(new ConvectionFlux());
+                readouts.Add(new RadiationFlux());
+                readouts.Add(new CriticalPart());
+                readouts.Add(new CriticalTemperature());
+                readouts.Add(new CriticalSkinTemperature());
+                readouts.Add(new CriticalThermalPercentage());
+                readouts.Add(new HottestPart());
+                readouts.Add(new HottestTemperature());
+                readouts.Add(new HottestSkinTemperature());
+                readouts.Add(new CoolestPart());
+                readouts.Add(new CoolestTemperature());
+                readouts.Add(new CoolestSkinTemperature());
+
                 // Misc
                 readouts.Add(new Separator());
                 readouts.Add(new GuiSizeAdjustor());
@@ -188,22 +199,20 @@
             }
         }
 
-        #endregion
-
-        #region Properties
-
         /// <summary>
         ///     Gets and sets the available readout modules.
         /// </summary>
         public static List<ReadoutModule> Readouts
         {
-            get { return readouts; }
-            set { readouts = value; }
-        }
-
-        #endregion
-
-        #region Methods
+            get
+            {
+                return readouts;
+            }
+            set
+            {
+                readouts = value;
+            }
+        }
 
         /// <summary>
         ///     Gets a list of readout modules which are associated with the specified category.
@@ -226,7 +235,7 @@
         /// </summary>
         public static void Reset()
         {
-            foreach (var readout in readouts)
+            foreach (ReadoutModule readout in readouts)
             {
                 readout.Reset();
             }
@@ -239,8 +248,8 @@
         {
             try
             {
-                var handler = SettingHandler.Load("HelpStrings.xml");
-                foreach (var readout in readouts)
+                SettingHandler handler = SettingHandler.Load("HelpStrings.xml");
+                foreach (ReadoutModule readout in readouts)
                 {
                     readout.HelpString = handler.GetSet(readout.Category + "." + readout.GetType().Name, readout.HelpString);
                 }
@@ -251,7 +260,5 @@
                 Logger.Exception(ex);
             }
         }
-
-        #endregion
     }
 }

--- a/KerbalEngineer/Flight/Readouts/ReadoutModule.cs
+++ b/KerbalEngineer/Flight/Readouts/ReadoutModule.cs
@@ -29,6 +29,8 @@
 
 namespace KerbalEngineer.Flight.Readouts
 {
+    using Extensions;
+
     public abstract class ReadoutModule
     {
         #region Fields
@@ -178,13 +180,13 @@
             {
                 GUILayout.Label(this.Name, this.NameStyle);
                 GUILayout.FlexibleSpace();
-                GUILayout.Label(value, this.ValueStyle);
+                GUILayout.Label(value.ToLength(20), this.ValueStyle);
             }
             else
             {
                 GUILayout.Label(this.Name, this.NameStyle, GUILayout.Height(this.NameStyle.fontSize * 1.2f));
                 GUILayout.FlexibleSpace();
-                GUILayout.Label(value, this.ValueStyle, GUILayout.Height(this.ValueStyle.fontSize * 1.2f));
+                GUILayout.Label(value.ToLength(20), this.ValueStyle, GUILayout.Height(this.ValueStyle.fontSize * 1.2f));
             }
             GUILayout.EndHorizontal();
 
@@ -198,13 +200,13 @@
             {
                 GUILayout.Label(name, this.NameStyle);
                 GUILayout.FlexibleSpace();
-                GUILayout.Label(value, this.ValueStyle);
+                GUILayout.Label(value.ToLength(20), this.ValueStyle);
             }
             else
             {
                 GUILayout.Label(name, this.NameStyle, GUILayout.Height(this.NameStyle.fontSize * 1.2f));
                 GUILayout.FlexibleSpace();
-                GUILayout.Label(value, this.ValueStyle, GUILayout.Height(this.ValueStyle.fontSize * 1.2f));
+                GUILayout.Label(value.ToLength(20), this.ValueStyle, GUILayout.Height(this.ValueStyle.fontSize * 1.2f));
             }
             GUILayout.EndHorizontal();
 

--- a/KerbalEngineer/Flight/Readouts/Rendezvous/RendezvousProcessor.cs
+++ b/KerbalEngineer/Flight/Readouts/Rendezvous/RendezvousProcessor.cs
@@ -1,7 +1,7 @@
 // 
 //     Kerbal Engineer Redux
 // 
-//     Copyright (C) 2014 CYBUTEK
+//     Copyright (C) 2015 CYBUTEK
 // 
 //     This program is free software: you can redistribute it and/or modify
 //     it under the terms of the GNU General Public License as published by
@@ -17,30 +17,19 @@
 //     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 // 
 
-#region Using Directives
-
-using System;
-
-using KerbalEngineer.Extensions;
-using KerbalEngineer.Helpers;
-
-#endregion
-
 namespace KerbalEngineer.Flight.Readouts.Rendezvous
 {
+    using System;
+    using Extensions;
+    using Helpers;
+
     public class RendezvousProcessor : IUpdatable, IUpdateRequest
     {
-        #region Fields
-
         private static readonly RendezvousProcessor instance = new RendezvousProcessor();
 
         private Orbit originOrbit;
         private Orbit targetOrbit;
 
-        #endregion
-
-        #region Properties
-
         /// <summary>
         ///     Gets the target's altitude above its reference body.
         /// </summary>
@@ -71,7 +60,10 @@
         /// </summary>
         public static RendezvousProcessor Instance
         {
-            get { return instance; }
+            get
+            {
+                return instance;
+            }
         }
 
         /// <summary>
@@ -149,10 +141,6 @@
         /// </summary>
         public bool UpdateRequested { get; set; }
 
-        #endregion
-
-        #region Methods: public
-
         /// <summary>
         ///     Request and update to calculate the details.
         /// </summary>
@@ -166,7 +154,13 @@
         /// </summary>
         public void Update()
         {
-            if (FlightGlobals.fetch.VesselTarget == null)
+            if (FlightGlobals.fetch == null ||
+                FlightGlobals.fetch.VesselTarget == null ||
+                FlightGlobals.ActiveVessel == null ||
+                FlightGlobals.ActiveVessel.targetObject == null ||
+                FlightGlobals.ActiveVessel.targetObject.GetOrbit() == null ||
+                FlightGlobals.ship_orbit == null ||
+                FlightGlobals.ship_orbit.referenceBody == null)
             {
                 ShowDetails = false;
                 return;
@@ -174,55 +168,50 @@
 
             ShowDetails = true;
 
-            this.targetOrbit = FlightGlobals.fetch.VesselTarget.GetOrbit();
-            this.originOrbit = (FlightGlobals.ship_orbit.referenceBody == Planetarium.fetch.Sun || FlightGlobals.ship_orbit.referenceBody == FlightGlobals.ActiveVessel.targetObject.GetOrbit().referenceBody)
+            targetOrbit = FlightGlobals.fetch.VesselTarget.GetOrbit();
+            originOrbit = (FlightGlobals.ship_orbit.referenceBody == Planetarium.fetch.Sun ||
+                           FlightGlobals.ship_orbit.referenceBody == FlightGlobals.ActiveVessel.targetObject.GetOrbit().referenceBody)
                 ? FlightGlobals.ship_orbit
                 : FlightGlobals.ship_orbit.referenceBody.orbit;
 
-            RelativeInclination = this.originOrbit.GetRelativeInclination(this.targetOrbit);
+            RelativeInclination = originOrbit.GetRelativeInclination(targetOrbit);
             RelativeVelocity = FlightGlobals.ship_tgtSpeed;
-            RelativeSpeed = FlightGlobals.ship_obtSpeed - this.targetOrbit.orbitalSpeed;
-            PhaseAngle = this.originOrbit.GetPhaseAngle(this.targetOrbit);
-            InterceptAngle = this.CalcInterceptAngle();
-            TimeToAscendingNode = this.originOrbit.GetTimeToVector(this.GetAscendingNode());
-            TimeToDescendingNode = this.originOrbit.GetTimeToVector(this.GetDescendingNode());
-            AngleToAscendingNode = this.originOrbit.GetAngleToVector(this.GetAscendingNode());
-            AngleToDescendingNode = this.originOrbit.GetAngleToVector(this.GetDescendingNode());
-            AltitudeSeaLevel = this.targetOrbit.altitude;
-            ApoapsisHeight = this.targetOrbit.ApA;
-            PeriapsisHeight = this.targetOrbit.PeA;
-            TimeToApoapsis = this.targetOrbit.timeToAp;
-            TimeToPeriapsis = this.targetOrbit.timeToPe;
-            SemiMajorAxis = this.targetOrbit.semiMajorAxis;
-            SemiMinorAxis = this.targetOrbit.semiMinorAxis;
-
-            Distance = Vector3d.Distance(this.targetOrbit.pos, this.originOrbit.pos);
-            OrbitalPeriod = this.targetOrbit.period;
-        }
-
-        #endregion
-
-        #region Methods: private
+            RelativeSpeed = FlightGlobals.ship_obtSpeed - targetOrbit.orbitalSpeed;
+            PhaseAngle = originOrbit.GetPhaseAngle(targetOrbit);
+            InterceptAngle = CalcInterceptAngle();
+            TimeToAscendingNode = originOrbit.GetTimeToVector(GetAscendingNode());
+            TimeToDescendingNode = originOrbit.GetTimeToVector(GetDescendingNode());
+            AngleToAscendingNode = originOrbit.GetAngleToVector(GetAscendingNode());
+            AngleToDescendingNode = originOrbit.GetAngleToVector(GetDescendingNode());
+            AltitudeSeaLevel = targetOrbit.altitude;
+            ApoapsisHeight = targetOrbit.ApA;
+            PeriapsisHeight = targetOrbit.PeA;
+            TimeToApoapsis = targetOrbit.timeToAp;
+            TimeToPeriapsis = targetOrbit.timeToPe;
+            SemiMajorAxis = targetOrbit.semiMajorAxis;
+            SemiMinorAxis = targetOrbit.semiMinorAxis;
+
+            Distance = Vector3d.Distance(targetOrbit.pos, originOrbit.pos);
+            OrbitalPeriod = targetOrbit.period;
+        }
 
         private double CalcInterceptAngle()
         {
-            var originRadius = (this.originOrbit.semiMinorAxis + this.originOrbit.semiMajorAxis) * 0.5;
-            var targetRadius = (this.targetOrbit.semiMinorAxis + this.targetOrbit.semiMajorAxis) * 0.5;
-            var angle = 180.0 * (1.0 - Math.Pow((originRadius + targetRadius) / (2.0 * targetRadius), 1.5));
+            double originRadius = (originOrbit.semiMinorAxis + originOrbit.semiMajorAxis) * 0.5;
+            double targetRadius = (targetOrbit.semiMinorAxis + targetOrbit.semiMajorAxis) * 0.5;
+            double angle = 180.0 * (1.0 - Math.Pow((originRadius + targetRadius) / (2.0 * targetRadius), 1.5));
             angle = PhaseAngle - angle;
             return RelativeInclination < 90.0 ? AngleHelper.Clamp360(angle) : AngleHelper.Clamp360(360.0 - (180.0 - angle));
         }
 
         private Vector3d GetAscendingNode()
         {
-            return Vector3d.Cross(this.targetOrbit.GetOrbitNormal(), this.originOrbit.GetOrbitNormal());
+            return Vector3d.Cross(targetOrbit.GetOrbitNormal(), originOrbit.GetOrbitNormal());
         }
 
         private Vector3d GetDescendingNode()
         {
-            return Vector3d.Cross(this.originOrbit.GetOrbitNormal(), this.targetOrbit.GetOrbitNormal());
-        }
-
-        #endregion
+            return Vector3d.Cross(originOrbit.GetOrbitNormal(), targetOrbit.GetOrbitNormal());
+        }
     }
 }

--- a/KerbalEngineer/Flight/Readouts/Surface/AtmosphericEfficiency.cs
+++ b/KerbalEngineer/Flight/Readouts/Surface/AtmosphericEfficiency.cs
@@ -1,7 +1,7 @@
 // 
 //     Kerbal Engineer Redux
 // 
-//     Copyright (C) 2014 CYBUTEK
+//     Copyright (C) 2015 CYBUTEK
 // 
 //     This program is free software: you can redistribute it and/or modify
 //     it under the terms of the GNU General Public License as published by
@@ -17,36 +17,26 @@
 //     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 // 
 
-#region Using Directives
-
-using KerbalEngineer.Extensions;
-using KerbalEngineer.Flight.Sections;
-
-#endregion
-
 namespace KerbalEngineer.Flight.Readouts.Surface
 {
+    using Extensions;
+    using Sections;
+
     public class AtmosphericEfficiency : ReadoutModule
     {
-        #region Constructors
-
         public AtmosphericEfficiency()
         {
-            this.Name = "Atmos. Efficiency";
-            this.Category = ReadoutCategory.GetCategory("Surface");
-            this.HelpString = "Shows you vessel's efficiency as a ratio of the current velocity and terminal velocity.  Less than 1 means that you are losing efficiency due to gravity and greater than 1 is due to drag.";
-            this.IsDefault = true;
+            Name = "Atmos. Efficiency";
+            Category = ReadoutCategory.GetCategory("Surface");
+            HelpString = "Shows you vessel's efficiency as a ratio of the current velocity and terminal velocity.  Less than 100% means that you are losing efficiency due to gravity and greater than 100% is due to drag.";
+            IsDefault = false;
         }
-
-        #endregion
-
-        #region Methods: public
 
         public override void Draw(SectionModule section)
         {
             if (AtmosphericProcessor.ShowDetails)
             {
-                this.DrawLine(AtmosphericProcessor.Efficiency.ToPercent(), section.IsHud);
+                DrawLine(AtmosphericProcessor.Efficiency.ToPercent(), section.IsHud);
             }
         }
 
@@ -59,7 +49,5 @@
         {
             AtmosphericProcessor.RequestUpdate();
         }
-
-        #endregion
     }
 }

--- a/KerbalEngineer/Flight/Readouts/Surface/HorizontalSpeed.cs
+++ b/KerbalEngineer/Flight/Readouts/Surface/HorizontalSpeed.cs
@@ -21,6 +21,7 @@
 
 using KerbalEngineer.Extensions;
 using KerbalEngineer.Flight.Sections;
+using System;
 
 #endregion
 
@@ -44,7 +45,11 @@
 
         public override void Draw(SectionModule section)
         {
-            this.DrawLine(FlightGlobals.ActiveVessel.horizontalSrfSpeed.ToSpeed(), section.IsHud);
+            // Used to do this but the bug-fix to horizontalSrfSpeed in KSP 1.0.3 actually made it worse so workaround
+            //this.DrawLine(FlightGlobals.ActiveVessel.horizontalSrfSpeed.ToSpeed(), section.IsHud);
+            var ves = FlightGlobals.ActiveVessel;
+            double horizSpeed = Math.Sqrt(ves.srfSpeed * ves.srfSpeed - ves.verticalSpeed * ves.verticalSpeed);
+            this.DrawLine(horizSpeed.ToSpeed(), section.IsHud);
         }
 
         #endregion

--- a/KerbalEngineer/Flight/Readouts/Surface/Longitude.cs
+++ b/KerbalEngineer/Flight/Readouts/Surface/Longitude.cs
@@ -17,35 +17,25 @@
 //     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 // 
 
-#region Using Directives
-
-using KerbalEngineer.Flight.Sections;
-
-#endregion
-
 namespace KerbalEngineer.Flight.Readouts.Surface
 {
+    using Helpers;
+    using Sections;
+
     public class Longitude : ReadoutModule
     {
-        #region Constructors
-
         public Longitude()
         {
-            this.Name = "Longitude";
-            this.Category = ReadoutCategory.GetCategory("Surface");
-            this.HelpString = "Shows the vessel's longitude around a celestial body.  Longitude is the angle from the bodies prime meridian.";
-            this.IsDefault = true;
+            Name = "Longitude";
+            Category = ReadoutCategory.GetCategory("Surface");
+            HelpString = "Shows the vessel's longitude around a celestial body.  Longitude is the angle from the bodies prime meridian.";
+            IsDefault = true;
         }
-
-        #endregion
-
-        #region Methods: public
 
         public override void Draw(SectionModule section)
         {
-            this.DrawLine(KSPUtil.PrintLongitude(FlightGlobals.ship_longitude), section.IsHud);
+            double angle = AngleHelper.Clamp180(FlightGlobals.ship_longitude);
+            DrawLine(Units.ToAngleDMS(angle) + (angle < 0.0 ? "W" : " E"), section.IsHud);
         }
-
-        #endregion
     }
 }

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Surface/MachNumber.cs
@@ -1,1 +1,43 @@
+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2015 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
 
+namespace KerbalEngineer.Flight.Readouts.Surface
+{
+    using Extensions;
+    using Sections;
+
+    public class MachNumber : ReadoutModule
+    {
+        public MachNumber()
+        {
+            Name = "Mach Number";
+            Category = ReadoutCategory.GetCategory("Surface");
+            HelpString = "Shows the vessel's mach number.";
+            IsDefault = true;
+        }
+
+        public override void Draw(SectionModule section)
+        {
+            if (FlightGlobals.ActiveVessel.atmDensity > 0.0)
+            {
+                DrawLine(FlightGlobals.ActiveVessel.mach.ToMach(), section.IsHud);
+            }
+        }
+    }
+}

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Thermal/ConvectionFlux.cs
@@ -1,1 +1,53 @@
+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2015 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
 
+namespace KerbalEngineer.Flight.Readouts.Thermal
+{
+    using Extensions;
+    using Sections;
+
+    public class ConvectionFlux : ReadoutModule
+    {
+        public ConvectionFlux()
+        {
+            Name = "Convection Flux";
+            Category = ReadoutCategory.GetCategory("Thermal");
+            HelpString = string.Empty;
+            IsDefault = true;
+        }
+
+        public override void Draw(SectionModule section)
+        {
+            if (ThermalProcessor.ShowDetails && FlightGlobals.ActiveVessel.atmDensity > 0.0)
+            {
+                DrawLine(ThermalProcessor.ConvectionFlux.ToFlux(), section.IsHud);
+            }
+        }
+
+        public override void Reset()
+        {
+            FlightEngineerCore.Instance.AddUpdatable(ThermalProcessor.Instance);
+        }
+
+        public override void Update()
+        {
+            ThermalProcessor.RequestUpdate();
+        }
+    }
+}

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Thermal/CoolestPart.cs
@@ -1,1 +1,52 @@
+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2015 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
 
+namespace KerbalEngineer.Flight.Readouts.Thermal
+{
+    using Sections;
+
+    public class CoolestPart : ReadoutModule
+    {
+        public CoolestPart()
+        {
+            Name = "Coolest Part";
+            Category = ReadoutCategory.GetCategory("Thermal");
+            HelpString = string.Empty;
+            IsDefault = true;
+        }
+
+        public override void Draw(SectionModule section)
+        {
+            if (ThermalProcessor.ShowDetails)
+            {
+                DrawLine(ThermalProcessor.CoolestPartName, section.IsHud);
+            }
+        }
+
+        public override void Reset()
+        {
+            FlightEngineerCore.Instance.AddUpdatable(ThermalProcessor.Instance);
+        }
+
+        public override void Update()
+        {
+            ThermalProcessor.RequestUpdate();
+        }
+    }
+}

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Thermal/CoolestSkinTemperature.cs
@@ -1,1 +1,53 @@
+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2015 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
 
+namespace KerbalEngineer.Flight.Readouts.Thermal
+{
+    using Helpers;
+    using Sections;
+
+    public class CoolestSkinTemperature : ReadoutModule
+    {
+        public CoolestSkinTemperature()
+        {
+            Name = "Coolest Skin Temperature";
+            Category = ReadoutCategory.GetCategory("Thermal");
+            HelpString = string.Empty;
+            IsDefault = true;
+        }
+
+        public override void Draw(SectionModule section)
+        {
+            if (ThermalProcessor.ShowDetails)
+            {
+                DrawLine(Units.ToTemperature(ThermalProcessor.CoolestSkinTemperature, ThermalProcessor.CoolestSkinTemperatureMax), section.IsHud);
+            }
+        }
+
+        public override void Reset()
+        {
+            FlightEngineerCore.Instance.AddUpdatable(ThermalProcessor.Instance);
+        }
+
+        public override void Update()
+        {
+            ThermalProcessor.RequestUpdate();
+        }
+    }
+}

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Thermal/CoolestTemperature.cs
@@ -1,1 +1,53 @@
+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2015 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
 
+namespace KerbalEngineer.Flight.Readouts.Thermal
+{
+    using Helpers;
+    using Sections;
+
+    public class CoolestTemperature : ReadoutModule
+    {
+        public CoolestTemperature()
+        {
+            Name = "Coolest Temperature";
+            Category = ReadoutCategory.GetCategory("Thermal");
+            HelpString = string.Empty;
+            IsDefault = true;
+        }
+
+        public override void Draw(SectionModule section)
+        {
+            if (ThermalProcessor.ShowDetails)
+            {
+                DrawLine(Units.ToTemperature(ThermalProcessor.CoolestTemperature, ThermalProcessor.CoolestTemperatureMax), section.IsHud);
+            }
+        }
+
+        public override void Reset()
+        {
+            FlightEngineerCore.Instance.AddUpdatable(ThermalProcessor.Instance);
+        }
+
+        public override void Update()
+        {
+            ThermalProcessor.RequestUpdate();
+        }
+    }
+}

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Thermal/CriticalPart.cs
@@ -1,1 +1,52 @@
+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2015 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
 
+namespace KerbalEngineer.Flight.Readouts.Thermal
+{
+    using Sections;
+
+    public class CriticalPart : ReadoutModule
+    {
+        public CriticalPart()
+        {
+            Name = "Critical Part";
+            Category = ReadoutCategory.GetCategory("Thermal");
+            HelpString = string.Empty;
+            IsDefault = true;
+        }
+
+        public override void Draw(SectionModule section)
+        {
+            if (ThermalProcessor.ShowDetails)
+            {
+                DrawLine(ThermalProcessor.CriticalPartName, section.IsHud);
+            }
+        }
+
+        public override void Reset()
+        {
+            FlightEngineerCore.Instance.AddUpdatable(ThermalProcessor.Instance);
+        }
+
+        public override void Update()
+        {
+            ThermalProcessor.RequestUpdate();
+        }
+    }
+}

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Thermal/CriticalSkinTemperature.cs
@@ -1,1 +1,53 @@
+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2015 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
 
+namespace KerbalEngineer.Flight.Readouts.Thermal
+{
+    using Helpers;
+    using Sections;
+
+    public class CriticalSkinTemperature : ReadoutModule
+    {
+        public CriticalSkinTemperature()
+        {
+            Name = "Critical Skin Temperature";
+            Category = ReadoutCategory.GetCategory("Thermal");
+            HelpString = string.Empty;
+            IsDefault = true;
+        }
+
+        public override void Draw(SectionModule section)
+        {
+            if (ThermalProcessor.ShowDetails)
+            {
+                DrawLine(Units.ToTemperature(ThermalProcessor.CriticalSkinTemperature, ThermalProcessor.CriticalSkinTemperatureMax), section.IsHud);
+            }
+        }
+
+        public override void Reset()
+        {
+            FlightEngineerCore.Instance.AddUpdatable(ThermalProcessor.Instance);
+        }
+
+        public override void Update()
+        {
+            ThermalProcessor.RequestUpdate();
+        }
+    }
+}

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Thermal/CriticalTemperature.cs
@@ -1,1 +1,53 @@
+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2015 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
 
+namespace KerbalEngineer.Flight.Readouts.Thermal
+{
+    using Helpers;
+    using Sections;
+
+    public class CriticalTemperature : ReadoutModule
+    {
+        public CriticalTemperature()
+        {
+            Name = "Critical Temperature";
+            Category = ReadoutCategory.GetCategory("Thermal");
+            HelpString = string.Empty;
+            IsDefault = true;
+        }
+
+        public override void Draw(SectionModule section)
+        {
+            if (ThermalProcessor.ShowDetails)
+            {
+                DrawLine(Units.ToTemperature(ThermalProcessor.CriticalTemperature, ThermalProcessor.CriticalTemperatureMax), section.IsHud);
+            }
+        }
+
+        public override void Reset()
+        {
+            FlightEngineerCore.Instance.AddUpdatable(ThermalProcessor.Instance);
+        }
+
+        public override void Update()
+        {
+            ThermalProcessor.RequestUpdate();
+        }
+    }
+}

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Thermal/CriticalThermalPercentage.cs
@@ -1,1 +1,53 @@
+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2015 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
 
+namespace KerbalEngineer.Flight.Readouts.Thermal
+{
+    using Extensions;
+    using Sections;
+
+    public class CriticalThermalPercentage : ReadoutModule
+    {
+        public CriticalThermalPercentage()
+        {
+            Name = "Critical Thermal Percentage";
+            Category = ReadoutCategory.GetCategory("Thermal");
+            HelpString = string.Empty;
+            IsDefault = true;
+        }
+
+        public override void Draw(SectionModule section)
+        {
+            if (ThermalProcessor.ShowDetails)
+            {
+                DrawLine(ThermalProcessor.CriticalTemperaturePercentage.ToPercent(), section.IsHud);
+            }
+        }
+
+        public override void Reset()
+        {
+            FlightEngineerCore.Instance.AddUpdatable(ThermalProcessor.Instance);
+        }
+
+        public override void Update()
+        {
+            ThermalProcessor.RequestUpdate();
+        }
+    }
+}

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Thermal/HottestPart.cs
@@ -1,1 +1,52 @@
+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2015 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
 
+namespace KerbalEngineer.Flight.Readouts.Thermal
+{
+    using Sections;
+
+    public class HottestPart : ReadoutModule
+    {
+        public HottestPart()
+        {
+            Name = "Hottest Part";
+            Category = ReadoutCategory.GetCategory("Thermal");
+            HelpString = string.Empty;
+            IsDefault = true;
+        }
+
+        public override void Draw(SectionModule section)
+        {
+            if (ThermalProcessor.ShowDetails)
+            {
+                DrawLine(ThermalProcessor.HottestPartName, section.IsHud);
+            }
+        }
+
+        public override void Reset()
+        {
+            FlightEngineerCore.Instance.AddUpdatable(ThermalProcessor.Instance);
+        }
+
+        public override void Update()
+        {
+            ThermalProcessor.RequestUpdate();
+        }
+    }
+}

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Thermal/HottestSkinTemperature.cs
@@ -1,1 +1,53 @@
+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2015 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
 
+namespace KerbalEngineer.Flight.Readouts.Thermal
+{
+    using Helpers;
+    using Sections;
+
+    public class HottestSkinTemperature : ReadoutModule
+    {
+        public HottestSkinTemperature()
+        {
+            Name = "Hottest Skin Temperature";
+            Category = ReadoutCategory.GetCategory("Thermal");
+            HelpString = string.Empty;
+            IsDefault = true;
+        }
+
+        public override void Draw(SectionModule section)
+        {
+            if (ThermalProcessor.ShowDetails)
+            {
+                DrawLine(Units.ToTemperature(ThermalProcessor.HottestSkinTemperature, ThermalProcessor.HottestSkinTemperatureMax), section.IsHud);
+            }
+        }
+
+        public override void Reset()
+        {
+            FlightEngineerCore.Instance.AddUpdatable(ThermalProcessor.Instance);
+        }
+
+        public override void Update()
+        {
+            ThermalProcessor.RequestUpdate();
+        }
+    }
+}

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Thermal/HottestTemperature.cs
@@ -1,1 +1,53 @@
+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2015 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
 
+namespace KerbalEngineer.Flight.Readouts.Thermal
+{
+    using Helpers;
+    using Sections;
+
+    public class HottestTemperature : ReadoutModule
+    {
+        public HottestTemperature()
+        {
+            Name = "Hottest Temperature";
+            Category = ReadoutCategory.GetCategory("Thermal");
+            HelpString = string.Empty;
+            IsDefault = true;
+        }
+
+        public override void Draw(SectionModule section)
+        {
+            if (ThermalProcessor.ShowDetails)
+            {
+                DrawLine(Units.ToTemperature(ThermalProcessor.HottestTemperature, ThermalProcessor.HottestTemperatureMax), section.IsHud);
+            }
+        }
+
+        public override void Reset()
+        {
+            FlightEngineerCore.Instance.AddUpdatable(ThermalProcessor.Instance);
+        }
+
+        public override void Update()
+        {
+            ThermalProcessor.RequestUpdate();
+        }
+    }
+}

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Thermal/InternalFlux.cs
@@ -1,1 +1,53 @@
+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2015 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
 
+namespace KerbalEngineer.Flight.Readouts.Thermal
+{
+    using Extensions;
+    using Sections;
+
+    public class InternalFlux : ReadoutModule
+    {
+        public InternalFlux()
+        {
+            Name = "Internal Flux";
+            Category = ReadoutCategory.GetCategory("Thermal");
+            HelpString = string.Empty;
+            IsDefault = true;
+        }
+
+        public override void Draw(SectionModule section)
+        {
+            if (ThermalProcessor.ShowDetails)
+            {
+                DrawLine(ThermalProcessor.InternalFlux.ToFlux(), section.IsHud);
+            }
+        }
+
+        public override void Reset()
+        {
+            FlightEngineerCore.Instance.AddUpdatable(ThermalProcessor.Instance);
+        }
+
+        public override void Update()
+        {
+            ThermalProcessor.RequestUpdate();
+        }
+    }
+}

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Thermal/RadiationFlux.cs
@@ -1,1 +1,53 @@
+// 
+//     Kerbal Engineer Redux
+// 
+//     Copyright (C) 2015 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
 
+namespace KerbalEngineer.Flight.Readouts.Thermal
+{
+    using Extensions;
+    using Sections;
+
+    public class RadiationFlux : ReadoutModule
+    {
+        public RadiationFlux()
+        {
+            Name = "Radiation Flux";
+            Category = ReadoutCategory.GetCategory("Thermal");
+            HelpString = string.Empty;
+            IsDefault = true;
+        }
+
+        public override void Draw(SectionModule section)
+        {
+            if (ThermalProcessor.ShowDetails)
+            {
+                DrawLine(ThermalProcessor.RadiationFlux.ToFlux(), section.IsHud);
+            }
+        }
+
+        public override void Reset()
+        {
+            FlightEngineerCore.Instance.AddUpdatable(ThermalProcessor.Instance);
+        }
+
+        public override void Update()
+        {
+            ThermalProcessor.RequestUpdate();
+        }
+    }
+}

--- /dev/null
+++ b/KerbalEngineer/Flight/Readouts/Thermal/ThermalProcessor.cs
@@ -1,1 +1,161 @@
+// 
+//     Copyright (C) 2015 CYBUTEK
+// 
+//     This program is free software: you can redistribute it and/or modify
+//     it under the terms of the GNU General Public License as published by
+//     the Free Software Foundation, either version 3 of the License, or
+//     (at your option) any later version.
+// 
+//     This program is distributed in the hope that it will be useful,
+//     but WITHOUT ANY WARRANTY; without even the implied warranty of
+//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//     GNU General Public License for more details.
+// 
+//     You should have received a copy of the GNU General Public License
+//     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+// 
 
+namespace KerbalEngineer.Flight.Readouts.Thermal
+{
+    using System;
+
+    public class ThermalProcessor : IUpdatable, IUpdateRequest
+    {
+        private static readonly ThermalProcessor instance = new ThermalProcessor();
+
+        static ThermalProcessor()
+        {
+            HottestTemperature = 0.0;
+            HottestTemperatureMax = 0.0;
+            HottestSkinTemperature = 0.0;
+            HottestSkinTemperatureMax = 0.0;
+            CoolestTemperature = 0.0;
+            CoolestTemperatureMax = 0.0;
+            CoolestSkinTemperature = 0.0;
+            CoolestSkinTemperatureMax = 0.0;
+            CriticalTemperature = 0.0;
+            CriticalTemperatureMax = 0.0;
+            CriticalSkinTemperature = 0.0;
+            CriticalSkinTemperatureMax = 0.0;
+            HottestPartName = string.Empty;
+            CoolestPartName = string.Empty;
+            CriticalPartName = string.Empty;
+        }
+
+        public static double ConvectionFlux { get; private set; }
+
+        public static string CoolestPartName { get; private set; }
+
+        public static double CoolestSkinTemperature { get; private set; }
+
+        public static double CoolestSkinTemperatureMax { get; private set; }
+
+        public static double CoolestTemperature { get; private set; }
+
+        public static double CoolestTemperatureMax { get; private set; }
+
+        public static string CriticalPartName { get; private set; }
+
+        public static double CriticalSkinTemperature { get; private set; }
+
+        public static double CriticalSkinTemperatureMax { get; private set; }
+
+        public static double CriticalTemperature { get; private set; }
+
+        public static double CriticalTemperatureMax { get; private set; }
+
+        public static double CriticalTemperaturePercentage { get; private set; }
+
+        public static string HottestPartName { get; private set; }
+
+        public static double HottestSkinTemperature { get; private set; }
+
+        public static double HottestSkinTemperatureMax { get; private set; }
+
+        public static double HottestTemperature { get; private set; }
+
+        public static double HottestTemperatureMax { get; private set; }
+
+        public static ThermalProcessor Instance
+        {
+            get
+            {
+                return instance;
+            }
+        }
+
+        public static double InternalFlux { get; private set; }
+
+        public static double RadiationFlux { get; private set; }
+
+        public static bool ShowDetails { get; private set; }
+
+        public void Update()
+        {
+            if (FlightGlobals.ActiveVessel.parts.Count == 0)
+            {
+                ShowDetails = false;
+                return;
+            }
+
+            ShowDetails = true;
+
+            ConvectionFlux = 0.0;
+            RadiationFlux = 0.0;
+            InternalFlux = 0.0;
+            HottestTemperature = 0.0;
+            HottestSkinTemperature = 0.0;
+            CoolestTemperature = double.MaxValue;
+            CoolestSkinTemperature = double.MaxValue;
+            CriticalTemperature = double.MaxValue;
+            CriticalSkinTemperature = double.MaxValue;
+            CriticalTemperaturePercentage = 0.0;
+            HottestPartName = string.Empty;
+            CoolestPartName = string.Empty;
+            CriticalPartName = string.Empty;
+
+            for (int i = 0; i < FlightGlobals.ActiveVessel.parts.Count; ++i)
+            {
+                Part part = FlightGlobals.ActiveVessel.parts[i];
+
+                ConvectionFlux = ConvectionFlux + part.thermalConvectionFlux;
+                RadiationFlux = RadiationFlux + part.thermalRadiationFlux;
+                InternalFlux = InternalFlux + part.thermalInternalFluxPrevious;
+
+                if (part.temperature > HottestTemperature || part.skinTemperature > HottestSkinTemperature)
+                {
+                    HottestTemperature = part.temperature;
+                    HottestTemperatureMax = part.maxTemp;
+                    HottestSkinTemperature = part.skinTemperature;
+                    HottestSkinTemperatureMax = part.skinMaxTemp;
+                    HottestPartName = part.partInfo.title;
+                }
+                if (part.temperature < CoolestTemperature || part.skinTemperature < CoolestSkinTemperature)
+                {
+                    CoolestTemperature = part.temperature;
+                    CoolestTemperatureMax = part.maxTemp;
+                    CoolestSkinTemperature = part.skinTemperature;
+                    CoolestSkinTemperatureMax = part.skinMaxTemp;
+                    CoolestPartName = part.partInfo.title;
+                }
+
+                if (part.temperature / part.maxTemp > CriticalTemperaturePercentage || part.skinTemperature / part.skinMaxTemp > CriticalTemperaturePercentage)
+                {
+                    CriticalTemperature = part.temperature;
+                    CriticalTemperatureMax = part.maxTemp;
+                    CriticalSkinTemperature = part.skinTemperature;
+                    CriticalSkinTemperatureMax = part.skinMaxTemp;
+                    CriticalTemperaturePercentage = Math.Max(part.temperature / part.maxTemp, part.skinTemperature / part.skinMaxTemp);
+                    CriticalPartName = part.partInfo.title;
+                }
+            }
+        }
+
+        public bool UpdateRequested { get; set; }
+
+        public static void RequestUpdate()
+        {
+            instance.UpdateRequested = true;
+        }
+    }
+}

--- a/KerbalEngineer/Flight/Readouts/Vessel/DeltaVStaged.cs
+++ b/KerbalEngineer/Flight/Readouts/Vessel/DeltaVStaged.cs
@@ -30,13 +30,6 @@
 {
     public class DeltaVStaged : ReadoutModule
     {
-        #region Fields
-
-        private int numberOfStages;
-        private bool showing;
-
-        #endregion
-
         #region Constructors
 
         public DeltaVStaged()

--- a/KerbalEngineer/Flight/Readouts/Vessel/IntakeAirDemandSupply.cs
+++ b/KerbalEngineer/Flight/Readouts/Vessel/IntakeAirDemandSupply.cs
@@ -55,20 +55,11 @@
             var demand = 0.0;
             foreach (var part in FlightGlobals.ActiveVessel.Parts)
             {
-                if (part.Modules.Contains("ModuleEngines"))
+                for (int i = 0; i < part.Modules.Count; i++)
                 {
-                    var engine = part.Modules["ModuleEngines"] as ModuleEngines;
-                    if (engine.isOperational)
-                    {
-                        demand += engine.propellants
-                            .Where(p => p.name == "IntakeAir")
-                            .Sum(p => p.currentRequirement);
-                    }
-                }
-                if (part.Modules.Contains("ModuleEnginesFX"))
-                {
-                    var engine = part.Modules["ModuleEnginesFX"] as ModuleEnginesFX;
-                    if (engine.isOperational)
+                    PartModule partmod = part.Modules[i];
+                    var engine = partmod as ModuleEngines;
+                    if (engine != null && engine.isOperational)
                     {
                         demand += engine.propellants
                             .Where(p => p.name == "IntakeAir")

--- a/KerbalEngineer/Flight/Readouts/Vessel/Mass.cs
+++ b/KerbalEngineer/Flight/Readouts/Vessel/Mass.cs
@@ -28,12 +28,6 @@
 {
     public class Mass : ReadoutModule
     {
-        #region Fields
-
-        private bool showing;
-
-        #endregion
-
         #region Constructors
 
         public Mass()

--- a/KerbalEngineer/Flight/Sections/SectionEditor.cs
+++ b/KerbalEngineer/Flight/Sections/SectionEditor.cs
@@ -215,15 +215,18 @@
             this.ParentSection.Name = GUILayout.TextField(this.ParentSection.Name, this.textStyle);
             var isShowingInControlBar = !string.IsNullOrEmpty(this.ParentSection.Abbreviation);
             this.ParentSection.Abbreviation = GUILayout.TextField(this.ParentSection.Abbreviation, this.textStyle, GUILayout.Width(75.0f));
+
+            ParentSection.IsHud = GUILayout.Toggle(this.ParentSection.IsHud, "HUD", this.readoutButtonStyle, GUILayout.Width(50.0f));
+            if (ParentSection.IsHud)
+            {
+                this.ParentSection.IsHudBackground = GUILayout.Toggle(this.ParentSection.IsHudBackground, "BG", this.readoutButtonStyle, GUILayout.Width(50.0f));
+            }
+
             if (this.ParentSection.IsCustom)
             {
                 if (isShowingInControlBar && string.IsNullOrEmpty(this.ParentSection.Abbreviation))
                 {
                     DisplayStack.Instance.RequestResize();
-                }
-                if (this.ParentSection.IsHud = GUILayout.Toggle(this.ParentSection.IsHud, "HUD", this.readoutButtonStyle, GUILayout.Width(50.0f)))
-                {
-                    this.ParentSection.IsHudBackground = GUILayout.Toggle(this.ParentSection.IsHudBackground, "BG", this.readoutButtonStyle, GUILayout.Width(50.0f));
                 }
 
                 if (GUILayout.Button("DELETE SECTION", this.readoutButtonStyle, GUILayout.Width(150.0f)))

--- a/KerbalEngineer/Flight/Sections/SectionLibrary.cs
+++ b/KerbalEngineer/Flight/Sections/SectionLibrary.cs
@@ -1,7 +1,7 @@
 // 
 //     Kerbal Engineer Redux
 // 
-//     Copyright (C) 2014 CYBUTEK
+//     Copyright (C) 2015 CYBUTEK
 // 
 //     This program is free software: you can redistribute it and/or modify
 //     it under the terms of the GNU General Public License as published by
@@ -19,22 +19,19 @@
 
 #region Using Directives
 
-using System.Collections.Generic;
-using System.Linq;
-
-using KerbalEngineer.Flight.Readouts;
-using KerbalEngineer.Settings;
-
-using UnityEngine;
-
 #endregion
 
 namespace KerbalEngineer.Flight.Sections
 {
+    using System.Collections.Generic;
+    using System.Linq;
+    using Readouts;
+    using Settings;
+    using UnityEngine;
+
     public static class SectionLibrary
     {
         #region Constructors
-
         /// <summary>
         ///     Sets up and populates the library with the stock sections on creation.
         /// </summary>
@@ -71,7 +68,15 @@
                 ReadoutModules = ReadoutLibrary.GetCategory(ReadoutCategory.GetCategory("Rendezvous")).Where(r => r.IsDefault).ToList()
             });
 
-            var hud1 = new SectionModule
+            CustomSections.Add(new SectionModule
+            {
+                Name = "THERMAL",
+                Abbreviation = "HEAT",
+                ReadoutModules = ReadoutLibrary.GetCategory(ReadoutCategory.GetCategory("Thermal")).Where(r => r.IsDefault).ToList(),
+                IsCustom = true
+            });
+            
+            SectionModule hud1 = new SectionModule
             {
                 Name = "HUD 1",
                 Abbreviation = "HUD 1",
@@ -90,7 +95,7 @@
             hud1.IsHud = true;
             CustomSections.Add(hud1);
 
-            var hud2 = new SectionModule
+            SectionModule hud2 = new SectionModule
             {
                 Name = "HUD 2",
                 Abbreviation = "HUD 2",
@@ -101,7 +106,8 @@
                     ReadoutLibrary.GetReadout("AltitudeTerrain"),
                     ReadoutLibrary.GetReadout("VerticalSpeed"),
                     ReadoutLibrary.GetReadout("HorizontalSpeed"),
-                    ReadoutLibrary.GetReadout("Biome")
+                    ReadoutLibrary.GetReadout("Biome"),
+                    ReadoutLibrary.GetReadout("MachNumber")
                 },
             };
             hud2.FloatingPositionX = Screen.width * 0.75f - (hud2.ReadoutModules.First().ContentWidth * 0.5f);
@@ -109,11 +115,9 @@
             hud2.IsHud = true;
             CustomSections.Add(hud2);
         }
-
         #endregion
 
         #region Properties
-
         /// <summary>
         ///     Gets and sets a list of custom sections.
         /// </summary>
@@ -133,13 +137,11 @@
         ///     Gets and sets a list of stock sections
         /// </summary>
         public static List<SectionModule> StockSections { get; set; }
-
         #endregion
 
         #region Updating
 
         #region Methods: public
-
         /// <summary>
         ///     Fixed update all of the sections.
         /// </summary>
@@ -160,17 +162,15 @@
             UpdateSections(StockSections);
             UpdateSections(CustomSections);
         }
-
         #endregion
 
         #region Methods: private
-
         /// <summary>
         ///     Fixed updates a list of sections.
         /// </summary>
         private static void FixedUpdateSections(IEnumerable<SectionModule> sections)
         {
-            foreach (var section in sections)
+            foreach (SectionModule section in sections)
             {
                 if (section.IsVisible)
                 {
@@ -184,13 +184,13 @@
         /// </summary>
         private static void UpdateSections(IEnumerable<SectionModule> sections)
         {
-            foreach (var section in sections)
+            foreach (SectionModule section in sections)
             {
                 if (section.IsVisible)
                 {
                     if (!section.IsFloating)
                     {
-                        foreach (var readout in section.ReadoutModules)
+                        foreach (ReadoutModule readout in section.ReadoutModules)
                         {
                             if (readout.ResizeRequested)
                             {
@@ -203,7 +203,7 @@
                     }
                     else
                     {
-                        foreach (var readout in section.ReadoutModules)
+                        foreach (ReadoutModule readout in section.ReadoutModules)
                         {
                             if (readout.ResizeRequested)
                             {
@@ -218,13 +218,11 @@
                 NumberOfSections++;
             }
         }
-
         #endregion
 
         #endregion
 
         #region Saving and Loading
-
         /// <summary>
         ///     Loads the state of all stored sections.
         /// </summary>
@@ -243,11 +241,11 @@
                 }
             });
 
-            var handler = SettingHandler.Load("SectionLibrary.xml", new[] {typeof(List<SectionModule>)});
+            SettingHandler handler = SettingHandler.Load("SectionLibrary.xml", new[] { typeof(List<SectionModule>) });
             StockSections = handler.Get("StockSections", StockSections);
             CustomSections = handler.Get("CustomSections", CustomSections);
 
-            foreach (var section in GetAllSections())
+            foreach (SectionModule section in GetAllSections())
             {
                 section.ClearNullReadouts();
             }
@@ -258,22 +256,20 @@
         /// </summary>
         public static void Save()
         {
-            var handler = new SettingHandler();
+            SettingHandler handler = new SettingHandler();
             handler.Set("StockSections", StockSections);
             handler.Set("CustomSections", CustomSections);
             handler.Save("SectionLibrary.xml");
         }
-
         #endregion
 
         #region Methods
-
         /// <summary>
         ///     Gets a list containing all section modules.
         /// </summary>
         public static List<SectionModule> GetAllSections()
         {
-            var sections = new List<SectionModule>();
+            List<SectionModule> sections = new List<SectionModule>();
             sections.AddRange(StockSections);
             sections.AddRange(CustomSections);
             return sections;
@@ -326,7 +322,6 @@
         {
             return StockSections.Remove(GetStockSection(name));
         }
-
         #endregion
     }
 }

--- a/KerbalEngineer/Flight/Sections/SectionWindow.cs
+++ b/KerbalEngineer/Flight/Sections/SectionWindow.cs
@@ -134,7 +134,11 @@
                                                    (!this.ParentSection.IsHud || this.ParentSection.IsEditorVisible) ? this.windowStyle
                                                        : this.ParentSection.IsHudBackground && this.ParentSection.LineCount > 0
                                                            ? this.hudWindowBgStyle
-                                                           : this.hudWindowStyle).ClampToScreen();
+                                                           : this.hudWindowStyle);
+
+            windowPosition = (ParentSection.IsHud) ? windowPosition.ClampInsideScreen() : windowPosition.ClampToScreen();
+
+
             this.ParentSection.FloatingPositionX = this.windowPosition.x;
             this.ParentSection.FloatingPositionY = this.windowPosition.y;
         }

--- a/KerbalEngineer/Helpers/AngleHelper.cs
+++ b/KerbalEngineer/Helpers/AngleHelper.cs
@@ -17,21 +17,30 @@
 //     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 // 
 
-#region Using Directives
-
-using UnityEngine;
-
-#endregion
-
 namespace KerbalEngineer.Helpers
 {
+    using UnityEngine;
+
     public static class AngleHelper
     {
-        #region Methods: public
+        public static double Clamp180(double angle)
+        {
+            angle = Clamp360(angle);
+            if (angle > 180.0)
+            {
+                angle = angle - 360.0;
+            }
+            return angle;
+        }
 
-        public static double Clamp360(double value)
+        public static double Clamp360(double angle)
         {
-            return ClampBetween(value, 0.0, 360.0);
+            angle = angle % 360.0;
+            if (angle < 0.0)
+            {
+                angle = angle + 360.0;
+            }
+            return angle;
         }
 
         public static double ClampBetween(double value, double minimum, double maximum)
@@ -51,8 +60,8 @@
 
         public static double GetAngleBetweenVectors(Vector3d left, Vector3d right)
         {
-            var angle = Vector3d.Angle(left, right);
-            var rotated = QuaternionD.AngleAxis(90.0, Vector3d.forward) * right;
+            double angle = Vector3d.Angle(left, right);
+            Vector3d rotated = QuaternionD.AngleAxis(90.0, Vector3d.forward) * right;
 
             if (Vector3d.Angle(rotated, left) > 90.0)
             {
@@ -60,7 +69,5 @@
             }
             return angle;
         }
-
-        #endregion
     }
 }

--- a/KerbalEngineer/Helpers/Units.cs
+++ b/KerbalEngineer/Helpers/Units.cs
@@ -1,7 +1,7 @@
 // 
 //     Kerbal Engineer Redux
 // 
-//     Copyright (C) 2014 CYBUTEK
+//     Copyright (C) 2015 CYBUTEK
 // 
 //     This program is free software: you can redistribute it and/or modify
 //     it under the terms of the GNU General Public License as published by
@@ -19,14 +19,10 @@
 
 namespace KerbalEngineer.Helpers
 {
-    #region Using Directives
     using System;
-
-    #endregion
 
     public static class Units
     {
-        #region Methods
         public const double GRAVITY = 9.80665;
 
         public static string Concat(int value1, int value2)
@@ -95,7 +91,7 @@
             int min = (int)Math.Floor(rem * 60);
             rem -= ((double)min / 60);
             int sec = (int)Math.Floor(rem * 3600);
-            return String.Format("{0:0}° {1:00}' {2:00}\"", deg, min, sec); 
+            return String.Format("{0:0}° {1:00}' {2:00}\"", deg, min, sec);
         }
 
         public static string ToDistance(double value, int decimals = 1)
@@ -127,6 +123,11 @@
             return value.ToString("N" + decimals) + "Mm";
         }
 
+        public static string ToFlux(double value)
+        {
+            return value.ToString("#,0.00") + "W";
+        }
+
         public static string ToForce(double value)
         {
             return value.ToString((value < 100000.0) ? (value < 10000.0) ? (value < 100.0) ? (Math.Abs(value) < Double.Epsilon) ? "N0" : "N3" : "N2" : "N1" : "N0") + "kN";
@@ -139,6 +140,11 @@
             return value1.ToString(format1) + " / " + value2.ToString(format2) + "kN";
         }
 
+        public static string ToMach(double value)
+        {
+            return value.ToString("0.00") + "Ma";
+        }
+
         public static string ToMass(double value, int decimals = 0)
         {
             if (value >= 1000.0)
@@ -182,6 +188,16 @@
             return value.ToString("N" + decimals) + "m/s";
         }
 
+        public static string ToTemperature(double value)
+        {
+            return value.ToString("#,0") + "K";
+        }
+
+        public static string ToTemperature(double value1, double value2)
+        {
+            return value1.ToString("#,0") + " / " + value2.ToString("#,0") + "K";
+        }
+
         public static string ToTime(double value)
         {
             return TimeFormatter.ConvertToString(value);
@@ -191,6 +207,5 @@
         {
             return value.ToString((value < 100.0) ? (Math.Abs(value) < Double.Epsilon) ? "N0" : "N1" : "N0") + "kNm";
         }
-        #endregion
     }
 }

--- a/KerbalEngineer/KerbalEngineer.csproj
+++ b/KerbalEngineer/KerbalEngineer.csproj
@@ -48,6 +48,7 @@
     <Compile Include="Editor\ResourceInfoItem.cs" />
     <Compile Include="Extensions\FloatExtensions.cs" />
     <Compile Include="Extensions\OrbitExtensions.cs" />
+    <Compile Include="Extensions\StringExtensions.cs" />
     <Compile Include="Flight\ActionMenuGui.cs" />
     <Compile Include="Flight\Presets\Preset.cs" />
     <Compile Include="Flight\Readouts\Miscellaneous\SystemTime.cs" />
@@ -70,11 +71,21 @@
     <Compile Include="Flight\Readouts\Orbital\ManoeuvreNode\NodeAngleToPrograde.cs" />
     <Compile Include="Flight\Readouts\Orbital\ManoeuvreNode\NodeTotalDeltaV.cs" />
     <Compile Include="Flight\Readouts\Orbital\ManoeuvreNode\NodeProgradeDeltaV.cs" />
+    <Compile Include="Flight\Readouts\Orbital\ManoeuvreNode\PostBurnApoapsis.cs" />
+    <Compile Include="Flight\Readouts\Orbital\ManoeuvreNode\PostBurnPeriapsis.cs" />
     <Compile Include="Flight\Readouts\Orbital\MeanAnomalyAtEpoc.cs" />
     <Compile Include="Flight\Readouts\Orbital\MeanAnomaly.cs" />
     <Compile Include="Flight\Readouts\Orbital\EccentricAnomaly.cs" />
     <Compile Include="Flight\Readouts\Orbital\ArgumentOfPeriapsis.cs" />
     <Compile Include="Flight\Readouts\Orbital\CurrentSoi.cs" />
+    <Compile Include="Flight\Readouts\Orbital\SemiMajorAxis.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="Flight\Readouts\Orbital\SpeedAtApoapsis.cs" />
+    <Compile Include="Flight\Readouts\Orbital\SpeedAtPeriapsis.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="Flight\Readouts\Orbital\TimeToAtmosphere.cs" />
     <Compile Include="Flight\Readouts\Orbital\TrueAnomaly.cs" />
     <Compile Include="Flight\Readouts\Orbital\TimeToEquatorialAscendingNode.cs" />
     <Compile Include="Flight\Readouts\Orbital\TimeToEquatorialDescendingNode.cs" />
@@ -89,6 +100,21 @@
     <Compile Include="Flight\Readouts\Surface\Biome.cs" />
     <Compile Include="Flight\Readouts\Surface\HorizontalAcceleration.cs" />
     <Compile Include="Flight\Readouts\Surface\VerticalAcceleration.cs" />
+    <Compile Include="Flight\Readouts\Surface\MachNumber.cs" />
+    <Compile Include="Flight\Readouts\Thermal\CoolestSkinTemperature.cs" />
+    <Compile Include="Flight\Readouts\Thermal\CriticalPart.cs" />
+    <Compile Include="Flight\Readouts\Thermal\CoolestPart.cs" />
+    <Compile Include="Flight\Readouts\Thermal\CoolestTemperature.cs" />
+    <Compile Include="Flight\Readouts\Thermal\CriticalThermalPercentage.cs" />
+    <Compile Include="Flight\Readouts\Thermal\CriticalSkinTemperature.cs" />
+    <Compile Include="Flight\Readouts\Thermal\CriticalTemperature.cs" />
+    <Compile Include="Flight\Readouts\Thermal\HottestSkinTemperature.cs" />
+    <Compile Include="Flight\Readouts\Thermal\InternalFlux.cs" />
+    <Compile Include="Flight\Readouts\Thermal\RadiationFlux.cs" />
+    <Compile Include="Flight\Readouts\Thermal\ConvectionFlux.cs" />
+    <Compile Include="Flight\Readouts\Thermal\HottestTemperature.cs" />
+    <Compile Include="Flight\Readouts\Thermal\HottestPart.cs" />
+    <Compile Include="Flight\Readouts\Thermal\ThermalProcessor.cs" />
     <Compile Include="Flight\Readouts\Vessel\AttitudeProcessor.cs" />
     <Compile Include="Flight\Readouts\Vessel\DeltaVCurrentTotal.cs" />
     <Compile Include="Flight\Readouts\Vessel\PitchRate.cs" />
@@ -145,7 +171,6 @@
     <Compile Include="Flight\Readouts\Orbital\OrbitalPeriod.cs" />
     <Compile Include="Flight\Readouts\Orbital\OrbitalSpeed.cs" />
     <Compile Include="Flight\Readouts\Orbital\PeriapsisHeight.cs" />
-    <Compile Include="Flight\Readouts\Orbital\SemiMajorAxis.cs" />
     <Compile Include="Flight\Readouts\Orbital\SemiMinorAxis.cs" />
     <Compile Include="Flight\Readouts\Orbital\TimeToApoapsis.cs" />
     <Compile Include="Flight\Readouts\Orbital\TimeToPeriapsis.cs" />
@@ -208,7 +233,7 @@
   </ItemGroup>
   <ItemGroup>
     <Reference Include="Assembly-CSharp">
-      <HintPath>..\..\..\..\..\..\Program Files (x86)\Steam\SteamApps\common\Kerbal Space Program\KSP_Data\Managed\Assembly-CSharp.dll</HintPath>
+      <HintPath>..\Game\KSP_Data\Managed\Assembly-CSharp.dll</HintPath>
       <Private>False</Private>
     </Reference>
     <Reference Include="System">
@@ -220,7 +245,7 @@
       <Private>False</Private>
     </Reference>
     <Reference Include="UnityEngine">
-      <HintPath>..\..\..\..\..\..\Program Files (x86)\Steam\SteamApps\common\Kerbal Space Program\KSP_Data\Managed\UnityEngine.dll</HintPath>
+      <HintPath>..\Game\KSP_Data\Managed\UnityEngine.dll</HintPath>
       <Private>False</Private>
     </Reference>
   </ItemGroup>

--- a/KerbalEngineer/LogMsg.cs
+++ b/KerbalEngineer/LogMsg.cs
@@ -15,7 +15,8 @@
 
         public void Flush()
         {
-            MonoBehaviour.print(this.buf);
+            if (this.buf.Length > 0)
+                MonoBehaviour.print(this.buf);
             this.buf.Length = 0;
         }
     }

--- a/KerbalEngineer/Properties/AssemblyInfo.cs
+++ b/KerbalEngineer/Properties/AssemblyInfo.cs
@@ -32,5 +32,5 @@
 // You can specify all the values or you can default the Build and Revision Numbers 
 // by using the '*' as shown below:
 // [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion(KerbalEngineer.EngineerGlobals.AssemblyVersion)]
+[assembly: AssemblyVersion(KerbalEngineer.EngineerGlobals.ASSEMBLY_VERSION)]
 

--- a/KerbalEngineer/VesselSimulator/EngineSim.cs
+++ b/KerbalEngineer/VesselSimulator/EngineSim.cs
@@ -31,6 +31,7 @@
         private static readonly Pool<EngineSim> pool = new Pool<EngineSim>(Create, Reset);
 
         private readonly ResourceContainer resourceConsumptions = new ResourceContainer();
+        private readonly ResourceContainer resourceFlowModes = new ResourceContainer();
 
         public double actualThrust = 0;
         public bool isActive = false;
@@ -52,6 +53,7 @@
         private static void Reset(EngineSim engineSim)
         {
             engineSim.resourceConsumptions.Reset();
+            engineSim.resourceFlowModes.Reset();
             engineSim.actualThrust = 0;
             engineSim.isActive = false;
             engineSim.isp = 0;
@@ -86,11 +88,10 @@
                          List<Propellant> propellants,
                          bool active,
                          float resultingThrust,
-                         List<Transform> thrustTransforms)
+                         List<Transform> thrustTransforms,
+                        LogMsg log)
         {
             EngineSim engineSim = pool.Borrow();
-
-            StringBuilder buffer = null;
 
             engineSim.isp = 0.0;
             engineSim.maxMach = 0.0f;
@@ -99,61 +100,75 @@
             engineSim.isActive = active;
             engineSim.thrustVec = vecThrust;
             engineSim.resourceConsumptions.Reset();
+            engineSim.resourceFlowModes.Reset();
             engineSim.appliedForces.Clear();
 
             double flowRate = 0.0;
             if (engineSim.partSim.hasVessel)
             {
+                if (log != null) log.buf.AppendLine("hasVessel is true"); 
+
                 float flowModifier = GetFlowModifier(atmChangeFlow, atmCurve, engineSim.partSim.part.atmDensity, velCurve, machNumber, ref engineSim.maxMach);
                 engineSim.isp = atmosphereCurve.Evaluate((float)atmosphere);
                 engineSim.thrust = GetThrust(Mathf.Lerp(minFuelFlow, maxFuelFlow, GetThrustPercent(thrustPercentage)) * flowModifier, engineSim.isp);
                 engineSim.actualThrust = engineSim.isActive ? resultingThrust : 0.0;
+                if (log != null)
+                {
+                    log.buf.AppendFormat("flowMod = {0:g6}\n", flowModifier);
+                    log.buf.AppendFormat("isp     = {0:g6}\n", engineSim.isp);
+                    log.buf.AppendFormat("thrust  = {0:g6}\n", engineSim.thrust);
+                    log.buf.AppendFormat("actual  = {0:g6}\n", engineSim.actualThrust);
+                }
 
                 if (throttleLocked)
                 {
+                    if (log != null) log.buf.AppendLine("throttleLocked is true, using thrust for flowRate");
                     flowRate = GetFlowRate(engineSim.thrust, engineSim.isp);
                 }
                 else
                 {
                     if (currentThrottle > 0.0f && engineSim.partSim.isLanded == false)
                     {
+                        if (log != null) log.buf.AppendLine("throttled up and not landed, using actualThrust for flowRate");
                         flowRate = GetFlowRate(engineSim.actualThrust, engineSim.isp);
                     }
                     else
                     {
+                        if (log != null) log.buf.AppendLine("throttled down or landed, using thrust for flowRate");
                         flowRate = GetFlowRate(engineSim.thrust, engineSim.isp);
                     }
                 }
             }
             else
             {
+                if (log != null) log.buf.AppendLine("hasVessel is false");
                 float flowModifier = GetFlowModifier(atmChangeFlow, atmCurve, CelestialBodies.SelectedBody.GetDensity(BuildAdvanced.Altitude), velCurve, machNumber, ref engineSim.maxMach);
                 engineSim.isp = atmosphereCurve.Evaluate((float)atmosphere);
                 engineSim.thrust = GetThrust(Mathf.Lerp(minFuelFlow, maxFuelFlow, GetThrustPercent(thrustPercentage)) * flowModifier, engineSim.isp);
+                engineSim.actualThrust = 0d;
+                if (log != null)
+                {
+                    log.buf.AppendFormat("flowMod = {0:g6}\n", flowModifier);
+                    log.buf.AppendFormat("isp     = {0:g6}\n", engineSim.isp);
+                    log.buf.AppendFormat("thrust  = {0:g6}\n", engineSim.thrust);
+                    log.buf.AppendFormat("actual  = {0:g6}\n", engineSim.actualThrust);
+                }
+
+                if (log != null) log.buf.AppendLine("no vessel, using thrust for flowRate");
                 flowRate = GetFlowRate(engineSim.thrust, engineSim.isp);
             }
 
-            if (SimManager.logOutput)
-            {
-                buffer = new StringBuilder(1024);
-                buffer.AppendFormat("flowRate = {0:g6}\n", flowRate);
-            }
-
-            engineSim.thrust = flowRate * (engineSim.isp * IspG);
-            // I did not look into the diff between those 2 so I made them equal...
-            engineSim.actualThrust = engineSim.thrust;
+            if (log != null) log.buf.AppendFormat("flowRate = {0:g6}\n", flowRate);
 
             float flowMass = 0f;
             for (int i = 0; i < propellants.Count; ++i)
             {
                 Propellant propellant = propellants[i];
-                flowMass += propellant.ratio * ResourceContainer.GetResourceDensity(propellant.id);
-            }
-
-            if (SimManager.logOutput)
-            {
-                buffer.AppendFormat("flowMass = {0:g6}\n", flowMass);
-            }
+                if (!propellant.ignoreForIsp)
+                    flowMass += propellant.ratio * ResourceContainer.GetResourceDensity(propellant.id);
+            }
+
+            if (log != null) log.buf.AppendFormat("flowMass = {0:g6}\n", flowMass);
 
             for (int i = 0; i < propellants.Count; ++i)
             {
@@ -165,21 +180,14 @@
                 }
 
                 double consumptionRate = propellant.ratio * flowRate / flowMass;
-                if (SimManager.logOutput)
-                {
-                    buffer.AppendFormat(
+                if (log != null) log.buf.AppendFormat(
                         "Add consumption({0}, {1}:{2:d}) = {3:g6}\n",
                         ResourceContainer.GetResourceName(propellant.id),
                         theEngine.name,
                         theEngine.partId,
                         consumptionRate);
-                }
                 engineSim.resourceConsumptions.Add(propellant.id, consumptionRate);
-            }
-
-            if (SimManager.logOutput)
-            {
-                MonoBehaviour.print(buffer);
+                engineSim.resourceFlowModes.Add(propellant.id, (double)propellant.GetFlowMode());
             }
 
             double thrustPerThrustTransform = engineSim.thrust / thrustTransforms.Count;
@@ -285,7 +293,7 @@
                     sourcePartSets.Add(type, sourcePartSet);
                 }
 
-                switch (ResourceContainer.GetResourceFlowMode(type))
+                switch ((ResourceFlowMode)this.resourceFlowModes[type])
                 {
                     case ResourceFlowMode.NO_FLOW:
                         if (partSim.resources[type] > SimManager.RESOURCE_MIN && partSim.resourceFlowStates[type] != 0)

--- a/KerbalEngineer/VesselSimulator/PartSim.cs
+++ b/KerbalEngineer/VesselSimulator/PartSim.cs
@@ -34,14 +34,15 @@
 
         private readonly List<AttachNodeSim> attachNodes = new List<AttachNodeSim>();
 
+        public double realMass;
         public double baseMass;
+        public double baseMassForCoM;
         public Vector3d centerOfMass;
-        public double cost;
+        public double baseCost;
         public int decoupledInStage;
         public bool fuelCrossFeed;
         public List<PartSim> fuelTargets = new List<PartSim>();
         public bool hasModuleEngines;
-        public bool hasModuleEnginesFX;
         public bool hasMultiModeEngine;
 
         public bool hasVessel;
@@ -55,8 +56,7 @@
         public bool isNoPhysics;
         public bool isSepratron;
         public bool isFairing;
-        public bool localCorrectThrust;
-        public float moduleMass;
+        public float fairingMass;
         public int stageIndex;
         public String name;
         public String noCrossFeedNodeKey;
@@ -88,7 +88,9 @@
             partSim.resourceDrains.Reset();
             partSim.resourceFlowStates.Reset();
             partSim.resources.Reset();
+            partSim.baseCost = 0d;
             partSim.baseMass = 0d;
+            partSim.baseMassForCoM = 0d;
             partSim.startMass = 0d;
         }
 
@@ -100,15 +102,13 @@
         public static PartSim New(Part thePart, int id, double atmosphere, LogMsg log)
         {
             PartSim partSim = pool.Borrow();
-
 
             partSim.part = thePart;
             partSim.centerOfMass = thePart.transform.TransformPoint(thePart.CoMOffset);
             partSim.partId = id;
             partSim.name = partSim.part.partInfo.name;
 
-            if (log != null)
-                log.buf.AppendLine("Create PartSim for " + partSim.name);
+            if (log != null) log.buf.AppendLine("Create PartSim for " + partSim.name);
 
             partSim.parent = null;
             partSim.parentAttach = partSim.part.attachMode;
@@ -118,25 +118,38 @@
             partSim.isFuelLine = partSim.part.HasModule<CModuleFuelLine>();
             partSim.isFuelTank = partSim.part is FuelTank;
             partSim.isSepratron = partSim.IsSepratron();
+            partSim.isFairing = partSim.IsFairing(partSim.part);
             partSim.inverseStage = partSim.part.inverseStage;
             //MonoBehaviour.print("inverseStage = " + inverseStage);
 
-            partSim.cost = partSim.part.GetCostWet();
+            partSim.baseCost = partSim.part.GetCostDry();
+
+            if (log != null)
+            {
+                log.buf.AppendLine("Parent part = " + (partSim.part.parent == null ? "null" : partSim.part.parent.partInfo.name));
+                log.buf.AppendLine("physicalSignificance = " + partSim.part.physicalSignificance);
+                log.buf.AppendLine("PhysicsSignificance = " + partSim.part.PhysicsSignificance);
+            }
 
             // Work out if the part should have no physical significance
+            // The root part is never "no physics"
             partSim.isNoPhysics = partSim.part.physicalSignificance == Part.PhysicalSignificance.NONE ||
-                               partSim.part.PhysicsSignificance == 1;
+                                    partSim.part.PhysicsSignificance == 1;
 
             if (partSim.part.HasModule<LaunchClamp>())
             {
-                if (log != null)
-                  log.buf.AppendLine("Ignoring mass of launch clamp");
+                partSim.realMass = 0d;
+                if (log != null) log.buf.AppendLine("Ignoring mass of launch clamp");
             }
             else
             {
-                partSim.baseMass = partSim.part.mass;
-                if (log != null)
-                    log.buf.AppendLine("Using part.mass of " + partSim.part.mass);
+                partSim.realMass = partSim.part.mass;
+                if (log != null) log.buf.AppendLine("Using part.mass of " + partSim.part.mass);
+            }
+
+            if (partSim.isFairing)
+            {
+                partSim.fairingMass = partSim.part.GetModuleMass((float)partSim.realMass);
             }
 
             for (int i = 0; i < partSim.part.Resources.Count; i++)
@@ -155,12 +168,9 @@
                 }
                 else
                 {
-                    if (log != null)
-                        log.buf.AppendLine(resource.resourceName + " is NaN. Skipping.");
-                }
-            }
-
-            partSim.startMass = partSim.GetMass(-1);
+                    if (log != null) log.buf.AppendLine(resource.resourceName + " is NaN. Skipping.");
+                }
+            }
 
             partSim.hasVessel = (partSim.part.vessel != null);
             partSim.isLanded = partSim.hasVessel && partSim.part.vessel.Landed;
@@ -172,13 +182,11 @@
             partSim.initialVesselName = partSim.part.initialVesselName;
 
             partSim.hasMultiModeEngine = partSim.part.HasModule<MultiModeEngine>();
-            partSim.hasModuleEnginesFX = partSim.part.HasModule<ModuleEnginesFX>();
             partSim.hasModuleEngines = partSim.part.HasModule<ModuleEngines>();
 
-            partSim.isEngine = partSim.hasMultiModeEngine || partSim.hasModuleEnginesFX || partSim.hasModuleEngines;
-
-            if (log != null)
-                log.buf.AppendLine("Created " + partSim.name + ". Decoupled in stage " + partSim.decoupledInStage);
+            partSim.isEngine = partSim.hasMultiModeEngine || partSim.hasModuleEngines;
+
+            if (log != null) log.buf.AppendLine("Created " + partSim.name + ". Decoupled in stage " + partSim.decoupledInStage);
 
             return partSim;
         }
@@ -201,7 +209,6 @@
 
         public void CreateEngineSims(List<EngineSim> allEngines, double atmosphere, double mach, bool vectoredThrust, bool fullThrust, LogMsg log)
         {
-            bool correctThrust = SimManager.DoesEngineUseCorrectedThrust(part);
             if (log != null)
             {
                 log.buf.AppendLine("CreateEngineSims for " + this.name);
@@ -210,26 +217,21 @@
                     PartModule partMod = this.part.Modules[i];
                     log.buf.AppendLine("Module: " + partMod.moduleName);
                 }
-
-                log.buf.AppendLine("correctThrust = " + correctThrust);
             }
 
             if (hasMultiModeEngine)
             {
-                // A multi-mode engine has multiple ModuleEnginesFX but only one is active at any point
-                // The mode of the engine is the engineID of the ModuleEnginesFX that is active
+                // A multi-mode engine has multiple ModuleEngines but only one is active at any point
+                // The mode of the engine is the engineID of the ModuleEngines that is active
                 string mode = part.GetModule<MultiModeEngine>().mode;
 
-                List<ModuleEnginesFX> engines = part.GetModules<ModuleEnginesFX>();
+                List<ModuleEngines> engines = part.GetModules<ModuleEngines>();
                 for (int i = 0; i < engines.Count; ++i)
                 {
-                    ModuleEnginesFX engine = engines[i];
+                    ModuleEngines engine = engines[i];
                     if (engine.engineID == mode)
                     {
-                        if (log != null)
-                        {
-                            log.buf.AppendLine("Module: " + engine.moduleName);
-                        }
+                        if (log != null) log.buf.AppendLine("Module: " + engine.moduleName);
 
                         Vector3 thrustvec = this.CalculateThrustVector(vectoredThrust ? engine.thrustTransforms : null, log);
 
@@ -251,47 +253,43 @@
                             engine.propellants,
                             engine.isOperational,
                             engine.resultingThrust,
-                            engine.thrustTransforms);
+                            engine.thrustTransforms,
+                            log);
                         allEngines.Add(engineSim);
                     }
                 }
             }
-            else
-            {
-                if (hasModuleEngines)
-                {
-                    List<ModuleEngines> engines = part.GetModules<ModuleEngines>();
-                    for (int i = 0; i < engines.Count; ++i)
-                    {
-                        ModuleEngines engine = engines[i];
-                        if (log != null)
-                        {
-                            log.buf.AppendLine("Module: " + engine.moduleName);
-                        }
-
-                        Vector3 thrustvec = this.CalculateThrustVector(vectoredThrust ? engine.thrustTransforms : null, log);
-
-                        EngineSim engineSim = EngineSim.New(
-                            this,
-                            atmosphere,
-                            (float)mach,
-                            engine.maxFuelFlow,
-                            engine.minFuelFlow,
-                            engine.thrustPercentage,
-                            thrustvec,
-                            engine.atmosphereCurve,
-                            engine.atmChangeFlow,
-                            engine.useAtmCurve ? engine.atmCurve : null,
-                            engine.useVelCurve ? engine.velCurve : null,
-                            engine.currentThrottle,
-                            engine.g,
-                            engine.throttleLocked || fullThrust,
-                            engine.propellants,
-                            engine.isOperational,
-                            engine.resultingThrust,
-                            engine.thrustTransforms);
-                        allEngines.Add(engineSim);
-                    }
+            else if (hasModuleEngines)
+            {
+                List<ModuleEngines> engines = part.GetModules<ModuleEngines>();
+                for (int i = 0; i < engines.Count; ++i)
+                {
+                    ModuleEngines engine = engines[i];
+                    if (log != null) log.buf.AppendLine("Module: " + engine.moduleName);
+
+                    Vector3 thrustvec = this.CalculateThrustVector(vectoredThrust ? engine.thrustTransforms : null, log);
+
+                    EngineSim engineSim = EngineSim.New(
+                        this,
+                        atmosphere,
+                        (float)mach,
+                        engine.maxFuelFlow,
+                        engine.minFuelFlow,
+                        engine.thrustPercentage,
+                        thrustvec,
+                        engine.atmosphereCurve,
+                        engine.atmChangeFlow,
+                        engine.useAtmCurve ? engine.atmCurve : null,
+                        engine.useVelCurve ? engine.velCurve : null,
+                        engine.currentThrottle,
+                        engine.g,
+                        engine.throttleLocked || fullThrust,
+                        engine.propellants,
+                        engine.isOperational,
+                        engine.resultingThrust,
+                        engine.thrustTransforms,
+                        log);
+                    allEngines.Add(engineSim);
                 }
             }
 
@@ -348,9 +346,13 @@
             buffer.Append(name);
             buffer.AppendFormat(":[id = {0:d}, decouple = {1:d}, invstage = {2:d}", partId, decoupledInStage, inverseStage);
 
-            buffer.AppendFormat(", vesselName = '{0}'", vesselName);
-            buffer.AppendFormat(", vesselType = {0}", SimManager.GetVesselTypeString(vesselType));
-            buffer.AppendFormat(", initialVesselName = '{0}'", initialVesselName);
+            //buffer.AppendFormat(", vesselName = '{0}'", vesselName);
+            //buffer.AppendFormat(", vesselType = {0}", SimManager.GetVesselTypeString(vesselType));
+            //buffer.AppendFormat(", initialVesselName = '{0}'", initialVesselName);
+
+            buffer.AppendFormat(", isNoPhys = {0}", isNoPhysics);
+            buffer.AppendFormat(", baseMass = {0}", baseMass);
+            buffer.AppendFormat(", baseMassForCoM = {0}", baseMassForCoM);
 
             buffer.AppendFormat(", fuelCF = {0}", fuelCrossFeed);
             buffer.AppendFormat(", noCFNKey = '{0}'", noCrossFeedNodeKey);
@@ -386,9 +388,7 @@
                 {
                     PartSim partSim = allParts[i];
                     if (partSim.parent == this)
-                    {
                         partSim.DumpPartToBuffer(buffer, newPrefix, allParts);
-                    }
                 }
             }
         }
@@ -398,31 +398,51 @@
             foreach (int type in types)
             {
                 if (resources.HasType(type) && resourceFlowStates[type] != 0 && resources[type] > SimManager.RESOURCE_PART_EMPTY_THRESH)
-                {
                     return false;
-                }
             }
 
             return true;
         }
 
-        public double GetMass(int currentStage)
-        {
-            double mass = baseMass;
+        public double GetMass(int currentStage, bool forCoM = false)
+        {
+            if (decoupledInStage >= currentStage)
+                return 0d;
+
+            double mass = forCoM ? baseMassForCoM : baseMass;
 
             for (int i = 0; i < resources.Types.Count; ++i)
             {
                 mass += resources.GetResourceMass(resources.Types[i]);
             }
 
-            if (hasVessel == false && isFairing && inverseStage < currentStage)
-            {
-                mass = mass + moduleMass;
+            if (hasVessel == false && isFairing && currentStage > inverseStage)
+            {
+                mass += fairingMass;
+            }
+            else if (hasVessel && isFairing && currentStage <= inverseStage)
+            {
+                mass -= fairingMass;
             }
 
             return mass;
         }
-                
+
+        public double GetCost(int currentStage)
+        {
+            if (decoupledInStage >= currentStage)
+                return 0d;
+
+            double cost = baseCost;
+
+            for (int i = 0; i < resources.Types.Count; ++i)
+            {
+                cost += resources.GetResourceCost(resources.Types[i]);
+            }
+
+            return cost;
+        }
+
         public void ReleasePart()
         {
             this.part = null;
@@ -442,14 +462,11 @@
             // Rule 1: Each part can be only visited once, If it is visited for second time in particular search it returns as is.
             if (visited.Contains(this))
             {
-                if (log != null)
-                    log.buf.AppendLine(indent + "Returning empty set, already visited (" + name + ":" + partId + ")");
-
+                if (log != null) log.buf.AppendLine(indent + "Returning empty set, already visited (" + name + ":" + partId + ")");
                 return;
             }
 
-            if (log != null)
-                log.buf.AppendLine(indent + "Adding this to visited");
+            if (log != null) log.buf.AppendLine(indent + "Adding this to visited");
 
             visited.Add(this);
 
@@ -466,13 +483,11 @@
                 {
                     if (visited.Contains(partSim))
                     {
-                        if (log != null)
-                            log.buf.AppendLine(indent + "Fuel target already visited, skipping (" + partSim.name + ":" + partSim.partId + ")");
+                        if (log != null) log.buf.AppendLine(indent + "Fuel target already visited, skipping (" + partSim.name + ":" + partSim.partId + ")");
                     }
                     else
                     {
-                        if (log != null)
-                            log.buf.AppendLine(indent + "Adding fuel target as source (" + partSim.name + ":" + partSim.partId + ")");
+                        if (log != null) log.buf.AppendLine(indent + "Adding fuel target as source (" + partSim.name + ":" + partSim.partId + ")");
 
                         partSim.GetSourceSet(type, allParts, visited, allSources, log, indent);
                     }
@@ -481,9 +496,7 @@
 
             if (allSources.Count > lastCount)
             {
-                if (log != null)
-                    log.buf.AppendLine(indent + "Returning " + (allSources.Count - lastCount) + " fuel target sources (" + this.name + ":" + this.partId + ")");
-
+                if (log != null) log.buf.AppendLine(indent + "Returning " + (allSources.Count - lastCount) + " fuel target sources (" + this.name + ":" + this.partId + ")");
                 return;
             }
 
@@ -512,13 +525,11 @@
                             {
                                 if (visited.Contains(attachSim.attachedPartSim))
                                 {
-                                    if (log != null)
-                                        log.buf.AppendLine(indent + "Attached part already visited, skipping (" + attachSim.attachedPartSim.name + ":" + attachSim.attachedPartSim.partId + ")");
+                                    if (log != null) log.buf.AppendLine(indent + "Attached part already visited, skipping (" + attachSim.attachedPartSim.name + ":" + attachSim.attachedPartSim.partId + ")");
                                 }
                                 else
                                 {
-                                    if (log != null)
-                                        log.buf.AppendLine(indent + "Adding attached part as source (" + attachSim.attachedPartSim.name + ":" + attachSim.attachedPartSim.partId + ")");
+                                    if (log != null) log.buf.AppendLine(indent + "Adding attached part as source (" + attachSim.attachedPartSim.name + ":" + attachSim.attachedPartSim.partId + ")");
 
                                     attachSim.attachedPartSim.GetSourceSet(type, allParts, visited, allSources, log, indent);
                                 }
@@ -529,9 +540,7 @@
 
                 if (allSources.Count > lastCount)
                 {
-                    if (log != null)
-                        log.buf.AppendLine(indent + "Returning " + (allSources.Count - lastCount) + " attached sources (" + this.name + ":" + this.partId + ")");
-
+                    if (log != null) log.buf.AppendLine(indent + "Returning " + (allSources.Count - lastCount) + " attached sources (" + this.name + ":" + this.partId + ")");
                     return;
                 }
             }
@@ -546,16 +555,14 @@
                 {
                     allSources.Add(this);
 
-                    if (log != null)
-                        log.buf.AppendLine(indent + "Returning enabled tank as only source (" + name + ":" + partId + ")");
+                    if (log != null) log.buf.AppendLine(indent + "Returning enabled tank as only source (" + name + ":" + partId + ")");
                 }
 
                 return;
             }
             else
             {
-                if (log != null)
-                    log.buf.AppendLine(indent + "Not fuel tank or disabled. HasType = " + resources.HasType(type) + "  FlowState = " + resourceFlowStates[type]);
+                if (log != null) log.buf.AppendLine(indent + "Not fuel tank or disabled. HasType = " + resources.HasType(type) + "  FlowState = " + resourceFlowStates[type]);
             }
 
             // Rule 7: If the part is radially attached to another part and it is child of that part in the ship's tree structure, it scans its 
@@ -566,8 +573,7 @@
                 {
                     if (visited.Contains(parent))
                     {
-                        if (log != null)
-                            log.buf.AppendLine(indent + "Parent part already visited, skipping (" + parent.name + ":" + parent.partId + ")");
+                        if (log != null) log.buf.AppendLine(indent + "Parent part already visited, skipping (" + parent.name + ":" + parent.partId + ")");
                     }
                     else
                     {
@@ -575,9 +581,7 @@
                         this.parent.GetSourceSet(type, allParts, visited, allSources, log, indent);
                         if (allSources.Count > lastCount)
                         {
-                            if (log != null)
-                                log.buf.AppendLine(indent + "Returning " + (allSources.Count  - lastCount) + " parent sources (" + this.name + ":" + this.partId + ")");
-
+                            if (log != null) log.buf.AppendLine(indent + "Returning " + (allSources.Count  - lastCount) + " parent sources (" + this.name + ":" + this.partId + ")");
                             return;
                         }
                     }
@@ -585,8 +589,7 @@
             }
 
             // Rule 8: If all preceding rules failed, part returns empty list.
-            if (log != null)
-                log.buf.AppendLine(indent + "Returning empty set, no sources found (" + name + ":" + partId + ")");
+            if (log != null) log.buf.AppendLine(indent + "Returning empty set, no sources found (" + name + ":" + partId + ")");
 
             return;
         }
@@ -623,10 +626,7 @@
 
         public void SetupAttachNodes(Dictionary<Part, PartSim> partSimLookup, LogMsg log)
         {
-            if (log != null)
-            {
-                log.buf.AppendLine("SetupAttachNodes for " + name + ":" + partId + "");
-            }
+            if (log != null) log.buf.AppendLine("SetupAttachNodes for " + name + ":" + partId + "");
 
             attachNodes.Clear();
 
@@ -634,29 +634,20 @@
             {
                 AttachNode attachNode = part.attachNodes[i];
 
-                if (log != null)
-                {
-                    log.buf.AppendLine("AttachNode " + attachNode.id + " = " + (attachNode.attachedPart != null ? attachNode.attachedPart.partInfo.name : "null"));
-                }
+                if (log != null) log.buf.AppendLine("AttachNode " + attachNode.id + " = " + (attachNode.attachedPart != null ? attachNode.attachedPart.partInfo.name : "null"));
 
                 if (attachNode.attachedPart != null && attachNode.id != "Strut")
                 {
                     PartSim attachedSim;
                     if (partSimLookup.TryGetValue(attachNode.attachedPart, out attachedSim))
                     {
-                        if (log != null)
-                        {
-                            log.buf.AppendLine("Adding attached node " + attachedSim.name + ":" + attachedSim.partId + "");
-                        }
+                        if (log != null) log.buf.AppendLine("Adding attached node " + attachedSim.name + ":" + attachedSim.partId + "");
 
                         attachNodes.Add(AttachNodeSim.New(attachedSim, attachNode.id, attachNode.nodeType));
                     }
                     else
                     {
-                        if (log != null)
-                        {
-                            log.buf.AppendLine("No PartSim for attached part (" + attachNode.attachedPart.partInfo.name + ")");
-                        }
+                        if (log != null) log.buf.AppendLine("No PartSim for attached part (" + attachNode.attachedPart.partInfo.name + ")");
                     }
                 }
             }
@@ -670,38 +661,15 @@
                     PartSim targetSim;
                     if (partSimLookup.TryGetValue(p, out targetSim))
                     {
-                        if (log != null)
-                        {
-                            log.buf.AppendLine("Fuel target: " + targetSim.name + ":" + targetSim.partId);
-                        }
+                        if (log != null) log.buf.AppendLine("Fuel target: " + targetSim.name + ":" + targetSim.partId);
 
                         fuelTargets.Add(targetSim);
                     }
                     else
                     {
-                        if (log != null)
-                        {
-                            log.buf.AppendLine("No PartSim for fuel target (" + p.name + ")");
-                        }
-                    }
-                }
-            }
-
-            if (isNoPhysics)
-            {
-                if (log != null)
-                    log.buf.AppendLine("Moving NoPhysics part mass of " + this.baseMass + " to parent part");
-
-                // Go up the parent chain until we find a part that is physically significant or we reach the root
-                PartSim MassParent = parent;
-                while (MassParent.isNoPhysics && (MassParent.parent != null))
-                    MassParent = MassParent.parent;
-
-                // Apply this part's mass to the part we have found
-                MassParent.baseMass += this.baseMass;
-
-                // And zero out this part's mass
-                this.baseMass = 0;
+                        if (log != null) log.buf.AppendLine("No PartSim for fuel target (" + p.name + ")");
+                    }
+                }
             }
         }
 
@@ -712,13 +680,11 @@
                 parent = null;
                 if (partSimLookup.TryGetValue(part.parent, out parent))
                 {
-                    if (log != null)
-                        log.buf.AppendLine("Parent part is " + parent.name + ":" + parent.partId);
+                    if (log != null) log.buf.AppendLine("Parent part is " + parent.name + ":" + parent.partId);
                 }
                 else
                 {
-                    if (log != null)
-                        log.buf.AppendLine("No PartSim for parent part (" + part.parent.partInfo.name + ")");
+                    if (log != null) log.buf.AppendLine("No PartSim for parent part (" + part.parent.partInfo.name + ")");
                 }
             }
         }
@@ -756,43 +722,27 @@
             {
                 Transform trans = thrustTransforms[i];
 
-                if (log != null)
-                {
-                    log.buf.AppendFormat("Transform = ({0:g6}, {1:g6}, {2:g6})   length = {3:g6}\n", trans.forward.x, trans.forward.y, trans.forward.z, trans.forward.magnitude);
-                }
+                if (log != null) log.buf.AppendFormat("Transform = ({0:g6}, {1:g6}, {2:g6})   length = {3:g6}\n", trans.forward.x, trans.forward.y, trans.forward.z, trans.forward.magnitude);
 
                 thrustvec -= trans.forward;
             }
 
-            if (log != null)
-            {
-                log.buf.AppendFormat("ThrustVec  = ({0:g6}, {1:g6}, {2:g6})   length = {3:g6}\n", thrustvec.x, thrustvec.y, thrustvec.z, thrustvec.magnitude);
-            }
+            if (log != null) log.buf.AppendFormat("ThrustVec  = ({0:g6}, {1:g6}, {2:g6})   length = {3:g6}\n", thrustvec.x, thrustvec.y, thrustvec.z, thrustvec.magnitude);
 
             thrustvec.Normalize();
 
-            if (log != null)
-            {
-                log.buf.AppendFormat("ThrustVecN = ({0:g6}, {1:g6}, {2:g6})   length = {3:g6}\n", thrustvec.x, thrustvec.y, thrustvec.z, thrustvec.magnitude);
-            }
+            if (log != null) log.buf.AppendFormat("ThrustVecN = ({0:g6}, {1:g6}, {2:g6})   length = {3:g6}\n", thrustvec.x, thrustvec.y, thrustvec.z, thrustvec.magnitude);
 
             return thrustvec;
         }
 
         private int DecoupledInStage(Part thePart, int stage = -1)
         {
-            if (IsDecoupler(thePart))
-            {
-                if (thePart.inverseStage > stage)
-                {
-                    stage = thePart.inverseStage;
-                }
-            }
+            if (IsDecoupler(thePart) && thePart.inverseStage > stage)
+                stage = thePart.inverseStage;
 
             if (thePart.parent != null)
-            {
                 stage = DecoupledInStage(thePart.parent, stage);
-            }
 
             return stage;
         }

--- a/KerbalEngineer/VesselSimulator/ResourceContainer.cs
+++ b/KerbalEngineer/VesselSimulator/ResourceContainer.cs
@@ -150,6 +150,12 @@
             return density == 0d ? 0d : this.resources[type] * density;
         }
 
+        public double GetResourceCost(int type)
+        {
+            double unitCost = GetResourceUnitCost(type);
+            return unitCost == 0d ? 0d : this.resources[type] * unitCost;
+        }
+
         public static ResourceFlowMode GetResourceFlowMode(int type)
         {
             return PartResourceLibrary.Instance.GetDefinition(type).resourceFlowMode;
@@ -157,7 +163,7 @@
 
         public static ResourceTransferMode GetResourceTransferMode(int type)
         {
-            return PartResourceLibrary.Instance.GetDefinition(type).resourceTransferMode;;
+            return PartResourceLibrary.Instance.GetDefinition(type).resourceTransferMode;
         }
 
         public static float GetResourceDensity(int type)
@@ -169,5 +175,10 @@
         {
             return PartResourceLibrary.Instance.GetDefinition(type).name;
         }
+
+        public static double GetResourceUnitCost(int type)
+        {
+            return PartResourceLibrary.Instance.GetDefinition(type).unitCost;
+        }
     }
 }

--- a/KerbalEngineer/VesselSimulator/Simulation.cs
+++ b/KerbalEngineer/VesselSimulator/Simulation.cs
@@ -30,6 +30,7 @@
 
 namespace KerbalEngineer.VesselSimulator
 {
+    using System.ComponentModel;
     using CompoundParts;
     using Extensions;
     using Helpers;
@@ -75,7 +76,6 @@
         public String vesselName;
         public VesselType vesselType;
         private WeightedVectorAverager vectorAverager = new WeightedVectorAverager();
-        private static ModuleProceduralFairing moduleProceduralFairing;
 
         public Simulation()
         {
@@ -119,7 +119,7 @@
                 for (int i = 0; i < allParts.Count; ++i)
                 {
                     PartSim partSim = allParts[i];
-                    vectorAverager.Add(partSim.centerOfMass, partSim.GetMass(currentStage));
+                    vectorAverager.Add(partSim.centerOfMass, partSim.GetMass(currentStage, true));
                 }
 
                 return vectorAverager.Get();
@@ -139,6 +139,7 @@
                 log.buf.AppendLine("PrepareSimulation started");
                 dumpTree = true;
             }
+            this._timer.Reset();
             this._timer.Start();
 
             // Store the parameters in members for ease of access in other functions
@@ -299,6 +300,7 @@
                 MonoBehaviour.print("RunSimulation started");
             }
 
+            this._timer.Reset();
             this._timer.Start();
 
             LogMsg log = null;
@@ -382,13 +384,14 @@
             // Create the array of stages that will be returned
             Stage[] stages = new Stage[this.currentStage + 1];
 
+            int startStage = currentStage;
+
             // Loop through the stages
             while (this.currentStage >= 0)
             {
                 if (log != null)
                 {
                     log.buf.AppendLine("Simulating stage " + this.currentStage);
-                    log.buf.AppendLine("ShipMass = " + this.ShipMass);
                     log.Flush();
                     this._timer.Reset();
                     this._timer.Start();
@@ -397,13 +400,18 @@
                 // Update active engines and resource drains
                 this.UpdateResourceDrains();
 
+                // Update the masses of the parts to correctly handle "no physics" parts
+                this.stageStartMass = this.UpdatePartMasses();
+
+                if (log != null)
+                    this.allParts[0].DumpPartToBuffer(log.buf, "", this.allParts);
+
                 // Create the Stage object for this stage
                 Stage stage = new Stage();
 
                 this.stageTime = 0d;
                 this.vecStageDeltaV = Vector3.zero;
 
-                this.stageStartMass = this.ShipMass;
                 this.stageStartCom = this.ShipCom;
 
                 this.stepStartMass = this.stageStartMass;
@@ -413,11 +421,11 @@
 
                 // Store various things in the Stage object
                 stage.thrust = this.totalStageThrust;
-                //MonoBehaviour.print("stage.thrust = " + stage.thrust);
+                if (log != null) log.buf.AppendLine("stage.thrust = " + stage.thrust);
                 stage.thrustToWeight = this.totalStageThrust / (this.stageStartMass * this.gravity);
                 stage.maxThrustToWeight = stage.thrustToWeight;
-                //MonoBehaviour.print("StageMass = " + stageStartMass);
-                //MonoBehaviour.print("Initial maxTWR = " + stage.maxThrustToWeight);
+                if (log != null) log.buf.AppendLine("StageMass = " + stageStartMass);
+                if (log != null) log.buf.AppendLine("Initial maxTWR = " + stage.maxThrustToWeight);
                 stage.actualThrust = this.totalStageActualThrust;
                 stage.actualThrustToWeight = this.totalStageActualThrust / (this.stageStartMass * this.gravity);
 
@@ -442,22 +450,31 @@
 
                 stage.thrustOffsetAngle = Math.Asin(sinThrustOffsetAngle) * 180 / Math.PI;
 
-                // Calculate the cost and mass of this stage and add all engines and tanks that are decoupled
-                // in the next stage to the dontStageParts list
+                // Calculate the total cost of the vessel at this point
+                stage.totalCost = 0d;
                 for (int i = 0; i < allParts.Count; ++i)
                 {
-                    PartSim partSim = allParts[i];
-
-                    if (partSim.decoupledInStage == this.currentStage - 1)
-                    {
-                        stage.cost += partSim.cost;
-                        stage.mass += partSim.GetStartMass();
-                    }
-
-                    if (partSim.hasVessel == false && partSim.isFairing && partSim.inverseStage == currentStage)
-                    {
-                        stage.mass += partSim.moduleMass;
-                    }
+                    if (this.currentStage > allParts[i].decoupledInStage)
+                        stage.totalCost += allParts[i].GetCost(currentStage);
+                }
+
+                // The total mass is simply the mass at the start of the stage
+                stage.totalMass = this.stageStartMass;
+
+                // If we have done a previous stage
+                if (currentStage < startStage)
+                {
+                    // Calculate what the previous stage's mass and cost were by subtraction
+                    Stage prev = stages[currentStage + 1];
+                    prev.cost = prev.totalCost - stage.totalCost;
+                    prev.mass = prev.totalMass - stage.totalMass;
+                }
+
+                // The above code will never run for the last stage so set those directly
+                if (currentStage == 0)
+                {
+                    stage.cost = stage.totalCost;
+                    stage.mass = stage.totalMass;
                 }
 
                 this.dontStageParts = dontStagePartsLists[this.currentStage];
@@ -620,8 +637,6 @@
                 // For each stage we total up the cost, mass, deltaV and time for this stage and all the stages above
                 for (int j = i; j >= 0; j--)
                 {
-                    stages[i].totalCost += stages[j].cost;
-                    stages[i].totalMass += stages[j].mass;
                     stages[i].totalDeltaV += stages[j].deltaV;
                     stages[i].totalTime += stages[j].time;
                     stages[i].partCount = i > 0 ? stages[i].totalPartCount - stages[i - 1].totalPartCount : stages[i].totalPartCount;
@@ -648,6 +663,52 @@
             FreePooledObject();
             
             return stages;
+        }
+
+        public double UpdatePartMasses()
+        {
+            for (int i = 0; i < this.allParts.Count; i++)
+            {
+                this.allParts[i].baseMass = this.allParts[i].realMass;
+                this.allParts[i].baseMassForCoM = this.allParts[i].realMass;
+            }
+
+            for (int i = 0; i < this.allParts.Count; i++)
+            {
+                PartSim part = this.allParts[i];
+
+                // Check if part should pass it's mass onto its parent.
+                if (part.isNoPhysics && part.parent != null)
+                {
+                    PartSim partParent = part.parent;
+
+                    // Loop through all parents until a physically significant parent is found.
+                    while (partParent != null)
+                    {
+                        // Check if parent is physically significant.
+                        if (partParent.isNoPhysics == false)
+                        {
+                            // Apply the mass to the parent and remove it from the originating part.
+                            partParent.baseMassForCoM += part.baseMassForCoM;
+                            part.baseMassForCoM = 0.0;
+
+                            // Break out of the recursive loop.
+                            break;
+                        }
+
+                        // Recursively loop through the parent parts.
+                        partParent = partParent.parent;
+                    }
+                }
+            }
+
+            double totalMass = 0d;
+            for (int i = 0; i < this.allParts.Count; i++)
+            {
+                totalMass += this.allParts[i].startMass = this.allParts[i].GetMass(currentStage);
+            }
+
+            return totalMass;
         }
 
         // Make sure we free them all, even if they should all be free already at this point

 Binary files a/Output/KerbalEngineer/KerbalEngineer.dll and b/Output/KerbalEngineer/KerbalEngineer.dll differ
--- a/Output/KerbalEngineer/KerbalEngineer.version
+++ b/Output/KerbalEngineer/KerbalEngineer.version
@@ -5,13 +5,13 @@
 	{
 		"MAJOR":1,
 		"MINOR":0,
-		"PATCH":16,
-		"BUILD":6
+		"PATCH":17,
+		"BUILD":0
 	},
 	"KSP_VERSION":
 	{
 		"MAJOR":1,
 		"MINOR":0,
-		"PATCH":2
+		"PATCH":4
 	}
 }