public MonitorPage(int idNum, ConfigNode node, RasterPropMonitor thatMonitor)
        {
            ourMonitor = thatMonitor;
            screenWidth = ourMonitor.screenWidth;
            screenHeight = ourMonitor.screenHeight;
            cameraAspect = ourMonitor.cameraAspect;
            cameraObject = thatMonitor.cameraStructure;
            defaultColor = ourMonitor.defaultFontTintValue;
            screenXMin = 0;
            screenYMin = 0;

            pageNumber = idNum;
            isMutable = false;
            if (!node.HasData)
            {
                throw new ArgumentException("Empty page?");
            }

            if (node.HasValue("name"))
            {
                string value = node.GetValue("name").Trim();
                if (!IsValidPageName(value))
                {
                    JUtil.LogMessage(ourMonitor, "Warning, name given for page #{0} is invalid, ignoring.", pageNumber);
                }
                else
                {
                    name = value;
                }
            }
            else
            {
                JUtil.LogMessage(ourMonitor, "Warning, page #{0} has no name. It's much better if it does.", pageNumber);
            }

            isDefault |= node.HasValue("default");

            if (node.HasValue("button"))
            {
                SmarterButton.CreateButton(thatMonitor.internalProp, node.GetValue("button"), this, thatMonitor.PageButtonClick);
            }

            // Page locking system -- simple locking:
            simpleLockingPage |= node.HasValue("lockingPage");
            // and name-based locking.
            if (node.HasValue("disableSwitchingTo"))
            {
                string[] tokens = node.GetValue("disableSwitchingTo").Split(',');
                foreach (string token in tokens)
                {
                    disableSwitchingTo.Add(token.Trim());
                }
            }

            unlocker |= node.HasValue("unlockerPage");

            if (node.HasValue("localMargins"))
            {
                Vector4 margindata = ConfigNode.ParseVector4(node.GetValue("localMargins"));
                screenXMin = (int)margindata.x;
                screenYMin = (int)margindata.y;
                screenWidth = screenWidth - (int)margindata.z - screenXMin;
                screenHeight = screenHeight - (int)margindata.w - screenYMin;
            }

            pageFont = node.GetInt("defaultFontNumber") ?? 0;

            if (node.HasValue("defaultFontTint"))
            {
                defaultColor = ConfigNode.ParseColor32(node.GetValue("defaultFontTint"));
            }

            if (node.HasValue("techsRequired"))
            {
                techsRequired = node.GetValue("techsRequired").Split(new[] { ' ', ',', ';', '\t', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries).ToList();
            }

            if (node.HasValue("fallbackOnNoTech"))
            {
                fallbackPageName = node.GetValue("fallbackOnNoTech").Trim();
            }

            if (node.HasNode("CONTEXTREDIRECT"))
            {
                foreach (string content in node.GetNode("CONTEXTREDIRECT").GetValues("redirect"))
                {
                    string[] tokens = content.Split(',');
                    if (tokens.Length > 2 || !IsValidPageName(tokens[0].Trim()) || !IsValidPageName(tokens[1].Trim()))
                    {
                        JUtil.LogMessage(ourMonitor, "Warning, invalid page redirect statement on page #{0}.", pageNumber);
                        continue;
                    }
                    redirectPages[tokens[0].Trim()] = tokens[1].Trim();
                }
                const string valueError = "Warning, invalid global button redirect statement on page #{0}: {1}";
                foreach (string content in node.GetNode("CONTEXTREDIRECT").GetValues("renumber"))
                {
                    string[] tokens = content.Split(',');
                    if (tokens.Length > 2)
                    {
                        JUtil.LogMessage(ourMonitor, valueError, pageNumber, "requires two arguments.");
                        continue;
                    }
                    int from, to;
                    if (!int.TryParse(tokens[0], out from) || !int.TryParse(tokens[1], out to))
                    {
                        JUtil.LogMessage(ourMonitor, valueError, pageNumber, "something isn't a number.");
                        continue;
                    }
                    redirectGlobals[from] = to;
                }
                JUtil.LogMessage(this, "Page '{2}' (#{0}) registers {1} page redirects and {3} global button redirects.", idNum, redirectPages.Count, name, redirectGlobals.Count);
            }

            foreach (ConfigNode handlerNode in node.GetNodes("PAGEHANDLER"))
            {
                MonoBehaviour handlerModule;
                HandlerSupportMethods supportMethods;
                MethodInfo handlerMethod = InstantiateHandler(handlerNode, ourMonitor, out handlerModule, out supportMethods);
                if (handlerMethod != null && handlerModule != null)
                {
                    try
                    {
                        pageHandlerMethod = (Func<int, int, string>)Delegate.CreateDelegate(typeof(Func<int, int, string>), handlerModule, handlerMethod);
                    }
                    catch
                    {
                        JUtil.LogErrorMessage(ourMonitor, "Incorrect signature for the page handler method {0}", handlerModule.name);
                        break;
                    }
                    pageHandlerS = supportMethods;
                    isMutable = true;
                    pageHandlerModule = handlerModule;
                    break;
                }
            }

            if (pageHandlerMethod == null)
            {
                if (node.HasValue("text"))
                {
                    text = JUtil.LoadPageDefinition(node.GetValue("text"));
                    isMutable |= text.IndexOf("$&$", StringComparison.Ordinal) != -1;
                }
            }

            if (node.HasValue("textOverlay"))
            {
                textOverlayBuffer = JUtil.LoadPageDefinition(node.GetValue("textOverlay")).Split(JUtil.LineSeparator, StringSplitOptions.None);
            }

            foreach (ConfigNode handlerNode in node.GetNodes("BACKGROUNDHANDLER"))
            {
                MonoBehaviour handlerModule;
                HandlerSupportMethods supportMethods;
                MethodInfo handlerMethod = InstantiateHandler(handlerNode, ourMonitor, out handlerModule, out supportMethods);
                if (handlerMethod != null && handlerModule != null)
                {
                    try
                    {
                        backgroundHandlerMethod = (Func<RenderTexture, float, bool>)Delegate.CreateDelegate(typeof(Func<RenderTexture, float, bool>), handlerModule, handlerMethod);
                    }
                    catch
                    {
                        JUtil.LogErrorMessage(ourMonitor, "Incorrect signature for the background handler method {0}", handlerModule.name);
                        break;
                    }
                    backgroundHandlerS = supportMethods;
                    isMutable = true;
                    showNoSignal = node.HasValue("showNoSignal");
                    background = BackgroundType.Handler;
                    backgroundHandlerModule = handlerModule;
                    break;
                }
            }

            if (background == BackgroundType.None)
            {
                if (node.HasValue("cameraTransform"))
                {
                    isMutable = true;
                    background = BackgroundType.Camera;
                    camera = node.GetValue("cameraTransform");
                    cameraFOV = defaultFOV;

                    cameraFlickerChance = node.GetFloat("flickerChance") ?? 0;
                    cameraFlickerRange = node.GetInt("flickerRange") ?? 0;

                    if (node.HasValue("fov"))
                    {
                        float fov;
                        cameraFOV = float.TryParse(node.GetValue("fov"), out fov) ? fov : defaultFOV;
                    }
                    else if (node.HasValue("zoomFov") && node.HasValue("zoomButtons"))
                    {
                        Vector3 zoomFov = ConfigNode.ParseVector3(node.GetValue("zoomFov"));
                        Vector2 zoomButtons = ConfigNode.ParseVector2(node.GetValue("zoomButtons"));
                        if ((int)zoomFov.z != 0 && ((int)zoomButtons.x != (int)zoomButtons.y))
                        {
                            maxFOV = Math.Max(zoomFov.x, zoomFov.y);
                            minFOV = Math.Min(zoomFov.x, zoomFov.y);
                            zoomSteps = (int)zoomFov.z;
                            zoomUpButton = (int)zoomButtons.x;
                            zoomDownButton = (int)zoomButtons.y;
                            zoomSkip = (maxFOV - minFOV) / zoomSteps;
                            currentZoom = 0;
                            cameraFOV = maxFOV;
                        }
                        else
                        {
                            JUtil.LogMessage(ourMonitor, "Ignored invalid camera zoom settings on page {0}.", pageNumber);
                        }
                    }
                }
            }
            if (background == BackgroundType.None)
            {
                if (node.HasValue("textureURL"))
                {
                    string textureURL = node.GetValue("textureURL").EnforceSlashes();
                    if (GameDatabase.Instance.ExistsTexture(textureURL))
                    {
                        backgroundTexture = GameDatabase.Instance.GetTexture(textureURL, false);
                        background = BackgroundType.Texture;
                    }
                }
            }
            if (node.HasValue("textureInterlayURL"))
            {
                string textureURL = node.GetValue("textureInterlayURL").EnforceSlashes();
                if (GameDatabase.Instance.ExistsTexture(textureURL))
                {
                    interlayTexture = GameDatabase.Instance.GetTexture(textureURL, false);
                }
                else
                {
                    JUtil.LogErrorMessage(ourMonitor, "Interlay texture could not be loaded.");
                }
            }
            if (node.HasValue("textureOverlayURL"))
            {
                string textureURL = node.GetValue("textureOverlayURL").EnforceSlashes();
                if (GameDatabase.Instance.ExistsTexture(textureURL))
                {
                    overlayTexture = GameDatabase.Instance.GetTexture(textureURL, false);
                }
                else
                {
                    JUtil.LogErrorMessage(ourMonitor, "Overlay texture {0} could not be loaded.", textureURL);
                }
            }
        }
        private static MethodInfo InstantiateHandler(ConfigNode node, RasterPropMonitor ourMonitor, out MonoBehaviour moduleInstance, out HandlerSupportMethods support)
        {
            moduleInstance               = null;
            support.activate             = null;
            support.buttonClick          = null;
            support.buttonRelease        = null;
            support.getHandlerReferences = null;
            if (node.HasValue("name") && node.HasValue("method"))
            {
                string moduleName = node.GetValue("name");
                string methodName = node.GetValue("method");

                var handlerConfiguration = new ConfigNode("MODULE");
                node.CopyTo(handlerConfiguration);

                MonoBehaviour thatModule = null;
                // Part modules are different in that they remain instantiated when you switch vessels, while the IVA doesn't.
                // Because of this RPM can't instantiate partmodule-based handlers itself -- there's no way to tell if this was done already or not.
                // Which means there can only be one instance of such a handler per pod, and it can't receive configuration values from RPM.
                if (node.HasValue("isPartModule"))
                {
                    foreach (PartModule potentialModule in ourMonitor.part.Modules)
                    {
                        if (potentialModule.ClassName == moduleName)
                        {
                            thatModule = potentialModule;
                            break;
                        }
                    }
                }
                else if (node.HasValue("multiHandler"))
                {
                    foreach (InternalModule potentialModule in ourMonitor.internalProp.internalModules)
                    {
                        if (potentialModule.ClassName == moduleName)
                        {
                            thatModule = potentialModule;
                            break;
                        }
                    }
                }

                if (thatModule == null && !node.HasValue("isPartModule"))
                {
                    try
                    {
                        thatModule = ourMonitor.internalProp.AddModule(handlerConfiguration);
                    }
                    catch
                    {
                        JUtil.LogErrorMessage(ourMonitor, "Caught exception when trying to instantiate module '{0}'. Something's fishy here", moduleName);
                    }
                    if (thatModule != null)
                    {
                        try
                        {
                            MethodInfo      configureMethod = thatModule.GetType().GetMethod("Configure", BindingFlags.Instance | BindingFlags.Public);
                            ParameterInfo[] parms           = configureMethod.GetParameters();

                            if (parms.Length == 1 && parms[0].ParameterType == typeof(ConfigNode))
                            {
                                configureMethod.Invoke(thatModule, new object[] { handlerConfiguration });
                            }
                        }
                        catch//(Exception e)
                        {
                            //JUtil.LogMessage(ourMonitor, "Exception {0}", e);
                            //JUtil.LogMessage(ourMonitor, "Module didn't have a Configure method.  This could be normal.");
                        }
                    }
                }

                if (thatModule == null)
                {
                    JUtil.LogMessage(ourMonitor, "Warning, handler module \"{0}\" could not be loaded. This could be perfectly normal.", moduleName);
                    return(null);
                }

                const string sigError = "Incorrect signature of the {0} method in {1}, ignoring option. If it doesn't work later, that's why.";

                if (node.HasValue("pageActiveMethod"))
                {
                    foreach (MethodInfo m in thatModule.GetType().GetMethods())
                    {
                        if (m.Name == node.GetValue("pageActiveMethod"))
                        {
                            try
                            {
                                support.activate = (Action <bool, int>)Delegate.CreateDelegate(typeof(Action <bool, int>), thatModule, m);
                            }
                            catch
                            {
                                JUtil.LogErrorMessage(ourMonitor, sigError, "page activation", moduleName);
                            }
                            break;
                        }
                    }
                }

                if (node.HasValue("buttonClickMethod"))
                {
                    foreach (MethodInfo m in thatModule.GetType().GetMethods())
                    {
                        if (m.Name == node.GetValue("buttonClickMethod"))
                        {
                            try
                            {
                                support.buttonClick = (Action <int>)Delegate.CreateDelegate(typeof(Action <int>), thatModule, m);
                            }
                            catch
                            {
                                JUtil.LogErrorMessage(ourMonitor, sigError, "button click", moduleName);
                            }
                            break;
                        }
                    }
                }

                if (node.HasValue("buttonReleaseMethod"))
                {
                    foreach (MethodInfo m in thatModule.GetType().GetMethods())
                    {
                        if (m.Name == node.GetValue("buttonReleaseMethod"))
                        {
                            try
                            {
                                support.buttonRelease = (Action <int>)Delegate.CreateDelegate(typeof(Action <int>), thatModule, m);
                            }
                            catch
                            {
                                JUtil.LogErrorMessage(ourMonitor, sigError, "button release", moduleName);
                            }
                            break;
                        }
                    }
                }

                if (node.HasValue("getHandlerReferencesMethod"))
                {
                    foreach (MethodInfo m in thatModule.GetType().GetMethods())
                    {
                        if (m.Name == node.GetValue("getHandlerReferencesMethod"))
                        {
                            try
                            {
                                support.getHandlerReferences = (Action <MonoBehaviour, MonoBehaviour>)Delegate.CreateDelegate(typeof(Action <MonoBehaviour, MonoBehaviour>), thatModule, m);
                            }
                            catch
                            {
                                JUtil.LogErrorMessage(ourMonitor, sigError, "handler references", moduleName);
                            }
                            break;
                        }
                    }
                }

                moduleInstance = thatModule;
                foreach (MethodInfo m in thatModule.GetType().GetMethods())
                {
                    if (m.Name == methodName)
                    {
                        return(m);
                    }
                }
            }
            return(null);
        }
        private static MethodInfo InstantiateHandler(ConfigNode node, RasterPropMonitor ourMonitor, out MonoBehaviour moduleInstance, out HandlerSupportMethods support)
        {
            moduleInstance = null;
            support.activate = null;
            support.buttonClick = null;
            support.buttonRelease = null;
            support.getHandlerReferences = null;
            if (node.HasValue("name") && node.HasValue("method"))
            {
                string moduleName = node.GetValue("name");
                string methodName = node.GetValue("method");

                var handlerConfiguration = new ConfigNode("MODULE");
                node.CopyTo(handlerConfiguration);

                MonoBehaviour thatModule = null;
                // Part modules are different in that they remain instantiated when you switch vessels, while the IVA doesn't.
                // Because of this RPM can't instantiate partmodule-based handlers itself -- there's no way to tell if this was done already or not.
                // Which means there can only be one instance of such a handler per pod, and it can't receive configuration values from RPM.
                if (node.HasValue("isPartModule"))
                {
                    foreach (PartModule potentialModule in ourMonitor.part.Modules)
                    {
                        if (potentialModule.ClassName == moduleName)
                        {
                            thatModule = potentialModule;
                            break;
                        }
                    }
                }
                else if (node.HasValue("multiHandler"))
                {

                    foreach (InternalModule potentialModule in ourMonitor.internalProp.internalModules)
                    {
                        if (potentialModule.ClassName == moduleName)
                        {
                            thatModule = potentialModule;
                            break;
                        }
                    }

                }

                if (thatModule == null && !node.HasValue("isPartModule"))
                {
                    try
                    {
                        thatModule = ourMonitor.internalProp.AddModule(handlerConfiguration);
                    }
                    catch
                    {
                        JUtil.LogErrorMessage(ourMonitor, "Caught exception when trying to instantiate module '{0}'. Something's fishy here", moduleName);
                    }
                }

                if (thatModule == null)
                {
                    JUtil.LogMessage(ourMonitor, "Warning, handler module \"{0}\" could not be loaded. This could be perfectly normal.", moduleName);
                    return null;
                }

                const string sigError = "Incorrect signature of the {0} method in {1}, ignoring option. If it doesn't work later, that's why.";

                if (node.HasValue("pageActiveMethod"))
                {
                    foreach (MethodInfo m in thatModule.GetType().GetMethods())
                    {
                        if (m.Name == node.GetValue("pageActiveMethod"))
                        {
                            try
                            {
                                support.activate = (Action<bool, int>)Delegate.CreateDelegate(typeof(Action<bool, int>), thatModule, m);
                            }
                            catch
                            {
                                JUtil.LogErrorMessage(ourMonitor, sigError, "page activation", moduleName);
                            }
                            break;
                        }
                    }
                }

                if (node.HasValue("buttonClickMethod"))
                {
                    foreach (MethodInfo m in thatModule.GetType().GetMethods())
                    {
                        if (m.Name == node.GetValue("buttonClickMethod"))
                        {
                            try
                            {
                                support.buttonClick = (Action<int>)Delegate.CreateDelegate(typeof(Action<int>), thatModule, m);
                            }
                            catch
                            {
                                JUtil.LogErrorMessage(ourMonitor, sigError, "button click", moduleName);
                            }
                            break;
                        }
                    }
                }

                if (node.HasValue("buttonReleaseMethod"))
                {
                    foreach (MethodInfo m in thatModule.GetType().GetMethods())
                    {
                        if (m.Name == node.GetValue("buttonReleaseMethod"))
                        {
                            try
                            {
                                support.buttonRelease = (Action<int>)Delegate.CreateDelegate(typeof(Action<int>), thatModule, m);
                            }
                            catch
                            {
                                JUtil.LogErrorMessage(ourMonitor, sigError, "button release", moduleName);
                            }
                            break;
                        }
                    }
                }

                if (node.HasValue("getHandlerReferencesMethod"))
                {
                    foreach (MethodInfo m in thatModule.GetType().GetMethods())
                    {
                        if (m.Name == node.GetValue("getHandlerReferencesMethod"))
                        {
                            try
                            {
                                support.getHandlerReferences = (Action<MonoBehaviour, MonoBehaviour>)Delegate.CreateDelegate(typeof(Action<MonoBehaviour, MonoBehaviour>), thatModule, m);
                            }
                            catch
                            {
                                JUtil.LogErrorMessage(ourMonitor, sigError, "handler references", moduleName);
                            }
                            break;
                        }
                    }
                }

                moduleInstance = thatModule;
                foreach (MethodInfo m in thatModule.GetType().GetMethods())
                {
                    if (m.Name == methodName)
                    {
                        return m;
                    }
                }

            }
            return null;
        }
        public MonitorPage(int idNum, ConfigNode node, RasterPropMonitor thatMonitor)
        {
            ourMonitor   = thatMonitor;
            screenWidth  = ourMonitor.screenWidth;
            screenHeight = ourMonitor.screenHeight;
            cameraAspect = ourMonitor.cameraAspect;
            cameraObject = thatMonitor.cameraStructure;
            defaultColor = ourMonitor.defaultFontTintValue;
            screenXMin   = 0;
            screenYMin   = 0;

            pageNumber = idNum;
            isMutable  = false;
            if (!node.HasData)
            {
                throw new ArgumentException("Empty page?");
            }

            if (node.HasValue("name"))
            {
                string value = node.GetValue("name").Trim();
                if (!IsValidPageName(value))
                {
                    JUtil.LogMessage(ourMonitor, "Warning, name given for page #{0} is invalid, ignoring.", pageNumber);
                }
                else
                {
                    name = value;
                }
            }
            else
            {
                JUtil.LogMessage(ourMonitor, "Warning, page #{0} has no name. It's much better if it does.", pageNumber);
            }

            isDefault |= node.HasValue("default");

            if (node.HasValue("button"))
            {
                SmarterButton.CreateButton(thatMonitor.internalProp, node.GetValue("button"), this, thatMonitor.PageButtonClick);
            }

            // Page locking system -- simple locking:
            simpleLockingPage |= node.HasValue("lockingPage");
            // and name-based locking.
            if (node.HasValue("disableSwitchingTo"))
            {
                string[] tokens = node.GetValue("disableSwitchingTo").Split(',');
                foreach (string token in tokens)
                {
                    disableSwitchingTo.Add(token.Trim());
                }
            }

            unlocker |= node.HasValue("unlockerPage");

            if (node.HasValue("localMargins"))
            {
                Vector4 margindata = ConfigNode.ParseVector4(node.GetValue("localMargins"));
                screenXMin   = (int)margindata.x;
                screenYMin   = (int)margindata.y;
                screenWidth  = screenWidth - (int)margindata.z - screenXMin;
                screenHeight = screenHeight - (int)margindata.w - screenYMin;
            }

            pageFont = node.GetInt("defaultFontNumber") ?? 0;

            if (node.HasValue("defaultFontTint"))
            {
                defaultColor = ConfigNode.ParseColor32(node.GetValue("defaultFontTint"));
            }

            if (node.HasValue("techsRequired"))
            {
                techsRequired = node.GetValue("techsRequired").Split(new[] { ' ', ',', ';', '\t', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries).ToList();
            }

            if (node.HasValue("fallbackOnNoTech"))
            {
                fallbackPageName = node.GetValue("fallbackOnNoTech").Trim();
            }

            if (node.HasNode("CONTEXTREDIRECT"))
            {
                ConfigNode[] redirectnodes = node.GetNodes("CONTEXTREDIRECT");
                for (int i = 0; i < redirectnodes.Length; ++i)
                {
                    string[] redirects = redirectnodes[i].GetValues("redirect");
                    for (int j = 0; j < redirects.Length; ++j)
                    {
                        string[] tokens = redirects[j].Split(',');
                        if (tokens.Length > 2 || !IsValidPageName(tokens[0].Trim()) || !IsValidPageName(tokens[1].Trim()))
                        {
                            JUtil.LogMessage(ourMonitor, "Warning, invalid page redirect statement on page #{0}.", pageNumber);
                            continue;
                        }
                        redirectPages[tokens[0].Trim()] = tokens[1].Trim();
                    }

                    string[] renumbers = redirectnodes[i].GetValues("renumber");
                    for (int j = 0; j < renumbers.Length; ++j)
                    {
                        string[] tokens = renumbers[j].Split(',');
                        if (tokens.Length > 2)
                        {
                            JUtil.LogMessage(ourMonitor, "Warning, invalid global button redirect statement on page #{0}: requires two arguments.", pageNumber);
                            continue;
                        }
                        int from, to;
                        if (!int.TryParse(tokens[0], out from) || !int.TryParse(tokens[1], out to))
                        {
                            JUtil.LogMessage(ourMonitor, "Warning, invalid global button redirect statement on page #{0}: something isn't a number", pageNumber);
                            continue;
                        }
                        redirectGlobals[from] = to;
                    }
                }

                JUtil.LogMessage(this, "Page '{2}' (#{0}) registers {1} page redirects and {3} global button redirects.", idNum, redirectPages.Count, name, redirectGlobals.Count);
            }

            foreach (ConfigNode handlerNode in node.GetNodes("PAGEHANDLER"))
            {
                MonoBehaviour         handlerModule;
                HandlerSupportMethods supportMethods;
                MethodInfo            handlerMethod = InstantiateHandler(handlerNode, ourMonitor, out handlerModule, out supportMethods);
                if (handlerMethod != null && handlerModule != null)
                {
                    try
                    {
                        pageHandlerMethod = (Func <int, int, string>)Delegate.CreateDelegate(typeof(Func <int, int, string>), handlerModule, handlerMethod);
                    }
                    catch
                    {
                        JUtil.LogErrorMessage(ourMonitor, "Incorrect signature for the page handler method {0}", handlerModule.name);
                        break;
                    }
                    pageHandlerS      = supportMethods;
                    isMutable         = true;
                    pageHandlerModule = handlerModule;
                    break;
                }
            }

            if (pageHandlerMethod == null)
            {
                if (node.HasValue("text"))
                {
                    text       = JUtil.LoadPageDefinition(node.GetValue("text"));
                    isMutable |= text.IndexOf("$&$", StringComparison.Ordinal) != -1;
                }
            }

            if (node.HasValue("textOverlay"))
            {
                textOverlay = JUtil.LoadPageDefinition(node.GetValue("textOverlay"));
            }

            foreach (ConfigNode handlerNode in node.GetNodes("BACKGROUNDHANDLER"))
            {
                MonoBehaviour         handlerModule;
                HandlerSupportMethods supportMethods;
                MethodInfo            handlerMethod = InstantiateHandler(handlerNode, ourMonitor, out handlerModule, out supportMethods);
                if (handlerMethod != null && handlerModule != null)
                {
                    try
                    {
                        backgroundHandlerMethod = (Func <RenderTexture, float, bool>)Delegate.CreateDelegate(typeof(Func <RenderTexture, float, bool>), handlerModule, handlerMethod);
                    }
                    catch
                    {
                        JUtil.LogErrorMessage(ourMonitor, "Incorrect signature for the background handler method {0}", handlerModule.name);
                        break;
                    }
                    backgroundHandlerS      = supportMethods;
                    isMutable               = true;
                    showNoSignal            = node.HasValue("showNoSignal");
                    background              = BackgroundType.Handler;
                    backgroundHandlerModule = handlerModule;
                    break;
                }
            }

            if (background == BackgroundType.None)
            {
                if (node.HasValue("cameraTransform"))
                {
                    isMutable  = true;
                    background = BackgroundType.Camera;
                    camera     = node.GetValue("cameraTransform");
                    cameraFOV  = defaultFOV;

                    cameraFlickerChance = node.GetFloat("flickerChance") ?? 0;
                    cameraFlickerRange  = node.GetInt("flickerRange") ?? 0;

                    if (node.HasValue("fov"))
                    {
                        float fov;
                        cameraFOV = float.TryParse(node.GetValue("fov"), out fov) ? fov : defaultFOV;
                    }
                    else if (node.HasValue("zoomFov") && node.HasValue("zoomButtons"))
                    {
                        Vector3 zoomFov     = ConfigNode.ParseVector3(node.GetValue("zoomFov"));
                        Vector2 zoomButtons = ConfigNode.ParseVector2(node.GetValue("zoomButtons"));
                        if ((int)zoomFov.z != 0 && ((int)zoomButtons.x != (int)zoomButtons.y))
                        {
                            maxFOV         = Math.Max(zoomFov.x, zoomFov.y);
                            minFOV         = Math.Min(zoomFov.x, zoomFov.y);
                            zoomSteps      = (int)zoomFov.z;
                            zoomUpButton   = (int)zoomButtons.x;
                            zoomDownButton = (int)zoomButtons.y;
                            zoomSkip       = (maxFOV - minFOV) / zoomSteps;
                            currentZoom    = 0;
                            cameraFOV      = maxFOV;
                        }
                        else
                        {
                            JUtil.LogMessage(ourMonitor, "Ignored invalid camera zoom settings on page {0}.", pageNumber);
                        }
                    }
                }
            }
            if (background == BackgroundType.None)
            {
                if (node.HasValue("textureURL"))
                {
                    string textureURL = node.GetValue("textureURL").EnforceSlashes();
                    if (GameDatabase.Instance.ExistsTexture(textureURL))
                    {
                        backgroundTexture = GameDatabase.Instance.GetTexture(textureURL, false);
                        background        = BackgroundType.Texture;
                    }
                }
            }
            if (node.HasValue("textureInterlayURL"))
            {
                string textureURL = node.GetValue("textureInterlayURL").EnforceSlashes();
                if (GameDatabase.Instance.ExistsTexture(textureURL))
                {
                    interlayTexture = GameDatabase.Instance.GetTexture(textureURL, false);
                }
                else
                {
                    JUtil.LogErrorMessage(ourMonitor, "Interlay texture {0} could not be loaded.", textureURL);
                }
            }
            if (node.HasValue("textureOverlayURL"))
            {
                string textureURL = node.GetValue("textureOverlayURL").EnforceSlashes();
                if (GameDatabase.Instance.ExistsTexture(textureURL))
                {
                    overlayTexture = GameDatabase.Instance.GetTexture(textureURL, false);
                }
                else
                {
                    JUtil.LogErrorMessage(ourMonitor, "Overlay texture {0} could not be loaded.", textureURL);
                }
            }
        }