/// <summary>
        /// Set up the SortBar for the Editors' crew assignment panel. (Callback)
        /// </summary>
        protected void Start()
        {
            try {
                // Game Event Hooks
                GameEvents.onEditorScreenChange.Add(OnEditorScreenChange);
                GameEvents.onEditorLoad.Add(OnEditorLoad);
                GameEvents.onEditorRestart.Add(OnEditorRestart);
                GameEvents.onEditorShipModified.Add(OnEditorShipModified);
                // We actually do need these:
                GameEvents.onGUIAstronautComplexSpawn.Add(OnACSpawn);
                GameEvents.onGUIAstronautComplexDespawn.Add(OnACDespawn);

                // Get Roster:
                UIScrollList[] lists = UIManager.instance.gameObject.GetComponentsInChildren<UIScrollList>(true);
                availableCrew = null;
                vesselCrew = null;
                foreach( UIScrollList list in lists ) {
                    if( list.name == "scrolllist_avail" ) {
                        availableCrew = list;
                        if( vesselCrew != null ) {
                            break;
                        }
                    }
                    else if( list.name == "scrolllist_crew" ) {
                        vesselCrew = list;
                        if( availableCrew != null ) {
                            break;
                        }
                    }
                }
                if( availableCrew == null ) {
                    throw new Exception("Could not find Available Crew List!");
                }
                if( vesselCrew == null ) {
                    throw new Exception("Could not find Vessel Crew List!");
                }
                StockRoster available = new StockRoster(availableCrew);

                // Get position: (This is probably the one time we actually want to do this here)
                Transform tab_crewavail = availableCrew.transform.parent.Find("tab_crewavail");
                BTButton tab = tab_crewavail.GetComponent<BTButton>();
                Vector3 tabPos = Utilities.GetPosition(tab_crewavail);
                float x = tabPos.x + tab.width + 5;
                float y = tabPos.y - 1;

                // Set up button list:
                SortButtonDef[] buttons = new SortButtonDef[]{
                    StandardButtonDefs.ByName, StandardButtonDefs.ByClass,
                    StandardButtonDefs.ByLevel, StandardButtonDefs.ByGender,
                    StandardButtonDefs.ByNumFlights
                };

                // Initialize the sort bar:
                sortBar = gameObject.AddComponent<SortBar>();
                sortBar.SetRoster(available);
                sortBar.SetButtons(buttons);
                sortBar.SetDefaultOrdering(StandardKerbalComparers.DefaultAvailable);
                sortBar.SetPos(x, y);
                sortBar.enabled = false;

                // Create a fly-in animation for the sort bar.
                baseX = x;
                baseY = y;
                float animBeginTime = 0.2f;
                animEndTime = 0.5f;
                anim = AnimationCurve.Linear(animBeginTime, -575f, animEndTime, 0f);

                // This is what I would have *liked* to have done, but Unity decided this should do absolutely nothing.
                /*AnimationCurve curve = AnimationCurve.Linear(0f, 0f, 10f, 100f);
                AnimationClip clip = new AnimationClip();
                clip.SetCurve("", typeof(Transform), "position.x", curve);
                sortBar.gameObject.AddComponent<Animation>().AddClip(clip, "flyin");*/

                // Add some extra hooks:
                availableCrew.AddValueChangedDelegate(OnAvailListValueChanged);
                Transform trans = UIManager.instance.transform.FindChild("panel_CrewAssignmentInEditor");
                foreach( BTButton btn in trans.GetComponentsInChildren<BTButton>() ) {
                    if( btn.name == "button_reset" ) {
                        btn.AddValueChangedDelegate(OnResetBtn);
                    }
                    else if( btn.name == "button_clear" ) {
                        btn.AddValueChangedDelegate(OnClearBtn);
                    }
                }
                trans = UIManager.instance.transform.FindChild("TopRightAnchor");
                foreach( UIButton btn in trans.GetComponentsInChildren<UIButton>() ) {
                    if( btn.name == "ButtonLoad" ) {
                        btn.AddValueChangedDelegate(OnLoadBtn);
                    }
                }

                fixDefaultAssignment = false;
                loadBtnPressed = false;
                noParts = true;
            }
            catch( Exception e ) {
                Debug.LogError("KerbalSorter: Unexpected error in EditorHook: " + e);
            }
        }
        /// <summary>
        /// Set up the SortBars for the Astronaut Complex. (Callback)
        /// </summary>
        protected void Start()
        {
            try {
                // Set up hooks:
                GameEvents.onGUIAstronautComplexSpawn.Add(OnACSpawn);
                GameEvents.onGUIAstronautComplexDespawn.Add(OnACDespawn);
                GameEvents.OnCrewmemberHired.Add(OnHire);
                GameEvents.OnCrewmemberSacked.Add(OnFire);

                // Get rosters:
                complex = UIManager.instance.gameObject.GetComponentsInChildren<CMAstronautComplex>(true).FirstOrDefault();
                if( complex == null ) throw new Exception("Could not find astronaut complex");
                UIScrollList availableList = complex.transform.Find("CrewPanels/panel_enlisted/panelManager/panel_available/scrolllist_available").GetComponent<UIScrollList>();
                UIScrollList assignedList = complex.transform.Find("CrewPanels/panel_enlisted/panelManager/panel_assigned/scrolllist_assigned").GetComponent<UIScrollList>();
                UIScrollList killedList = complex.transform.Find("CrewPanels/panel_enlisted/panelManager/panel_kia/scrolllist_kia").GetComponent<UIScrollList>();
                UIScrollList applicantList = complex.transform.Find("CrewPanels/panel_applicants/scrolllist_applicants").GetComponent<UIScrollList>();
                available = new StockRoster(availableList);
                assigned = new StockRoster(assignedList);
                killed = new StockRoster(killedList);
                applicants = new StockRoster(applicantList);

                // Set up button list:
                SortButtonDef[] buttonsCrew = new SortButtonDef[]{
                    StandardButtonDefs.ByName, StandardButtonDefs.ByClass,
                    StandardButtonDefs.ByLevel, StandardButtonDefs.ByGender,
                    StandardButtonDefs.ByNumFlights
                };
                SortButtonDef[] buttonsApplicants = new SortButtonDef[]{
                    StandardButtonDefs.ByName, StandardButtonDefs.ByClass, StandardButtonDefs.ByGender
                };

                // Initialize the crew sort bar:
                sortBarCrew = gameObject.AddComponent<SortBar>();
                sortBarCrew.SetRoster(available);
                sortBarCrew.SetButtons(buttonsCrew);
                sortBarCrew.SetDefaultOrdering(StandardKerbalComparers.DefaultAvailable);
                sortBarCrew.enabled = false;
                curPanel = CrewPanel.Available;

                /// Initialize the applicant sort bar:
                sortBarApplicants = gameObject.AddComponent<SortBar>();
                sortBarApplicants.SetRoster(applicants);
                sortBarApplicants.SetButtons(buttonsApplicants);
                sortBarApplicants.SetDefaultOrdering(StandardKerbalComparers.DefaultApplicant);
                sortBarApplicants.enabled = false;

                // Assign enable listeners to the rosters:
                Utilities.AddOnEnableListener(availableList.gameObject, OnTabAvailable, true);
                Utilities.AddOnEnableListener(assignedList.gameObject, OnTabAssigned, true);
                Utilities.AddOnEnableListener(killedList.gameObject, OnTabKilled, true);

                // There's no other way to detect KSI's presence, unfortunately. :/
                foreach( AssemblyLoader.LoadedAssembly asm in AssemblyLoader.loadedAssemblies ){
                    if( asm.dllName == "KSI" ){
                        KSILoaded = true;
                    }
                }
            }
            catch( Exception e ) {
                Debug.LogError("KerbalSorter: Unexpected error in AstronautComplexHook: " + e);
            }
        }
        /// <summary>
        /// Set up the Sort Bar for the Launch Windows. (Callback)
        /// </summary>
        protected void Start()
        {
            try {
                GameEvents.onGUILaunchScreenSpawn.Add(LaunchScreenSpawn);
                GameEvents.onGUILaunchScreenDespawn.Add(LaunchScreenDespawn);
                GameEvents.onGUILaunchScreenVesselSelected.Add(VesselSelect);
                // We actually do need these:
                GameEvents.onGUIAstronautComplexSpawn.Add(OnACSpawn);
                GameEvents.onGUIAstronautComplexDespawn.Add(OnACDespawn);

                // Get the Roster and the vessel crew list:
                VesselSpawnDialog window = UIManager.instance.gameObject.GetComponentsInChildren<VesselSpawnDialog>(true).FirstOrDefault();
                if( window == null ) {
                    throw new Exception("Could not find Launch Window!");
                }
                UIScrollList[] lists = window.GetComponentsInChildren<UIScrollList>(true);
                availableCrew = null;
                vesselCrew = null;
                foreach( UIScrollList list in lists ) {
                    if( list.name == "scrolllist_avail" ) {
                        availableCrew = list;
                        if( vesselCrew != null ) {
                            break;
                        }
                    }
                    else if( list.name == "scrolllist_crew" ) {
                        vesselCrew = list;
                        if( availableCrew != null ) {
                            break;
                        }
                    }
                }
                if( availableCrew == null ) {
                    throw new Exception("Could not find Available Crew List!");
                }
                if( vesselCrew == null ) {
                    throw new Exception("Could not find Vessel Crew List!");
                }
                StockRoster available = new StockRoster(availableCrew);

                // Set up button list:
                SortButtonDef[] buttons = new SortButtonDef[]{
                    StandardButtonDefs.ByName, StandardButtonDefs.ByClass,
                    StandardButtonDefs.ByLevel, StandardButtonDefs.ByGender,
                    StandardButtonDefs.ByNumFlights
                };

                // Initialize the sort bar:
                sortBar = gameObject.AddComponent<SortBar>();
                sortBar.SetRoster(available);
                sortBar.SetButtons(buttons);
                sortBar.SetDefaultOrdering(StandardKerbalComparers.DefaultAvailable);
                sortBar.enabled = false;

                // Set up some hooks to detect when the list is changing:
                availableCrew.AddValueChangedDelegate(OnAvailListValueChanged);
                Transform anchorButtons = window.transform.FindChild("anchor/vesselInfo/crewAssignment/crewAssignmentSpawnpoint/anchorButtons");
                BTButton btn = anchorButtons.FindChild("button_reset").GetComponent<BTButton>();
                btn.AddValueChangedDelegate(OnResetBtn);
                btn = anchorButtons.FindChild("button_clear").GetComponent<BTButton>();
                btn.AddValueChangedDelegate(OnClearBtn);
            }
            catch( Exception e ) {
                Debug.LogError("KerbalSorter: Unexpected error in LaunchWindowHook: " + e);
            }
        }