<NME> Global.java <BEF> /* * Copyright 2015 The SageTV Authors. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package sage.api; import sage.Airing; import sage.BigBrother; import sage.Burner; import sage.Catbert; import sage.Channel; import sage.EPG; import sage.EPGDataSource; import sage.ExternalTuningManager; import sage.FileDownloader; import sage.FileTransfer; import sage.SchedulerSelector; import sage.SeekerSelector; import sage.IOUtils; import sage.LinuxUtils; import sage.MMC; import sage.ManualRecord; import sage.MediaFile; import sage.MiniClientSageRenderer; import sage.NetworkClient; import sage.NewStorageDeviceDetector; import sage.Playlist; import sage.Pooler; import sage.PredefinedJEPFunction; import sage.PseudoMenu; import sage.Ripper; import sage.SFIRTuner; import sage.Sage; import sage.SageConstants; import sage.SageTV; import sage.Scheduler; import sage.Seeker; import sage.UIClient; import sage.UIManager; import sage.UserEvent; import sage.Widget; import sage.Wizard; import sage.ZComp; import sage.ZDataTable; import sage.ZLabel; import sage.ZPseudoComp; /** * System methods used for dealing with Sage specifics */ public class Global { private Global() {} public static void init(Catbert.ReflectionFunctionTable rft) { rft.put(new PredefinedJEPFunction("Global", "Refresh") { /** * Re-evaluates and redraws all UI elements on the current menu * * @declaration public void Refresh(); */ public Object runSafely(Catbert.FastStack stack) throws Exception { if (stack.getUIMgrSafe() == null) return null; PseudoMenu currUI = stack.getUIMgrSafe().getCurrUI(); if (currUI != null) currUI.refresh(); return null; } }); rft.put(new PredefinedJEPFunction("Global", "RefreshArea", new String[] {"WidgetName"}) { /** * Finds the Widget on the current menu who's name matches the argument and then re-evaluates and redraws all UI elements, and their children for this Widget * @param WidgetName the name that a UI component's Widget must match, if null or zero length, then this is the same as calling {@link #Refresh Refresh()} * * @declaration public void RefreshArea(String WidgetName); */ public Object runSafely(Catbert.FastStack stack) throws Exception { String s = getString(stack); PseudoMenu currUI = (stack.getUIMgrSafe() == null) ? null : stack.getUIMgrSafe().getCurrUI(); if (currUI != null) currUI.refreshByWidgetName(s); return null; } }); rft.put(new PredefinedJEPFunction("Global", "RefreshAreaForVariable", new String[] { "Name", "Value" }) { /** * Searches all visible UI elements in the current menu finding any that have a variable with the specified name * matching the specified value. For any elements it finds, it will re-evaluate and redraws its UI elements, and its children * @param Name the name of the variable to match * @param Value the value of the variable to match on * @since 6.6 * * @declaration public void RefreshAreaForVariable(String Name, Object Value); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ Object val = stack.pop(); String name = getString(stack); PseudoMenu ui = (stack.getUIMgrSafe() == null) ? null : stack.getUIMgrSafe().getCurrUI(); if (ui != null) ui.refreshByValue(name, val); return null; }}); rft.put(new PredefinedJEPFunction("Global", "Repaint") { /** * Redraws all UI elements on the current menu * * @declaration public void Repaint(); */ public Object runSafely(Catbert.FastStack stack) throws Exception { if (stack.getUIMgrSafe() == null) return null; PseudoMenu currUI = stack.getUIMgrSafe().getCurrUI(); if (currUI != null) currUI.repaint(); return null; } }); rft.put(new PredefinedJEPFunction("Global", "RepaintArea", new String[] {"WidgetName"}) { /** * Finds the Widget on the current menu who's name matches the argument and then redraws all UI elements, and their children for this Widget * @param WidgetName the name that a UI component's Widget must match, if null or zero length, then this is the same as calling {@link #Repaint Repaint()} * * @declaration public void RepaintArea(String WidgetName); */ public Object runSafely(Catbert.FastStack stack) throws Exception { String s = getString(stack); PseudoMenu currUI = (stack.getUIMgrSafe() == null) ? null : stack.getUIMgrSafe().getCurrUI(); if (currUI != null) currUI.repaintByWidgetName(s); return null; } }); rft.put(new PredefinedJEPFunction("Global", "AddStaticContext", 2, new String[]{"Name", "Value"}) { /** * Sets the variable with the specified name to the specified value. This variable will * exist for the lifetime of the current Menu. When the next Menu transition occurs, * all values in the static context will be copied to the highest level context for the new Menu. * The static context is then cleared. This is the way you can pass an Object from one menu to * another, an example is showing the detailed info for an Airing by adding the Airing to the * static context and then transitioning to a Menu that will display the details for that Airing. * * @param Name the name to use for this 'static context' variable * @param Value the value to set this 'static context' variable to * @return the passed in Value * * @declaration public Object AddStaticContext(String Name, Object Value); */ public Object runSafely(Catbert.FastStack stack) throws Exception { Object rv = stack.pop(); String varName = getString(stack); if (stack.getUIMgrSafe() != null) stack.getUIMgrSafe().getStaticContext().put(varName, rv); return rv; } }); rft.put(new PredefinedJEPFunction("Global", "AddGlobalContext", 2, new String[]{"Name", "Value"}) { /** * Sets the variable with the specified name to the specified value. This variable * will exist for the lifetime of the SageTV application and is always in scope for all expression evaluation. This is a 'global variable'. * @param Name the name to use for this 'global context' variable * @param Value the value to set this 'global context' variable to * @return the passed in Value * * @declaration public Object AddGlobalContext(String Name, Object Value); */ public Object runSafely(Catbert.FastStack stack) throws Exception { Object rv = stack.pop(); String varName = getString(stack); if (stack.getUIMgrSafe() != null) stack.getUIMgrSafe().getGlobalContext().put(varName, rv); return rv; } }); rft.put(new PredefinedJEPFunction("Global", "AreThereUnresolvedConflicts") { /** * Returns whether or not there are unresolved scheduling conflicts * @return true if there are unresolved scheduling conflicts, false otherwise * * @declaration public boolean AreThereUnresolvedConflicts(); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ return Boolean.valueOf(SchedulerSelector.getInstance().areThereDontKnows()); }}); rft.put(new PredefinedJEPFunction("Global", "IsAsleep") { /** * Returns true if SageTV is in the Sleep state. * @return true if SageTV is in the Sleep state * * @declaration public boolean IsAsleep(); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ return Boolean.valueOf(stack.getUIMgrSafe().isAsleep()); }}); rft.put(new PredefinedJEPFunction("Global", "GetTotalDiskspaceAvailable", true) { /** * Gets the total diskspace available for television recording by SageTV. This is the unused space in the video directories. * @return the total diskspace available for television recording by SageTV (in bytes) * * @declaration public long GetTotalDiskspaceAvailable(); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ return new Long(SeekerSelector.getInstance().getAvailVideoDiskspace()); }}); rft.put(new PredefinedJEPFunction("Global", "GetTotalLibraryDuration", true) { /** * Returns the total duration of all of the content in the media library * @return the total duration of all of the content in the media library in milliseconds * * @declaration public long GetTotalLibraryDuration(); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ return new Long(SeekerSelector.getInstance().getTotalImportedLibraryDuration()); }}); rft.put(new PredefinedJEPFunction("Global", "GetTotalVideoDuration", true) { /** * Returns the total duration of all of the recorded television content * @return the total duration of all of the recorded television content in milliseconds * * @declaration public long GetTotalVideoDuration(); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ return new Long(SeekerSelector.getInstance().getTotalVideoDuration()); }}); rft.put(new PredefinedJEPFunction("Global", "GetUsedLibraryDiskspace", true) { /** * Returns the total number of bytes on disk used by the content in the imported video, picturees and music libraries * @return the total number of bytes on disk used by the content in the imported video, picturees and music libraries * * @declaration public long GetUsedLibraryDiskspace(); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ return new Long(SeekerSelector.getInstance().getUsedImportedLibraryDiskspace()); }}); rft.put(new PredefinedJEPFunction("Global", "GetUsedVideoDiskspace", true) { /** * Returns the total number of bytes on disk used by recorded television content * @return the total number of bytes on disk used by recorded television content * * @declaration public long GetUsedVideoDiskspace(); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ return new Long(SeekerSelector.getInstance().getUsedVideoDiskspace()); }}); rft.put(new PredefinedJEPFunction("Global", "AreAiringsSameShow", 2, new String[] {"Airing1", "Airing2"}) { /** * Returns true if two Airings represent the same Show. This means that they both are the same content (i.e. one is a repeat of the other) * Just because two Airings use the same Show object (in terms of object reference) doesn't mean this call will return true. * @param Airing1 one of the two Airing objects to compare * @param Airing2 the other Airing object to compare * @return true if two Airings represent the same Show, false otherwise * * @declaration public boolean AreAiringsSameShow(Airing Airing1, Airing Airing2); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ return Boolean.valueOf(BigBrother.areSameShow(getAir(stack), getAir(stack), false)); }}); rft.put(new PredefinedJEPFunction("Global", "GetLastEPGDownloadTime", true) { /** * Returns the last time that SageTV did an EPG update. The returned value uses the same units as java.lang.System.currentTimeMillis() * @return the last time that SageTV did an EPG update * * @declaration public long GetLastEPGDownloadTime(); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ return new Long(EPG.getInstance().getLastRun()); }}); rft.put(new PredefinedJEPFunction("Global", "GetLogo", 1, new String[] { "LogoName" }) { /** * Gets an Image object that represents the specified name. This is normally used for Channel Logos. * @param LogoName the name to use to lookup the logo image * @return the image object that corresponds to the specified name if one exists, the null image otherwise * * @declaration public MetaImage GetLogo(String LogoName); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ return EPG.getInstance().getLogo(getString(stack), stack.getUIComponent()); }}); rft.put(new PredefinedJEPFunction("Global", "GetTimeUntilNextEPGDownload", true) { /** * The amount of time in milliseconds until SageTV will perform an EPG update again. Zero if no update is planned. * @return the amount of time in milliseconds until SageTV will perform an EPG update again. Zero if no update is planned * * @declaration public long GetTimeUntilNextEPGDownload(); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ return new Long(EPG.getInstance().getTimeTillUpdate()); }}); rft.put(new PredefinedJEPFunction("Global", "GetAllLineups") { /** * Returns the name of all the EPG lineups in the system * @return a list of all the names of the EPG lineups in the system * * @declaration public String[] GetAllLineups(); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ return EPG.getInstance().getAllProviderNames(); }}); rft.put(new PredefinedJEPFunction("Global", "IsChannelDownloadComplete", new String[] { "Lineup" }, true) { /** * Returns true if the channel download has been completed on the specified lineup * @param Lineup the name of the Lineup * @return true if the channel download has been completed on the specified lineup, false otherwise * * @declaration public boolean IsChannelDownloadComplete(String Lineup); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ String lineup = getString(stack); return Boolean.valueOf(EPG.getInstance().getEPGDSForEPGDSName(lineup).isChanDownloadComplete()); }}); rft.put(new PredefinedJEPFunction("Global", "GetEPGProperty", new String[]{"EPGDataSource", "Property", "Parameter"}, true) { /** * Gets a property from a specific EPG data source with an optional parameter * @param EPGDataSource the name of the EPG data source * @param Property the property name to get * @param Parameter optional parameter * @return the value of the requested property * @since 9.0 * * @declaration public Object GetEPGProperty(String EPGDataSource, String Property, String Parameter); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ String parameter = getString(stack); String property = getString(stack); String dataSource = getString(stack); try { return EPG.getProperty(dataSource, property, parameter); } catch (sage.EPGServerException e) { return e.getMessage(); } }}); rft.put(new PredefinedJEPFunction("Global", "SetEPGProperty", new String[]{"EPGDataSource", "Property", "Value"}, true) { /** * Sets a property for a specific EPG data source to the provided value * @param EPGDataSource the name of the EPG data source * @param Property the property name to set * @param Value the value to set * @return result of setting the property * @since 9.0 * * @declaration public Object SetEPGProperty(String EPGDataSource, String Property, String Value); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ String value = getString(stack); String property = getString(stack); String dataSource = getString(stack); try { return EPG.setProperty(dataSource, property, value); } catch (sage.EPGServerException e) { return e.getMessage(); } }}); rft.put(new PredefinedJEPFunction("Global", "GetLocalMarketsFromEPGServer", true) { /** * Gets a list of all the possible United States local broadcast markets from the EPG server * @return a String[] of all the possible United States local broadcast markets from the EPG server or a String error message of "NO_KEY", "INVALID_KEY", or "CONNECTION_FAILURE" * * @declaration public Object GetLocalMarketsFromEPGServer(); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ try { return EPG.getInstance().getLocalMarketsAndCacheNames(); } catch (sage.EPGServerException e) { System.out.println("ERROR communicating with EPG server of: " + e); return e.getMessage(); } }}); rft.put(new PredefinedJEPFunction("Global", "GetLineupsForZipCodeFromEPGServer", 1, new String[]{"ZipCode"}, true) { /** * Gets a list from the EPG server of all the possible EPG Lineups that are available in a given zip code * @param ZipCode the zip code to search for EPG lineups in * @return a String[] from the EPG server of all the possible EPG lineups in the specified zip code or a String error message of "NO_KEY", "INVALID_KEY", or "CONNECTION_FAILURE" * * @declaration public Object GetLineupsForZipCodeFromEPGServer(String ZipCode); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ try { return EPG.getInstance().getProvidersAndCacheNames(getString(stack)); } catch (sage.EPGServerException e) { System.out.println("ERROR communicating with EPG server of: " + e); return e.getMessage(); } }}); rft.put(new PredefinedJEPFunction("Global", "GetCurrentlyRecordingMediaFiles", true) { /** * Returns a list of all of the files that SageTV is currently recording * @return a list of all of the files that SageTV is currently recording * * @declaration public MediaFile[] GetCurrentlyRecordingMediaFiles(); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ return SeekerSelector.getInstance().getCurrRecordFiles(); }}); rft.put(new PredefinedJEPFunction("Global", "GetSuggestedIntelligentRecordings", true) { /** * Gets a list of all of the Airings that SageTV would record if Intelligent Recording was enabled. * This does not include Manual Recordings or Favorites. * @return a list of all of the Airings that SageTV would record if Intelligent Recording was enabled. * @since 4.1 * * @declaration public Airing[] GetSuggestedIntelligentRecordings(); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ return SeekerSelector.getInstance().getIRScheduledAirings(); }}); rft.put(new PredefinedJEPFunction("Global", "GetScheduledRecordings", true) { /** * Gets a list of all of the Airings that SageTV is planning to record in the future * @return a list of all of the Airings that SageTV is planning to record in the future * * @declaration public Airing[] GetScheduledRecordings(); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ return SeekerSelector.getInstance().getInterleavedScheduledAirings(); }}); rft.put(new PredefinedJEPFunction("Global", "GetScheduledRecordingsForDevice", 1, new String[] { "CaptureDevice"}, true) { /** * Gets a list of all of the Airings that SageTV is planning to record in the future on the specified CaptureDevice * @param CaptureDevice the name of a CaptureDevice for SageTV to get the scheduled recordings for * @return a list of all of the Airings that SageTV is planning to record in the future on the specified CaptureDevice * * @declaration public Airing[] GetScheduledRecordingsForDevice(String CaptureDevice); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ return SeekerSelector.getInstance().getScheduledAiringsForSource(getString(stack)); }}); rft.put(new PredefinedJEPFunction("Global", "GetScheduledRecordingsForTime", 2, new String[] { "StartTime", "StopTime" }, true) { /** * Gets a list of all of the Airings that SageTV is planning on recording during the specified time span * @param StartTime the starting time to get all of the scheduled recordings for * @param StopTime the ending time to get all of the scheduled recordings for * @return a list of all of the Airings that SageTV is planning on recording during the specified start-stop time window * * @declaration public Airing[] GetScheduledRecordingsForTime(long StartTime, long StopTime); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ long stop = getLong(stack); return SeekerSelector.getInstance().getInterleavedScheduledAirings(getLong(stack), stop); }}); rft.put(new PredefinedJEPFunction("Global", "GetScheduledRecordingsForDeviceForTime", 3, new String[] { "CaptureDevice", "StartTime", "StopTime"}, true) { /** * Gets a list of all of the Airings that SageTV is planning on recording during the specified time span on a specified CaptureDevice * @param CaptureDevice the name of a CaptureDevice for SageTV to get the scheduled recordings for * @param StartTime the starting time to get all of the scheduled recordings for * @param StopTime the ending time to get all of the scheduled recordings for * @return a list of all of the Airings that SageTV is planning on recording during the specified start-stop time window on the specified CaptureDevice * * @declaration public Airing[] GetScheduledRecordingsForDeviceForTime(String CaptureDevice, long StartTime, long StopTime); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ long stop = getLong(stack); long start = getLong(stack); return SeekerSelector.getInstance().getScheduledAiringsForSource(getString(stack), start, stop); }}); rft.put(new PredefinedJEPFunction("Global", "GetRecentlyWatched", 1, new String[] {"DurationToLookBack"}, true) { /** * Gets a list of all of the Airings that have been watched within the specified amount of time * @param DurationToLookBack tha amount of time in milliseconds that should be searched for watched Airings * @return a list of all of the Airings that have been watched within the specified amount of time * * @declaration public Airing[] GetRecentlyWatched(long DurationToLookBack); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ return SeekerSelector.getInstance().getRecentWatches(Sage.time() - getLong(stack)); }}); rft.put(new PredefinedJEPFunction("Global", "RunLibraryImportScan", 1, new String[] {"WaitUntilDone"}, true) { /** * Tells SageTV to run a library import scan now. This will scan all of the library import directories for new content. * @param WaitUntilDone if this parameter is true then this call will not return until SageTV has finished the import scan, otherwise it returns immediately * * @declaration public void RunLibraryImportScan(boolean WaitUntilDone); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ SeekerSelector.getInstance().scanLibrary(Catbert.evalBool(stack.pop())); return null; }}); rft.put(new PredefinedJEPFunction("Global", "Exit") { /** * Causes the SageTV application to terminate. If this is called from the non-primary UI session then it will terminate the UI session it is called from. * * @declaration public void Exit(); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ UIManager uiMgr = stack.getUIMgrSafe(); if (uiMgr.getLocalUIClientName().equals(Seeker.LOCAL_PROCESS_CLIENT)) SageTV.exit(); else uiMgr.goodbye(); return null; }}); rft.put(new PredefinedJEPFunction("Global", "SageCommand", -1, new String[]{"Command"}) { /** * Causes the corresponding Sage Command to be executed just like it would be if the user performed it. * These are always done asynchronously with the exception of "Back" and "Forward" since those effect * the current UI and may be used to override a menu transition. * @param Command the name of the Sage Command to execute * * @declaration public void SageCommand(String Command); */ /** * Causes the corresponding Sage Command to be executed just like it would be if the user performed it. * These are always done asynchronously with the exception of "Back" and "Forward" since those effect * the current UI and may be used to override a menu transition. The payload will be passed along and * be accessible in the listener object in the STV. * @param Command the name of the Sage Command to execute * @param Payload an object to pass along with the event * @since 8.1 * * @declaration public void SageCommand(String Command, Object Payload); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ Object payload = null; if (curNumberOfParameters == 2) payload = stack.pop(); String cmd = getString(stack); stack.getUIMgrSafe().doUserEvent2(UserEvent.getEvtCodeForName(cmd), payload); return null; }}); rft.put(new PredefinedJEPFunction("Global", "RemoveUnusedLineups") { /** * Removes all of the lineups from SageTV's configuration that are no longer in use by a CaptureDevice * @return true if any lineups were removed, false otherwise * * @declaration public boolean RemoveUnusedLineups(); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ // Execute this on the server if we're the client; but then clean us up locally since removals // aren't propogated in the property exchange. But do it first so anything the server has that we don't // gets propogated back down correctly boolean killedAny = false; EPGDataSource[] allDS = EPG.getInstance().getDataSources(); for (int i = 0; i < allDS.length; i++) { if (!MMC.getInstance().isProviderUsed(allDS[i].getProviderID())) { EPG.getInstance().removeDataSource(allDS[i]); killedAny = true; } } EPG.getInstance().kick(); SchedulerSelector.getInstance().kick(false); if (Sage.client) { return makeNetworkedCall(stack); } return Boolean.valueOf(killedAny); }}); rft.put(new PredefinedJEPFunction("Global", "GetApplicationLaunchTime") { /** * Returns the time that the SageTV application was instantiated. * @return the time that the SageTV application was instantiated * * @declaration public long GetApplicationLaunchTime(); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ return new Long(SageTV.getInstanceStartTime()); }}); rft.put(new PredefinedJEPFunction("Global", "GetFocusContext") { /** * Copies all variables from the currently focused UI element's variable context to the current context * of the calling Action. Any variables that are in a common parent hierarchy are not copied as part of this. * @return true if there was a focused element and it's context was copied, false if there was no focused element found * * @declaration public boolean GetFocusContext(); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ throw new IllegalArgumentException("GetFocusContext() can only be used by itself"); }}); rft.put(new PredefinedJEPFunction("Global", "Fork") { /** * Spawns a new thread of execution that will be used for further processing of Widget chain. This is analagous to 'forking' a thread * to continue execution of a widget chain in parallel to the current system execution. * * @declaration public void Fork(); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ throw new IllegalArgumentException("Fork() can only be used by itself"); }}); rft.put(new PredefinedJEPFunction("Global", "TransmitCommandUsingInfraredTuningPlugin", new String[] {"TuningPlugin","TuningPluginPort","RemoteName", "CommandName", "RepeatFactor"}, true) { /** * Causes SageTV to instruct the specified tuning plugin to send a command * @param TuningPlugin the name of the tuning plugin that should send the command * @param TuningPluginPort the name of the port the specified tuning plugin is on * @param RemoteName the name of the 'Remote Control' that should be used to send the command * @param CommandName the name of the command to be sent * @param RepeatFactor the 'repeat factor' to use for sending the infrared command, 2 is the default * * @declaration public void TransmitCommandUsingInfraredTuningPlugin(String TuningPlugin, int TuningPluginPort, String RemoteName, String CommandName, int RepeatFactor); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ int rep = getInt(stack); String cmd = getString(stack); String remoteName = getString(stack); int portNum = getInt(stack); SFIRTuner tun = ExternalTuningManager.getIRTunerPlugin(getString(stack), portNum); if (tun != null) tun.playCommand(remoteName, cmd, rep, false); return null; }}); rft.put(new PredefinedJEPFunction("Global", "DebugLog", 1, new String[] {"DebugString"}) { /** * Prints out a message to SageTV's debug log * @param DebugString the string to print out * * @declaration public void DebugLog(String DebugString); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ String s = getString(stack); if (Sage.DBG) System.out.println(s); return null; }}); rft.put(new PredefinedJEPFunction("Global", "CloseOptionsMenu", -1, new String[]{"WidgetName", "WaitForClose"}) { /** * Closes the last OptionsMenu that was shown and continues execution of the Action * chain that spawned that OptionsMenu at the sibling after this OptionsMenu. The * feature of continuing execution can be used to prompt the user with a question * through an OptionsMenu before continuing on execution of an Action chain. * An example is confirming something they just did before it actually gets done. * * @declaration public void CloseOptionsMenu(); */ /** * Closes the OptionsMenu who's Widget name (or themed Widget name) matches that of the argument and continues execution of the Action * chain that spawned that OptionsMenu at the sibling after this OptionsMenu. The * feature of continuing execution can be used to prompt the user with a question * through an OptionsMenu before continuing on execution of an Action chain. * An example is confirming something they just did before it actually gets done. * If this OptionsMenu is not on top, then it cannot be closed until it becomes the one on top. * @param WidgetName the name of the Widget for the OptionsMenu or the themed OptionsMenu source for that Widget that should be closed * @param WaitForClose if true then this call will not return until the specified OptionsMenu target is closed * @return returns true if the target OptionsMenu is not open or if it was closed as a result of this call, will only return false if waitForClose is true and the target OptionsMenu is not on top * @since 7.1 * * @declaration public boolean CloseOptionsMenu(String WidgetName, boolean WaitForClose); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ if (curNumberOfParameters == 2) { boolean waitForClose = getBool(stack); String widgName = getString(stack); return stack.getUIMgrSafe().removePopup(widgName, waitForClose) ? Boolean.TRUE : Boolean.FALSE; } else { stack.getUIMgrSafe().removePopup(); return null; } }}); rft.put(new PredefinedJEPFunction("Global", "IsOptionsMenuOpen") { /** * Returns true if an options menu is currently open in the UI. * @return true if an options menu is currently open in the UI, false otherwise * @since 7.1 * * @declaration public boolean IsOptionsMenuOpen(); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ UIManager uiMgr = stack.getUIMgr(); if (uiMgr != null) { PseudoMenu currUI = uiMgr.getCurrUI(); return (currUI != null && currUI.hasPopup()) ? Boolean.TRUE : Boolean.FALSE; } return Boolean.FALSE; }}); rft.put(new PredefinedJEPFunction("Global", "GetSageCommandNames") { /** * Gets the names of all of the SageTV commands that are available in the system * @return a list of the names of all of the SageTV commands that are available in the system * * @declaration public java.util.Vector GetSageCommandNames(); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ java.util.Vector rv = new java.util.Vector(java.util.Arrays.asList(UserEvent.PRETTY_UENAMES)); rv.remove(0); // ? rv.remove(0); // ? rv.remove(rv.size() - 1); // Anything return rv; }}); rft.put(new PredefinedJEPFunction("Global", "ApplyServiceLevelToLineup", 2, new String[] { "Lineup", "ServiceLevel" }, true) { /** * Applies a service level to a given lineup. This is specific to the EPG data source that is being used. * @param Lineup the name of the EPG lineup to modify * @param ServiceLevel the service level to apply to the lineup * * @declaration public void ApplyServiceLevelToLineup(String Lineup, int ServiceLevel); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ int lev = getInt(stack); EPGDataSource ds = EPG.getInstance().getEPGDSForEPGDSName(getString(stack)); if (ds != null) ds.applyServiceLevel(lev); return null; }}); rft.put(new PredefinedJEPFunction("Global", "SetFocusForVariable", new String[] { "Name", "Value" }) { /** * Searches all UI elements in the current menu until it finds one that has a variable with the specified name * matching the specified value. Once it finds this UI element, it gives it the focus. If scrolling of a table * or panel is necessary to make it visible, that scrolling will occur. * @param Name the name of the variable to match * @param Value the value of the variable to match on * @return true if the focus was set * * @declaration public boolean SetFocusForVariable(String Name, Object Value); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ Object val = stack.pop(); String name = getString(stack); PseudoMenu ui = stack.getUIMgrSafe().getCurrUI(); return Boolean.valueOf(ui.setFocusByValue(name, val)); }}); rft.put(new PredefinedJEPFunction("Global", "EnsureVisibilityForVariable", new String[] { "Name", "Value", "DisplayIndex" }) { /** * Searches the tables in the current menu for a cell that matches the passed in name/value pair; * if found it will ensure that it is currently visible in the UI at the specified visual index of the table. * The name should match the name of the TableComponent-Cell. For example if the TableComponent with a Cell * subtype had a name of "File" and listed all of the MediaFiles; then calling * EnsureVisibilityForVariable("File", MyMediaFile, 1) would cause the table to scroll so that the second row * showed the cell whose File value corresponded to MyMediaFile. This does NOT change the focus, * if you wish to scroll a table and shift the focus then use SetFocusForVariable * * @param Name the name of the variable to match on * @param Value the value of the variable to match * @param DisplayIndex 0-based value signifying which visually displayed row or column should show the corresonding cell * @return true if there was a matching variable found * * @declaration public boolean EnsureVisibilityForVariable(String Name, Object Value, int DisplayIndex); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ int dispIndex = getInt(stack); Object val = stack.pop(); String name = getString(stack); PseudoMenu ui = stack.getUIMgrSafe().getCurrUI(); return Boolean.valueOf(ui.ensureVisbilityForValue(name, val, dispIndex)); }}); rft.put(new PredefinedJEPFunction("Global", "GetVariableFromContext", new String[] { "MatchName", "MatchValue", "LookupName" }) { /** * Searches all UI elements in the current menu until it finds one that has a variable with the specified name * matching the specified value. Once it finds this UI element, it then does a lookup of the other * specified variable in that UI element's context and returns that value * @param MatchName the name of the variable to match * @param MatchValue the value of the variable to match on * @param LookupName the variable to lookup in the matching context * @return the value of the variable * @since 7.0 * * @declaration public Object GetVariableFromContext(String MatchName, Object MatchValue, String LookupName); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ String lookupName = getString(stack); Object val = stack.pop(); String name = getString(stack); PseudoMenu ui = stack.getUIMgrSafe().getCurrUI(); // Look for a visible one first; if we don't find it, then also accept non-visible ones as well if (ui != null) { ZPseudoComp rvContext = ui.getCompForVariable(name, val, stack.getUIComponent()); if (rvContext != null) { if ("Focused".equals(lookupName)) return Boolean.valueOf(rvContext.isFocused()); else if ("FocusedChild".equals(lookupName)) return Boolean.valueOf(rvContext.doesHierarchyHaveFocus()); else return rvContext.getRelatedContext().get(lookupName); } } return null; }}); rft.put(new PredefinedJEPFunction("Global", "GetVisibilityForVariable", new String[] { "MatchName", "MatchValue" }) { /** * Searches all UI elements in the current menu until it finds one that has a variable with the specified name * matching the specified value. Once it finds this UI element, it will return true if that UI element is currently * visible and false otherwise * @param MatchName the name of the variable to match * @param MatchValue the value of the variable to match on * @return true if the found component is visible, false otherwise * @since 7.0 * * @declaration public boolean GetVisibilityForVariable(String MatchName, Object MatchValue); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ /* Object val = stack.pop(); String name = getString(stack); PseudoMenu ui = stack.getUIMgrSafe().getCurrUI(); return Boolean.valueOf(ui.getPassesConditionalForVariable(name, val));*/ Object val = stack.pop(); String name = getString(stack); if (stack.getUIMgr() == null) return null; PseudoMenu ui = stack.getUIMgr().getCurrUI(); // Look for a visible one first; if we don't find it, then also accept non-visible ones as well if (ui != null) { ZPseudoComp uiComp = ui.getCompForVariable(name, val, stack.getUIComponent()); return (uiComp != null && uiComp.passesUpwardConditional() && uiComp.getNumKids() > 0) ? Boolean.TRUE : Boolean.FALSE; } return Boolean.FALSE; }}); rft.put(new PredefinedJEPFunction("Global", "GetUIComponentForVariable", new String[] { "MatchName", "MatchValue" }) { /** * Searches all UI elements in the current menu until it finds one that has a variable with the specified name * matching the specified value. It then returns on Object representing that UI component. The search method * prefers visible components over hidden ones. * @param MatchName the name of the variable to match * @param MatchValue the value of the variable to match on * @return the UI component with the specified variable set * @since 7.0 * * @declaration public Object GetUIComponentForVariable(String MatchName, Object MatchValue); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ Object val = stack.pop(); String name = getString(stack); if (stack.getUIMgr() == null) return null; PseudoMenu ui = stack.getUIMgr().getCurrUI(); // Look for a visible one first; if we don't find it, then also accept non-visible ones as well if (ui != null) { return ui.getCompForVariable(name, val, stack.getUIComponent()); } return null; }}); rft.put(new PredefinedJEPFunction("Global", "GetUIComponentContext") { /** * Returns the UI component that this execution originated from. For * 'green' process chains; this will correspond to the UI component that received the event. For 'blue' * UI chains; this will correspond to the UI component who's conditionality is being determined or who's data * is being evaluated. This will be null if there is no UI context; such as for non-UI hooks and calls made from * Java directly. * @return the UIComponent that corresponds to the UI context used for the current evaluation, null if there is no context * @since 7.0 * * @declaration public Object GetUIComponentContext(); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ return stack.getUIComponent(); }}); rft.put(new PredefinedJEPFunction("Global", "SetFocusToUIComponent", new String[] { "UIComponent" }) { /** * Sets focus in the specified UI component. The UIComponent must be focusable for this to succeed * @param UIComponent the specified UIComponent, can be retrieved using {@link #GetUIComponentForVariable GetUIComponentForVariable} API call * @return true if setting the focus in the specified component succeeded, false otherwise * @since 7.0 * * @declaration public boolean SetFocusToUIComponent(Object UIComponent); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ ZPseudoComp uiComp = getUIComp(stack); if (uiComp != null && uiComp.isFocusable()) { return uiComp.setFocus() ? Boolean.TRUE : Boolean.FALSE; } return Boolean.FALSE; }}); rft.put(new PredefinedJEPFunction("Global", "GetTableFocusedVisibleRow", new String[] { "UIComponent" }) { /** * Gets the row number that currently has focus in the specified table. The argument may be the table itself; or a component between * the table and the focused component. * @param UIComponent the specified UIComponent, can be retrieved using {@link #GetUIComponentForVariable GetUIComponentForVariable} API call * @return the row number (1-based) which is currently focused in the table, -1 is returned if the value can't be resolved * @since 7.0 * * @declaration public int GetTableFocusedVisibleRow(Object UIComponent); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ ZPseudoComp uiComp = getUIComp(stack); if (uiComp != null) { // Now get the child focused component if it exists // if (uiComp.doesHierarchyHaveFocus()) { ZComp focusOwner = uiComp.getLastFocusedChild(); if (focusOwner == null) return new Integer(-1); if (focusOwner instanceof ZPseudoComp) { ZPseudoComp focusComp = (ZPseudoComp) focusOwner; // This depends upon the orientation of the table ZDataTable tabParent = focusComp.getTableParent(); boolean vert = true; if (tabParent != null && tabParent.getTableDimensions() == ZDataTable.HORIZONTAL_DIMENSION) vert = false; // Now calculate its visible row position Object o1 = focusComp.getRelatedContext().safeLookup("TableRow"); Object o2 = focusComp.getRelatedContext().safeLookup("NumColsPerPage"); Object o3 = focusComp.getRelatedContext().safeLookup("VScrollIndex"); Object o4 = focusComp.getRelatedContext().safeLookup("NumRowsPerPage"); Object o5 = focusComp.getRelatedContext().safeLookup("HScrollIndex"); int tablePosition = o1 != null ? (Integer.parseInt(o1.toString()) - 1) : 0; int colsPerPage = o2 != null ? Math.max(1, Integer.parseInt(o2.toString())) : 1; int vscrollIndex = o3 != null ? (Integer.parseInt(o3.toString()) - 1) : 0; int rowsPerPage = o4 != null ? Math.max(1, Integer.parseInt(o4.toString())) : 1; int hscrollIndex = o5 != null ? (Integer.parseInt(o5.toString()) - 1) : 0; if (vert) { Object o7 = focusComp.getRelatedContext().safeLookup("NumRows"); int numRows = o7 != null ? Integer.parseInt(o7.toString()) : 1; return new Integer(1 + (((tablePosition - colsPerPage * vscrollIndex - rowsPerPage * hscrollIndex + numRows) % numRows) / colsPerPage)); } else { Object o6 = focusComp.getRelatedContext().safeLookup("NumCols"); int numCols = o6 != null ? Integer.parseInt(o6.toString()) : 1; return new Integer(1 + (((tablePosition - colsPerPage * vscrollIndex - rowsPerPage * hscrollIndex + numCols) % numCols) % rowsPerPage)); } } } } return new Integer(-1); }}); rft.put(new PredefinedJEPFunction("Global", "GetTableFocusedVisibleColumn", new String[] { "UIComponent" }) { /** * Gets the column number that currently has focus in the specified table. The argument may be the table itself; or a component between * the table and the focused component. * @param UIComponent the specified UIComponent, can be retrieved using {@link #GetUIComponentForVariable GetUIComponentForVariable} API call * @return the column number (1-based) which is currently focused in the table, -1 is returned if the value can't be resolved * @since 7.0 * * @declaration public int GetTableFocusedVisibleColumn(Object UIComponent); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ ZPseudoComp uiComp = getUIComp(stack); if (uiComp != null) { // Now get the child focused component if it exists // if (uiComp.doesHierarchyHaveFocus()) { ZComp focusOwner = uiComp.getLastFocusedChild(); if (focusOwner == null) return new Integer(-1); if (focusOwner instanceof ZPseudoComp) { ZPseudoComp focusComp = (ZPseudoComp) focusOwner; // This depends upon the orientation of the table ZDataTable tabParent = focusComp.getTableParent(); boolean vert = true; if (tabParent != null && tabParent.getTableDimensions() == ZDataTable.HORIZONTAL_DIMENSION) vert = false; // Now calculate its visible column position Object o1 = focusComp.getRelatedContext().safeLookup("TableRow"); Object o2 = focusComp.getRelatedContext().safeLookup("NumColsPerPage"); Object o3 = focusComp.getRelatedContext().safeLookup("VScrollIndex"); Object o4 = focusComp.getRelatedContext().safeLookup("NumRowsPerPage"); Object o5 = focusComp.getRelatedContext().safeLookup("HScrollIndex"); int tablePosition = o1 != null ? (Integer.parseInt(o1.toString()) - 1) : 0; int colsPerPage = o2 != null ? Math.max(1, Integer.parseInt(o2.toString())) : 1; int vscrollIndex = o3 != null ? (Integer.parseInt(o3.toString()) - 1) : 0; int rowsPerPage = o4 != null ? Math.max(1, Integer.parseInt(o4.toString())) : 1; int hscrollIndex = o5 != null ? (Integer.parseInt(o5.toString()) - 1) : 0; // return new Integer(1 + (tablePosition / rowsPerPage) - hscrollIndex); if (vert) { Object o7 = focusComp.getRelatedContext().safeLookup("NumRows"); int numRows = o7 != null ? Integer.parseInt(o7.toString()) : 1; return new Integer(1 + (((tablePosition - colsPerPage * vscrollIndex - rowsPerPage * hscrollIndex + numRows) % numRows) % colsPerPage)); } else { Object o6 = focusComp.getRelatedContext().safeLookup("NumCols"); int numCols = o6 != null ? Integer.parseInt(o6.toString()) : 1; return new Integer(1 + (((tablePosition - colsPerPage * vscrollIndex - rowsPerPage * hscrollIndex + numCols) % numCols) / rowsPerPage)); } } } } return new Integer(-1); }}); rft.put(new PredefinedJEPFunction("Global", "GetTableFocusedVisiblePosition", new String[] { "UIComponent" }) { /** * Gets the <b>visible</b> table position that currently has focus in the specified table. The argument may be the table itself; or a component between * the table and the focused component. This starts counting from the first component which is currently visible in the table. * @param UIComponent the specified UIComponent, can be retrieved using {@link #GetUIComponentForVariable GetUIComponentForVariable} API call * @return the visible position (1-based) which is currently focused in the table, -1 is returned if the value can't be resolved * @since 7.0 * * @declaration public int GetTableFocusedVisiblePosition(Object UIComponent); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ ZPseudoComp uiComp = getUIComp(stack); if (uiComp != null) { // if (uiComp.doesHierarchyHaveFocus()) { ZComp focusOwner = uiComp.getLastFocusedChild(); if (focusOwner == null) return new Integer(-1); if (focusOwner instanceof ZPseudoComp) { // Now calculate its visible position ZPseudoComp focusComp = (ZPseudoComp) focusOwner; Object o1 = focusComp.getRelatedContext().safeLookup("TableRow"); Object o2 = focusComp.getRelatedContext().safeLookup("NumColsPerPage"); Object o3 = focusComp.getRelatedContext().safeLookup("VScrollIndex"); Object o4 = focusComp.getRelatedContext().safeLookup("NumRowsPerPage"); Object o5 = focusComp.getRelatedContext().safeLookup("HScrollIndex"); Object o6 = focusComp.getRelatedContext().safeLookup("NumCols"); Object o7 = focusComp.getRelatedContext().safeLookup("NumRows"); int tablePosition = o1 != null ? (Integer.parseInt(o1.toString()) - 1) : 0; int colsPerPage = o2 != null ? Math.max(1, Integer.parseInt(o2.toString())) : 1; int vscrollIndex = o3 != null ? (Integer.parseInt(o3.toString()) - 1) : 0; int rowsPerPage = o4 != null ? Math.max(1, Integer.parseInt(o4.toString())) : 1; int hscrollIndex = o5 != null ? (Integer.parseInt(o5.toString()) - 1) : 0; int numCols = o6 != null ? Integer.parseInt(o6.toString()) : 1; int numRows = o7 != null ? Integer.parseInt(o7.toString()) : 1; return new Integer(1 + (tablePosition - colsPerPage * vscrollIndex - rowsPerPage * hscrollIndex + numRows*numCols) % (numRows * numCols)); } } } return new Integer(-1); }}); rft.put(new PredefinedJEPFunction("Global", "GetTableFocusedPosition", new String[] { "UIComponent" }) { /** * Gets the table position that currently has focus in the specified table. The argument may be the table itself; or a component between * the table and the focused component. This is the equivalent of the "TableRow" variable for the currently focused table cell; which is * the cell's index in the data backing the table. * @param UIComponent the specified UIComponent, can be retrieved using {@link #GetUIComponentForVariable GetUIComponentForVariable} API call * @return the position (1-based) which is currently focused in the table, -1 is returned if the value can't be resolved * @since 7.0 * * @declaration public int GetTableFocusedPosition(Object UIComponent); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ ZPseudoComp uiComp = getUIComp(stack); if (uiComp != null) { ZComp focusOwner = uiComp.getLastFocusedChild(); if (focusOwner == null) return new Integer(-1); if (focusOwner instanceof ZPseudoComp) { // Now calculate its visible position ZPseudoComp focusComp = (ZPseudoComp) focusOwner; Object o1 = focusComp.getRelatedContext().safeLookup("TableRow"); int tablePosition = o1 != null ? (Integer.parseInt(o1.toString()) - 1) : 0; return new Integer(1 + tablePosition); } } return new Integer(-1); }}); rft.put(new PredefinedJEPFunction("Global", "GetDataFromTableFocusedOffset", new String[] { "UIComponent", "Offset", "WrapIndex" }) { /** * Gets the data value for the table that is used for the cell at the specified position relative to what is currently * <b>focused</b> for the table. The UIComponent should either be the table itself; or it should have the desired table as an ancestor of it. * Position values are zero-based; and may be negative. If WrapIndex is false then positions greater then the size of the table's data or * less than zero will return null; otherwise they will be mod'd to return a value within the range of the data. * @param UIComponent the specified UIComponent, can be retrieved using {@link #GetUIComponentForVariable GetUIComponentForVariable} API call * @param Offset the offset of the cell who's table data should be returned; relative to the current focused position (last focused if not currently focused) * @param WrapIndex true if offsets that fall outside of the size of the data should be wrapped so that they return a data value * @return the value of the table data at the specified offset * @since 7.0 * * @declaration public Object GetDataFromTableFocusedOffset(Object UIComponent, int Offset, boolean WrapIndex); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ boolean wrapIndex = getBool(stack); int offset = getInt(stack); ZPseudoComp uiComp = getUIComp(stack); if (uiComp != null) { // Now get the child focused component if it exists ZComp focusOwner = uiComp.getLastFocusedChild(); if (focusOwner instanceof ZPseudoComp) { // Now calculate its visible position ZPseudoComp focusComp = (ZPseudoComp) focusOwner; ZDataTable tabParent = focusComp.getTableParent(); if (tabParent != null) { Object o1 = focusComp.getRelatedContext().safeLookup("TableRow"); int tablePosition = o1 != null ? (Integer.parseInt(o1.toString()) - 1) : 0; return tabParent.getTableDataFromOffset(tablePosition + offset, wrapIndex); } } else { // Get the one at the first position instead ZDataTable tabParent = uiComp.getTableParent(); if (tabParent != null) { return tabParent.getTableDataFromOffset(offset, wrapIndex); } } } return null; }}); rft.put(new PredefinedJEPFunction("Global", "GetDataFromTableVisiblePosition", new String[] { "UIComponent", "Offset", "WrapIndex" }) { /** * Gets the data value for the table that is used for the cell at the specified position relative to what is currently * <b>visible</b> for the table. The UIComponent should either be the table itself; or it should have the desired table as an ancestor of it. * Offset values are zero-based; and may be negative. If WrapIndex is false then positions greater then the size of the table's data or * less than zero will return null; otherwise they will be mod'd to return a value within the range of the data. * @param UIComponent the specified UIComponent, can be retrieved using {@link #GetUIComponentForVariable GetUIComponentForVariable} API call * @param Offset the offset of the cell who's table data should be returned; relative to the first visible position * @param WrapIndex true if offsets that fall outside of the size of the data should be wrapped so that they return a data value * @return the value of the table data at the specified offset * @since 7.0 * * @declaration public Object GetDataFromTableVisiblePosition(Object UIComponent, int Offset, boolean WrapIndex); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ boolean wrapIndex = getBool(stack); int position = getInt(stack); ZPseudoComp uiComp = getUIComp(stack); if (uiComp != null) { ZDataTable tabParent = uiComp.getTableParent(); if (tabParent == null) return null; int colsPerPage = Math.max(1, tabParent.getNumColsPerPage()); int vscrollIndex = tabParent.getVScrollIndex(); int rowsPerPage = Math.max(1, tabParent.getNumRowsPerPage()); int hscrollIndex = tabParent.getHScrollIndex(); int visPos = position + colsPerPage * vscrollIndex + rowsPerPage * hscrollIndex; return tabParent.getTableDataFromOffset(visPos, wrapIndex); } return null; }}); rft.put(new PredefinedJEPFunction("Global", "IsTableTransitionToNext", new String[] { "UIComponent" }) { /** * Returns true if the specified table argument (or the first table parent of the argument) is on the leading edge of a transition * to a cell after the current one. It could be a page event, or a moving a single unit. Right and Down directionality is considered to be 'next'. * This can be used to trigger effects that relate to navigation occurring in a table. This will only be true for a single rendering pass on the * leading edge of the transition. Focus will be moved before this becomes true. If effect animations are disabled; this will always return false. * @param UIComponent the specified UIComponent, can be retrieved using {@link #GetUIComponentForVariable GetUIComponentForVariable} API call * @return true if the table is currently transitioning in the next direction * @since 7.0 * * @declaration public boolean IsTableTransitionToNext(Object UIComponent); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ ZPseudoComp uiComp = getUIComp(stack); if (stack.getUIComponent() != null) stack.getUIComponent().setNextTransitionListen(); if (uiComp != null && uiComp.getUIMgr().areEffectsEnabled()) { ZDataTable tabParent = uiComp.getTableParent(); if (tabParent != null) { return tabParent.isDoingNextTransition() ? Boolean.TRUE : Boolean.FALSE; } } return Boolean.FALSE; }}); rft.put(new PredefinedJEPFunction("Global", "IsTableTransitionToPrevious", new String[] { "UIComponent" }) { /** * Returns true if the specified table argument (or the first table parent of the argument) is on the leading edge of a transition * to a cell before the current one. It could be a page event, or a moving a single unit. Left and Up directionality is considered to be 'previous'. * This can be used to trigger effects that relate to navigation occurring in a table. This will only be true for a single rendering pass on the * leading edge of the transition. Focus will be moved before this becomes true. If effect animations are disabled; this will always return false. * @param UIComponent the specified UIComponent, can be retrieved using {@link #GetUIComponentForVariable GetUIComponentForVariable} API call * @return true if the table is currently transitioning in the previous direction * @since 7.0 * * @declaration public boolean IsTableTransitionToPrevious(Object UIComponent); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ ZPseudoComp uiComp = getUIComp(stack); if (stack.getUIComponent() != null) stack.getUIComponent().setPrevTransitionListen(); if (uiComp != null && uiComp.getUIMgr().areEffectsEnabled()) { ZDataTable tabParent = uiComp.getTableParent(); if (tabParent != null) { return tabParent.isDoingPrevTransition() ? Boolean.TRUE : Boolean.FALSE; } } return Boolean.FALSE; }}); rft.put(new PredefinedJEPFunction("Global", "IsTransitioningToMenu", new String[] { "MenuName" }) { /** * Returns true if the specified menu name matches the name of the menu widget that the UI is in the process * of transitioning to. This will only be true during the processing of MenuUnloaded effects. If a null argument is given; then this is * true in the case that any menu transition is about to occur. The name match is case-insensitive. * @param MenuName the name of the menu to test to see if we're transitioning to; null if it matches any menu name * @return true if the specified menu name matches the name of the menu widget that the UI is in the process of transitioning to, false otherwise * @since 7.0 * * @declaration public boolean IsTransitioningToMenu(String MenuName); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ String menuName = getString(stack); UIManager uiMgr = stack.getUIMgrSafe(); if (uiMgr != null) { Widget nextUI = uiMgr.getMenuTransitionTarget(); return (nextUI != null && (menuName == null || nextUI.getName().equalsIgnoreCase(menuName))) ? Boolean.TRUE : Boolean.FALSE; } return Boolean.FALSE; }}); rft.put(new PredefinedJEPFunction("Global", "IsTransitioningFromMenu", new String[] { "MenuName" }) { /** * Returns true if the specified menu name matches the name of the menu widget for the previously loaded menu. The name match is case-insensitive. * Unlike <b>IsTransitioningToMenu</b>, this is true even after the transition is complete. A null argument always returns false. * @param MenuName the name of the menu to test to see if it was the previously loaded menu * @return true if the specified menu name matches the name of the menu widget for the previously loaded menu, false otherwise * @since 7.0 * * @declaration public boolean IsTransitioningFromMenu(String MenuName); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ String menuName = getString(stack); UIManager uiMgr = stack.getUIMgrSafe(); if (uiMgr != null) { Widget nextUI = uiMgr.getMenuTransitionSource(); PseudoMenu currUI = uiMgr.getCurrUI(); return (nextUI != null && currUI != null && currUI.getUI() != null && /*currUI.getUI().isMenuLoadingState() &&*/ nextUI.getName().equalsIgnoreCase(menuName)) ? Boolean.TRUE : Boolean.FALSE; } return Boolean.FALSE; }}); rft.put(new PredefinedJEPFunction("Global", "IsTransitioningToMenus", new String[] { "MenuNames" }) { /** * Returns true if one of the specified menu name matches the name of the menu widget that the UI is in the process * of transitioning to. This will only be true during the processing of MenuUnloaded effects. If a null argument or empty list is given; then this is * true in the case that any menu transition is about to occur. The name match is case-insensitive. * @param MenuNames the names of the menu to test to see if we're transitioning to; null or empty list if it matches any menu name * @return true if one of the specified menu name matches the name of the menu widget that the UI is in the process of transitioning to, false otherwise * @since 8.0 * * @declaration public boolean IsTransitioningToMenus(String[] MenuNames); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ String[] menuNames = getStringList(stack); UIManager uiMgr = stack.getUIMgrSafe(); if (uiMgr != null) { Widget nextUI = uiMgr.getMenuTransitionTarget(); if (nextUI == null) return Boolean.FALSE; if (menuNames == null || menuNames.length == 0) return Boolean.TRUE; for (int i = 0; i < menuNames.length; i++) if (menuNames[i] != null && nextUI.getName().equalsIgnoreCase(menuNames[i])) return Boolean.TRUE; } return Boolean.FALSE; }}); rft.put(new PredefinedJEPFunction("Global", "IsTransitioningFromMenus", new String[] { "MenuNames" }) { /** * Returns true if one of the specified menu names matches the name of the menu widget for the previously loaded menu. The name match is case-insensitive. * Unlike <b>IsTransitioningToMenus</b>, this is true even after the transition is complete. A null argument or empty list always returns false. * @param MenuNames the names of the menus to test to see if it was the previously loaded menu * @return true if one of the specified menu names matches the name of the menu widget for the previously loaded menu, false otherwise * @since 8.0 * * @declaration public boolean IsTransitioningFromMenus(String[] MenuNames); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ String[] menuNames = getStringList(stack); UIManager uiMgr = stack.getUIMgrSafe(); if (uiMgr != null) { Widget nextUI = uiMgr.getMenuTransitionSource(); PseudoMenu currUI = uiMgr.getCurrUI(); if (nextUI == null || currUI == null || currUI.getUI() == null) return Boolean.FALSE; if (menuNames == null || menuNames.length == 0) return Boolean.FALSE; for (int i = 0; i < menuNames.length; i++) if (menuNames[i] != null && nextUI.getName().equalsIgnoreCase(menuNames[i])) return Boolean.TRUE; } return Boolean.FALSE; }}); rft.put(new PredefinedJEPFunction("Global", "GetTextForUIComponent", new String[] { "UIComponent" }) { /** * Gets the value displayed for the textual component of the specified UI object. If its not a Text component; then * its children will be searched depth-first until one is found and then that will be used for the return value. * @param UIComponent the specified UIComponent, can be retrieved using {@link #GetUIComponentForVariable GetUIComponentForVariable} API call * @return the text value displayed by the argument itself; or if its not a text component then the value displayed by the first text child of the component; null if neither condition is met * @since 7.0 * * @declaration public String GetTextForUIComponent(Object UIComponent); */ public Object runSafely(Catbert.FastStack stack) throws Exception{ ZPseudoComp uiComp = getUIComp(stack); if (uiComp != null) { // Check to make sure its a TEXT widget, and if so then just return the string stored in its ZLabel child ZLabel label = uiComp.findFirstLabelChild(); if (label != null) return label.getText(); } return null; }}); rft.put(new PredefinedJEPFunction("Global", "GetUIComponentLastFocusedChild", new String[] { "UIComponent" }) { /** * If the specified
{'commit': 'diff --git a/java/sage/Airing.java b/java/sage/Airing.java\nindex 5676e420..8c7088d8 100644\n--- a/java/sage/Airing.java\n+++ b/java/sage/Airing.java\n@@ -517,13 +517,9 @@ public class Airing extends DBObject implements Schedulable\n   {\n     super.write(out, flags);\n     out.writeInt(showID);\n-    if (!Wizard.COMPACT_DB || SageConstants.PVR)\n-      out.writeInt(stationID);\n+    out.writeInt(stationID);\n     out.writeLong(time);\n-    if (!Wizard.COMPACT_DB || SageConstants.PVR)\n-      out.writeLong(duration);\n-    else\n-      out.writeInt((int)duration);\n+    out.writeLong(duration);\n     out.writeByte(partsB);\n     out.writeInt(miscB);\n     out.writeByte(prB);\ndiff --git a/java/sage/FSManager.java b/java/sage/FSManager.java\nindex 251b7a61..64d03db5 100644\n--- a/java/sage/FSManager.java\n+++ b/java/sage/FSManager.java\n@@ -126,7 +126,7 @@ public class FSManager implements Runnable\n           }\n         }\n       }\n-      if (!Sage.client && SageConstants.PVR)\n+      if (!Sage.client)\n       {\n         // Do our encoder HALT detection here so we can run it more frequent than what the Seeker does\n         seeky.checkForEncoderHalts();\ndiff --git a/java/sage/MediaFile.java b/java/sage/MediaFile.java\nindex a6c89fc8..89e56d1b 100644\n--- a/java/sage/MediaFile.java\n+++ b/java/sage/MediaFile.java\n@@ -486,15 +486,14 @@ public class MediaFile extends DBObject implements SegmentedFile\n       out.writeLong(times[2*i]);\n       out.writeLong(times[2*i + 1]);\n     }\n-    if (!Wizard.COMPACT_DB || SageConstants.PVR)\n-      out.writeUTF(videoDirectory);\n+    out.writeUTF(videoDirectory);\n     if (!Wizard.COMPACT_DB)\n     {\n       out.writeUTF(name);\n       out.writeBoolean(archive);\n       out.writeBoolean(true); // padding to help avoid reversing db encryption algorithms\n     }\n-    else if (SageConstants.PVR)\n+    else\n       out.writeBoolean(archive);\n     out.writeInt(infoAiringID);\n     if (!Wizard.COMPACT_DB)\n@@ -504,7 +503,7 @@ public class MediaFile extends DBObject implements SegmentedFile\n       out.writeByte((byte)0); // Media type\n       out.writeByte((byte)0); // Media subtype\n     }\n-    else if (SageConstants.PVR)\n+    else\n       out.writeUTF(encodedBy);\n     out.writeByte(generalType);\n     out.writeByte(acquisitionTech);\ndiff --git a/java/sage/MetaImage.java b/java/sage/MetaImage.java\nindex 7988373f..4c58f8f8 100644\n--- a/java/sage/MetaImage.java\n+++ b/java/sage/MetaImage.java\n@@ -93,8 +93,7 @@ public class MetaImage\n   private static final int URL_IMAGE_LOAD_DELAY = 150;//Sage.getInt("url_image_load_delay", 750);\n   private static final boolean ENABLE_JPEG_AUTOROTATE = Sage.getBoolean("autorotate_jpeg_images", true);\n   private static final int MAX_CACHED_URL_IMAGES = Sage.getInt("num_cached_url_images", 1000);\n-  private static final boolean ENABLE_OFFLINE_URL_CACHE =\n-      SageConstants.PVR && Sage.get("ui/thumbnail_folder", "GeneratedThumbnails").length() > 0;\n+  private static final boolean ENABLE_OFFLINE_URL_CACHE = Sage.get("ui/thumbnail_folder", "GeneratedThumbnails").length() > 0;\n   private static final boolean DELETE_TRACKED_LOCAL_CACHE_FILE_ON_IMAGE_LOAD = false;\n   private static final long URL_RETRY_TIMEOUT_MILLIS =\n       Sage.getLong("images_retry_timeout_mins", 5) * Sage.MILLIS_PER_MIN;\ndiff --git a/java/sage/SageConstants.java b/java/sage/SageConstants.java\nindex 03f94b80..e2172004 100644\n--- a/java/sage/SageConstants.java\n+++ b/java/sage/SageConstants.java\n@@ -22,6 +22,5 @@ public final class SageConstants\n     // Non-instantiable\n   }\n \n-  public static final boolean PVR = true;\n   public static final int BUILD_VERSION = 441;\n }\ndiff --git a/java/sage/SageTV.java b/java/sage/SageTV.java\nindex 217262c0..2100e9e7 100644\n--- a/java/sage/SageTV.java\n+++ b/java/sage/SageTV.java\n@@ -337,78 +337,72 @@ public class SageTV implements Runnable\n     // all of the plugin objects are actually loaded.\n     sage.plugin.PluginEventManager.getInstance();\n \n-    if (SageConstants.PVR)\n-    {\n-      Sage.setSplashText(Sage.rez("Module_Init", new Object[] { Sage.rez("EPG") }));\n-      guide = EPG.prime();\n-      //\t\tSystem.gc();\n-      Sage.setSplashText(Sage.rez("Module_Init", new Object[] { Sage.rez("Profiler") }));\n-      god = Carny.prime();\n-      sage.msg.MsgManager.getInstance();\n-      System.gc();\n-      Sage.setSplashText(Sage.rez("Module_Init", new Object[] { Sage.rez("Acquisition_System") }));\n-      mmc = MMC.getInstance();\n-    }\n+    Sage.setSplashText(Sage.rez("Module_Init", new Object[] { Sage.rez("EPG") }));\n+    guide = EPG.prime();\n+    //\t\tSystem.gc();\n+    Sage.setSplashText(Sage.rez("Module_Init", new Object[] { Sage.rez("Profiler") }));\n+    god = Carny.prime();\n+    sage.msg.MsgManager.getInstance();\n+    System.gc();\n+    Sage.setSplashText(Sage.rez("Module_Init", new Object[] { Sage.rez("Acquisition_System") }));\n+    mmc = MMC.getInstance();\n \n-    if (SageConstants.PVR)\n+    if (Sage.client)\n+      mmc.addCaptureDeviceManager(new ClientCaptureManager());\n+    else\n     {\n-      if (Sage.client)\n-        mmc.addCaptureDeviceManager(new ClientCaptureManager());\n-      else\n+      mmc.addCaptureDeviceManager(new NetworkEncoderManager());\n+      if ((Sage.MAC_OS_X || Sage.LINUX_OS)) {\n+        try {\n+          mmc.addCaptureDeviceManager(new HDHomeRunCaptureManager());\n+        } catch (Throwable t) {\n+          System.out.println("ERROR instantiating HDHomeRun capture manager: " + t);\n+        }\n+      }\n+      if (Sage.WINDOWS_OS)\n+        mmc.addCaptureDeviceManager(new DShowCaptureManager());\n+      else if (Sage.LINUX_OS)\n       {\n-        mmc.addCaptureDeviceManager(new NetworkEncoderManager());\n-        if ((Sage.MAC_OS_X || Sage.LINUX_OS)) {\n-          try {\n-            mmc.addCaptureDeviceManager(new HDHomeRunCaptureManager());\n-          } catch (Throwable t) {\n-            System.out.println("ERROR instantiating HDHomeRun capture manager: " + t);\n-          }\n+        if (!Sage.getBoolean("linux/enable_vweb_capture",false))\n+        {\n+          mmc.addCaptureDeviceManager(new LinuxIVTVCaptureManager());\n         }\n-        if (Sage.WINDOWS_OS)\n-          mmc.addCaptureDeviceManager(new DShowCaptureManager());\n-        else if (Sage.LINUX_OS)\n+        if (!Sage.getBoolean("linux/disable_dvb_capture",false))\n         {\n-          if (!Sage.getBoolean("linux/enable_vweb_capture",false))\n-          {\n-            mmc.addCaptureDeviceManager(new LinuxIVTVCaptureManager());\n-          }\n-          if (!Sage.getBoolean("linux/disable_dvb_capture",false))\n-          {\n-            mmc.addCaptureDeviceManager(new LinuxDVBCaptureManager());\n-          }\n-          if (Sage.getBoolean("linux/enable_firewire_capture",false))\n-          {\n-            mmc.addCaptureDeviceManager(new LinuxFirewireCaptureManager());\n-          }\n+          mmc.addCaptureDeviceManager(new LinuxDVBCaptureManager());\n         }\n-        else if (Sage.MAC_OS_X)\n+        if (Sage.getBoolean("linux/enable_firewire_capture",false))\n         {\n-          // TODO: roll Trinity into MacNative...\n-          mmc.addCaptureDeviceManager(new MacTrinityCaptureManager());\n-          try {\n-            mmc.addCaptureDeviceManager(new MacNativeCaptureManager());\n-          } catch (Throwable t) {\n-            System.out.println("ERROR instantiating Mac native capture manager: " + t);\n-          }\n+          mmc.addCaptureDeviceManager(new LinuxFirewireCaptureManager());\n         }\n-        else\n+      }\n+      else if (Sage.MAC_OS_X)\n+      {\n+        // TODO: roll Trinity into MacNative...\n+        mmc.addCaptureDeviceManager(new MacTrinityCaptureManager());\n+        try {\n+          mmc.addCaptureDeviceManager(new MacNativeCaptureManager());\n+        } catch (Throwable t) {\n+          System.out.println("ERROR instantiating Mac native capture manager: " + t);\n+        }\n+      }\n+      else\n+      {\n+        String customCapDevMgr = Sage.get("mmc/custom_capture_device_mgr", "");\n+        if (customCapDevMgr.length() > 0)\n         {\n-          String customCapDevMgr = Sage.get("mmc/custom_capture_device_mgr", "");\n-          if (customCapDevMgr.length() > 0)\n+          try\n           {\n-            try\n-            {\n-              mmc.addCaptureDeviceManager((CaptureDeviceManager)Class.forName(customCapDevMgr).newInstance());\n-            }\n-            catch (Exception e)\n-            {\n-              System.out.println("ERROR instantiating custom capture device mgr \\"" + customCapDevMgr + "\\" of " + e);\n-            }\n+            mmc.addCaptureDeviceManager((CaptureDeviceManager)Class.forName(customCapDevMgr).newInstance());\n+          }\n+          catch (Exception e)\n+          {\n+            System.out.println("ERROR instantiating custom capture device mgr \\"" + customCapDevMgr + "\\" of " + e);\n           }\n         }\n       }\n-      mmc.prime();\n     }\n+    mmc.prime();\n \n     //\t\tSystem.gc();\n     Sage.setSplashText(Sage.rez("Module_Init", new Object[] { Sage.rez("SageTV_Core") }));\n@@ -469,13 +463,10 @@ public class SageTV implements Runnable\n     //t.setDaemon(true);\n     t.start();\n \n-    if (SageConstants.PVR)\n-    {\n-      sage.msg.MsgManager.getInstance().init();\n-      t = new Thread(sage.msg.MsgManager.getInstance(), "MsgManager");\n-      t.setDaemon(true);\n-      t.start();\n-    }\n+    sage.msg.MsgManager.getInstance().init();\n+    t = new Thread(sage.msg.MsgManager.getInstance(), "MsgManager");\n+    t.setDaemon(true);\n+    t.start();\n \n \n     if (!Sage.client)\n@@ -489,18 +480,15 @@ public class SageTV implements Runnable\n     //t.setDaemon(true);\n     //t.start();\n \n-    if (SageConstants.PVR)\n-    {\n-      t = new Thread(guide, "EPG");\n-      t.setDaemon(true);\n-      t.setPriority(Thread.MIN_PRIORITY);\n-      t.start();\n+    t = new Thread(guide, "EPG");\n+    t.setDaemon(true);\n+    t.setPriority(Thread.MIN_PRIORITY);\n+    t.start();\n \n-      t = new Thread(god, "Carny");\n-      t.setDaemon(true);\n-      t.setPriority(Thread.MIN_PRIORITY);\n-      t.start();\n-    }\n+    t = new Thread(god, "Carny");\n+    t.setDaemon(true);\n+    t.setPriority(Thread.MIN_PRIORITY);\n+    t.start();\n \n     /*\n      * NOTE: We have to launch the MediaServer before the Seeker finished it\'s startup. Otherwise a network encoder could try\n@@ -509,7 +497,7 @@ public class SageTV implements Runnable\n     // We always need the local server for the cases when we have to send active files through the MediaServer\n     localServerEnabled = !Sage.client;//Sage.isHeadless();\n     // Disable the non-local server for now for the embedded systems\n-    serverEnabled = SageConstants.PVR && !Sage.client && Sage.getBoolean("enable_server", true);\n+    serverEnabled = !Sage.client && Sage.getBoolean("enable_server", true);\n     // Narflex - 02/24/2012 - Since we now have Qian\'s server code handling all the streaming there should no\n     // longer be any reason why we run these servers on SageTVClient on embedded aside from if we added\n     // filedownloader playback support later (7818 and 42024 servers)\n@@ -518,13 +506,10 @@ public class SageTV implements Runnable\n       launchMediaServer();\n     }\n \n-    if (SageConstants.PVR)\n-    {\n-      t = new Thread(myScheduler = SchedulerSelector.getInstance(), "Scheduler");\n-      t.setDaemon(true);\n-      t.setPriority(Thread.MIN_PRIORITY);\n-      t.start();\n-    }\n+    t = new Thread(myScheduler = SchedulerSelector.getInstance(), "Scheduler");\n+    t.setDaemon(true);\n+    t.setPriority(Thread.MIN_PRIORITY);\n+    t.start();\n \n     if (Sage.WINDOWS_OS || Sage.MAC_OS_X)\n     {\n@@ -544,7 +529,7 @@ public class SageTV implements Runnable\n     Sage.setSplashText(Sage.rez("SageTV_Init_Wait"));\n     int maxSeekWait = 30000; // Up this back to 30 seconds from 10....if there\'s a really nasty schedule I want to be sure it\'s generated\n     // before we go into the UI and fail to display default video.\n-    while (!Sage.client && !mySeeker.isPrepped() && maxSeekWait > 0 && SageConstants.PVR && mmc.getConfiguredCaptureDevices().length > 0)\n+    while (!Sage.client && !mySeeker.isPrepped() && maxSeekWait > 0 && mmc.getConfiguredCaptureDevices().length > 0)\n     {\n       try{Thread.sleep(250);}catch(Exception e){}\n       maxSeekWait -= 250;\n@@ -560,7 +545,7 @@ public class SageTV implements Runnable\n     if (!Sage.isHeadless())\n       java.awt.EventQueue.invokeLater(UIManager.getLocalUI());\n \n-    if (SageConstants.PVR && !Sage.client && Sage.getBoolean("enable_encoding_server", false))\n+    if (!Sage.client && Sage.getBoolean("enable_encoding_server", false))\n     {\n       String portsString = Sage.get("encoding_server_port", "6969");\n       java.util.StringTokenizer toker = new java.util.StringTokenizer(portsString, ",;");\n@@ -1212,8 +1197,7 @@ public class SageTV implements Runnable\n     if (mmc != null)\n       mmc.goodbye();\n     if (Sage.DBG) System.out.println("Killed MMC.");\n-    if (SageConstants.PVR)\n-      sage.msg.MsgManager.getInstance().kill();\n+    sage.msg.MsgManager.getInstance().kill();\n     java.util.Iterator uiWalker = UIManager.getUIIterator();\n     while (uiWalker.hasNext())\n       ((UIManager) uiWalker.next()).goodbye();\ndiff --git a/java/sage/Seeker.java b/java/sage/Seeker.java\nindex 0aea2158..2becf568 100644\n--- a/java/sage/Seeker.java\n+++ b/java/sage/Seeker.java\n@@ -174,7 +174,7 @@ public class Seeker implements Hunter\n         {}\n       }\n     }\n-    if (videoStore.isEmpty() && SageConstants.PVR)\n+    if (videoStore.isEmpty())\n     {\n       if (Sage.WINDOWS_OS && !Sage.isHeadless())\n         videoStore.add(new VideoStorage(Sage.VISTA_OS ? new File(Sage.readStringValue(Sage.HKEY_CURRENT_USER,\n@@ -323,7 +323,7 @@ public class Seeker implements Hunter\n       defaultArchiveDirs += new File("/Users/Shared/SageTV/Video").getAbsolutePath() + "," + VIDEO_DIR_MASK + ";";\n       archiveDirStrs = Sage.get(prefs + ARCHIVE_DIRECTORY, defaultArchiveDirs);\n     }\n-    else if (Sage.LINUX_OS && SageConstants.PVR)\n+    else if (Sage.LINUX_OS)\n     {\n       String defaultArchiveDirs = SageTV.LINUX_ROOT_MEDIA_PATH + "/videos" + "," + VIDEO_DIR_MASK + ";";\n       new File(SageTV.LINUX_ROOT_MEDIA_PATH + "/videos").mkdirs();\n@@ -410,7 +410,7 @@ public class Seeker implements Hunter\n \n   private void init()\n   {\n-    mmcPresent = Sage.getBoolean(prefs + MMC_PRESENT, true) && (Sage.MAC_OS_X || mmc.getCaptureDeviceNames().length > 0) && !Sage.client && SageConstants.PVR;\n+    mmcPresent = Sage.getBoolean(prefs + MMC_PRESENT, true) && (Sage.MAC_OS_X || mmc.getCaptureDeviceNames().length > 0) && !Sage.client;\n     defaultQuality = MMC.cleanQualityName(Sage.get(prefs + DEFAULT_RECORDING_QUALITY, Sage.rez("Great")));\n \n     fastMuxSwitch = Sage.getBoolean(prefs + FAST_MUX_SWITCH, true);\n@@ -1417,20 +1417,17 @@ public class Seeker implements Hunter\n       controlImportCPUUsage();\n \n     // If this is a video storage directory then skip it so we don\'t double import (if it\'s video)\n-    if (SageConstants.PVR)\n-    {\n-      File[] vidDirs = getVideoStoreDirectories();\n-      for (int i = 0; i < vidDirs.length; i++)\n-        if (vidDirs[i].equals(importDir))\n+    File[] vidDirs = getVideoStoreDirectories();\n+    for (int i = 0; i < vidDirs.length; i++)\n+      if (vidDirs[i].equals(importDir))\n+      {\n+        importMask = importMask & ~VIDEO_DIR_MASK;\n+        if (importMask == 0)\n         {\n-          importMask = importMask & ~VIDEO_DIR_MASK;\n-          if (importMask == 0)\n-          {\n-            if (Sage.DBG) System.out.println("Skipping video import dir that\'s also a recording dir:" + vidDirs[i]);\n-            return;\n-          }\n+          if (Sage.DBG) System.out.println("Skipping video import dir that\'s also a recording dir:" + vidDirs[i]);\n+          return;\n         }\n-    }\n+      }\n \n     String[] testFiles = importDir.list();\n     String importDirPath = importDir.getAbsolutePath();\n@@ -3311,7 +3308,7 @@ if (encState.currRecord.getDuration() + (Sage.time() - encState.lastResetTime) >\n     if (!Sage.getBoolean("seeker/disable_video_directory_verifications", false))\n       verifyFiles(false, true);\n \n-    if (!sched.isPrepped() || !SageConstants.PVR) return true;\n+    if (!sched.isPrepped()) return true;\n \n     enforceKeepAtMost();\n \n@@ -3621,8 +3618,7 @@ if (encState.currRecord.getDuration() + (Sage.time() - encState.lastResetTime) >\n \n     long altExpireTime = Sage.LINUX_OS ? Sage.getLong("window_size", 0) : 0;\n \n-    if (SageConstants.PVR)\n-      verifyFiles(true, false);\n+    verifyFiles(true, false);\n \n     Thread watchdog = new Thread("SeekerWatchdog")\n     {\ndiff --git a/java/sage/SeriesInfo.java b/java/sage/SeriesInfo.java\nindex f793198b..5783dc28 100644\n--- a/java/sage/SeriesInfo.java\n+++ b/java/sage/SeriesInfo.java\n@@ -202,23 +202,22 @@ public class SeriesInfo extends DBObject\n       out.writeUTF(characters[i]);\n     }\n     out.writeUTF(imageUrl);\n-    if (SageConstants.PVR)\n+\n+    if (props == null)\n+      out.writeUTF("");\n+    else\n     {\n-      if (props == null)\n-        out.writeUTF("");\n-      else\n+      StringBuilder sb = new StringBuilder();\n+      for (Map.Entry<Object, Object> ent : props.entrySet())\n       {\n-        StringBuilder sb = new StringBuilder();\n-        for (Map.Entry<Object, Object> ent : props.entrySet())\n-        {\n-          sb.append(MediaFormat.escapeString(ent.getKey().toString()));\n-          sb.append(\'=\');\n-          sb.append(MediaFormat.escapeString(ent.getValue().toString()));\n-          sb.append(\';\');\n-        }\n-        out.writeUTF(sb.toString());\n+        sb.append(MediaFormat.escapeString(ent.getKey().toString()));\n+        sb.append(\'=\');\n+        sb.append(MediaFormat.escapeString(ent.getValue().toString()));\n+        sb.append(\';\');\n       }\n+      out.writeUTF(sb.toString());\n     }\n+\n     out.writeInt(showcardID);\n     out.writeShort(seriesImages.length);\n     for (int i = 0; i < seriesImages.length; i++)\ndiff --git a/java/sage/Show.java b/java/sage/Show.java\nindex 51099ee9..3589856f 100644\n--- a/java/sage/Show.java\n+++ b/java/sage/Show.java\n@@ -699,15 +699,12 @@ public final class Show extends DBObject\n     out.writeInt((year == null) ? 0 : (useLookupIdx ? year.lookupIdx : year.id));\n     out.writeInt((pr == null) ? 0 : (useLookupIdx ? pr.lookupIdx : pr.id));\n \n-    if (!Wizard.COMPACT_DB || SageConstants.PVR)\n-    {\n-      if (!Wizard.COMPACT_DB)\n-        out.writeInt(bonuses.length);\n-      else\n-        out.writeShort(bonuses.length);\n-      for (int i = 0; i < bonuses.length; i++)\n-        out.writeInt(useLookupIdx ? bonuses[i].lookupIdx : bonuses[i].id);\n-    }\n+    if (!Wizard.COMPACT_DB)\n+      out.writeInt(bonuses.length);\n+    else\n+      out.writeShort(bonuses.length);\n+    for (int i = 0; i < bonuses.length; i++)\n+      out.writeInt(useLookupIdx ? bonuses[i].lookupIdx : bonuses[i].id);\n \n     long lastWatchedData = lastWatched;\n     if (dontLike) {\ndiff --git a/java/sage/VideoFrame.java b/java/sage/VideoFrame.java\nindex c0fc04bd..caa92784 100644\n--- a/java/sage/VideoFrame.java\n+++ b/java/sage/VideoFrame.java\n@@ -5001,7 +5001,7 @@ public final class VideoFrame extends BasicVideoFrame implements Runnable\n           return true;//new DShowLivePlayer();\n         else if (theFile.isDVD())\n           return true;//new DShowDVDPlayer();\n-        else if (theFile.isLiveBufferedStream() && theFile.isMusic() && SageConstants.PVR)\n+        else if (theFile.isLiveBufferedStream() && theFile.isMusic())\n           return true;//new DShowRadioPlayer();\n         else if (theFile.isMusic())\n           return true;//new DShowMusicPlayer();\n@@ -5102,7 +5102,7 @@ public final class VideoFrame extends BasicVideoFrame implements Runnable\n         return new DShowLivePlayer();\n       else if (theFile.isDVD())\n         return new DShowDVDPlayer();\n-      else if (theFile.isLiveBufferedStream() && theFile.isMusic() && SageConstants.PVR)\n+      else if (theFile.isLiveBufferedStream() && theFile.isMusic())\n         return new DShowRadioPlayer();\n       else if (theFile.isMusic() && ((!sage.media.format.MediaFormat.AAC.equals(theFile.getPrimaryAudioFormat()) &&\n           !sage.media.format.MediaFormat.VORBIS.equals(theFile.getPrimaryAudioFormat()) &&\ndiff --git a/java/sage/Wizard.java b/java/sage/Wizard.java\nindex 54bac45f..98db29cf 100644\n--- a/java/sage/Wizard.java\n+++ b/java/sage/Wizard.java\n@@ -208,7 +208,7 @@ public class Wizard implements EPGDBPublic2\n   // 85 fixed Wizard bug where we were loading using BYTE_CHARSET instead of I18N_CHARSET\n   // 86 added support for encoded Schedules Direct image URLs for Channel, Show and SeriesInfo objects\n   // 87 added support for encoded Schedules Direct image URLs for Person\n-  public static byte VERSION = SageConstants.PVR ? 0x57 : 0x46;\n+  public static byte VERSION = 0x57;\n   public static final byte BAD_VERSION = 0x00;\n \n   // This flag is to deal with the problem where we used 32-bit ints for Airing durations in compact DB mode. For PVR\n@@ -440,17 +440,11 @@ public class Wizard implements EPGDBPublic2\n \n   static\n   {\n-    if (SageConstants.PVR)\n-      WRITE_ORDER = new byte[] { YEAR_CODE, NETWORK_CODE, TITLE_CODE, CHANNEL_CODE, BONUS_CODE, PEOPLE_CODE, SUBCATEGORY_CODE,\n-        RATED_CODE, PR_CODE, ER_CODE, CATEGORY_CODE, PRIME_TITLE_CODE,\n-        SHOW_CODE, AIRING_CODE, MANUAL_CODE, MEDIAFILE_CODE, WATCH_CODE, AGENT_CODE,\n-        WASTED_CODE, PLAYLIST_CODE, TVEDITORIAL_CODE, SERIESINFO_CODE, USERRECORD_CODE };\n-    else\n-      WRITE_ORDER = new byte[] { YEAR_CODE, NETWORK_CODE, TITLE_CODE, CHANNEL_CODE, BONUS_CODE, PEOPLE_CODE, SUBCATEGORY_CODE,\n-        RATED_CODE, PR_CODE, ER_CODE, CATEGORY_CODE, PRIME_TITLE_CODE,\n-        SHOW_CODE, AIRING_CODE, MANUAL_CODE, MEDIAFILE_CODE, WATCH_CODE, AGENT_CODE,\n-        WASTED_CODE, PLAYLIST_CODE, TVEDITORIAL_CODE, SERIESINFO_CODE };\n-  }\n+    WRITE_ORDER = new byte[] { YEAR_CODE, NETWORK_CODE, TITLE_CODE, CHANNEL_CODE, BONUS_CODE, PEOPLE_CODE, SUBCATEGORY_CODE,\n+      RATED_CODE, PR_CODE, ER_CODE, CATEGORY_CODE, PRIME_TITLE_CODE,\n+      SHOW_CODE, AIRING_CODE, MANUAL_CODE, MEDIAFILE_CODE, WATCH_CODE, AGENT_CODE,\n+      WASTED_CODE, PLAYLIST_CODE, TVEDITORIAL_CODE, SERIESINFO_CODE, USERRECORD_CODE };\n+ }\n   private static final Object instanceLock = new Object();\n \n   private static class WizardHolder\n@@ -2386,8 +2380,7 @@ public class Wizard implements EPGDBPublic2\n       }\n     }\n \n-    if (SageConstants.PVR)\n-      god.submitJob(new Object[] { Carny.STD_JOB, null });\n+    god.submitJob(new Object[] { Carny.STD_JOB, null });\n \n     // Only update maintenance time for a Full maintenance\n     if ( maintenanceType == MaintenanceType.FULL ){\n@@ -2489,7 +2482,7 @@ public class Wizard implements EPGDBPublic2\n       if (!dbBackupFile.isFile() || dbBackupFile.length() == 0)\n         saveNow = true;\n       long loadEnd = Sage.time();\n-      if (!Sage.client && SageConstants.PVR)\n+      if (!Sage.client)\n       {\n         if (Sage.getBoolean(prefsRoot + CLEAR_PROFILE, false))\n         {\ndiff --git a/java/sage/api/Configuration.java b/java/sage/api/Configuration.java\nindex 9cbcd789..cfa1c07d 100644\n--- a/java/sage/api/Configuration.java\n+++ b/java/sage/api/Configuration.java\n@@ -1868,7 +1868,7 @@ public class Configuration{\n        * @declaration public boolean IsSageTVServerEnabled();\n        */\n       public Object runSafely(Catbert.FastStack stack) throws Exception{\n-        return Boolean.valueOf(Sage.getBoolean("enable_server", SageConstants.PVR));\n+        return Boolean.valueOf(Sage.getBoolean("enable_server", true));\n       }});\n     rft.put(new PredefinedJEPFunction("Configuration", "SetSageTVServerEnabled", 1, new String[]{"Enabled"}, true)\n     {\ndiff --git a/java/sage/api/Global.java b/java/sage/api/Global.java\nindex 791d5b0e..8b4cca7e 100644\n--- a/java/sage/api/Global.java\n+++ b/java/sage/api/Global.java\n@@ -2870,7 +2870,7 @@ public class Global {\n     });\n     rft.put(new PredefinedJEPFunction("Global", "IsPVR", true)\n     {\n-      boolean forcedPVRMode = SageConstants.PVR;\n+      boolean forcedPVRMode = true;\n       {\n         String res = Sage.get("forced_pvr_mode", null);\n         if (res != null)\n', 'commit_subject': 'Merge pull request #331 from stuckless/sageconstants_refactor', 'repo_name': 'google/sagetv', 'committer': {'name': 'GitHub', 'email': '1505422b2465e9a84f6fdfaa161078890c593f06@github.com', 'time_sec': '1499128639', 'tz_offset': '-420', 'date': {'seconds': '1499128639'}}, 'commit_tree': '37e15c766d5144d7b279bc6e5b1cce478e3386dd', 'commit_message': 'Merge pull request #331 from stuckless/sageconstants_refactor\n\nRemoved PVR flag', 'language_name': 'C++', 'license': 'apache-2.0', 'hunks': '@@ -2870,7 +2870,7 @@ public class Global {\n     });\n     rft.put(new PredefinedJEPFunction("Global", "IsPVR", true)\n     {\n-      boolean forcedPVRMode = SageConstants.PVR;\n+      boolean forcedPVRMode = true;\n       {\n         String res = Sage.get("forced_pvr_mode", null);\n         if (res != null)\n', 'addition_count': 1, 'deletion_count': 1, 'src_file': 'a/java/sage/api/Global.java', 'tgt_file': 'b/java/sage/api/Global.java', 'file_extension': '.java', 'before_file': '/*\n * Copyright 2015 The SageTV Authors. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the "License");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *  http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an "AS IS" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage sage.api;\n\nimport sage.Airing;\nimport sage.BigBrother;\nimport sage.Burner;\nimport sage.Catbert;\nimport sage.Channel;\nimport sage.EPG;\nimport sage.EPGDataSource;\nimport sage.ExternalTuningManager;\nimport sage.FileDownloader;\nimport sage.FileTransfer;\nimport sage.SchedulerSelector;\nimport sage.SeekerSelector;\nimport sage.IOUtils;\nimport sage.LinuxUtils;\nimport sage.MMC;\nimport sage.ManualRecord;\nimport sage.MediaFile;\nimport sage.MiniClientSageRenderer;\nimport sage.NetworkClient;\nimport sage.NewStorageDeviceDetector;\nimport sage.Playlist;\nimport sage.Pooler;\nimport sage.PredefinedJEPFunction;\nimport sage.PseudoMenu;\nimport sage.Ripper;\nimport sage.SFIRTuner;\nimport sage.Sage;\nimport sage.SageConstants;\nimport sage.SageTV;\nimport sage.Scheduler;\nimport sage.Seeker;\nimport sage.UIClient;\nimport sage.UIManager;\nimport sage.UserEvent;\nimport sage.Widget;\nimport sage.Wizard;\nimport sage.ZComp;\nimport sage.ZDataTable;\nimport sage.ZLabel;\nimport sage.ZPseudoComp;\n\n/**\n * System methods used for dealing with Sage specifics\n */\npublic class Global {\n  private Global() {}\n  public static void init(Catbert.ReflectionFunctionTable rft)\n  {\n    rft.put(new PredefinedJEPFunction("Global", "Refresh")\n    {\n      /**\n       * Re-evaluates and redraws all UI elements on the current menu\n       *\n       * @declaration public void Refresh();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception\n      {\n        if (stack.getUIMgrSafe() == null) return null;\n        PseudoMenu currUI = stack.getUIMgrSafe().getCurrUI();\n        if (currUI != null) currUI.refresh();\n        return null;\n      }\n    });\n    rft.put(new PredefinedJEPFunction("Global", "RefreshArea", new String[] {"WidgetName"})\n    {\n      /**\n       * Finds the Widget on the current menu who\'s name matches the argument and then re-evaluates and redraws all UI elements, and their children for this Widget\n       * @param WidgetName the name that a UI component\'s Widget must match, if null or zero length, then this is the same as calling {@link #Refresh Refresh()}\n       *\n       * @declaration public void RefreshArea(String WidgetName);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception\n      {\n        String s = getString(stack);\n        PseudoMenu currUI = (stack.getUIMgrSafe() == null) ? null : stack.getUIMgrSafe().getCurrUI();\n        if (currUI != null) currUI.refreshByWidgetName(s);\n        return null;\n      }\n    });\n    rft.put(new PredefinedJEPFunction("Global", "RefreshAreaForVariable", new String[] { "Name", "Value" })\n    {\n      /**\n       * Searches all visible UI elements in the current menu finding any that have a variable with the specified name\n       * matching the specified value. For any elements it finds, it will re-evaluate and redraws its UI elements, and its children\n       * @param Name the name of the variable to match\n       * @param Value the value of the variable to match on\n       * @since 6.6\n       *\n       * @declaration public void RefreshAreaForVariable(String Name, Object Value);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        Object val = stack.pop();\n        String name = getString(stack);\n        PseudoMenu ui = (stack.getUIMgrSafe() == null) ? null : stack.getUIMgrSafe().getCurrUI();\n        if (ui != null) ui.refreshByValue(name, val);\n        return null;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "Repaint")\n    {\n      /**\n       * Redraws all UI elements on the current menu\n       *\n       * @declaration public void Repaint();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception\n      {\n        if (stack.getUIMgrSafe() == null) return null;\n        PseudoMenu currUI = stack.getUIMgrSafe().getCurrUI();\n        if (currUI != null) currUI.repaint();\n        return null;\n      }\n    });\n    rft.put(new PredefinedJEPFunction("Global", "RepaintArea", new String[] {"WidgetName"})\n    {\n      /**\n       * Finds the Widget on the current menu who\'s name matches the argument and then redraws all UI elements, and their children for this Widget\n       * @param WidgetName the name that a UI component\'s Widget must match, if null or zero length, then this is the same as calling {@link #Repaint Repaint()}\n       *\n       * @declaration public void RepaintArea(String WidgetName);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception\n      {\n        String s = getString(stack);\n        PseudoMenu currUI = (stack.getUIMgrSafe() == null) ? null : stack.getUIMgrSafe().getCurrUI();\n        if (currUI != null) currUI.repaintByWidgetName(s);\n        return null;\n      }\n    });\n    rft.put(new PredefinedJEPFunction("Global", "AddStaticContext", 2, new String[]{"Name", "Value"})\n    {\n      /**\n       * Sets the variable with the specified name to the specified value. This variable will\n       * exist for the lifetime of the current Menu. When the next Menu transition occurs,\n       * all values in the static context will be copied to the highest level context for the new Menu.\n       * The static context is then cleared. This is the way you can pass an Object from one menu to\n       * another, an example is showing the detailed info for an Airing by adding the Airing to the\n       * static context and then transitioning to a Menu that will display the details for that Airing.\n       *\n       * @param Name the name to use for this \'static context\' variable\n       * @param Value the value to set this \'static context\' variable to\n       * @return the passed in Value\n       *\n       * @declaration public Object AddStaticContext(String Name, Object Value);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception\n      {\n        Object rv = stack.pop();\n        String varName = getString(stack);\n        if (stack.getUIMgrSafe() != null)\n          stack.getUIMgrSafe().getStaticContext().put(varName, rv);\n        return rv;\n      }\n    });\n    rft.put(new PredefinedJEPFunction("Global", "AddGlobalContext", 2, new String[]{"Name", "Value"})\n    {\n      /**\n       * Sets the variable with the specified name to the specified value. This variable\n       * will exist for the lifetime of the SageTV application and is always in scope for all expression evaluation. This is a \'global variable\'.\n       * @param Name the name to use for this \'global context\' variable\n       * @param Value the value to set this \'global context\' variable to\n       * @return the passed in Value\n       *\n       * @declaration public Object AddGlobalContext(String Name, Object Value);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception\n      {\n        Object rv = stack.pop();\n        String varName = getString(stack);\n        if (stack.getUIMgrSafe() != null)\n          stack.getUIMgrSafe().getGlobalContext().put(varName, rv);\n        return rv;\n      }\n    });\n    rft.put(new PredefinedJEPFunction("Global", "AreThereUnresolvedConflicts")\n    {\n      /**\n       * Returns whether or not there are unresolved scheduling conflicts\n       * @return true if there are unresolved scheduling conflicts, false otherwise\n       *\n       * @declaration public boolean AreThereUnresolvedConflicts();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        return Boolean.valueOf(SchedulerSelector.getInstance().areThereDontKnows());\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "IsAsleep")\n    {\n      /**\n       * Returns true if SageTV is in the Sleep state.\n       * @return true if SageTV is in the Sleep state\n       *\n       * @declaration public boolean IsAsleep();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        return Boolean.valueOf(stack.getUIMgrSafe().isAsleep());\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetTotalDiskspaceAvailable", true)\n    {\n      /**\n       * Gets the total diskspace available for television recording by SageTV. This is the unused space in the video directories.\n       * @return the total diskspace available for television recording by SageTV (in bytes)\n       *\n       * @declaration public long GetTotalDiskspaceAvailable();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        return new Long(SeekerSelector.getInstance().getAvailVideoDiskspace());\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetTotalLibraryDuration", true)\n    {\n      /**\n       * Returns the total duration of all of the content in the media library\n       * @return the total duration of all of the content in the media library in milliseconds\n       *\n       * @declaration public long GetTotalLibraryDuration();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        return new Long(SeekerSelector.getInstance().getTotalImportedLibraryDuration());\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetTotalVideoDuration", true)\n    {\n      /**\n       * Returns the total duration of all of the recorded television content\n       * @return the total duration of all of the recorded television content in milliseconds\n       *\n       * @declaration public long GetTotalVideoDuration();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        return new Long(SeekerSelector.getInstance().getTotalVideoDuration());\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetUsedLibraryDiskspace", true)\n    {\n      /**\n       * Returns the total number of bytes on disk used by the content in the imported video, picturees and music libraries\n       * @return the total number of bytes on disk used by the content in the imported video, picturees and music libraries\n       *\n       * @declaration public long GetUsedLibraryDiskspace();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        return new Long(SeekerSelector.getInstance().getUsedImportedLibraryDiskspace());\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetUsedVideoDiskspace", true)\n    {\n      /**\n       * Returns the total number of bytes on disk used by recorded television content\n       * @return the total number of bytes on disk used by recorded television content\n       *\n       * @declaration public long GetUsedVideoDiskspace();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        return new Long(SeekerSelector.getInstance().getUsedVideoDiskspace());\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "AreAiringsSameShow", 2, new String[] {"Airing1", "Airing2"})\n    {\n      /**\n       * Returns true if two Airings represent the same Show. This means that they both are the same content (i.e. one is a repeat of the other)\n       * Just because two Airings use the same Show object (in terms of object reference) doesn\'t mean this call will return true.\n       * @param Airing1 one of the two Airing objects to compare\n       * @param Airing2 the other Airing object to compare\n       * @return true if two Airings represent the same Show, false otherwise\n       *\n       * @declaration public boolean AreAiringsSameShow(Airing Airing1, Airing Airing2);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        return Boolean.valueOf(BigBrother.areSameShow(getAir(stack), getAir(stack), false));\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetLastEPGDownloadTime", true)\n    {\n      /**\n       * Returns the last time that SageTV did an EPG update. The returned value uses the same units as java.lang.System.currentTimeMillis()\n       * @return the last time that SageTV did an EPG update\n       *\n       * @declaration public long GetLastEPGDownloadTime();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        return new Long(EPG.getInstance().getLastRun());\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetLogo", 1, new String[] { "LogoName" })\n    {\n      /**\n       * Gets an Image object that represents the specified name. This is normally used for Channel Logos.\n       * @param LogoName the name to use to lookup the logo image\n       * @return the image object that corresponds to the specified name if one exists, the null image otherwise\n       *\n       * @declaration public MetaImage GetLogo(String LogoName);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        return EPG.getInstance().getLogo(getString(stack), stack.getUIComponent());\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetTimeUntilNextEPGDownload", true)\n    {\n      /**\n       * The amount of time in milliseconds until SageTV will perform an EPG update again. Zero if no update is planned.\n       * @return the amount of time in milliseconds until SageTV will perform an EPG update again. Zero if no update is planned\n       *\n       * @declaration public long GetTimeUntilNextEPGDownload();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        return new Long(EPG.getInstance().getTimeTillUpdate());\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetAllLineups")\n    {\n      /**\n       * Returns the name of all the EPG lineups in the system\n       * @return a list of all the names of the EPG lineups in the system\n       *\n       * @declaration public String[] GetAllLineups();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        return EPG.getInstance().getAllProviderNames();\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "IsChannelDownloadComplete", new String[] { "Lineup" }, true)\n    {\n      /**\n       * Returns true if the channel download has been completed on the specified lineup\n       * @param Lineup the name of the Lineup\n       * @return true if the channel download has been completed on the specified lineup, false otherwise\n       *\n       * @declaration public boolean IsChannelDownloadComplete(String Lineup);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        String lineup = getString(stack);\n        return Boolean.valueOf(EPG.getInstance().getEPGDSForEPGDSName(lineup).isChanDownloadComplete());\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetEPGProperty", new String[]{"EPGDataSource", "Property", "Parameter"}, true)\n    {\n      /**\n       * Gets a property from a specific EPG data source with an optional parameter\n       * @param EPGDataSource the name of the EPG data source\n       * @param Property the property name to get\n       * @param Parameter optional parameter\n       * @return the value of the requested property\n       * @since 9.0\n       *\n       * @declaration public Object GetEPGProperty(String EPGDataSource, String Property, String Parameter);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        String parameter = getString(stack);\n        String property = getString(stack);\n        String dataSource = getString(stack);\n\n        try\n        {\n          return EPG.getProperty(dataSource, property, parameter);\n        }\n        catch (sage.EPGServerException e)\n        {\n          return e.getMessage();\n        }\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "SetEPGProperty", new String[]{"EPGDataSource", "Property", "Value"}, true)\n    {\n      /**\n       * Sets a property for a specific EPG data source to the provided value\n       * @param EPGDataSource the name of the EPG data source\n       * @param Property the property name to set\n       * @param Value the value to set\n       * @return result of setting the property\n       * @since 9.0\n       *\n       * @declaration public Object SetEPGProperty(String EPGDataSource, String Property, String Value);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        String value = getString(stack);\n        String property = getString(stack);\n        String dataSource = getString(stack);\n\n        try\n        {\n          return EPG.setProperty(dataSource, property, value);\n        }\n        catch (sage.EPGServerException e)\n        {\n          return e.getMessage();\n        }\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetLocalMarketsFromEPGServer", true)\n    {\n      /**\n       * Gets a list of all the possible United States local broadcast markets from the EPG server\n       * @return a String[] of all the possible United States local broadcast markets from the EPG server or a String error message of "NO_KEY", "INVALID_KEY", or "CONNECTION_FAILURE"\n       *\n       * @declaration public Object GetLocalMarketsFromEPGServer();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        try {\n          return EPG.getInstance().getLocalMarketsAndCacheNames();\n        } catch (sage.EPGServerException e) {\n          System.out.println("ERROR communicating with EPG server of: " + e);\n          return e.getMessage();\n        }\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetLineupsForZipCodeFromEPGServer", 1, new String[]{"ZipCode"}, true)\n    {\n      /**\n       * Gets a list from the EPG server of all the possible EPG Lineups that are available in a given zip code\n       * @param ZipCode the zip code to search for EPG lineups in\n       * @return a String[] from the EPG server of all the possible EPG lineups in the specified zip code or a String error message of "NO_KEY", "INVALID_KEY", or "CONNECTION_FAILURE"\n       *\n       * @declaration public Object GetLineupsForZipCodeFromEPGServer(String ZipCode);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        try {\n          return EPG.getInstance().getProvidersAndCacheNames(getString(stack));\n        } catch (sage.EPGServerException e) {\n          System.out.println("ERROR communicating with EPG server of: " + e);\n          return e.getMessage();\n        }\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetCurrentlyRecordingMediaFiles", true)\n    {\n      /**\n       * Returns a list of all of the files that SageTV is currently recording\n       * @return a list of all of the files that SageTV is currently recording\n       *\n       * @declaration public MediaFile[] GetCurrentlyRecordingMediaFiles();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        return SeekerSelector.getInstance().getCurrRecordFiles();\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetSuggestedIntelligentRecordings", true)\n    {\n      /**\n       * Gets a list of all of the Airings that SageTV would record if Intelligent Recording was enabled.\n       * This does not include Manual Recordings or Favorites.\n       * @return a list of all of the Airings that SageTV would record if Intelligent Recording was enabled.\n       * @since 4.1\n       *\n       * @declaration public Airing[] GetSuggestedIntelligentRecordings();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        return SeekerSelector.getInstance().getIRScheduledAirings();\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetScheduledRecordings", true)\n    {\n      /**\n       * Gets a list of all of the Airings that SageTV is planning to record in the future\n       * @return a list of all of the Airings that SageTV is planning to record in the future\n       *\n       * @declaration public Airing[] GetScheduledRecordings();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        return SeekerSelector.getInstance().getInterleavedScheduledAirings();\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetScheduledRecordingsForDevice", 1, new String[] { "CaptureDevice"}, true)\n    {\n      /**\n       * Gets a list of all of the Airings that SageTV is planning to record in the future on the specified CaptureDevice\n       * @param CaptureDevice the name of a CaptureDevice for SageTV to get the scheduled recordings for\n       * @return a list of all of the Airings that SageTV is planning to record in the future on the specified CaptureDevice\n       *\n       * @declaration public Airing[] GetScheduledRecordingsForDevice(String CaptureDevice);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        return SeekerSelector.getInstance().getScheduledAiringsForSource(getString(stack));\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetScheduledRecordingsForTime", 2, new String[] { "StartTime", "StopTime" }, true)\n    {\n      /**\n       * Gets a list of all of the Airings that SageTV is planning on recording during the specified time span\n       * @param StartTime the starting time to get all of the scheduled recordings for\n       * @param StopTime the ending time to get all of the scheduled recordings for\n       * @return a list of all of the Airings that SageTV is planning on recording during the specified start-stop time window\n       *\n       * @declaration public Airing[] GetScheduledRecordingsForTime(long StartTime, long StopTime);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        long stop = getLong(stack);\n        return SeekerSelector.getInstance().getInterleavedScheduledAirings(getLong(stack), stop);\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetScheduledRecordingsForDeviceForTime", 3, new String[] { "CaptureDevice", "StartTime", "StopTime"}, true)\n    {\n      /**\n       * Gets a list of all of the Airings that SageTV is planning on recording during the specified time span on a specified CaptureDevice\n       * @param CaptureDevice the name of a CaptureDevice for SageTV to get the scheduled recordings for\n       * @param StartTime the starting time to get all of the scheduled recordings for\n       * @param StopTime the ending time to get all of the scheduled recordings for\n       * @return a list of all of the Airings that SageTV is planning on recording during the specified start-stop time window on the specified CaptureDevice\n       *\n       * @declaration public Airing[] GetScheduledRecordingsForDeviceForTime(String CaptureDevice, long StartTime, long StopTime);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        long stop = getLong(stack);\n        long start = getLong(stack);\n        return SeekerSelector.getInstance().getScheduledAiringsForSource(getString(stack), start, stop);\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetRecentlyWatched", 1, new String[] {"DurationToLookBack"}, true)\n    {\n      /**\n       * Gets a list of all of the Airings that have been watched within the specified amount of time\n       * @param DurationToLookBack tha amount of time in milliseconds that should be searched for watched Airings\n       * @return a list of all of the Airings that have been watched within the specified amount of time\n       *\n       * @declaration public Airing[] GetRecentlyWatched(long DurationToLookBack);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        return SeekerSelector.getInstance().getRecentWatches(Sage.time() - getLong(stack));\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "RunLibraryImportScan", 1, new String[] {"WaitUntilDone"}, true)\n    {\n      /**\n       * Tells SageTV to run a library import scan now. This will scan all of the library import directories for new content.\n       * @param WaitUntilDone if this parameter is true then this call will not return until SageTV has finished the import scan, otherwise it returns immediately\n       *\n       * @declaration public void RunLibraryImportScan(boolean WaitUntilDone);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        SeekerSelector.getInstance().scanLibrary(Catbert.evalBool(stack.pop())); return null;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "Exit")\n    {\n      /**\n       * Causes the SageTV application to terminate. If this is called from the non-primary UI session then it will terminate the UI session it is called from.\n       *\n       * @declaration public void Exit();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        UIManager uiMgr = stack.getUIMgrSafe();\n        if (uiMgr.getLocalUIClientName().equals(Seeker.LOCAL_PROCESS_CLIENT))\n          SageTV.exit();\n        else\n          uiMgr.goodbye();\n        return null;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "SageCommand", -1, new String[]{"Command"})\n    {\n      /**\n       * Causes the corresponding Sage Command to be executed just like it would be if the user performed it.\n       * These are always done asynchronously with the exception of "Back" and "Forward" since those effect\n       * the current UI and may be used to override a menu transition.\n       * @param Command the name of the Sage Command to execute\n       *\n       * @declaration public void SageCommand(String Command);\n       */\n\n      /**\n       * Causes the corresponding Sage Command to be executed just like it would be if the user performed it.\n       * These are always done asynchronously with the exception of "Back" and "Forward" since those effect\n       * the current UI and may be used to override a menu transition. The payload will be passed along and\n       * be accessible in the listener object in the STV.\n       * @param Command the name of the Sage Command to execute\n       * @param Payload an object to pass along with the event\n       * @since 8.1\n       *\n       * @declaration public void SageCommand(String Command, Object Payload);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        Object payload = null;\n        if (curNumberOfParameters == 2)\n          payload = stack.pop();\n        String cmd = getString(stack);\n        stack.getUIMgrSafe().doUserEvent2(UserEvent.getEvtCodeForName(cmd), payload); return null;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "RemoveUnusedLineups")\n    {\n      /**\n       * Removes all of the lineups from SageTV\'s configuration that are no longer in use by a CaptureDevice\n       * @return true if any lineups were removed, false otherwise\n       *\n       * @declaration public boolean RemoveUnusedLineups();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        // Execute this on the server if we\'re the client; but then clean us up locally since removals\n        // aren\'t propogated in the property exchange. But do it first so anything the server has that we don\'t\n        // gets propogated back down correctly\n        boolean killedAny = false;\n        EPGDataSource[] allDS = EPG.getInstance().getDataSources();\n        for (int i = 0; i < allDS.length; i++)\n        {\n          if (!MMC.getInstance().isProviderUsed(allDS[i].getProviderID()))\n          {\n            EPG.getInstance().removeDataSource(allDS[i]);\n            killedAny = true;\n          }\n        }\n        EPG.getInstance().kick();\n        SchedulerSelector.getInstance().kick(false);\n        if (Sage.client)\n        {\n          return makeNetworkedCall(stack);\n        }\n        return Boolean.valueOf(killedAny);\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetApplicationLaunchTime")\n    {\n      /**\n       * Returns the time that the SageTV application was instantiated.\n       * @return the time that the SageTV application was instantiated\n       *\n       * @declaration public long GetApplicationLaunchTime();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        return new Long(SageTV.getInstanceStartTime());\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetFocusContext")\n    {\n      /**\n       * Copies all variables from the currently focused UI element\'s variable context to the current context\n       * of the calling Action. Any variables that are in a common parent hierarchy are not copied as part of this.\n       * @return true if there was a focused element and it\'s context was copied, false if there was no focused element found\n       *\n       * @declaration public boolean GetFocusContext();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        throw new IllegalArgumentException("GetFocusContext() can only be used by itself");\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "Fork")\n    {\n      /**\n       * Spawns a new thread of execution that will be used for further processing of Widget chain. This is analagous to \'forking\' a thread\n       * to continue execution of a widget chain in parallel to the current system execution.\n       *\n       * @declaration public void Fork();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        throw new IllegalArgumentException("Fork() can only be used by itself");\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "TransmitCommandUsingInfraredTuningPlugin", new String[] {"TuningPlugin","TuningPluginPort","RemoteName", "CommandName", "RepeatFactor"}, true)\n    {\n      /**\n       * Causes SageTV to instruct the specified tuning plugin to send a command\n       * @param TuningPlugin the name of the tuning plugin that should send the command\n       * @param TuningPluginPort the name of the port the specified tuning plugin is on\n       * @param RemoteName the name of the \'Remote Control\' that should be used to send the command\n       * @param CommandName the name of the command to be sent\n       * @param RepeatFactor the \'repeat factor\' to use for sending the infrared command, 2 is the default\n       *\n       * @declaration public void TransmitCommandUsingInfraredTuningPlugin(String TuningPlugin, int TuningPluginPort, String RemoteName, String CommandName, int RepeatFactor);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        int rep = getInt(stack);\n        String cmd = getString(stack);\n        String remoteName = getString(stack);\n        int portNum = getInt(stack);\n        SFIRTuner tun = ExternalTuningManager.getIRTunerPlugin(getString(stack), portNum);\n        if (tun != null)\n          tun.playCommand(remoteName, cmd, rep, false);\n        return null;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "DebugLog", 1, new String[] {"DebugString"})\n    {\n      /**\n       * Prints out a message to SageTV\'s debug log\n       * @param DebugString the string to print out\n       *\n       * @declaration public void DebugLog(String DebugString);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        String s = getString(stack);\n        if (Sage.DBG) System.out.println(s);\n        return null;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "CloseOptionsMenu", -1, new String[]{"WidgetName", "WaitForClose"})\n    {\n      /**\n       * Closes the last OptionsMenu that was shown and continues execution of the Action\n       * chain that spawned that OptionsMenu at the sibling after this OptionsMenu. The\n       * feature of continuing execution can be used to prompt the user with a question\n       * through an OptionsMenu before continuing on execution of an Action chain.\n       * An example is confirming something they just did before it actually gets done.\n       *\n       * @declaration public void CloseOptionsMenu();\n       */\n\n      /**\n       * Closes the OptionsMenu who\'s Widget name (or themed Widget name) matches that of the argument and continues execution of the Action\n       * chain that spawned that OptionsMenu at the sibling after this OptionsMenu. The\n       * feature of continuing execution can be used to prompt the user with a question\n       * through an OptionsMenu before continuing on execution of an Action chain.\n       * An example is confirming something they just did before it actually gets done.\n       * If this OptionsMenu is not on top, then it cannot be closed until it becomes the one on top.\n       * @param WidgetName the name of the Widget for the OptionsMenu or the themed OptionsMenu source for that Widget that should be closed\n       * @param WaitForClose if true then this call will not return until the specified OptionsMenu target is closed\n       * @return returns true if the target OptionsMenu is not open or if it was closed as a result of this call, will only return false if waitForClose is true and the target OptionsMenu is not on top\n       * @since 7.1\n       *\n       * @declaration public boolean CloseOptionsMenu(String WidgetName, boolean WaitForClose);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        if (curNumberOfParameters == 2)\n        {\n          boolean waitForClose = getBool(stack);\n          String widgName = getString(stack);\n          return stack.getUIMgrSafe().removePopup(widgName, waitForClose) ? Boolean.TRUE : Boolean.FALSE;\n        }\n        else\n        {\n          stack.getUIMgrSafe().removePopup(); return null;\n        }\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "IsOptionsMenuOpen")\n    {\n      /**\n       * Returns true if an options menu is currently open in the UI.\n       * @return true if an options menu is currently open in the UI, false otherwise\n       * @since 7.1\n       *\n       * @declaration public boolean IsOptionsMenuOpen();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        UIManager uiMgr = stack.getUIMgr();\n        if (uiMgr != null)\n        {\n          PseudoMenu currUI = uiMgr.getCurrUI();\n          return (currUI != null && currUI.hasPopup()) ? Boolean.TRUE : Boolean.FALSE;\n        }\n        return Boolean.FALSE;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetSageCommandNames")\n    {\n      /**\n       * Gets the names of all of the SageTV commands that are available in the system\n       * @return a list of the names of all of the SageTV commands that are available in the system\n       *\n       * @declaration public java.util.Vector GetSageCommandNames();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        java.util.Vector rv = new java.util.Vector(java.util.Arrays.asList(UserEvent.PRETTY_UENAMES));\n        rv.remove(0); // ?\n        rv.remove(0); // ?\n        rv.remove(rv.size() - 1); // Anything\n        return rv;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "ApplyServiceLevelToLineup", 2, new String[] { "Lineup", "ServiceLevel" }, true)\n    {\n      /**\n       * Applies a service level to a given lineup. This is specific to the EPG data source that is being used.\n       * @param Lineup the name of the EPG lineup to modify\n       * @param ServiceLevel the service level to apply to the lineup\n       *\n       * @declaration public void ApplyServiceLevelToLineup(String Lineup, int ServiceLevel);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        int lev = getInt(stack);\n        EPGDataSource ds = EPG.getInstance().getEPGDSForEPGDSName(getString(stack));\n        if (ds != null)\n          ds.applyServiceLevel(lev);\n        return null;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "SetFocusForVariable", new String[] { "Name", "Value" })\n    {\n      /**\n       * Searches all UI elements in the current menu until it finds one that has a variable with the specified name\n       * matching the specified value. Once it finds this UI element, it gives it the focus.  If scrolling of a table\n       * or panel is necessary to make it visible, that scrolling will occur.\n       * @param Name the name of the variable to match\n       * @param Value the value of the variable to match on\n       * @return true if the focus was set\n       *\n       * @declaration public boolean SetFocusForVariable(String Name, Object Value);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        Object val = stack.pop();\n        String name = getString(stack);\n        PseudoMenu ui = stack.getUIMgrSafe().getCurrUI();\n        return Boolean.valueOf(ui.setFocusByValue(name, val));\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "EnsureVisibilityForVariable", new String[] { "Name", "Value", "DisplayIndex" })\n    {\n      /**\n       * Searches the tables in the current menu for a cell that matches the passed in name/value pair;\n       * if found it will ensure that it is currently visible in the UI at the specified visual index of the table.\n       * The name should match the name of the TableComponent-Cell. For example if the TableComponent with a Cell\n       * subtype had a name of "File" and listed all of the MediaFiles; then calling\n       * EnsureVisibilityForVariable("File", MyMediaFile, 1) would cause the table to scroll so that the second row\n       * showed the cell whose File value corresponded to MyMediaFile.  This does NOT change the focus,\n       * if you wish to scroll a table and shift the focus then use SetFocusForVariable\n       *\n       * @param Name the name of the variable to match on\n       * @param Value the value of the variable to match\n       * @param DisplayIndex 0-based value signifying which visually displayed row or column should show the corresonding cell\n       * @return true if there was a matching variable found\n       *\n       * @declaration public boolean EnsureVisibilityForVariable(String Name, Object Value, int DisplayIndex);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        int dispIndex = getInt(stack);\n        Object val = stack.pop();\n        String name = getString(stack);\n        PseudoMenu ui = stack.getUIMgrSafe().getCurrUI();\n        return Boolean.valueOf(ui.ensureVisbilityForValue(name, val, dispIndex));\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetVariableFromContext", new String[] { "MatchName", "MatchValue", "LookupName" })\n    {\n      /**\n       * Searches all UI elements in the current menu until it finds one that has a variable with the specified name\n       * matching the specified value. Once it finds this UI element, it then does a lookup of the other\n       * specified variable in that UI element\'s context and returns that value\n       * @param MatchName the name of the variable to match\n       * @param MatchValue the value of the variable to match on\n       * @param LookupName the variable to lookup in the matching context\n       * @return the value of the variable\n       * @since 7.0\n       *\n       * @declaration public Object GetVariableFromContext(String MatchName, Object MatchValue, String LookupName);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        String lookupName = getString(stack);\n        Object val = stack.pop();\n        String name = getString(stack);\n        PseudoMenu ui = stack.getUIMgrSafe().getCurrUI();\n        // Look for a visible one first; if we don\'t find it, then also accept non-visible ones as well\n        if (ui != null)\n        {\n          ZPseudoComp rvContext = ui.getCompForVariable(name, val, stack.getUIComponent());\n          if (rvContext != null)\n          {\n            if ("Focused".equals(lookupName))\n              return Boolean.valueOf(rvContext.isFocused());\n            else if ("FocusedChild".equals(lookupName))\n              return Boolean.valueOf(rvContext.doesHierarchyHaveFocus());\n            else\n              return rvContext.getRelatedContext().get(lookupName);\n          }\n        }\n        return null;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetVisibilityForVariable", new String[] { "MatchName", "MatchValue" })\n    {\n      /**\n       * Searches all UI elements in the current menu until it finds one that has a variable with the specified name\n       * matching the specified value. Once it finds this UI element, it will return true if that UI element is currently\n       * visible and false otherwise\n       * @param MatchName the name of the variable to match\n       * @param MatchValue the value of the variable to match on\n       * @return true if the found component is visible, false otherwise\n       * @since 7.0\n       *\n       * @declaration public boolean GetVisibilityForVariable(String MatchName, Object MatchValue);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        /*\t\t\t Object val = stack.pop();\n\t\t\t String name = getString(stack);\n\t\t\t PseudoMenu ui = stack.getUIMgrSafe().getCurrUI();\n\t\t\t return Boolean.valueOf(ui.getPassesConditionalForVariable(name, val));*/\n        Object val = stack.pop();\n        String name = getString(stack);\n        if (stack.getUIMgr() == null) return null;\n        PseudoMenu ui = stack.getUIMgr().getCurrUI();\n        // Look for a visible one first; if we don\'t find it, then also accept non-visible ones as well\n        if (ui != null)\n        {\n          ZPseudoComp uiComp = ui.getCompForVariable(name, val, stack.getUIComponent());\n          return (uiComp != null && uiComp.passesUpwardConditional() && uiComp.getNumKids() > 0) ? Boolean.TRUE : Boolean.FALSE;\n        }\n        return Boolean.FALSE;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetUIComponentForVariable", new String[] { "MatchName", "MatchValue" })\n    {\n      /**\n       * Searches all UI elements in the current menu until it finds one that has a variable with the specified name\n       * matching the specified value. It then returns on Object representing that UI component. The search method\n       * prefers visible components over hidden ones.\n       * @param MatchName the name of the variable to match\n       * @param MatchValue the value of the variable to match on\n       * @return the UI component with the specified variable set\n       * @since 7.0\n       *\n       * @declaration public Object GetUIComponentForVariable(String MatchName, Object MatchValue);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        Object val = stack.pop();\n        String name = getString(stack);\n        if (stack.getUIMgr() == null) return null;\n        PseudoMenu ui = stack.getUIMgr().getCurrUI();\n        // Look for a visible one first; if we don\'t find it, then also accept non-visible ones as well\n        if (ui != null)\n        {\n          return ui.getCompForVariable(name, val, stack.getUIComponent());\n        }\n        return null;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetUIComponentContext")\n    {\n      /**\n       * Returns the UI component that this execution originated from. For\n       * \'green\' process chains; this will correspond to the UI component that received the event. For \'blue\'\n       * UI chains; this will correspond to the UI component who\'s conditionality is being determined or who\'s data\n       * is being evaluated. This will be null if there is no UI context; such as for non-UI hooks and calls made from\n       * Java directly.\n       * @return the UIComponent that corresponds to the UI context used for the current evaluation, null if there is no context\n       * @since 7.0\n       *\n       * @declaration public Object GetUIComponentContext();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        return stack.getUIComponent();\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "SetFocusToUIComponent", new String[] { "UIComponent" })\n    {\n      /**\n       * Sets focus in the specified UI component. The UIComponent must be focusable for this to succeed\n       * @param UIComponent the specified UIComponent, can be retrieved using {@link #GetUIComponentForVariable GetUIComponentForVariable} API call\n       * @return true if setting the focus in the specified component succeeded, false otherwise\n       * @since 7.0\n       *\n       * @declaration public boolean SetFocusToUIComponent(Object UIComponent);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        ZPseudoComp uiComp = getUIComp(stack);\n        if (uiComp != null && uiComp.isFocusable())\n        {\n          return uiComp.setFocus() ? Boolean.TRUE : Boolean.FALSE;\n        }\n        return Boolean.FALSE;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetTableFocusedVisibleRow", new String[] { "UIComponent" })\n    {\n      /**\n       * Gets the row number that currently has focus in the specified table. The argument may be the table itself; or a component between\n       * the table and the focused component.\n       * @param UIComponent the specified UIComponent, can be retrieved using {@link #GetUIComponentForVariable GetUIComponentForVariable} API call\n       * @return the row number (1-based) which is currently focused in the table, -1 is returned if the value can\'t be resolved\n       * @since 7.0\n       *\n       * @declaration public int GetTableFocusedVisibleRow(Object UIComponent);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        ZPseudoComp uiComp = getUIComp(stack);\n        if (uiComp != null)\n        {\n          // Now get the child focused component if it exists\n          //\t\t\t\t if (uiComp.doesHierarchyHaveFocus())\n          {\n            ZComp focusOwner = uiComp.getLastFocusedChild();\n            if (focusOwner == null)\n              return new Integer(-1);\n            if (focusOwner instanceof ZPseudoComp)\n            {\n              ZPseudoComp focusComp = (ZPseudoComp) focusOwner;\n              // This depends upon the orientation of the table\n              ZDataTable tabParent = focusComp.getTableParent();\n              boolean vert = true;\n              if (tabParent != null && tabParent.getTableDimensions() == ZDataTable.HORIZONTAL_DIMENSION)\n                vert = false;\n              // Now calculate its visible row position\n              Object o1 = focusComp.getRelatedContext().safeLookup("TableRow");\n              Object o2 = focusComp.getRelatedContext().safeLookup("NumColsPerPage");\n              Object o3 = focusComp.getRelatedContext().safeLookup("VScrollIndex");\n              Object o4 = focusComp.getRelatedContext().safeLookup("NumRowsPerPage");\n              Object o5 = focusComp.getRelatedContext().safeLookup("HScrollIndex");\n              int tablePosition = o1 != null ? (Integer.parseInt(o1.toString()) - 1) : 0;\n              int colsPerPage = o2 != null ? Math.max(1, Integer.parseInt(o2.toString())) : 1;\n              int vscrollIndex = o3 != null ? (Integer.parseInt(o3.toString()) - 1) : 0;\n              int rowsPerPage = o4 != null ? Math.max(1, Integer.parseInt(o4.toString())) : 1;\n              int hscrollIndex = o5 != null ? (Integer.parseInt(o5.toString()) - 1) : 0;\n              if (vert)\n              {\n                Object o7 = focusComp.getRelatedContext().safeLookup("NumRows");\n                int numRows = o7 != null ? Integer.parseInt(o7.toString()) : 1;\n                return new Integer(1 + (((tablePosition - colsPerPage * vscrollIndex - rowsPerPage * hscrollIndex + numRows) % numRows) / colsPerPage));\n              }\n              else\n              {\n                Object o6 = focusComp.getRelatedContext().safeLookup("NumCols");\n                int numCols = o6 != null ? Integer.parseInt(o6.toString()) : 1;\n                return new Integer(1 + (((tablePosition - colsPerPage * vscrollIndex - rowsPerPage * hscrollIndex + numCols) % numCols) % rowsPerPage));\n              }\n            }\n          }\n        }\n        return new Integer(-1);\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetTableFocusedVisibleColumn", new String[] { "UIComponent" })\n    {\n      /**\n       * Gets the column number that currently has focus in the specified table. The argument may be the table itself; or a component between\n       * the table and the focused component.\n       * @param UIComponent the specified UIComponent, can be retrieved using {@link #GetUIComponentForVariable GetUIComponentForVariable} API call\n       * @return the column number (1-based) which is currently focused in the table, -1 is returned if the value can\'t be resolved\n       * @since 7.0\n       *\n       * @declaration public int GetTableFocusedVisibleColumn(Object UIComponent);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        ZPseudoComp uiComp = getUIComp(stack);\n        if (uiComp != null)\n        {\n          // Now get the child focused component if it exists\n          //\t\t\t\t if (uiComp.doesHierarchyHaveFocus())\n          {\n            ZComp focusOwner = uiComp.getLastFocusedChild();\n            if (focusOwner == null)\n              return new Integer(-1);\n            if (focusOwner instanceof ZPseudoComp)\n            {\n              ZPseudoComp focusComp = (ZPseudoComp) focusOwner;\n              // This depends upon the orientation of the table\n              ZDataTable tabParent = focusComp.getTableParent();\n              boolean vert = true;\n              if (tabParent != null && tabParent.getTableDimensions() == ZDataTable.HORIZONTAL_DIMENSION)\n                vert = false;\n              // Now calculate its visible column position\n              Object o1 = focusComp.getRelatedContext().safeLookup("TableRow");\n              Object o2 = focusComp.getRelatedContext().safeLookup("NumColsPerPage");\n              Object o3 = focusComp.getRelatedContext().safeLookup("VScrollIndex");\n              Object o4 = focusComp.getRelatedContext().safeLookup("NumRowsPerPage");\n              Object o5 = focusComp.getRelatedContext().safeLookup("HScrollIndex");\n              int tablePosition = o1 != null ? (Integer.parseInt(o1.toString()) - 1) : 0;\n              int colsPerPage = o2 != null ? Math.max(1, Integer.parseInt(o2.toString())) : 1;\n              int vscrollIndex = o3 != null ? (Integer.parseInt(o3.toString()) - 1) : 0;\n              int rowsPerPage = o4 != null ? Math.max(1, Integer.parseInt(o4.toString())) : 1;\n              int hscrollIndex = o5 != null ? (Integer.parseInt(o5.toString()) - 1) : 0;\n              //\t\t\t\t\t\t return new Integer(1 + (tablePosition / rowsPerPage) - hscrollIndex);\n              if (vert)\n              {\n                Object o7 = focusComp.getRelatedContext().safeLookup("NumRows");\n                int numRows = o7 != null ? Integer.parseInt(o7.toString()) : 1;\n                return new Integer(1 + (((tablePosition - colsPerPage * vscrollIndex - rowsPerPage * hscrollIndex + numRows) % numRows) % colsPerPage));\n              }\n              else\n              {\n                Object o6 = focusComp.getRelatedContext().safeLookup("NumCols");\n                int numCols = o6 != null ? Integer.parseInt(o6.toString()) : 1;\n                return new Integer(1 + (((tablePosition - colsPerPage * vscrollIndex - rowsPerPage * hscrollIndex + numCols) % numCols) / rowsPerPage));\n              }\n            }\n          }\n        }\n        return new Integer(-1);\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetTableFocusedVisiblePosition", new String[] { "UIComponent" })\n    {\n      /**\n       * Gets the <b>visible</b> table position that currently has focus in the specified table. The argument may be the table itself; or a component between\n       * the table and the focused component. This starts counting from the first component which is currently visible in the table.\n       * @param UIComponent the specified UIComponent, can be retrieved using {@link #GetUIComponentForVariable GetUIComponentForVariable} API call\n       * @return the visible position (1-based) which is currently focused in the table, -1 is returned if the value can\'t be resolved\n       * @since 7.0\n       *\n       * @declaration public int GetTableFocusedVisiblePosition(Object UIComponent);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        ZPseudoComp uiComp = getUIComp(stack);\n        if (uiComp != null)\n        {\n          //\t\t\t\t if (uiComp.doesHierarchyHaveFocus())\n          {\n            ZComp focusOwner = uiComp.getLastFocusedChild();\n            if (focusOwner == null)\n              return new Integer(-1);\n            if (focusOwner instanceof ZPseudoComp)\n            {\n              // Now calculate its visible position\n              ZPseudoComp focusComp = (ZPseudoComp) focusOwner;\n              Object o1 = focusComp.getRelatedContext().safeLookup("TableRow");\n              Object o2 = focusComp.getRelatedContext().safeLookup("NumColsPerPage");\n              Object o3 = focusComp.getRelatedContext().safeLookup("VScrollIndex");\n              Object o4 = focusComp.getRelatedContext().safeLookup("NumRowsPerPage");\n              Object o5 = focusComp.getRelatedContext().safeLookup("HScrollIndex");\n              Object o6 = focusComp.getRelatedContext().safeLookup("NumCols");\n              Object o7 = focusComp.getRelatedContext().safeLookup("NumRows");\n              int tablePosition = o1 != null ? (Integer.parseInt(o1.toString()) - 1) : 0;\n              int colsPerPage = o2 != null ? Math.max(1, Integer.parseInt(o2.toString())) : 1;\n              int vscrollIndex = o3 != null ? (Integer.parseInt(o3.toString()) - 1) : 0;\n              int rowsPerPage = o4 != null ? Math.max(1, Integer.parseInt(o4.toString())) : 1;\n              int hscrollIndex = o5 != null ? (Integer.parseInt(o5.toString()) - 1) : 0;\n              int numCols = o6 != null ? Integer.parseInt(o6.toString()) : 1;\n              int numRows = o7 != null ? Integer.parseInt(o7.toString()) : 1;\n              return new Integer(1 + (tablePosition - colsPerPage * vscrollIndex - rowsPerPage * hscrollIndex + numRows*numCols) % (numRows * numCols));\n            }\n          }\n        }\n        return new Integer(-1);\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetTableFocusedPosition", new String[] { "UIComponent" })\n    {\n      /**\n       * Gets the table position that currently has focus in the specified table. The argument may be the table itself; or a component between\n       * the table and the focused component. This is the equivalent of the "TableRow" variable for the currently focused table cell; which is\n       * the cell\'s index in the data backing the table.\n       * @param UIComponent the specified UIComponent, can be retrieved using {@link #GetUIComponentForVariable GetUIComponentForVariable} API call\n       * @return the position (1-based) which is currently focused in the table, -1 is returned if the value can\'t be resolved\n       * @since 7.0\n       *\n       * @declaration public int GetTableFocusedPosition(Object UIComponent);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        ZPseudoComp uiComp = getUIComp(stack);\n        if (uiComp != null)\n        {\n          ZComp focusOwner = uiComp.getLastFocusedChild();\n          if (focusOwner == null)\n            return new Integer(-1);\n          if (focusOwner instanceof ZPseudoComp)\n          {\n            // Now calculate its visible position\n            ZPseudoComp focusComp = (ZPseudoComp) focusOwner;\n            Object o1 = focusComp.getRelatedContext().safeLookup("TableRow");\n            int tablePosition = o1 != null ? (Integer.parseInt(o1.toString()) - 1) : 0;\n            return new Integer(1 + tablePosition);\n          }\n        }\n        return new Integer(-1);\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetDataFromTableFocusedOffset", new String[] { "UIComponent", "Offset", "WrapIndex" })\n    {\n      /**\n       * Gets the data value for the table that is used for the cell at the specified position relative to what is currently\n       * <b>focused</b> for the table. The UIComponent should either be the table itself; or it should have the desired table as an ancestor of it.\n       * Position values are zero-based; and may be negative. If WrapIndex is false then positions greater then the size of the table\'s data or\n       * less than zero will return null; otherwise they will be mod\'d to return a value within the range of the data.\n       * @param UIComponent the specified UIComponent, can be retrieved using {@link #GetUIComponentForVariable GetUIComponentForVariable} API call\n       * @param Offset the offset of the cell who\'s table data should be returned; relative to the current focused position (last focused if not currently focused)\n       * @param WrapIndex true if offsets that fall outside of the size of the data should be wrapped so that they return a data value\n       * @return the value of the table data at the specified offset\n       * @since 7.0\n       *\n       * @declaration public Object GetDataFromTableFocusedOffset(Object UIComponent, int Offset, boolean WrapIndex);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        boolean wrapIndex = getBool(stack);\n        int offset = getInt(stack);\n        ZPseudoComp uiComp = getUIComp(stack);\n        if (uiComp != null)\n        {\n          // Now get the child focused component if it exists\n          ZComp focusOwner = uiComp.getLastFocusedChild();\n          if (focusOwner instanceof ZPseudoComp)\n          {\n            // Now calculate its visible position\n            ZPseudoComp focusComp = (ZPseudoComp) focusOwner;\n            ZDataTable tabParent = focusComp.getTableParent();\n            if (tabParent != null)\n            {\n              Object o1 = focusComp.getRelatedContext().safeLookup("TableRow");\n              int tablePosition = o1 != null ? (Integer.parseInt(o1.toString()) - 1) : 0;\n              return tabParent.getTableDataFromOffset(tablePosition + offset, wrapIndex);\n            }\n          }\n          else\n          {\n            // Get the one at the first position instead\n            ZDataTable tabParent = uiComp.getTableParent();\n            if (tabParent != null)\n            {\n              return tabParent.getTableDataFromOffset(offset, wrapIndex);\n            }\n          }\n        }\n        return null;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetDataFromTableVisiblePosition", new String[] { "UIComponent", "Offset", "WrapIndex" })\n    {\n      /**\n       * Gets the data value for the table that is used for the cell at the specified position relative to what is currently\n       * <b>visible</b> for the table. The UIComponent should either be the table itself; or it should have the desired table as an ancestor of it.\n       * Offset values are zero-based; and may be negative. If WrapIndex is false then positions greater then the size of the table\'s data or\n       * less than zero will return null; otherwise they will be mod\'d to return a value within the range of the data.\n       * @param UIComponent the specified UIComponent, can be retrieved using {@link #GetUIComponentForVariable GetUIComponentForVariable} API call\n       * @param Offset the offset of the cell who\'s table data should be returned; relative to the first visible position\n       * @param WrapIndex true if offsets that fall outside of the size of the data should be wrapped so that they return a data value\n       * @return the value of the table data at the specified offset\n       * @since 7.0\n       *\n       * @declaration public Object GetDataFromTableVisiblePosition(Object UIComponent, int Offset, boolean WrapIndex);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        boolean wrapIndex = getBool(stack);\n        int position = getInt(stack);\n        ZPseudoComp uiComp = getUIComp(stack);\n        if (uiComp != null)\n        {\n          ZDataTable tabParent = uiComp.getTableParent();\n          if (tabParent == null)\n            return null;\n          int colsPerPage = Math.max(1, tabParent.getNumColsPerPage());\n          int vscrollIndex = tabParent.getVScrollIndex();\n          int rowsPerPage = Math.max(1, tabParent.getNumRowsPerPage());\n          int hscrollIndex = tabParent.getHScrollIndex();\n          int visPos = position + colsPerPage * vscrollIndex + rowsPerPage * hscrollIndex;\n          return tabParent.getTableDataFromOffset(visPos, wrapIndex);\n        }\n        return null;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "IsTableTransitionToNext", new String[] { "UIComponent" })\n    {\n      /**\n       * Returns true if the specified table argument (or the first table parent of the argument) is on the leading edge of a transition\n       * to a cell after the current one. It could be a page event, or a moving a single unit. Right and Down directionality is considered to be \'next\'.\n       * This can be used to trigger effects that relate to navigation occurring in a table. This will only be true for a single rendering pass on the\n       * leading edge of the transition. Focus will be moved before this becomes true. If effect animations are disabled; this will always return false.\n       * @param UIComponent the specified UIComponent, can be retrieved using {@link #GetUIComponentForVariable GetUIComponentForVariable} API call\n       * @return true if the table is currently transitioning in the next direction\n       * @since 7.0\n       *\n       * @declaration public boolean IsTableTransitionToNext(Object UIComponent);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        ZPseudoComp uiComp = getUIComp(stack);\n        if (stack.getUIComponent() != null)\n          stack.getUIComponent().setNextTransitionListen();\n        if (uiComp != null && uiComp.getUIMgr().areEffectsEnabled())\n        {\n          ZDataTable tabParent = uiComp.getTableParent();\n          if (tabParent != null)\n          {\n            return tabParent.isDoingNextTransition() ? Boolean.TRUE : Boolean.FALSE;\n          }\n        }\n        return Boolean.FALSE;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "IsTableTransitionToPrevious", new String[] { "UIComponent" })\n    {\n      /**\n       * Returns true if the specified table argument (or the first table parent of the argument) is on the leading edge of a transition\n       * to a cell before the current one. It could be a page event, or a moving a single unit. Left and Up directionality is considered to be \'previous\'.\n       * This can be used to trigger effects that relate to navigation occurring in a table. This will only be true for a single rendering pass on the\n       * leading edge of the transition. Focus will be moved before this becomes true. If effect animations are disabled; this will always return false.\n       * @param UIComponent the specified UIComponent, can be retrieved using {@link #GetUIComponentForVariable GetUIComponentForVariable} API call\n       * @return true if the table is currently transitioning in the previous direction\n       * @since 7.0\n       *\n       * @declaration public boolean IsTableTransitionToPrevious(Object UIComponent);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        ZPseudoComp uiComp = getUIComp(stack);\n        if (stack.getUIComponent() != null)\n          stack.getUIComponent().setPrevTransitionListen();\n        if (uiComp != null && uiComp.getUIMgr().areEffectsEnabled())\n        {\n          ZDataTable tabParent = uiComp.getTableParent();\n          if (tabParent != null)\n          {\n            return tabParent.isDoingPrevTransition() ? Boolean.TRUE : Boolean.FALSE;\n          }\n        }\n        return Boolean.FALSE;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "IsTransitioningToMenu", new String[] { "MenuName" })\n    {\n      /**\n       * Returns true if the specified menu name matches the name of the menu widget that the UI is in the process\n       * of transitioning to. This will only be true during the processing of MenuUnloaded effects. If a null argument is given; then this is\n       * true in the case that any menu transition is about to occur. The name match is case-insensitive.\n       * @param MenuName the name of the menu to test to see if we\'re transitioning to; null if it matches any menu name\n       * @return true if the specified menu name matches the name of the menu widget that the UI is in the process of transitioning to, false otherwise\n       * @since 7.0\n       *\n       * @declaration public boolean IsTransitioningToMenu(String MenuName);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        String menuName = getString(stack);\n        UIManager uiMgr = stack.getUIMgrSafe();\n        if (uiMgr != null)\n        {\n          Widget nextUI = uiMgr.getMenuTransitionTarget();\n          return (nextUI != null && (menuName == null || nextUI.getName().equalsIgnoreCase(menuName))) ? Boolean.TRUE : Boolean.FALSE;\n        }\n        return Boolean.FALSE;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "IsTransitioningFromMenu", new String[] { "MenuName" })\n    {\n      /**\n       * Returns true if the specified menu name matches the name of the menu widget for the previously loaded menu. The name match is case-insensitive.\n       * Unlike <b>IsTransitioningToMenu</b>, this is true even after the transition is complete. A null argument always returns false.\n       * @param MenuName the name of the menu to test to see if it was the previously loaded menu\n       * @return true if the specified menu name matches the name of the menu widget for the previously loaded menu, false otherwise\n       * @since 7.0\n       *\n       * @declaration public boolean IsTransitioningFromMenu(String MenuName);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        String menuName = getString(stack);\n        UIManager uiMgr = stack.getUIMgrSafe();\n        if (uiMgr != null)\n        {\n          Widget nextUI = uiMgr.getMenuTransitionSource();\n          PseudoMenu currUI = uiMgr.getCurrUI();\n          return (nextUI != null && currUI != null && currUI.getUI() != null &&\n              /*currUI.getUI().isMenuLoadingState() &&*/ nextUI.getName().equalsIgnoreCase(menuName)) ? Boolean.TRUE : Boolean.FALSE;\n        }\n        return Boolean.FALSE;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "IsTransitioningToMenus", new String[] { "MenuNames" })\n    {\n      /**\n       * Returns true if one of the specified menu name matches the name of the menu widget that the UI is in the process\n       * of transitioning to. This will only be true during the processing of MenuUnloaded effects. If a null argument or empty list is given; then this is\n       * true in the case that any menu transition is about to occur. The name match is case-insensitive.\n       * @param MenuNames the names of the menu to test to see if we\'re transitioning to; null or empty list if it matches any menu name\n       * @return true if one of the specified menu name matches the name of the menu widget that the UI is in the process of transitioning to, false otherwise\n       * @since 8.0\n       *\n       * @declaration public boolean IsTransitioningToMenus(String[] MenuNames);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        String[] menuNames = getStringList(stack);\n        UIManager uiMgr = stack.getUIMgrSafe();\n        if (uiMgr != null)\n        {\n          Widget nextUI = uiMgr.getMenuTransitionTarget();\n          if (nextUI == null)\n            return Boolean.FALSE;\n          if (menuNames == null || menuNames.length == 0)\n            return Boolean.TRUE;\n          for (int i = 0; i < menuNames.length; i++)\n            if (menuNames[i] != null && nextUI.getName().equalsIgnoreCase(menuNames[i]))\n              return Boolean.TRUE;\n        }\n        return Boolean.FALSE;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "IsTransitioningFromMenus", new String[] { "MenuNames" })\n    {\n      /**\n       * Returns true if one of the specified menu names matches the name of the menu widget for the previously loaded menu. The name match is case-insensitive.\n       * Unlike <b>IsTransitioningToMenus</b>, this is true even after the transition is complete. A null argument or empty list always returns false.\n       * @param MenuNames the names of the menus to test to see if it was the previously loaded menu\n       * @return true if one of the specified menu names matches the name of the menu widget for the previously loaded menu, false otherwise\n       * @since 8.0\n       *\n       * @declaration public boolean IsTransitioningFromMenus(String[] MenuNames);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        String[] menuNames = getStringList(stack);\n        UIManager uiMgr = stack.getUIMgrSafe();\n        if (uiMgr != null)\n        {\n          Widget nextUI = uiMgr.getMenuTransitionSource();\n          PseudoMenu currUI = uiMgr.getCurrUI();\n          if (nextUI == null || currUI == null || currUI.getUI() == null)\n            return Boolean.FALSE;\n          if (menuNames == null || menuNames.length == 0)\n            return Boolean.FALSE;\n          for (int i = 0; i < menuNames.length; i++)\n            if (menuNames[i] != null && nextUI.getName().equalsIgnoreCase(menuNames[i]))\n              return Boolean.TRUE;\n        }\n        return Boolean.FALSE;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetTextForUIComponent", new String[] { "UIComponent" })\n    {\n      /**\n       * Gets the value displayed for the textual component of the specified UI object. If its not a Text component; then\n       * its children will be searched depth-first until one is found and then that will be used for the return value.\n       * @param UIComponent the specified UIComponent, can be retrieved using {@link #GetUIComponentForVariable GetUIComponentForVariable} API call\n       * @return the text value displayed by the argument itself; or if its not a text component then the value displayed by the first text child of the component; null if neither condition is met\n       * @since 7.0\n       *\n       * @declaration public String GetTextForUIComponent(Object UIComponent);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        ZPseudoComp uiComp = getUIComp(stack);\n        if (uiComp != null)\n        {\n          // Check to make sure its a TEXT widget, and if so then just return the string stored in its ZLabel child\n          ZLabel label = uiComp.findFirstLabelChild();\n          if (label != null)\n            return label.getText();\n        }\n        return null;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetUIComponentLastFocusedChild", new String[] { "UIComponent" })\n    {\n      /**\n       * If the specified component currently has a focused child; that child\'s UI object will\n       * be returned. If not, then the last focused child for this component will be returned.\n       * @param UIComponent the specified UIComponent, can be retrieved using {@link #GetUIComponentForVariable GetUIComponentForVariable} API call\n       * @return the currently focused child UI object for the specified component if it exists; otherwise the last focused child UI object for the specified component\n       * @since 7.0\n       *\n       * @declaration public Object GetUIComponentLastFocusedChild(Object UIComponent);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        ZPseudoComp uiComp = getUIComp(stack);\n        if (uiComp != null)\n        {\n          ZComp rv = uiComp.getLastFocusedChild();\n          if (rv instanceof ZPseudoComp)\n            return rv;\n        }\n        return null;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetUIComponentPositionX", new String[] { "UIComponent" })\n    {\n      /**\n       * Returns the X position in pixels in the UI of the specified UI component. This will be a value relative to the overall UI; not its parent.\n       * @param UIComponent the specified UIComponent, can be retrieved using {@link #GetUIComponentForVariable GetUIComponentForVariable} API call\n       * @return the X position in pixels relative to the overall UI of the specified component\n       * @since 7.0\n       *\n       * @declaration public int GetUIComponentPositionX(Object UIComponent);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        ZPseudoComp uiComp = getUIComp(stack);\n        if (uiComp != null)\n        {\n          return new Integer(uiComp.getTrueX());\n        }\n        return null;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetUIComponentPositionY", new String[] { "UIComponent" })\n    {\n      /**\n       * Returns the Y position in pixels in the UI of the specified UI component. This will be a value relative to the overall UI; not its parent.\n       * @param UIComponent the specified UIComponent, can be retrieved using {@link #GetUIComponentForVariable GetUIComponentForVariable} API call\n       * @return the Y position in pixels relative to the overall UI of the specified component\n       * @since 7.0\n       *\n       * @declaration public int GetUIComponentPositionY(Object UIComponent);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        ZPseudoComp uiComp = getUIComp(stack);\n        if (uiComp != null)\n        {\n          return new Integer(uiComp.getTrueY());\n        }\n        return null;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetUIComponentWidth", new String[] { "UIComponent" })\n    {\n      /**\n       * Returns the width in pixels in the UI of the specified UI component.\n       * @param UIComponent the specified UIComponent, can be retrieved using {@link #GetUIComponentForVariable GetUIComponentForVariable} API call\n       * @return the width in pixels of the specified component\n       * @since 7.0\n       *\n       * @declaration public int GetUIComponentWidth(Object UIComponent);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        ZPseudoComp uiComp = getUIComp(stack);\n        if (uiComp != null)\n        {\n          return new Integer(uiComp.getWidth());\n        }\n        return null;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetUIComponentHeight", new String[] { "UIComponent" })\n    {\n      /**\n       * Returns the height in pixels in the UI of the specified UI component.\n       * @param UIComponent the specified UIComponent, can be retrieved using {@link #GetUIComponentForVariable GetUIComponentForVariable} API call\n       * @return the height in pixels of the specified component\n       * @since 7.0\n       *\n       * @declaration public int GetUIComponentHeight(Object UIComponent);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        ZPseudoComp uiComp = getUIComp(stack);\n        if (uiComp != null)\n        {\n          return new Integer(uiComp.getHeight());\n        }\n        return null;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetUIComponentPositionXf", new String[] { "UIComponent" })\n    {\n      /**\n       * Returns the X position in the UI of the specified UI component. This will be a value relative to the overall UI; not its parent.\n       * @param UIComponent the specified UIComponent, can be retrieved using {@link #GetUIComponentForVariable GetUIComponentForVariable} API call\n       * @return the X position relative to the overall UI width of the specified component, this will be a floating point number\n       * @since 8.0\n       *\n       * @declaration public float GetUIComponentPositionXf(Object UIComponent);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        ZPseudoComp uiComp = getUIComp(stack);\n        if (uiComp != null)\n        {\n          return new Float(uiComp.getTrueXf() / uiComp.getReality().getWidth());\n        }\n        return null;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetUIComponentPositionYf", new String[] { "UIComponent" })\n    {\n      /**\n       * Returns the Y position in the UI of the specified UI component. This will be a value relative to the overall UI; not its parent.\n       * @param UIComponent the specified UIComponent, can be retrieved using {@link #GetUIComponentForVariable GetUIComponentForVariable} API call\n       * @return the Y position relative to the overall UI height of the specified component, this will be a floating point number\n       * @since 8.0\n       *\n       * @declaration public float GetUIComponentPositionYf(Object UIComponent);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        ZPseudoComp uiComp = getUIComp(stack);\n        if (uiComp != null)\n        {\n          return new Float(uiComp.getTrueYf() / uiComp.getReality().getHeight());\n        }\n        return null;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetUIComponentWidthf", new String[] { "UIComponent" })\n    {\n      /**\n       * Returns the width in the UI of the specified UI component relative to the entire UI width.\n       * @param UIComponent the specified UIComponent, can be retrieved using {@link #GetUIComponentForVariable GetUIComponentForVariable} API call\n       * @return the width of the specified component relative to the entire UI width, this will be a floating point number\n       * @since 8.0\n       *\n       * @declaration public int GetUIComponentWidthf(Object UIComponent);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        ZPseudoComp uiComp = getUIComp(stack);\n        if (uiComp != null)\n        {\n          return new Float(uiComp.getWidthf() / uiComp.getReality().getWidth());\n        }\n        return null;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetUIComponentHeightf", new String[] { "UIComponent" })\n    {\n      /**\n       * Returns the height in the UI of the specified UI component relative to the entire UI height.\n       * @param UIComponent the specified UIComponent, can be retrieved using {@link #GetUIComponentForVariable GetUIComponentForVariable} API call\n       * @return the height of the specified component relative to the entire UI height, this will be a floating point number\n       * @since 8.0\n       *\n       * @declaration public float GetUIComponentHeightf(Object UIComponent);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        ZPseudoComp uiComp = getUIComp(stack);\n        if (uiComp != null)\n        {\n          return new Float(uiComp.getHeightf() / uiComp.getReality().getHeight());\n        }\n        return null;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "SendEventToUIComponent", new String[] { "UIComponent", "Command", "RepeatCount" })\n    {\n      /**\n       * Sends an event to a specific UI component for processing. Similar to using the {@link #SageCommand SageCommand()} API call, but this\n       * version is targeted at a specific component. Normal event processing of cursor navigation, selection, entry events will continue up the hierarchy from the target component if it\n       * does not consume it; it will stop at the menu level though and any menu-level default handling for the event will not occur (i.e. media player control, menu navigation, power, etc.).\n       * @param UIComponent the UIComponent object to target the event at, can be retrieved using {@link #GetUIComponentForVariable GetUIComponentForVariable} API call\n       * @param Command the name of the command to send\n       * @param RepeatCount the number of times to send the command\n       * @return true if the event was consumed by the target component\'s hierarchy\n       * @since 7.0\n       *\n       * @declaration public Object SendEventToUIComponent(Object UIComponent, String Command, int RepeatCount);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        int numTimes = getInt(stack);\n        int evtCode = UserEvent.getEvtCodeForName(getString(stack));\n        ZPseudoComp uiComp = getUIComp(stack);\n        if (uiComp != null)\n        {\n          boolean rv = false;\n          for (int i = 0; i < numTimes; i++)\n            rv = uiComp.action(new UserEvent(uiComp.getUIMgr().getRouter().getEventCreationTime(), evtCode, -1));\n          return Boolean.valueOf(rv);\n        }\n        return Boolean.FALSE;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetChildUIComponentForVariable", new String[] { "UIComponent", "MatchName", "MatchValue" })\n    {\n      /**\n       * Searches all child UI elements in of the specified UIComponent until it finds one that has a variable with the specified name\n       * matching the specified value. It then returns on Object representing that UI component\n       * @param UIComponent the UI component who\'s children should be searched\n       * @param MatchName the name of the variable to match\n       * @param MatchValue the value of the variable to match on\n       * @return the UI component with the specified variable set\n       * @since 7.0\n       *\n       * @declaration public Object GetChildUIComponentForVariable(Object UIComponent, String MatchName, Object MatchValue);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        Object val = stack.pop();\n        String name = getString(stack);\n        ZPseudoComp uiComp = getUIComp(stack);\n        if (uiComp != null)\n        {\n          Object[] rvHolder = new Object[2];\n          uiComp.getCompForVariable(name, val, rvHolder, true);\n          return (rvHolder[0] != null) ? ((ZPseudoComp) rvHolder[0]) : ((ZPseudoComp) rvHolder[1]);\n        }\n        return null;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetVariableFromUIComponent", new String[] { "UIComponent", "VarName" })\n    {\n      /**\n       * Retrieves the variable with the specified name from the context of the passed in UIComponent.\n       * @param UIComponent the UI component who\'s variable should be returned\n       * @param VarName the name of the variable to lookup\n       * @return the value of the variable\n       * @since 7.0\n       *\n       * @declaration public Object GetVariableFromUIComponent(Object UIComponent, String VarName);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        String name = getString(stack);\n        ZPseudoComp uiComp = getUIComp(stack);\n        if (uiComp != null)\n        {\n          if ("Focused".equals(name))\n            return Boolean.valueOf(uiComp.isFocused());\n          else if ("FocusedChild".equals(name))\n            return Boolean.valueOf(uiComp.doesHierarchyHaveFocus());\n          else\n            return uiComp.getRelatedContext().safeLookup(name);\n        }\n        return null;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "SetVariableForUIComponent", new String[] { "UIComponent", "VarName", "VarValue" })\n    {\n      /**\n       * Sets the variable with the specified name in the context of the passed in UIComponent. This behaves the same way as\n       * if an assignment was done to that variable within the passed in UIComponent context within the Studio. This may result\n       * in setting the value at a higher level in the hierarchy if the variable is defined above the specified component.\n       * @param UIComponent the UI component who\'s context should be used when setting the variable\n       * @param VarName the name of the variable to set\n       * @param VarValue the value to set the variable to\n       * @since 7.1\n       *\n       * @declaration public void SetVariableForUIComponent(Object UIComponent, String VarName, Object VarValue);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        Object value = stack.pop();\n        String name = getString(stack);\n        ZPseudoComp uiComp = getUIComp(stack);\n        if (uiComp != null)\n        {\n          uiComp.getRelatedContext().set(name, value);\n        }\n        return null;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "PassiveListen")\n    {\n      /**\n       * Should only be used in the Action chain from a Listener Widget. Normally SageTV will stop processing Listeners\n       * for an event once the first one is reached. If you use PassiveListen() in the action chain for a\n       * Listener then SageTV will not stop processing at the current Listener.\n       *\n       * @declaration public void PassiveListen();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        throw new IllegalArgumentException("PassiveListen() can only be used by itself");\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetAiringsThatWontBeRecorded", new String[] { "OnlyUnresolved" }, true)\n    {\n      /**\n       * Returns all of the Airings that the user has requested to record that SageTV will not be recording. This would be due to\n       * scheduling conflicts.\n       * @param OnlyUnresolved if true then only unresolved scheduling conflicts will be returned, if false then all conflicts will be returned\n       * @return the list of Airings that will not be recorded due to scheduling conflicts\n       *\n       * @declaration public java.util.Vector GetAiringsThatWontBeRecorded(boolean OnlyUnresolved);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        java.util.Map conMap = Catbert.evalBool(stack.pop()) ? SchedulerSelector.getInstance().getUnresolvedConflictsMap() :\n          SchedulerSelector.getInstance().getConflictsMap();\n        java.util.Vector rv = new java.util.Vector();\n        java.util.Iterator walker = conMap.values().iterator();\n        while (walker.hasNext())\n        {\n          rv.addAll((java.util.List) walker.next());\n        }\n        return rv;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "IsClient")\n    {\n      /**\n       * Returns true if this is an instance of SageTV Client\n       * @return true if this is an instance of SageTV Client, false otherwise\n       *\n       * @declaration public boolean IsClient();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        return Boolean.valueOf(Sage.isTrueClient());\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "IsRemoteUI")\n    {\n      /**\n       * Returns true if this UI is being remoted onto another device such as a media extender. This also returns\n       * true for Placeshifter clients.\n       * @return true if this UI is being remoted onto another device such as a media extender, false otherwise\n       *\n       * @since 4.1\n       * @declaration public boolean IsRemoteUI();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        return Boolean.valueOf(stack.getUIMgr() != null && stack.getUIMgr().getUIClientType() == UIClient.REMOTE_UI);\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "IsDesktopUI")\n    {\n      /**\n       * Returns true if this UI is being run in a desktop environment. It may or may not be remoted. This is\n       * intended to distinguish Placeshifter clients from Media Extenders since both return true for IsRemoteUI().\n       * @return true if this UI is being run in a desktop environment, false otherwise\n       *\n       * @since 4.1.10\n       * @declaration public boolean IsDesktopUI();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        if (stack.getUIMgr() == null) // if we have no UI, we\'re not a desktop\n          return Boolean.FALSE;\n        int uiType = stack.getUIMgr().getUIClientType();\n        // If we\'re a SageTVClient or a full SageTV UI instance on windows or Mac then we have a desktop\n        if ((Sage.WINDOWS_OS || Sage.MAC_OS_X) && (uiType == UIClient.LOCAL || uiType == UIClient.REMOTE_CLIENT))\n          return Boolean.TRUE;\n        // If we\'re a Remote UI with a mouse then we\'re a desktop\n        if (uiType == UIClient.REMOTE_UI)\n        {\n          if (stack.getUIMgr().getRootPanel().getRenderEngine() instanceof MiniClientSageRenderer)\n          {\n            String ipdp = ((MiniClientSageRenderer) stack.getUIMgr().getRootPanel().getRenderEngine()).getInputDevsProp();\n            if (ipdp != null && ipdp.indexOf("MOUSE") != -1)\n              return Boolean.TRUE;\n          }\n        }\n        return Boolean.FALSE; // this means we\'re a full SageTV UI running under Linux\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "IsTouchUI")\n    {\n      /**\n       * Returns true if this UI is being run in a touch environment, such as a phone or tablet.\n       * @return true if this UI is being run in a touch environment, false otherwise\n       *\n       * @since 9.0.4\n       * @declaration public boolean IsTouchUI();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        if (stack.getUIMgr() == null) // if we have no UI, we\'re not touch enabled\n          return Boolean.FALSE;\n        int uiType = stack.getUIMgr().getUIClientType();\n        // If we\'re a Remote UI with a TOUCH then we\'re a touch enabled UI\n        if (uiType == UIClient.REMOTE_UI)\n        {\n          if (stack.getUIMgr().getRootPanel().getRenderEngine() instanceof MiniClientSageRenderer)\n          {\n            String ipdp = ((MiniClientSageRenderer) stack.getUIMgr().getRootPanel().getRenderEngine()).getInputDevsProp();\n            if (ipdp != null && ipdp.indexOf("TOUCH") != -1)\n              return Boolean.TRUE;\n          }\n        }\n        return Boolean.FALSE; // Touch is not enabled on this UI\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "IsServerUI")\n    {\n      /**\n       * Returns true if this UI is being run on the same system as the SageTV Server it\'s connected to.\n       * Also returns true for standalone SageTV applications. This indicates the UI should have the ability\n       * to configure all \'server\' based options. For SageTVClient, you must be connected to the loopback address\n       * for this to return true.\n       * @return true if this is the main UI for a SageTV Server\n       * @since 5.0.5\n       *\n       * @declaration public boolean IsServerUI();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        UIManager uiMgr = stack.getUIMgr();\n        if (uiMgr == null) // if we have no UI, we\'re not a desktop\n          return Boolean.FALSE;\n        return uiMgr.isServerUI() ? Boolean.TRUE : Boolean.FALSE;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetConnectedClients", true)\n    {\n      /**\n       * Returns a list of all the clients that are currently connected to this server.\n       * @return a list of all the clients that are currently connected to this server.\n       *\n       * @declaration public String[] GetConnectedClients();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        return NetworkClient.getConnectedClients();\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetUIContextNames")\n    {\n      /**\n       * Returns a list of the names of the different UI contexts that are available. One will be the local context\n       * which is the UI for the SageTV app (which doesn\'t exist in service mode). The other contexts can be UIs that\n       * are for remote devices such as media extenders. This context name can then be passed back in using\n       * the sage.SageTV.apiUI(String uiContextName, String methodName, Object[] args) call in order to execute an API call\n       * from Java within a specific UI context.  For media extenders, these names generally correspond to the MAC address\n       * of the media extender.\n       * @return a list of the UI context names available\n       * @since 4.1\n       *\n       * @declaration public String[] GetUIContextNames();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        java.util.ArrayList rv = new java.util.ArrayList();\n        java.util.Iterator walker = UIManager.getUIIterator();\n        while (walker.hasNext())\n        {\n          UIManager foo = (UIManager) walker.next();\n          // If we\'re in service mode then don\'t put the local UI in here.\n          if (Sage.isHeadless() && Seeker.LOCAL_PROCESS_CLIENT.equals(foo.getLocalUIClientName()))\n            continue;\n          rv.add(foo.getLocalUIClientName());\n        }\n        return rv.toArray(Pooler.EMPTY_STRING_ARRAY);\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetUIContextName")\n    {\n      /**\n       * Returns the name of the UI context that makes the API call. See {@link #GetUIContextNames GetUIContextNames()}\n       * for more information.\n       * @return the UI context name that made this API call, null if there is no UI context\n       * @since 5.1\n       *\n       * @declaration public String GetUIContextName();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        UIManager uiMgr = stack.getUIMgr();\n        if (uiMgr != null)\n          return uiMgr.getLocalUIClientName();\n        else\n          return sage.Catbert.uiContextThreadNames.get();\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetRemoteClientVersion")\n    {\n      /**\n       * Returns the version string for this connected remote client\n       * @return the version string for this connected remote client, or the empty string if it\'s undefined or not a remote client\n       * @since 6.4\n       *\n       * @declaration public String GetRemoteClientVersion();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        UIManager uiMgr = stack.getUIMgr();\n        if (uiMgr != null && uiMgr.getUIClientType() == UIClient.REMOTE_UI)\n        {\n          return ((MiniClientSageRenderer) uiMgr.getRootPanel().getRenderEngine()).getRemoteVersion();\n        }\n        return "";\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetRemoteUIType")\n    {\n      /**\n       * Returns the type of client that is connected on this remote interface\n       * @return the type of client that is connected on this remote interface; this can be one of "SD Media Extender", "HD Media Extender", "HD Media Player", "Placeshifter" or "Local"\n       * @since 6.4\n       *\n       * @declaration public String GetRemoteUIType();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        UIManager uiMgr = stack.getUIMgr();\n        if (uiMgr != null && uiMgr.getUIClientType() == UIClient.REMOTE_UI)\n        {\n          MiniClientSageRenderer mcsr = (MiniClientSageRenderer) uiMgr.getRootPanel().getRenderEngine();\n          if (mcsr.isMediaExtender())\n          {\n            if (mcsr.isSupportedVideoCodec("MPEG2-VIDEO@HL"))\n              return Sage.rez(mcsr.isStandaloneMediaPlayer() ? "HD_Media_Player" : "HD_Media_Extender");\n            else\n              return Sage.rez("SD_Media_Extender");\n          }\n          else\n            return Sage.rez("Placeshifter");\n        }\n        return Sage.rez("Local");\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "CreateTimedRecording", new String[] { "Channel", "StartTime", "StopTime", "Recurrence" })\n    {\n      /**\n       * Creates a new time based recording for SageTV.\n       * @param Channel the Channel object that this recording should be performed on\n       * @param StartTime the time the recording should begin\n       * @param StopTime the time the recording should end\n       * @param Recurrence the name of the recurrence to use; this can be either Once, Daily, Weekly or Continuous (Continuous as of V6.6)\n       *               (or a localized version of one of those); OR it can be a combination of any of the following strings to indicate specified\n       *                days: Su, Mo, Tu, We, Th, Fr, Sa (for example, MoTuWe to do Mondays, Tuesdays and Wednesdays)\n       * @return true if the creation of the timed recording succeeded, otherwise a localized error string is returned\n       *\n       * @declaration public Object CreateTimedRecording(Channel Channel, long StartTime, long StopTime, String Recurrence);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        final int recurCode = ManualRecord.getRecurrenceCodeForName(getString(stack));\n        final long stop = getLong(stack);\n        final long start = getLong(stack);\n        final Channel c = getChannel(stack);\n        final Object taskID = Catbert.getNewTaskID();\n        final UIClient uiClient = Sage.client ? stack.getUIMgrSafe() : stack.getUIMgr();\n        Pooler.execute(new Runnable()\n        {\n          public void run()\n          {\n            Object rv;\n            Airing baseAir = null;\n            /* // This causes problems since you can\'t link more than one timed record to the same airing\n\t\t\t\t\tif (Sage.getBoolean("link_airing_to_timed_record", true))\n\t\t\t\t\t{\n\t\t\t\t\t\tAiring[] overlapAirs = Wizard.getInstance().getAirings(c.stationID, start, stop, false);\n\t\t\t\t\t\tif (overlapAirs != null && overlapAirs.length > 0)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tlong mostOverlap = 0;\n\t\t\t\t\t\t\tfor (int i = 0; i < overlapAirs.length; i++)\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tlong currOverlap = Math.min(stop, overlapAirs[i].getEndTime()) -\n\t\t\t\t\t\t\t\t\tMath.max(start, overlapAirs[i].getStartTime());\n\t\t\t\t\t\t\t\tif (currOverlap > mostOverlap)\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tmostOverlap = currOverlap;\n\t\t\t\t\t\t\t\t\tbaseAir = overlapAirs[i];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}*/\n            rv = Catbert.getRecordFailureObject(SeekerSelector.getInstance().timedRecord(start, stop, c.getStationID(), recurCode, baseAir, uiClient));\n            Catbert.asyncTaskComplete(taskID, rv);\n          }\n        }, "AsyncCreateTimedRecording");\n        return taskID;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "IsFullScreen")\n    {\n      /**\n       * Returns whether or not SageTV is in full screen mode\n       * @return true if SageTV is in full screen mode, false otherwise\n       *\n       * @declaration public boolean IsFullScreen();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        return Boolean.valueOf(stack.getUIMgrSafe().isFullScreen());\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "SetFullScreen", new String[] { "FullScreen" })\n    {\n      /**\n       * Sets SageTV to be in full or non-full screen mode\n       * @param FullScreen true if SageTV should be put into full screen mode, false if it should be put into windowed mode\n       *\n       * @declaration public void SetFullScreen(boolean FullScreen);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        stack.getUIMgrSafe().setFullScreen(evalBool(stack.pop()));\n        return null;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetServerAddress")\n    {\n      /**\n       * Gets the hostname of the SageTV server if this is a client, otherwise it returns the name of the host SageTV is running on\n       * @return the hostname of the SageTV server if this is a client, otherwise it returns the name of the host SageTV is running on\n       *\n       * @declaration public String GetServerAddress();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        return Sage.client ? Sage.preferredServer : SageTV.hostname;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetOS")\n    {\n      /**\n       * Gets the name of the operating system that is being used.\n       * @return the name of the operating system that is being used\n       *\n       * @declaration public String GetOS();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        return System.getProperty("os.name");\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "IsWindowsOS")\n    {\n      /**\n       * Returns true if SageTV is currently running on a Windows operating system.\n       * @return true if SageTV is currently running on a Windows operating system, false otherwise\n       *\n       * @declaration public boolean IsWindowsOS();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        return Sage.WINDOWS_OS ? Boolean.TRUE : Boolean.FALSE;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "IsLinuxOS")\n    {\n      /**\n       * Returns true if SageTV is currently running on a Linux operating system.\n       * @return true if SageTV is currently running on a Linux operating system, false otherwise\n       *\n       * @since 6.0.20\n       *\n       * @declaration public boolean IsLinuxOS();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        return Sage.LINUX_OS ? Boolean.TRUE : Boolean.FALSE;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "IsMacOS")\n    {\n      /**\n       * Returns true if SageTV is currently running on a Macintosh operating system.\n       * @return true if SageTV is currently running on a Macintosh operating system, false otherwise\n       *\n       * @since 6.0.20\n       *\n       * @declaration public boolean IsMacOS();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        return Sage.MAC_OS_X ? Boolean.TRUE : Boolean.FALSE;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "DVDBurnTheBurnList", new String[] { "BurnList" }, true)\n    {\n      /**\n       * Instructs the DVD burning engine inside SageTV to start prepping the specified Playlist to be burned to a DVD, and then perform the actual burn.\n       * NOTE: Currently this is only supported on the Linux operating system\n       * @param BurnList the Playlist of all of the video files to burn to the DVD\n       * @return true if the burn process was successfully started, otherwise a localized error message string is returned\n       *\n       * @declaration public Object DVDBurnTheBurnList(Playlist BurnList);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        Playlist p = (Playlist) stack.pop();\n        // Convert the Playlist to a list of File objects\n        MediaFile[] burnFiles = p.getMediaFiles();\n        java.util.ArrayList rawFiles = new java.util.ArrayList();\n        for (int i = 0; i < burnFiles.length; i++)\n          rawFiles.addAll(java.util.Arrays.asList(burnFiles[i].getFiles()));\n        return Burner.getGlobalBurner().burnFilesToDVD((java.io.File[]) rawFiles.toArray(new java.io.File[0]));\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "DVDCancelBurn", true)\n    {\n      /**\n       * Cancels a previous request that was made to perform DVD burning.\n       *\n       * @declaration public void DVDCancelBurn();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        Burner.getGlobalBurner().cancel();\n        return null;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "DVDGetCurrentBurnStatus", true)\n    {\n      /**\n       * Gets the current status of a previously invoked DVD burning process.\n       * @return true if the DVD burning process is completed and was a success, "Error" if it completed and was a failure,\n       *          otherwise a localized status message indicating progress is returned\n       *\n       * @declaration public Object DVDGetCurrentBurnStatus();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        if (Burner.getGlobalBurner().isComplete())\n        {\n          if (Burner.getGlobalBurner().wasSuccessful())\n            return Boolean.TRUE;\n          else\n            return "Error";\n        }\n        else\n          return Burner.getGlobalBurner().getStatusMessage();\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "CDBurnTheBurnList", new String[] { "BurnList" }, true)\n    {\n      /**\n       * Instructs the CD burning engine inside SageTV to start prepping the specified Playlist to be burned to a CD, and then perform the actual burn.\n       * NOTE: Currently this is only supported on the Linux operating system\n       * @param BurnList the Playlist of all of the music files to burn to the CD\n       * @return true if the burn process was successfully started, otherwise a localized error message string is returned\n       *\n       * @declaration public Object CDBurnTheBurnList(Playlist BurnList);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        Playlist p = (Playlist) stack.pop();\n        // Convert the Playlist to a list of File objects\n        MediaFile[] burnFiles = p.getMediaFiles();\n        return Burner.getGlobalBurner().burnFilesToCD(burnFiles);\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "CDCancelBurn", true)\n    {\n      /**\n       * Cancels a previous request that was made to perform CD burning.\n       *\n       * @declaration public void CDCancelBurn();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        Burner.getGlobalBurner().cancel();\n        return null;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "CDGetCurrentBurnStatus", true)\n    {\n      /**\n       * Gets the current status of a previously invoked CD burning process.\n       * @return true if the CD burning process is completed and was a success, "Error" if it completed and was a failure,\n       *          otherwise a localized status message indicating progress is returned\n       *\n       * @declaration public Object CDGetCurrentBurnStatus();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        if (Burner.getGlobalBurner().isComplete())\n        {\n          if (Burner.getGlobalBurner().wasSuccessful())\n            return Boolean.TRUE;\n          else\n            return "Error";\n        }\n        else\n          return Burner.getGlobalBurner().getStatusMessage();\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "CDRipToLibrary", new String[] { "LibraryDir", "BitrateKbps" }, true)\n    {\n      /**\n       * Instructs the CD ripping engine to rip the contents of a CD and encode it in MP3 format and then store it in the music library.\n       * NOTE: This is currently only supported on the Linux operating system\n       * @param LibraryDir the directory that the ripped files should be stored in, if the space on this disk is managed by SageTV it will make room for the files that are to be ripped\n       * @param BitrateKbps the bitrate to use for the audio encoding in kilobits per second\n       * @return true if the ripping process was successfully started, otherwise a localized error message string is returned\n       *\n       * @declaration public Object CDRipToLibrary(java.io.File LibraryDir, String BitrateKbps);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        String bitrate = getString(stack);\n        java.io.File folder = getFile(stack);\n        return Ripper.getGlobalRipper().ripFilesFromCD(folder, bitrate);\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "CDCancelRip", true)\n    {\n      /**\n       * Cancels a previous request that was made to perform CD ripping\n       *\n       * @declaration public void CDCancelRip();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        Ripper.getGlobalRipper().cancel();\n        return null;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "CDGetCurrentRipStatus", true)\n    {\n      /**\n       * Gets the current status of a previously invoked CD ripping process.\n       * @return true if the CD ripping process is completed and was a success, "Error" if it completed and was a failure,\n       *          otherwise a localized status message indicating progress is returned\n       *\n       * @declaration public Object CDGetCurrentRipStatus();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        if (Ripper.getGlobalRipper().isComplete())\n        {\n          if (Ripper.getGlobalRipper().wasSuccessful())\n            return Boolean.TRUE;\n          else\n            return "Error";\n        }\n        else\n          return Ripper.getGlobalRipper().getStatusMessage();\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "StartFileCopy", new String[] { "Filename", "SourceDirectory", "DestDirectory" })\n    {\n      /**\n       * Instructs the file transfer engine to copy the specified file(s) from the source directory to the destination directory.\n       * If there is no filename specified then the contents of the directory are copied recursively. If the destination directory\n       * is within the path of SageTV managed diskspace then the appropriate free space will be cleared on the disk in order for the file copy to succeed.\n       * This also works for uploading files from a SageTV client to a SageTV server.\n       * @param Filename the name of the file in the SourceDirectory to copy, or null if the whole directory should be copied\n       * @param SourceDirectory the source directory for the file copy (smb:// paths are OK)\n       * @param DestDirectory the destination directory for the file copy\n       * @return true if the copy process was successfully started, false if the file copy is unable to be performed\n       *\n       * @declaration public Object StartFileCopy(String Filename, String SourceDirectory, java.io.File DestDirectory);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        java.io.File dest = getFile(stack);\n        String src = getString(stack);\n        String filename = getString(stack);\n        if (filename != null && filename.length() > 0)\n        {\n          if (src.endsWith(java.io.File.separator))\n            src = src + filename;\n          else\n            src = src + java.io.File.separator + filename;\n        }\n        if (Sage.DBG) System.out.println("Requested file copy of " + src + " to " + dest);\n        return FileTransfer.getFileTransfer(stack.getUIMgrSafe()).transferFile(src, dest);\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "CancelFileCopy")\n    {\n      /**\n       * Cancels a previous request that was made to perform a file copy\n       *\n       * @declaration public void CancelFileCopy();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        if (Sage.DBG) System.out.println("Cancelling current file copy operation.");\n        FileTransfer.getFileTransfer(stack.getUIMgrSafe()).cancel();\n        return null;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetFileCopyStatus")\n    {\n      /**\n       * Gets the current status of a previously invoked file copy process.\n       * @return true if the file copy process is completed and was a success, "Error" will be the prefix if it was a failure,\n       *          otherwise a localized status message indicating progress is returned\n       *\n       * @declaration public Object GetFileCopyStatus();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        if (FileTransfer.getFileTransfer(stack.getUIMgrSafe()).isComplete())\n        {\n          if (FileTransfer.getFileTransfer(stack.getUIMgrSafe()).wasSuccessful())\n            return Boolean.TRUE;\n          else\n            return "Error: " + FileTransfer.getFileTransfer(stack.getUIMgrSafe()).getStatusMessage();\n        }\n        else\n          return FileTransfer.getFileTransfer(stack.getUIMgrSafe()).getStatusMessage();\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "StartFileDownload", -1, new String[] { "ServerAddress", "SourceFile", "DestFile" })\n    {\n      /**\n       * Instructs the file transfer engine to download the specified file from the server to the local destination file. You may also\n       * download from remote http:// or ftp:// addresses; in that case just specify the URL in the ServerAddress argument and leave sourceFile as null.\n       * When downloading from http or ftp addresses, the target will be the server\'s filesystem for remote clients; otherwise it is the local filesystem.\n       * When smb:// URLs are specified; they will be access from the server\'s network for remote clients, otherwise the source will be from the local network.\n       * smb:// URLs target download will be the local filesystem. Only one download process is allowed per-UI using the \'FileDownload\' API calls. If you wish\n       * to handle multiple downloads; then use the \'BackgroundFileDownload\' API calls.\n       * @param ServerAddress the address of the SageTV server to download from, or null if you\'re using SageTVClient and you want to download from the server you\'re connected to, or a valid smb, http or ftp URL\n       * @param SourceFile the file path on the server you want to download\n       * @param DestFile the destination file for the file download\n       * @return true if the copy process was successfully started, false if the file doesn\'t exist on the server or it couldn\'t be contacted\n       *\n       * @declaration public boolean StartFileDownload(String ServerAddress, String SourceFile, java.io.File DestFile);\n       */\n\n      /**\n       * Instructs the file transfer engine to download the specified file from the server to the local destination file. You may also\n       * download from remote http:// or ftp:// addresses; in that case just specify the URL in the ServerAddress argument and leave sourceFile as null.\n       * When downloading from http or ftp addresses, the target will be the server\'s filesystem for remote clients; otherwise it is the local filesystem.\n       * When smb:// URLs are specified; they will be access from the server\'s network for remote clients, otherwise the source will be from the local network.\n       * smb:// URLs target download will be the local filesystem. Only one download process is allowed per-UI using the \'FileDownload\' API calls. If you wish\n       * to handle multiple downloads; then use the \'BackgroundFileDownload\' API calls.\n       * @param ServerAddress the address of the SageTV server to download from, or null if you\'re using SageTVClient and you want to download from the server you\'re connected to, or a valid smb, http or ftp URL\n       * @param SourceFile the file path on the server you want to download\n       * @param DestFile the destination file for the file download\n       * @param RequestProperties a Properties object that specifies the request properties to use in an HTTP download request, can be null\n       * @return true if the copy process was successfully started, false if the file doesn\'t exist on the server or it couldn\'t be contacted\n       * @since 9.0\n       *\n       * @declaration public boolean StartFileDownload(String ServerAddress, String SourceFile, java.io.File DestFile, java.util.Properties RequestProperties);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        java.util.Properties props = null;\n        if (curNumberOfParameters == 4)\n          props = (java.util.Properties) stack.pop();\n        java.io.File dest = getFile(stack);\n        String src = getString(stack);\n        String serverName = getString(stack);\n        return FileDownloader.getFileDownloader(stack.getUIMgrSafe()).downloadFile(serverName, src, dest, false, props);\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "StartBackgroundFileDownload", new String[] { "ServerAddress", "SourceFile", "DestFile", "RequestProperties" })\n    {\n      /**\n       * Instructs the file transfer engine to download the specified file from the server to the local destination file. You may also\n       * download from remote http:// or ftp:// addresses; in that case just specify the URL in the ServerAddress argument and leave sourceFile as null.\n       * When downloading from http or ftp addresses, the target will be the server\'s filesystem for remote clients; otherwise it is the local filesystem.\n       * When smb:// URLs are specified; they will be access from the server\'s network for remote clients, otherwise the source will be from the local network.\n       * smb:// URLs target download will be the local filesystem. This call is different then the regular StartFileDownload API call because it allows for multiple\n       * downloads to occur at the same time. The \'key\' for the downloads are the DestFile objects.\n       * @param ServerAddress the address of the SageTV server to download from, or null if you\'re using SageTVClient and you want to download from the server you\'re connected to, or a valid smb, http or ftp URL\n       * @param SourceFile the file path on the server you want to download\n       * @param DestFile the destination file for the file download\n       * @param RequestProperties a Properties object that specifies the request properties to use in an HTTP download request, can be null\n       * @return true if the copy process was successfully started, false if the file doesn\'t exist on the server or it couldn\'t be contacted\n       * @since 7.0\n       *\n       * @declaration public boolean StartBackgroundFileDownload(String ServerAddress, String SourceFile, java.io.File DestFile, java.util.Properties RequestProperties);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        java.util.Properties props = (java.util.Properties) stack.pop();\n        java.io.File dest = getFile(stack);\n        String src = getString(stack);\n        String serverName = getString(stack);\n        return new FileDownloader(null).downloadFile(serverName, src, dest, false, props);\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "StartCircularFileDownload", -1, new String[] { "ServerAddress", "SourceFile", "DestFile" })\n    {\n      /**\n       * Instructs the file transfer engine to download the specified file from the server to the local destination file. You may also\n       * download from remote http:// or ftp:// addresses; in that case just specify the URL in the ServerAddress argument and leave sourceFile as null.\n       * When downloading from http or ftp addresses, the target will be the server\'s filesystem for remote clients; otherwise it is the local filesystem.\n       * When smb:// URLs are specified; they will be access from the server\'s network for remote clients, otherwise the source will be from the local network.\n       * smb:// URLs target download will be the local filesystem.\n       * The \'Circular\' version of this API call will write to a temporary circular file; this is designed for systems with limited storage capacity.\n       * This version of the API call may not be used by SageTVClient (if it is; then it will internally switch to the non-circular file method)\n       * @param ServerAddress the address of the SageTV server to download from, or null if you\'re using SageTVClient and you want to download from the server you\'re connected to, or a valid smb, http or ftp URL\n       * @param SourceFile the file path on the server you want to download\n       * @param DestFile the destination file for the file download\n       * @return true if the copy process was successfully started, false if the file doesn\'t exist on the server or it couldn\'t be contacted\n       * @since 6.4\n       *\n       * @declaration public boolean StartCircularFileDownload(String ServerAddress, String SourceFile, java.io.File DestFile);\n       */\n\n      /**\n       * Instructs the file transfer engine to download the specified file from the server to the local destination file. You may also\n       * download from remote http:// or ftp:// addresses; in that case just specify the URL in the ServerAddress argument and leave sourceFile as null.\n       * When downloading from http or ftp addresses, the target will be the server\'s filesystem for remote clients; otherwise it is the local filesystem.\n       * When smb:// URLs are specified; they will be access from the server\'s network for remote clients, otherwise the source will be from the local network.\n       * smb:// URLs target download will be the local filesystem.\n       * The \'Circular\' version of this API call will write to a temporary circular file; this is designed for systems with limited storage capacity.\n       * This version of the API call may not be used by SageTVClient (if it is; then it will internally switch to the non-circular file method)\n       * @param ServerAddress the address of the SageTV server to download from, or null if you\'re using SageTVClient and you want to download from the server you\'re connected to, or a valid smb, http or ftp URL\n       * @param SourceFile the file path on the server you want to download\n       * @param DestFile the destination file for the file download\n       * @param RequestProperties a Properties object that specifies the request properties to use in an HTTP download request, can be null\n       * @return true if the copy process was successfully started, false if the file doesn\'t exist on the server or it couldn\'t be contacted\n       * @since 9.0\n       *\n       * @declaration public boolean StartCircularFileDownload(String ServerAddress, String SourceFile, java.io.File DestFile, java.util.Properties RequestProperties);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        java.util.Properties props = null;\n        if (curNumberOfParameters == 4)\n          props = (java.util.Properties) stack.pop();\n        java.io.File dest = getFile(stack);\n        String src = getString(stack);\n        String serverName = getString(stack);\n        return FileDownloader.getFileDownloader(stack.getUIMgrSafe()).downloadFile(serverName, src, dest, true, props);\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "CancelFileDownload")\n    {\n      /**\n       * Cancels a previous request that was made to perform a file download\n       *\n       * @declaration public void CancelFileDownload();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        if (Sage.DBG) System.out.println("Cancelling current file download operation.");\n        FileDownloader.getFileDownloader(stack.getUIMgrSafe()).cancel();\n        return null;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "CancelBackgroundFileDownload", new String[] { "DestFile" })\n    {\n      /**\n       * Cancels a previous request that was made to perform a background file download.\n       * @param DestFile the destination file specified in the original download request\n       * @since 7.0\n       *\n       * @declaration public void CancelBackgroundFileDownload(java.io.File DestFile);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        java.io.File dFile = getFile(stack);\n        if (Sage.DBG) System.out.println("Cancelling current file download operation for:" + dFile);\n        FileDownloader downer = FileDownloader.getFileDownloader(dFile);\n        if (downer != null)\n          downer.cancel();\n        return null;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetFileDownloadStatus")\n    {\n      /**\n       * Gets the current status of a previously invoked file download process.\n       * @return true if the file download process is completed and was a success, "Error" will be the prefix if it was a failure,\n       *          otherwise a localized status message indicating progress is returned\n       *\n       * @declaration public Object GetFileDownloadStatus();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        if (FileDownloader.getFileDownloader(stack.getUIMgrSafe()).isComplete())\n        {\n          if (FileDownloader.getFileDownloader(stack.getUIMgrSafe()).wasSuccessful())\n            return Boolean.TRUE;\n          else\n            return "Error: " + FileDownloader.getFileDownloader(stack.getUIMgrSafe()).getStatusMessage();\n        }\n        else\n          return FileDownloader.getFileDownloader(stack.getUIMgrSafe()).getStatusMessage();\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetBackgroundFileDownloadStatus", new String[] { "DestFile" })\n    {\n      /**\n       * Gets the current status of a previously invoked file background download process.\n       * @param DestFile the destination file specified in the original download request\n       * @return true if the file download process is completed and was a success, "Error" will be the prefix if it was a failure,\n       *          otherwise a localized status message indicating progress is returned\n       * @since 7.0\n       *\n       * @declaration public Object GetBackgroundFileDownloadStatus(java.io.File DestFile);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        java.io.File dFile = getFile(stack);\n        FileDownloader downer = FileDownloader.getFileDownloader(dFile);\n        if (downer != null)\n        {\n          if (downer.isComplete())\n          {\n            if (downer.wasSuccessful())\n              return Boolean.TRUE;\n            else\n              return "Error: " + downer.getStatusMessage();\n          }\n          else\n            return downer.getStatusMessage();\n        }\n        else\n        {\n          Object rv = FileDownloader.getBGDownloadResult(dFile);\n          if (rv == null)\n            return Sage.rez("Error: Invalid Download Target Specified");\n          else\n            return rv;\n        }\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetFileDownloadStreamTime")\n    {\n      /**\n       * Gets the current stream time of a previously invoked file download process. This is only valid\n       * for when the file being downloaded is an FLV, MP3, MP4 or Quicktime file\n       * @return the stream time in milliseconds of the current download; or zero if it doesn\'t know\n       * @since 6.3\n       *\n       * @declaration public long GetFileDownloadStreamTime();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        return new Long(FileDownloader.getFileDownloader(stack.getUIMgrSafe()).getLastDownloadTimestamp());\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "IsFileDownloadProgressivePlay")\n    {\n      /**\n       * Returns whether or not the current file being downloaded can be played back while being downloaded. This is only valid\n       * for when the file being downloaded is an FLV, MP3, MP4 or Quicktime file. It will always be true for MP3 &amp; FLV files;\n       * and for MP4/Quicktime files it\'ll be true if the sample section is before the movie data in the file. If this is true\n       * and the download stream time is greater than zero; then it\'s OK to start progressive playback of downloaded media.\n       * @return true if the current file being downloaded can potentially be played back while being downloaded, false if it definitely cannot be\n       * @since 6.3\n       *\n       * @declaration public boolean IsFileDownloadProgressivePlay();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        return Boolean.valueOf(FileDownloader.getFileDownloader(stack.getUIMgrSafe()).isProgressivePlay());\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetBackgroundFileDownloadStreamTime", new String[] { "DestFile" })\n    {\n      /**\n       * Gets the current stream time of a previously invoked file download process. This is only valid\n       * for when the file being downloaded is an FLV, MP3, MP4 or Quicktime file\n       * @param DestFile the destination file specified in the original download request\n       * @return the stream time in milliseconds of the current download; or zero if it doesn\'t know or the download is completed\n       * @since 7.0\n       *\n       * @declaration public long GetBackgroundFileDownloadStreamTime(java.io.File DestFile);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        java.io.File dFile = getFile(stack);\n        FileDownloader downer = FileDownloader.getFileDownloader(dFile);\n        if (downer != null)\n          return new Long(downer.getLastDownloadTimestamp());\n        else\n          return new Long(0);\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "IsBackgroundFileDownloadProgressivePlay", new String[] { "DestFile" })\n    {\n      /**\n       * Returns whether or not the current file being downloaded can be played back while being downloaded. This is only valid\n       * for when the file being downloaded is an FLV, MP3, MP4 or Quicktime file. It will always be true for MP3 &amp; FLV files;\n       * and for MP4/Quicktime files it\'ll be true if the sample section is before the movie data in the file. If this is true\n       * and the download stream time is greater than zero; then it\'s OK to start progressive playback of downloaded media.\n       * @param DestFile the destination file specified in the original download request\n       * @return true if the current file being downloaded can potentially be played back while being downloaded, false if it definitely cannot be or is an invalid or completed download\n       * @since 7.0\n       *\n       * @declaration public boolean IsBackgroundFileDownloadProgressivePlay(java.io.File DestFile);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        java.io.File dFile = getFile(stack);\n        FileDownloader downer = FileDownloader.getFileDownloader(dFile);\n        if (downer != null)\n          return Boolean.valueOf(downer.isProgressivePlay());\n        else\n          return Boolean.FALSE;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetBackgroundFileDownloadTotalSize", new String[] { "DestFile" })\n    {\n      /**\n       * Gets the total size of the specified background download target. This may not always be known in cases\n       * where the server does not indicate the specific length of the file.\n       * @param DestFile the destination file specified in the original download request\n       * @return the size in bytes of the remote file being downloaded; zero if the download specified is complete or invalid\n       * @since 7.0\n       *\n       * @declaration public long GetBackgroundFileDownloadTotalSize(java.io.File DestFile);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        java.io.File dFile = getFile(stack);\n        FileDownloader downer = FileDownloader.getFileDownloader(dFile);\n        if (downer != null)\n          return new Long(downer.getRemoteSize());\n        else\n          return new Long(0);\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "SetRemoteEventEncryptionEnabled", new String[] { "EnableEncryption" })\n    {\n      /**\n       * This is used to enable/disable encryption on the event channel for the SageTV MiniClient. The MiniClient is used\n       * for the media extenders and for placeshifting. When using a non-local MiniClient connection, or if local MiniClient\n       * connections are configured to require authentication; the event channel between the two will start off in an encrypted\n       * mode so that a password can be exchanged.  This API call can then be used with a false argument to disable encryption\n       * of the event channel in order to increase performance. It can also be used to re-enable encryption at a later time if\n       * sensitive information is going to be transmitted again.\n       *\n       * @param EnableEncryption true if the MiniClient event channel should start encrypting events, false if it should stop\n       * @return true if the MiniClient supports encryption and the operation should succeed, the connection will terminate if it fails\n       * @since 4.1.7\n       *\n       * @declaration public boolean SetRemoteEventEncryptionEnabled(boolean EnableEncryption);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        boolean b = Catbert.evalBool(stack.pop());\n        if (stack.getUIMgr() != null && stack.getUIMgr().getUIClientType() == UIClient.REMOTE_UI &&\n            stack.getUIMgr().getRootPanel().getRenderEngine() instanceof MiniClientSageRenderer)\n        {\n          Object rv = new Boolean(((MiniClientSageRenderer)stack.getUIMgr().getRootPanel().getRenderEngine()).setEventEncryption(b));\n          // Force a UI refresh so that the event gets sent to the client\n          // Fixes a bug where local FS operations would hang if encryption was on; but even if you turned it off it\n          // might still be on because a UI update had not been sent yet. So this refresh fixes that.\n          PseudoMenu currUI = stack.getUIMgrSafe().getCurrUI();\n          if (currUI != null) currUI.refresh();\n          return rv;\n        }\n        return Boolean.FALSE;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "CachePlaceshifterLogin")\n    {\n      /**\n       * This is used to store an authentication block on the current client that it can use in the future to automatically\n       * connect to this server w/out having to login. The channel must be encrypted when this call is made. See the API call\n       * SetRemoteEventEncryptionEnabled for more details on that.\n       *\n       * @since 6.6\n       *\n       * @declaration public void CachePlaceshifterLogin();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        if (stack.getUIMgr() != null && stack.getUIMgr().getUIClientType() == UIClient.REMOTE_UI &&\n            stack.getUIMgr().getRootPanel().getRenderEngine() instanceof MiniClientSageRenderer)\n        {\n          ((MiniClientSageRenderer)stack.getUIMgr().getRootPanel().getRenderEngine()).cacheAuthenticationNow();\n        }\n        return null;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "CanCachePlaceshifterLogin")\n    {\n      /**\n       * This indicates whether the server and the client both support caching of placeshifter logins.\n       * @return true if both the server and client support caching of placeshifter login information\n       * @since 6.6\n       *\n       * @declaration public boolean CanCachePlaceshifterLogin();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        if (stack.getUIMgr() != null && stack.getUIMgr().getUIClientType() == UIClient.REMOTE_UI &&\n            stack.getUIMgr().getRootPanel().getRenderEngine() instanceof MiniClientSageRenderer)\n        {\n          return Boolean.valueOf(((MiniClientSageRenderer)stack.getUIMgr().getRootPanel().getRenderEngine()).canCacheAuthentication());\n        }\n        return Boolean.FALSE;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "ReloadSystemHooks")\n    {\n      /**\n       * This is a Windows only API call which tells SageTV to unload and then reload any system hooks it has installed.\n       * This allows reconfiguration of parameters in the UI and then realization of those changes on the fly.\n       *\n       * @since 4.1.13\n       *\n       * @declaration public void ReloadSystemHooks();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        UIManager ui = stack.getUIMgr();\n        if (ui != null)\n          ui.reloadSystemHooks();\n        return null;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "UpdateLocatorServer")\n    {\n      /**\n       * This API call can be used to tell SageTV to do an update with the Locator server right now.\n       * It\'s useful for when you change external network configuration stuff like ports or IPs.\n       *\n       * @since 4.1.13\n       *\n       * @declaration public void UpdateLocatorServer();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        SageTV.forceLocatorUpdate();\n        return null;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetFullUIWidth")\n    {\n      /**\n       * Returns the width in pixels of the user interface for the calling SageTV UI context.\n       * @return the width in pixels of the user interface for the calling SageTV UI context\n       *\n       * @since 5.1\n       *\n       * @declaration public int GetFullUIWidth();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        UIManager uiMgr = stack.getUIMgr();\n        if (uiMgr == null)\n          return new Integer(0);\n        else\n          return new Integer(uiMgr.getRootPanel().getWidth());\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetFullUIHeight")\n    {\n      /**\n       * Returns the height in pixels of the user interface for the calling SageTV UI context.\n       * @return the height in pixels of the user interface for the calling SageTV UI context\n       *\n       * @since 5.1\n       *\n       * @declaration public int GetFullUIHeight();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        UIManager uiMgr = stack.getUIMgr();\n        if (uiMgr == null)\n          return new Integer(0);\n        else\n          return new Integer(uiMgr.getRootPanel().getHeight());\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetDisplayResolutionWidth")\n    {\n      /**\n       * Returns the width in pixels of the current display resolution set\n       * @return the width in pixels of the current display resolution set\n       *\n       * @since 5.1\n       *\n       * @declaration public int GetDisplayResolutionWidth();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        UIManager uiMgr = stack.getUIMgr();\n        if (uiMgr == null)\n          return new Integer(0);\n        else\n        {\n          java.awt.Dimension d = uiMgr.getUIDisplayResolution();\n          return (d == null) ? new Integer(720) : new Integer(d.width);\n        }\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetDisplayResolutionHeight")\n    {\n      /**\n       * Returns the height in pixels of the current display resolution set\n       * @return the height in pixels of the current display resolution set\n       *\n       * @since 5.1\n       *\n       * @declaration public int GetDisplayResolutionHeight();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        UIManager uiMgr = stack.getUIMgr();\n        if (uiMgr == null)\n          return new Integer(0);\n        else\n        {\n          java.awt.Dimension d = uiMgr.getUIDisplayResolution();\n          return (d == null) ? new Integer(480) : new Integer(d.height);\n        }\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetDisplayResolution")\n    {\n      /**\n       * Returns a string describing the current display resolution set\n       * @return a string describing the current display resolution set\n       *\n       * @since 6.3\n       *\n       * @declaration public String GetDisplayResolution();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        UIManager uiMgr = stack.getUIMgr();\n        if (uiMgr == null)\n          return "";\n        else\n        {\n          sage.media.format.VideoFormat d = uiMgr.getDisplayResolution();\n          return (d == null) ? "" : d.getFormatName();\n        }\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetDisplayResolutionOptions")\n    {\n      /**\n       * Returns a list of the possible display resolutions. This is currently only used\n       * on media extender devices that have adjustable output resolution\n       * @return an array of the display resolution names that can be used, null if this change is not supported\n       *\n       * @since 6.0\n       *\n       * @declaration public String[] GetDisplayResolutionOptions();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        if (stack.getUIMgr() != null && stack.getUIMgr().getUIClientType() == UIClient.REMOTE_UI &&\n            stack.getUIMgr().getRootPanel().getRenderEngine() instanceof MiniClientSageRenderer)\n        {\n          return ((MiniClientSageRenderer)stack.getUIMgr().getRootPanel().getRenderEngine()).getResolutionOptions();\n        }\n        return null;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetDisplayResolutionDetails", new String[] { "Resolution" })\n    {\n      /**\n       * Returns the detailed format description for the specific resolution returned from GetDisplayResolutionOptions()\n       * NOTE: This API call is only valid on embedded platforms.\n       * @param Resolution the resolution to get the details for\n       * @return a the detailed format description for a specific Resolution\n       *\n       * @since 6.4\n       *\n       * @declaration public String GetDisplayResolutionDetails(String Resolution);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        getString(stack);\n        return null;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetPreferredDisplayResolutions")\n    {\n      /**\n       * Returns a list of the preferred display resolutions. This is currently only used\n       * on media extender devices that have adjustable output resolution. This information is obtained from the HDMI/DVI connector\n       * @return a list of the preferred display resolutions\n       *\n       * @since 6.3\n       *\n       * @declaration public String[] GetPreferredDisplayResolutions();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        if (stack.getUIMgr() != null && stack.getUIMgr().getUIClientType() == UIClient.REMOTE_UI &&\n            stack.getUIMgr().getRootPanel().getRenderEngine() instanceof MiniClientSageRenderer)\n        {\n          return ((MiniClientSageRenderer)stack.getUIMgr().getRootPanel().getRenderEngine()).getPreferredResolutionOptions();\n        }\n        return null;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "SetDisplayResolution", new String[] { "Resolution" })\n    {\n      /**\n       * Sets the current output display resolution. This is currently only used\n       * on media extender devices that have adjustable output resolution.\n       * @param Resolution this must be a value from {@link #GetDisplayResolutionOptions GetDisplayResolutionOptions()} and should be the new desired output resolution\n       *\n       * @since 6.0\n       *\n       * @declaration public void SetDisplayResolution(String Resolution);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        String newRes = getString(stack);\n        if (stack.getUIMgr() != null && stack.getUIMgr().getUIClientType() == UIClient.REMOTE_UI &&\n            stack.getUIMgr().getRootPanel().getRenderEngine() instanceof MiniClientSageRenderer)\n        {\n          ((MiniClientSageRenderer)stack.getUIMgr().getRootPanel().getRenderEngine()).pushResolutionChange(newRes);\n        }\n        return null;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "DiscoverSageTVServers", new String[] { "Timeout" })\n    {\n      /**\n       * Returns a list of the SageTV servers on the network. Each item will be "name;IP address"\n       * @param Timeout the timeout for the discovery process in milliseconds\n       * @return an array of the SageTV servers on the network. Each item will be "name;IP address"\n       *\n       * @since 6.3\n       *\n       * @declaration public String[] DiscoverSageTVServers(long Timeout);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        long timeout = getLong(stack);\n        java.util.ArrayList servers = new java.util.ArrayList();\n        if (Sage.DBG) System.out.println("Sending out discovery packets to find SageTVPlaceshifter/Extender Servers...");\n        java.net.DatagramSocket sock = null;\n        try\n        {\n          // Try on the encoder discovery port which is less likely to be in use\n          try\n          {\n            sock = new java.net.DatagramSocket(8271);\n          }\n          catch (java.net.BindException be2)\n          {\n            // Just create it wherever\n            sock = new java.net.DatagramSocket();\n          }\n          java.net.DatagramPacket pack = new java.net.DatagramPacket(new byte[512], 512);\n          byte[] data = pack.getData();\n          data[0] = \'S\';\n          data[1] = \'T\';\n          data[2] = \'V\';\n          data[3] = 1;\n          pack.setLength(32);\n          sock.setBroadcast(true);\n          // Find the broadcast address for this subnet.\n          pack.setAddress(java.net.InetAddress.getByName("255.255.255.255"));\n          pack.setPort(31100);\n          sock.send(pack);\n          long startTime = System.currentTimeMillis();\n          do\n          {\n            int currTimeout = (int)Math.max(1, (startTime + timeout) - System.currentTimeMillis());\n            sock.setSoTimeout(currTimeout);\n            sock.receive(pack);\n            if (pack.getLength() >= 4)\n            {\n              if (Sage.DBG) System.out.println("Discovery packet received:" + pack);\n              if (data[0] == \'S\' && data[1] == \'T\' && data[2] == \'V\' && data[3] == 2)\n              {\n                // Make sure it\'s not us\n                String had = pack.getAddress().getHostAddress();\n                if (!IOUtils.isLocalhostAddress(pack.getAddress()))\n                {\n                  StringBuffer si = new StringBuffer();\n                  String theName = pack.getAddress().getHostName();\n\n                  si.append(theName == null ? had : theName);\n                  si.append(";");\n                  si.append(had);\n                  if (data[3] == 3)\n                  {\n                    // This is an embedded server so we would use the FAT client mode here\n                    si.append(":" + SageTV.DEFAULT_SAGETV_PORT);\n                  }\n                  //if (pack.getLength() >= 15) // it also has the port in it\n                  {\n                    //\tsi.port = ((data[13] & 0xFF) << 8) | (data[14] & 0xFF);\n                  }\n                  if (Sage.DBG) System.out.println("Added server info:" + si);\n                  servers.add(si.toString());\n                }\n              }\n            }\n          } while (true);//(startTime + timeout > System.currentTimeMillis());\n        }\n        catch (Exception e)\n        {\n          //System.out.println("Error discovering servers:" + e);\n        }\n        finally\n        {\n          if (sock != null)\n          {\n            try\n            {\n              sock.close();\n            }catch (Exception e){}\n            sock = null;\n          }\n        }\n        return servers.toArray(Pooler.EMPTY_STRING_ARRAY);\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "IsEmbeddedSystem")\n    {\n      /**\n       * Returns true if running on an \'embedded\' platform. This will be true for the standalone environment on products like the HD300\n       * and false otherwise. Used for making STVs that have different options based on whether they\'re on a PC vs. embedded system.\n       * @return true if running on an embedded system, false otherwise\n       * @since 7.0\n       *\n       * @declaration public boolean IsEmbeddedSystem();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception\n      {\n        return Boolean.FALSE;\n      }\n    });\n    rft.put(new PredefinedJEPFunction("Global", "IsEmbeddedServer", true)\n    {\n      /**\n       * Returns true if running on an \'embedded\' platform in standalone mode or running as a SageTV Client that is connected to a server running on an embedded platform.\n       * This will be true for the standalone environment on products like the HD300\n       * and false otherwise. Used for making STVs that have different options based on whether they\'re on a PC vs. embedded system.\n       * @return true if running against an embedded server, false otherwise\n       * @since 7.1\n       *\n       * @declaration public boolean IsEmbeddedServer();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception\n      {\n        return Boolean.FALSE;\n      }\n    });\n    rft.put(new PredefinedJEPFunction("Global", "IsPVR", true)\n    {\n      boolean forcedPVRMode = SageConstants.PVR;\n      {\n        String res = Sage.get("forced_pvr_mode", null);\n        if (res != null)\n          forcedPVRMode = "true".equalsIgnoreCase(res);\n      }\n      /**\n       * Returns true if running on a system or connected to a server that has PVR functionality. Used for making STVs that have different options based on whether\n       * or not PVR functionality is available. Even if no capture devices are configured and the system is PVR capable, this will still return true.\n       * @return true if PVR is available, false otherwise\n       * @since 7.1\n       *\n       * @declaration public boolean IsPVR();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception\n      {\n        return forcedPVRMode ? Boolean.TRUE : Boolean.FALSE;\n      }\n    });\n    rft.put(new PredefinedJEPFunction("Global", "GetHotplugStorageMap")\n    {\n      /**\n       * Returns a map of name-&gt;file for any hotplug storage devies on the system. The\n       * names are user-presentable and the path is the java.io.File root which corresponds to the root of that device.\n       * NOTE: This is only valid on embedded platforms.\n       * @return a Map of name-&gt;file for hotplugged storage devices\n       *\n       * @since 6.4\n       *\n       * @declaration public java.util.Map GetHotplugStorageMap();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        return NewStorageDeviceDetector.getInstance().getDeviceMap();\n      }\n    });\n    rft.put(new PredefinedJEPFunction("Global", "IsDoingLibraryImportScan", true)\n    {\n      /**\n       * Returns true if the server is currently scanning the import directories for new files\n       * @return true if the server is currently scanning the import directories for new files\n       *\n       * @since 6.6\n       *\n       * @declaration public boolean IsDoingLibraryImportScan();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        return SeekerSelector.getInstance().isDoingImportScan() ? Boolean.TRUE : Boolean.FALSE;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "SwitchEmbeddedModeTo", new String[] { "NewMode" })\n    {\n      /**\n       * Executes a predefined application in the context of an embedded client. This is used for launching things\n       * like Netflix, YouTube Leanback and also specifying alternate modes the embedded client can exit into.\n       * @param NewMode the name of the application\n       *\n       * @since 8.0\n       *\n       * @declaration public void SwitchEmbeddedModeTo(String NewMode);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        String newMode = getString(stack);\n        if (stack.getUIMgr() != null && stack.getUIMgr().getUIClientType() == UIClient.REMOTE_UI &&\n            stack.getUIMgr().getRootPanel().getRenderEngine() instanceof MiniClientSageRenderer)\n        {\n          if ("netflix".equals(newMode))\n          {\n            // Specify that we launched Netflix from a list of Apps since that\'s how we do it in the UI\n            newMode = "netflix --ui-query-string=source_type=2";\n          }\n          else if (newMode.startsWith("youtube"))\n          {\n            if (!Sage.getBoolean("enable_youtube_leanback", false))\n            {\n              if (Sage.DBG) System.out.println("ERROR: Requested to launch youtube, but it is disabled!");\n              return null;\n            }\n            if (Sage.DBG) System.out.println("Testing YouTube connectivity before launching app...");\n            try\n            {\n              java.net.InetSocketAddress sa = new java.net.InetSocketAddress("www.youtube.com", 80);\n              java.net.Socket ytTest = new java.net.Socket();\n              ytTest.connect(sa, 10000);\n              if (Sage.DBG) System.out.println("Connection succeeded!");\n              ytTest.close();\n            }\n            catch (Exception e)\n            {\n              // Display an error in the UI about this\n              Catbert.processUISpecificHook("MediaPlayerError", new Object[] { Sage.rez("GENERAL_ERROR_TITLE"), Sage.rez("YT_CONNECTION_ERROR") },\n                  stack.getUIMgr(), true);\n              return null;\n            }\n          }\n          ((MiniClientSageRenderer)stack.getUIMgr().getRootPanel().getRenderEngine()).switchAppMode(newMode);\n        }\n        return null;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "PrepareForFirmwareLoad", true)\n    {\n      /**\n       * Prepares the device for a firmware download &amp; flash. This internally will stop the library importing process,\n       * empty all of the database tables, clear the UI caches, and then force a complete garbage collection.\n       * NOTE: This is only valid on embedded platforms.\n       *\n       * @since 7.0\n       *\n       * @declaration public void PrepareForFirmwareLoad();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        return null;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "AreScreenshotsSupported")\n    {\n      /**\n       * Returns true if it\'s possible to take screenshots of the UI using the API on this UI client\n       * @return true if it\'s possible to take screenshots of the UI using the API on this UI client\n       * @since 8.0\n       *\n       * @declaration public boolean AreScreenshotsSupported();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        UIManager uiMgr = stack.getUIMgr();\n        if (uiMgr != null && uiMgr.getUIClientType() == UIClient.REMOTE_UI)\n        {\n          return ((MiniClientSageRenderer) uiMgr.getRootPanel().getRenderEngine()).supportsScreenshots() ? Boolean.TRUE : Boolean.FALSE;\n        }\n        return Boolean.FALSE;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "SaveScreenshotToFile", new String[] { "FilePath" })\n    {\n      /**\n       * Takes a screenshot of the current UI and saves it to the specified file in PNG format. This is only supported\n       * on clients that return true to the API call {@link #AreScreenshotsSupported AreScreenshotsSupported()}.\n       * @param FilePath the file path to save the screenshot to (should have a .png file extension)\n       * @return true if the screenshot was successfully saved to the specified file, false otherwise\n       * @since 8.0\n       *\n       * @declaration public boolean SaveScreenshotToFile(java.io.File FilePath);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        UIManager uiMgr = stack.getUIMgr();\n        java.io.File f = getFile(stack);\n        if (uiMgr != null && uiMgr.getUIClientType() == UIClient.REMOTE_UI)\n        {\n          return ((MiniClientSageRenderer) uiMgr.getRootPanel().getRenderEngine()).saveScreenshotToFile(f) ? Boolean.TRUE : Boolean.FALSE;\n        }\n        return Boolean.FALSE;\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "GetEmbeddedPanel")\n    {\n      /**\n       * Gets a java.awt.Panel which can be used for embedding Java UI elements directly into SageTV\n       * @return a java.awt.Panel object which can be sized, made visible and have children added to it\n       *\n       * @declaration public java.awt.Panel GetEmbeddedPanel();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception\n      {\n        return stack.getUIMgrSafe().getEmbeddedPanel();\n      }\n    });\n    rft.put(new PredefinedJEPFunction("Global", "SetEmbeddedPanelBounds", new String[] { "x", "y", "width", "height"})\n    {\n      /**\n       * Sets the bounding region to be used for the embedded panel. These are floating point numbers relative to the total size of the UI.\n       * @param x the relative X position (0.0-1.0)\n       * @param y the relative Y position (0.0-1.0)\n       * @param width the relative width (0.0-1.0)\n       * @param height the relative height (0.0-1.0)\n       * @since 6.4\n       *\n       * @declaration public void SetEmbeddedPanelBounds(float x, float y, float width, float height);\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception\n      {\n        float h = getFloat(stack);\n        float w = getFloat(stack);\n        float y = getFloat(stack);\n        float x = getFloat(stack);\n        stack.getUIMgrSafe().setEmbeddedBounds(x, y, w, h);\n        return null;\n      }\n    });\n    rft.put(new PredefinedJEPFunction("Global", "IsClientDisconnected")\n    {\n      /**\n       * Returns true if this is an instance of SageTVClient (or a remote client connected via SageTVClient)\n       * and there is currently not a connection to the server. This should be used during startup to go to the\n       * server connection lost menu for remote clients connected through SageTVClient (SageTVClient itself will do it automatically).\n       * @return true if the SageTVClient connection is currently disconnected\n       * @since 8.0\n       *\n       * @declaration public boolean IsClientDisconnected();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception\n      {\n        if (!Sage.client || SageTV.neddy == null)\n          return Boolean.FALSE;\n        return SageTV.neddy.isClientConnected() ? Boolean.FALSE : Boolean.TRUE;\n      }\n    });\n    rft.put(new PredefinedJEPFunction("Global", "GetClientServerConnectionProgress")\n    {\n      /**\n       * Returns a string describing the state of the client/server connection process.\n       * NOTE: This is only useful on embedded with a fat client setup.\n       * @return a string describing the state of the client/server connection process, null if this cannot be determined properly\n       * @since 8.0\n       *\n       * @declaration public String GetClientServerConnectionProgress();\n       */\n\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        return null;\n      }});\n\n    /**\n     * Returns a string describing the state of the epg system.\n     * @return a string describing the Epg state one of: [Idle, Maintenance, Updating]\n     * @since 8.1\n     *\n     * @declaration public String GetEPGUpdateState();\n     */\n\n    rft.put(new PredefinedJEPFunction("Global", "GetEPGUpdateState", true) {\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        return EPG.getInstance().getEpgStateString();\n      }});\n    rft.put(new PredefinedJEPFunction("Global", "IsSDEPGServiceAvailable", true)\n    {\n      /**\n       * Returns true if the Schedules Direct EPG service is available.\n       * This is determined by trying to communicate with Schedules Direct if an unexpired token is\n       * present. If no token currently exists or it is expired, a new token will be acquired. If\n       * the token is unable to be obtained for any reason, the service is considered unavailable.\n       * @return true if the Schedules Direct EPG service is configured and able to authenticate, false otherwise\n       * @since 9.0\n       *\n       * @declaration public boolean IsSDEPGServiceAvailable();\n       */\n      public Object runSafely(Catbert.FastStack stack) throws Exception{\n        return sage.epg.sd.SDRipper.isAvailable();\n      }});\n    /*\n\t\trft.put(new PredefinedJEPFunction("Global", "", -1)\n\t\t{public Object runSafely(Catbert.FastStack stack) throws Exception{\n\n\t\t\t}});\n     */\n  }\n}\n', 'message': 'Merge pull request #331 from stuckless/sageconstants_refactor\n\nRemoved PVR flag', 'author_name': 'GitHub', 'lang': 'java'}