Generally compatible with TT refactor. ttrefactor
Generally compatible with TT refactor.

file:a/EVAManager.cfg (deleted)
--- a/EVAManager.cfg
+++ /dev/null
@@ -1,74 +1,1 @@
-// EVAManager
-//
-// EVAPartModule.cfg
-//
-// Copyright © 2014, toadicus
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without modification,
-// are permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice,
-//    this list of conditions and the following disclaimer.
-//
-// 2. Redistributions in binary form must reproduce the above copyright notice,
-//    this list of conditions and the following disclaimer in the documentation and/or other
-//    materials provided with the distribution.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
-// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-DELETE_EVA_RESOURCE[EVA\sPropellant] {}
-
-EVA_RESOURCE
-{
-	name = EVA Propellant
-	amount = 0
-	maxAmount = 5
-}
-
-@PART[*]:HAS[#CrewCapacity[1]]
-{
-	RESOURCE
-	{
-		name = EVA Propellant
-		amount = 5
-		maxAmount = 5
-	}
-}
-
-@PART[*]:HAS[#CrewCapacity[2]]
-{
-	RESOURCE
-	{
-		name = EVA Propellant
-		amount = 10
-		maxAmount = 10
-	}
-}
-
-@PART[*]:HAS[#CrewCapacity[3]]
-{
-	RESOURCE
-	{
-		name = EVA Propellant
-		amount = 15
-		maxAmount = 15
-	}
-}
-
-@PART[*]:HAS[#CrewCapacity[4]]
-{
-	RESOURCE
-	{
-		name = EVA Propellant
-		amount = 20
-		maxAmount = 20
-	}
-}
-

--- a/EVAManager.cs
+++ b/EVAManager.cs
@@ -29,6 +29,7 @@
 using System.Linq;
 using System.Text.RegularExpressions;
 using ToadicusTools;
+using ToadicusTools.Extensions;
 using UnityEngine;
 
 namespace EVAManager
@@ -43,10 +44,13 @@
 
 		private const string empty = "";
 
+		private const string MODULE = "MODULE";
+		private const string RESOURCE = "RESOURCE";
+
 		private List<ConfigAction> evaConfigs;
 		private List<ConfigAction> passQueue;
 
-		private Part evaPart;
+		private List<Part> evaParts;
 
 		private Pass pass;
 
@@ -54,6 +58,7 @@
 		{
 			pass = Pass.Collect;
 			this.passQueue = new List<ConfigAction>();
+			this.evaParts = new List<Part>();
 		}
 
 		public virtual void Update()
@@ -64,7 +69,7 @@
 			}
 
 			#if DEBUG
-			Tools.DebugLogger log;
+			Logging.DebugLogger log;
 			#endif
 
 			if (this.passQueue.Count > 0 && this.evaConfigs != null)
@@ -74,19 +79,25 @@
 				this.passQueue.Clear();
 			}
 
+			ConfigAction action;
+
 			switch (pass)
 			{
 				case Pass.Collect:
-					foreach (var loadedPart in PartLoader.LoadedPartsList)
-					{
-						if (loadedPart.name.ToLower() == "kerbaleva")
+					AvailablePart loadedPart;
+					for (int idx = 0; idx < PartLoader.LoadedPartsList.Count; idx++)
+					{
+						loadedPart = PartLoader.LoadedPartsList[idx];
+						string lowerName = loadedPart.name.ToLower();
+
+						if (lowerName == "kerbaleva" || lowerName == "kerbalevafemale")
 						{
-							Tools.PostDebugMessage(this, "Found {0}", loadedPart.name);
-
-							evaPart = loadedPart.partPrefab;
+							this.LogDebug("Found {0}", loadedPart.name);
+
+							evaParts.Add(loadedPart.partPrefab);
 
 							#if DEBUG
-							log = Tools.DebugLogger.New(this);
+							log = Logging.DebugLogger.New(this);
 
 							log.AppendLine("Modules before run:");
 
@@ -110,7 +121,10 @@
 							log.Print();
 							#endif
 
-							break;
+							if (this.evaParts.Count == 2)
+							{
+								break;
+							}
 						}
 					}
 
@@ -118,9 +132,12 @@
 
 					Regex rgx = new Regex(patchPattern);
 
-					foreach (var urlConfig in GameDatabase.Instance.root.AllConfigs)
-					{
-						Tools.PostDebugMessage(
+					UrlDir.UrlConfig urlConfig;
+					IEnumerator<UrlDir.UrlConfig> enumerator = GameDatabase.Instance.root.AllConfigs.GetEnumerator();
+					while (enumerator.MoveNext())
+					{
+						urlConfig = enumerator.Current;
+						Logging.PostDebugMessage(
 							this,
 							"Checking urlconfig; name: {0}, type: {1}, config.name: {2}",
 							urlConfig.name,
@@ -129,7 +146,7 @@
 
 						Match match = rgx.Match(urlConfig.type);
 
-						Tools.PostDebugMessage(this, "Found {0}match for {1}{2}",
+						this.LogDebug("Found {0}match for {1}{2}",
 							!match.Success ? "no " : "",
 							urlConfig.type,
 							!match.Success ? "" : string.Format(
@@ -152,33 +169,32 @@
 					pass = Pass.Delete;
 					break;
 				case Pass.Delete:
-					foreach (ConfigAction action in this.evaConfigs)
-					{
+					for (int idx = 0; idx < this.evaConfigs.Count; idx++)
+					{
+						action = this.evaConfigs[idx];
 						if (action.Operator == "DELETE")
 						{
-							Tools.PostDebugMessage(this, "Trying delete action on {0}", action);
+							this.LogDebug("Trying delete action on {0}", action);
 
 							if (action.MatchName == string.Empty)
 							{
-								Debug.LogWarning(string.Format(
-									"[{0}] match name required for 'delete' action but not present; ignoring.",
-									this.GetType().Name));
+								this.LogWarning("Match name required for 'delete' action but not present; ignoring.");
 								continue;
 							}
 
 							switch (action.ClassType)
 							{
-								case "MODULE":
-									this.delModuleByName(action.MatchName);
+								case MODULE:
+									this.delModuleByName(evaParts[0], action.MatchName);
+									this.delModuleByName(evaParts[1], action.MatchName);
 									break;
-								case "RESOURCE":
-									this.delResourceByName(action.MatchName);
+								case RESOURCE:
+									this.delResourceByName(evaParts[0], action.MatchName);
+									this.delResourceByName(evaParts[1], action.MatchName);
 									break;
 								default:
-									Debug.LogWarning(string.Format(
-										"[{0}] Class type '{1}' not implemented for 'delete' action.",
-										this.GetType().Name,
-										action.ClassType));
+									this.LogWarning("Class type '{0}' not implemented for 'delete' action.",
+										action.ClassType);
 									continue;
 							}
 						}
@@ -187,33 +203,32 @@
 					pass = Pass.Edit;
 					break;
 				case Pass.Edit:
-					foreach (ConfigAction action in this.evaConfigs)
-					{
+					for (int idx = 0; idx < this.evaConfigs.Count; idx++)
+					{
+						action = this.evaConfigs[idx];
 						if (action.Operator == "EDIT")
 						{
-							Tools.PostDebugMessage(this, "Trying edit action on {0}", action);
+							this.LogDebug("Trying edit action on {0}", action);
 
 							if (action.MatchName == string.Empty)
 							{
-								Debug.LogWarning(string.Format(
-									"[{0}] match name required for 'edit' action but not present; ignoring.",
-									this.GetType().Name));
+								this.LogWarning("Match name required for 'edit' action but not present; ignoring.");
 								continue;
 							}
 
 							switch (action.ClassType)
 							{
-								case "MODULE":
-									this.editModuleByNameFromConfig(action.MatchName, action.Node);
+								case MODULE:
+									this.editModuleByNameFromConfig(evaParts[0], action.MatchName, action.Node);
+									this.editModuleByNameFromConfig(evaParts[1], action.MatchName, action.Node);
 									break;
-								case "RESOURCE":
-									this.editResourceByNameFromConfig(action.MatchName, action.Node);
+								case RESOURCE:
+									this.editResourceByNameFromConfig(evaParts[0], action.MatchName, action.Node);
+									this.editResourceByNameFromConfig(evaParts[1], action.MatchName, action.Node);
 									break;
 								default:
-									Debug.LogWarning(string.Format(
-										"[{0}] Class type '{1}' not implemented for 'delete' action.",
-										this.GetType().Name,
-										action.ClassType));
+									this.LogWarning("Class type '{0}' not implemented for 'delete' action.",
+										action.ClassType);
 									continue;
 							}
 						}
@@ -221,31 +236,30 @@
 					pass = Pass.Insert;
 					break;
 				case Pass.Insert:
-					foreach (ConfigAction action in this.evaConfigs)
-					{
+					for (int idx = 0; idx < this.evaConfigs.Count; idx++)
+					{
+						action = this.evaConfigs[idx];
 						if (action.Operator == empty)
 						{
 							if (action.MatchName != string.Empty)
 							{
-								Debug.LogWarning(string.Format(
-									"[{0}] match name ('{1}') not used for 'add' action; ignoring.",
-									this.GetType().Name,
-									action.MatchName));
+								this.LogWarning("match name ('{0}') not used for 'add' action; ignoring.",
+									action.MatchName);
 							}
 
 							switch (action.ClassType)
 							{
-								case "MODULE":
-									this.addModuleFromConfig(action.Node);
+								case MODULE:
+									this.addModuleFromConfig(evaParts[0], action.Node);
+									this.addModuleFromConfig(evaParts[1], action.Node);
 									break;
-								case "RESOURCE":
-									this.addResourceFromConfig(action.Node);
+								case RESOURCE:
+									this.addResourceFromConfig(evaParts[0], action.Node);
+									this.addResourceFromConfig(evaParts[1], action.Node);
 									break;
 								default:
-									Debug.LogWarning(string.Format(
-										"[{0}] Class type '{1}' not implemented for 'add' action.",
-										this.GetType().Name,
-										action.ClassType));
+									this.LogWarning("Class type '{0}' not implemented for 'add' action.",
+										action.ClassType);
 									continue;
 							}
 						}
@@ -254,7 +268,7 @@
 					break;
 				case Pass.Done:
 					#if DEBUG
-					log = Tools.DebugLogger.New(this);
+					log = Logging.DebugLogger.New(this);
 
 					log.AppendLine("Modules after run:");
 
@@ -280,36 +294,28 @@
 
 					GameObject.Destroy(this);
 
-					Tools.PostDebugMessage(this, "Destruction Requested.");
+					this.LogDebug("Destruction Requested.");
 					break;
 			}
 		}
 
-		private void addModuleFromConfig(ConfigNode evaModuleNode)
+		private void addModuleFromConfig(Part evaPart, ConfigNode evaModuleNode)
 		{
 			string moduleName;
 
 			if (evaModuleNode.TryGetValue("name", out moduleName))
 			{
-				if (evaPart.GetComponents<PartModule>().Any(m => m.GetType().Name == moduleName))
-				{
-					Debug.LogWarning(string.Format(
-						"[{0}] Skipping module {1}: already present in kerbalEVA",
-						this.GetType().Name,
-						moduleName
-					));
+				/*if (evaPart.GetComponents<PartModule>().Any(m => m.GetType().Name == moduleName))
+				{
+					this.LogWarning("Skipping module {0}: already present in kerbalEVA", moduleName);
 					return;
-				}
+				}*/
 
 				Type moduleClass = AssemblyLoader.GetClassByName(typeof(PartModule), moduleName);
 
 				if (moduleClass == null)
 				{
-					Debug.LogWarning(string.Format(
-						"[{0}] Skipping module {1}: class not found in loaded assemblies.",
-						this.GetType().Name,
-						moduleName
-					));
+					this.LogWarning("Skipping module {0}: class not found in loaded assemblies.", moduleName);
 					return;
 				}
 
@@ -329,10 +335,8 @@
 				}
 				catch (Exception ex)
 				{
-					Debug.Log(string.Format(
-						"TweakableEVAManager handled exception {0} while adding modules to kerbalEVA.",
-						ex.GetType().Name
-					));
+					this.LogError("Handled exception {0} while adding modules to {1}.",
+						ex.GetType().Name, evaPart);
 
 					#if DEBUG
 					Debug.LogException(ex);
@@ -341,119 +345,96 @@
 
 				if (evaPart.GetComponents<PartModule>().Any(m => m.GetType().Name == moduleName))
 				{
-					Debug.Log(string.Format("[{0}] added module {1} to kerbalEVA part.",
-						this.GetType().Name,
-						moduleName
-					));
+					this.Log("Added module {0} to {1}.", moduleName, evaPart);
 				}
 				else
 				{
-					Debug.LogWarning(string.Format(
-						"[{0}] failed to add {1} to kerbalEVA part.",
-						this.GetType().Name,
-						moduleName
-					));
+					this.LogWarning("Failed to add {0} to {1}.", moduleName, evaPart);
 				}
 			}
 			else
 			{
-				Debug.Log(string.Format(
-					"[{0}] Skipping malformed EVA_MODULE node: missing 'name' field.",
-					this.GetType().Name
-				));
+				this.LogWarning("Skipping malformed EVA_MODULE node: missing 'name' field.");
 				return;
 			}
 		}
 
-		private void addResourceFromConfig(ConfigNode evaResourceNode)
+		private void addResourceFromConfig(Part evaPart, ConfigNode evaResourceNode)
 		{
 			string resourceName;
 
 			if (evaResourceNode.TryGetValue("name", out resourceName))
 			{
-				Tools.PostDebugMessage(this, "Adding resource '{0}'", resourceName);
+				this.LogDebug("Adding resource '{0}'", resourceName);
 
 				PartResourceDefinition resourceInfo =
 					PartResourceLibrary.Instance.GetDefinition(resourceName);
 
 				if (resourceInfo == null)
 				{
-					Debug.LogWarning(string.Format(
-						"[{0}]: Skipping resource {1}: definition not present in library.",
-						this.GetType().Name,
-						resourceName
-					));
+					this.LogWarning("Skipping resource {0}: definition not present in library.", resourceName);
 
 					return;
 				}
 
-				Tools.PostDebugMessage(this, "Resource '{0}' is in library.", resourceName);
+				this.LogDebug("Resource '{0}' is in library.", resourceName);
 
 				if (evaPart.GetComponents<PartResource>().Any(r => r.resourceName == resourceName))
 				{
-					Debug.LogWarning(string.Format(
-						"[{0}] Skipping resource {1}: already present in kerbalEVA.",
-						this.GetType().Name,
-						resourceName
-					));
+					this.LogWarning("Skipping resource {0}: already present in kerbalEVA.", resourceName);
 
 					return;
 				}
 
-				Tools.PostDebugMessage(this, "Resource '{0}' is not present.", resourceName);
+				this.LogDebug("Resource '{0}' is not present.", resourceName);
 
 				PartResource resource = evaPart.gameObject.AddComponent<EVAPartResource>();
 
-				Tools.PostDebugMessage(this, "Resource '{0}' component built.", resourceName);
+				this.LogDebug("Resource '{0}' component built.", resourceName);
 
 				resource.SetInfo(resourceInfo);
 				((EVAPartResource)resource).Load(evaResourceNode);
 
-				Debug.Log(string.Format("[{0}] Added resource {1} to kerbalEVA part.",
-					this.GetType().Name,
-					resource.resourceName
-				));
-
-				Tools.PostDebugMessage(this, "Resource '{0}' loaded.", resourceName);
+				this.Log("Added resource {0} to {1}", resource.resourceName, evaPart);
+
+				this.LogDebug("Resource '{0}' loaded.", resourceName);
 			}
 			else
 			{
-				Debug.Log(string.Format(
-					"[{0}] Skipping malformed EVA_RESOURCE node: missing 'name' field.",
-					this.GetType().Name
-				));
+				this.Log("Skipping malformed EVA_RESOURCE node: missing 'name' field.");
 				return;
 			}
 		}
 
-		private void delModuleByName(string matchName)
-		{
-			PartModule module = this.matchFirstModuleByName(matchName);
+		private void delModuleByName(Part evaPart, string matchName)
+		{
+			PartModule module = this.matchFirstModuleByName(evaPart, matchName);
 
 			if (module != null)
 			{
-				GameObject.Destroy(module);
-			}
-		}
-
-		private void delResourceByName(string matchName)
-		{
-			PartResource resource = this.matchFirstResourceByName(matchName);
+				evaPart.Modules.Remove(module);
+				GameObject.DestroyImmediate(module);
+
+				this.Log("Removed module {0} from {1} and marked for destruction.", matchName, evaPart);
+			}
+		}
+
+		private void delResourceByName(Part evaPart, string matchName)
+		{
+			PartResource resource = this.matchFirstResourceByName(evaPart, matchName);
 
 			if (resource != null)
 			{
+				evaPart.Resources.list.Remove(resource);
 				GameObject.Destroy(resource);
 
-				Tools.PostDebugMessage(
-					this,
-					"EVA resource {0} marked for destruction.",
-					resource.resourceName);
-			}
-		}
-
-		private void editModuleByNameFromConfig(string matchName, ConfigNode config)
-		{
-			PartModule module = this.matchFirstModuleByName(matchName);
+				this.Log("Removed resource {0} from {1} and marked for destruction.", matchName, evaPart);
+			}
+		}
+
+		private void editModuleByNameFromConfig(Part evaPart, string matchName, ConfigNode config)
+		{
+			PartModule module = this.matchFirstModuleByName(evaPart, matchName);
 
 			if (module != null)
 			{
@@ -463,13 +444,13 @@
 
 					GameObject.Destroy(module);
 
-					Tools.PostDebugMessage(this, "EVA module {0} marked for destruction.", module.GetType().Name);
-
-					ConfigAction copyAction = new ConfigAction(empty, "MODULE", empty, config);
+					this.LogDebug("EVA module {0} marked for destruction.", module.GetType().Name);
+
+					ConfigAction copyAction = new ConfigAction(empty, MODULE, empty, config);
 
 					this.passQueue.Add(copyAction);
 
-					Tools.PostDebugMessage(
+					Logging.PostDebugMessage(
 						this,
 						"EVA module {0} marked for insertion\n(action: {1})",
 						config.GetValue("name"),
@@ -483,9 +464,9 @@
 			}
 		}
 
-		private void editResourceByNameFromConfig(string matchName, ConfigNode config)
-		{
-			PartResource resource = this.matchFirstResourceByName(matchName);
+		private void editResourceByNameFromConfig(Part evaPart, string matchName, ConfigNode config)
+		{
+			PartResource resource = this.matchFirstResourceByName(evaPart, matchName);
 
 			if (resource != null)
 			{
@@ -495,13 +476,13 @@
 
 					GameObject.Destroy(resource);
 
-					Tools.PostDebugMessage(this, "EVA resource {0} marked for destruction.", resource.resourceName);
-
-					ConfigAction copyAction = new ConfigAction(empty, "RESOURCE", empty, config);
+					this.LogDebug("EVA resource {0} marked for destruction.", resource.resourceName);
+
+					ConfigAction copyAction = new ConfigAction(empty, RESOURCE, empty, config);
 
 					this.passQueue.Add(copyAction);
 
-					Tools.PostDebugMessage(
+					Logging.PostDebugMessage(
 						this,
 						"EVA resource {0} marked for insertion\n(action: {1})",
 						config.GetValue("name"),
@@ -515,12 +496,15 @@
 			}
 		}
 
-		private PartModule matchFirstModuleByName(string matchName)
+		private PartModule matchFirstModuleByName(Part evaPart, string matchName)
 		{
 			Regex rgx = new Regex(@matchName);
 
-			foreach (PartModule module in evaPart.GetComponents<PartModule>())
-			{
+			PartModule[] modules = evaPart.GetComponents<PartModule>();
+			PartModule module;
+			for (int idx = 0; idx < modules.Length; idx++)
+			{
+				module = modules[idx];
 				Match match = rgx.Match(module.GetType().Name);
 
 				if (match.Success)
@@ -532,15 +516,18 @@
 			return null;
 		}
 
-		private PartResource matchFirstResourceByName(string matchName)
+		private PartResource matchFirstResourceByName(Part evaPart, string matchName)
 		{
 			Regex rgx = new Regex(@matchName);
 
-			foreach (PartResource resource in evaPart.GetComponents<PartResource>())
-			{
+			PartResource[] resources = evaPart.GetComponents<PartResource>();
+			PartResource resource;
+			for (int idx = 0; idx < resources.Length; idx++)
+			{
+				resource = resources[idx];
 				Match match = rgx.Match(resource.resourceName);
 
-				Tools.PostDebugMessage(
+				Logging.PostDebugMessage(
 					this,
 					"EVA resource {0} is {1}a match for action.",
 					resource.resourceName,
@@ -559,8 +546,10 @@
 		{
 			bool success = true;
 
-			foreach (ConfigNode.Value cfgValue in config.values)
-			{
+			ConfigNode.Value cfgValue;
+			for (int idx = 0; idx < config.values.Count; idx++)
+			{
+				cfgValue = config.values[idx];
 				try
 				{
 					var namedField = obj.GetType().GetField(cfgValue.name,
@@ -580,28 +569,21 @@
 
 						success &= true;
 
-						Tools.PostDebugMessage(this, "Assigned field '{0}' with new value '{1}'.", namedField.Name, convertedValue);
+						this.LogDebug("Assigned field '{0}' with new value '{1}'.", namedField.Name, convertedValue);
 					}
 					else
 					{
-						Debug.LogWarning(string.Format(
-							"[{0}] Failed assigning value '{1}': field not found in class '{2}'",
-							this.GetType().Name,
+						this.LogWarning("Failed assigning value '{0}': field not found in class '{1}'",
 							cfgValue.name,
 							obj.GetType().Name
-						));
+						);
 
 						success &= false;
 					}
 				}
 				catch (Exception ex)
 				{
-					Debug.LogWarning(string.Format(
-						"[{0}] Failed assigning value '{1}': {2}",
-						this.GetType().Name,
-						cfgValue.name,
-						ex.Message
-					));
+					this.LogWarning("Failed assigning value '{0}': {1}", cfgValue.name,	ex.Message);
 
 					success &= false;
 
@@ -616,8 +598,10 @@
 
 		private ConfigNode mergeConfigs(ConfigNode source, ConfigNode target)
 		{
-			foreach (ConfigNode.Value value in target.values)
-			{
+			ConfigNode.Value value;
+			for (int idx = 0; idx < target.values.Count; idx++)
+			{
+				value = target.values[idx];
 				if (source.HasValue(value.name))
 				{
 					source.RemoveValue(value.name);
@@ -651,14 +635,22 @@
 
 			source.AddValue("name", module.GetType().Name);
 
-			foreach (var field in module.GetType().GetFields(
+			System.Reflection.FieldInfo[] fieldInfos = module.GetType().GetFields(
 				System.Reflection.BindingFlags.Public |
 				System.Reflection.BindingFlags.NonPublic |
 				System.Reflection.BindingFlags.Instance
-			))
-			{
-				foreach (object attr in field.GetCustomAttributes(true))
-				{
+			);
+			System.Reflection.FieldInfo field;
+			for (int fIdx = 0; fIdx < fieldInfos.Length; fIdx++)
+			{
+				field = fieldInfos[fIdx];
+
+				object[] attrs = field.GetCustomAttributes(true);
+				object attr;
+				for (int aIdx = 0; aIdx < attrs.Length; aIdx++)
+				{
+					attr = attrs[aIdx];
+
 					if (attr is KSPField)
 					{
 						source.AddValue(field.Name, field.GetValue(module));
@@ -674,7 +666,7 @@
 		#if DEBUG
 		public void OnDestroy()
 		{
-			Tools.PostDebugMessage(this, "Destroyed.");
+			this.LogDebug("Destroyed.");
 		}
 		#endif
 

--- a/EVAManager.csproj
+++ b/EVAManager.csproj
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <PropertyGroup>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug_win</Configuration>
     <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
     <ProductVersion>8.0.30703</ProductVersion>
     <SchemaVersion>2.0</SchemaVersion>
@@ -12,7 +12,7 @@
     <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
     <UseMSBuildEngine>False</UseMSBuildEngine>
   </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug_win|AnyCPU' ">
     <DebugSymbols>true</DebugSymbols>
     <DebugType>full</DebugType>
     <Optimize>false</Optimize>
@@ -23,12 +23,11 @@
     <ConsolePause>false</ConsolePause>
     <CustomCommands>
       <CustomCommands>
-        <Command type="AfterBuild" command="xcopy /y ${ProjectDir}\EVAManager.cfg C:\Users\andy\Games\KSP_win\GameData\EVAManager\" />
-        <Command type="AfterBuild" command="xcopy /y ${TargetFile} C:\Users\andy\Games\KSP_win\GameData\EVAManager\" />
+        <Command type="AfterBuild" command="xcopy /y ${TargetFile} ${ProjectDir}\GameData\EVAManager\" />
       </CustomCommands>
     </CustomCommands>
   </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release_win|AnyCPU' ">
     <DebugType>full</DebugType>
     <Optimize>true</Optimize>
     <OutputPath>bin\Release</OutputPath>
@@ -37,8 +36,35 @@
     <ConsolePause>false</ConsolePause>
     <CustomCommands>
       <CustomCommands>
-        <Command type="AfterBuild" command="xcopy /y ${TargetFile} C:\Users\andy\Games\KSP_win\GameData\EVAManager\" />
-        <Command type="AfterBuild" command="xcopy /y ${ProjectDir}\EVAManager.cfg C:\Users\andy\Games\KSP_win\GameData\EVAManager\" />
+        <Command type="AfterBuild" command="xcopy /y ${TargetFile} ${ProjectDir}\GameData\EVAManager\" />
+      </CustomCommands>
+    </CustomCommands>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release_linux|AnyCPU' ">
+    <DebugType>full</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release</OutputPath>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <ConsolePause>false</ConsolePause>
+    <CustomCommands>
+      <CustomCommands>
+        <Command type="AfterBuild" command="cp -vfa ${TargetFile} ${ProjectDir}/GameData/EVAManager/" />
+      </CustomCommands>
+    </CustomCommands>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug_linux|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug</OutputPath>
+    <DefineConstants>DEBUG;</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <ConsolePause>false</ConsolePause>
+    <CustomCommands>
+      <CustomCommands>
+        <Command type="AfterBuild" command="cp -vfa ${TargetFile} ${ProjectDir}/GameData/EVAManager/" />
       </CustomCommands>
     </CustomCommands>
   </PropertyGroup>
@@ -56,16 +82,46 @@
   </ItemGroup>
   <ItemGroup>
     <Compile Include="EVAManager.cs" />
-    <Compile Include="..\ToadicusTools\Tools.cs">
-      <Link>Tools.cs</Link>
+    <Compile Include="EVAPartResource.cs" />
+    <Compile Include="..\ToadicusTools\Extensions\ComponentExtensions.cs">
+      <Link>ToadicusTools\ComponentExtensions.cs</Link>
     </Compile>
-    <Compile Include="EVAPartResource.cs" />
-    <Compile Include="..\ToadicusTools\ConfigNodeExtensions.cs">
-      <Link>ConfigNodeExtensions.cs</Link>
+    <Compile Include="..\ToadicusTools\Enums.cs">
+      <Link>ToadicusTools\Enums.cs</Link>
     </Compile>
-  </ItemGroup>
-  <ItemGroup>
-    <None Include="EVAManager.cfg" />
+    <Compile Include="..\ToadicusTools\Text\Extensions.cs">
+      <Link>ToadicusTools\Extensions.cs</Link>
+    </Compile>
+    <Compile Include="..\ToadicusTools\Logging.cs">
+      <Link>ToadicusTools\Logging.cs</Link>
+    </Compile>
+    <Compile Include="..\ToadicusTools\MathTools.cs">
+      <Link>ToadicusTools\MathTools.cs</Link>
+    </Compile>
+    <Compile Include="..\ToadicusTools\MuMechTools\MuMech_Tools.cs">
+      <Link>ToadicusTools\MuMech_Tools.cs</Link>
+    </Compile>
+    <Compile Include="..\ToadicusTools\Extensions\PartExtensions.cs">
+      <Link>ToadicusTools\PartExtensions.cs</Link>
+    </Compile>
+    <Compile Include="..\ToadicusTools\Debug\PooledDebugLogger.cs">
+      <Link>ToadicusTools\PooledDebugLogger.cs</Link>
+    </Compile>
+    <Compile Include="..\ToadicusTools\APIHelpers\PooledObject.cs">
+      <Link>ToadicusTools\PooledObject.cs</Link>
+    </Compile>
+    <Compile Include="..\ToadicusTools\Text\PooledStringBuilder.cs">
+      <Link>ToadicusTools\PooledStringBuilder.cs</Link>
+    </Compile>
+    <Compile Include="..\ToadicusTools\Text\SIFormatProvider.cs">
+      <Link>ToadicusTools\SIFormatProvider.cs</Link>
+    </Compile>
+    <Compile Include="..\ToadicusTools\Text\TextTools.cs">
+      <Link>ToadicusTools\TextTools.cs</Link>
+    </Compile>
+    <Compile Include="..\ToadicusTools\Extensions\ConfigNodeExtensions.cs">
+      <Link>ToadicusTools\ConfigNodeExtensions.cs</Link>
+    </Compile>
   </ItemGroup>
   <ProjectExtensions>
     <MonoDevelop>
@@ -76,4 +132,11 @@
       </Properties>
     </MonoDevelop>
   </ProjectExtensions>
+  <ItemGroup>
+    <Folder Include="GameData\EVAManager\" />
+    <Folder Include="ToadicusTools\" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="GameData\EVAManager\EVAManager.cfg.example" />
+  </ItemGroup>
 </Project>

--- a/EVAPartResource.cs
+++ b/EVAPartResource.cs
@@ -26,6 +26,7 @@
 using KSP;
 using System;
 using ToadicusTools;
+using ToadicusTools.Extensions;
 using UnityEngine;
 
 namespace EVAManager
@@ -49,7 +50,7 @@
 
 				baseAwake.Invoke(this, null);
 
-				Tools.PostDebugMessage(this, "base Awake.");
+				Logging.PostDebugMessage(this, "base Awake.");
 			}
 			#if DEBUG
 			catch (Exception ex)
@@ -69,7 +70,7 @@
 			GameEvents.onCrewOnEva.Add(this.onEvaHandler);
 			GameEvents.onCrewBoardVessel.Add(this.onBoardHandler);
 
-			Tools.PostDebugMessage(this, "Awake");
+			Logging.PostDebugMessage(this, "Awake");
 		}
 
 		public void OnDestroy()
@@ -84,7 +85,7 @@
 
 			this.FillFromPod = node.GetValue("FillFromPod", this.FillFromPod);
 
-			Tools.PostDebugMessage(this, "Loaded.");
+			Logging.PostDebugMessage(this, "Loaded.");
 		}
 
 		public new void Save(ConfigNode node)
@@ -100,7 +101,7 @@
 				node.AddValue("FillFromPod", this.FillFromPod.ToString());
 			}
 
-			Tools.PostDebugMessage(this, "Saved.");
+			Logging.PostDebugMessage(this, "Saved.");
 		}
 
 		private void onEvaHandler(GameEvents.FromToAction<Part, Part> data)
@@ -128,7 +129,7 @@
 
 					this.amount += gotAmount;
 
-					Tools.PostDebugMessage(this, "Filled {0} {1} from {2}",
+					Logging.PostDebugMessage(this, "Filled {0} {1} from {2}",
 						gotAmount,
 						this.resourceName,
 						data.to.partInfo.title
@@ -155,7 +156,7 @@
 
 					this.amount += sentAmount;
 
-					Tools.PostDebugMessage(this, "Returned {0} {1} to {2}",
+					Logging.PostDebugMessage(this, "Returned {0} {1} to {2}",
 						-sentAmount,
 						this.resourceName,
 						data.to.partInfo.title

--- /dev/null
+++ b/GameData/EVAManager/EVAManager.cfg.example
@@ -1,1 +1,55 @@
+// EVAManager
+//
+// EVAManager.cfg
+//
+// Copyright © 2014, toadicus
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice,
+//    this list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation and/or other
+//    materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+// This is a fun proof-of-concept patch set that adds EVA Propellant to parts that house Kerbals.  This requires you to
+// ration EVA fuel over the course of a mission inside of individual jaunts.  If you like the idea, rename this file to
+// remove the .example extension!
+
+DELETE_EVA_RESOURCE[EVA\sPropellant] {}
+
+EVA_RESOURCE
+{
+	name = EVA Propellant
+	amount = 0
+	maxAmount = 5
+}
+
+@PART[*]:HAS[#CrewCapacity[>0]]
+{
+	RESOURCE
+	{
+		name = EVA Propellant
+		amount = 5
+		@amount *= #$/CrewCapacity$
+		maxAmount = 5
+		@maxAmount *= #$/CrewCapacity$
+	}
+}
+
+@RESOURCE_DEFINITION[EVA*Propellant]
+{
+	@density = 0.000807
+}
+