SageTV Community  

Go Back   SageTV Community > SageTV Development and Customizations > SageTV Studio
Forum Rules FAQs Community Downloads Today's Posts Search

Notices

SageTV Studio Discussion related to the SageTV Studio application produced by SageTV. Questions, issues, problems, suggestions, etc. relating to the Studio software application should be posted here.

Reply
 
Thread Tools Search this Thread Display Modes
  #161  
Old 02-09-2009, 10:14 PM
Opus4's Avatar
Opus4 Opus4 is offline
Administrator
 
Join Date: Sep 2003
Location: NJ
Posts: 19,624
The API docs have been updated & RemoveFavorite() is now listed. Also, the Studio Information Resources topic now has a link to a downloadable copy of the API docs.

- Andy
__________________
SageTV Open Source v9 is available.
- Read the SageTV FAQ. Older PDF User's Guides mostly still apply: SageTV V7.0 & SageTV Studio v7.1.
- Hauppauge remote help: 1) Basics/Extending it 2) Replace it 3) Use it w/o needing focus
- HD Extenders: A) FAQs B) URC MX-700 remote setup
Note: This is a users' forum; see the Rules. For official tech support fill out a Support Request.
Reply With Quote
  #162  
Old 02-20-2009, 06:32 PM
Ikarius's Avatar
Ikarius Ikarius is offline
Sage Advanced User
 
Join Date: Aug 2008
Posts: 84
Studio tools on OSX?

Hey there, I was hoping to get sage development working (fully- which to me means gkusnick's killer tools) on OSX. Unfortunately, it does not appear to be working.

What I know: When I add the class to the startup in the SageClient.properties file, when I launch studio, it immediately pops open the context menu, as if I right-clicked on something, and if I click elsewhere in studio/do anything else, it pops the context menu right back up, making Studio unusable. No evidence of the Plugins menu, either.

What I suspect: Apple has only shipped a 64-bit version of 1.6 java for OSX. Indications are that they won't be shipping a 32-bit version of 1.6. Thus, on OSX we're stuck with 1.5 unless Sage reworks their stuff to work in a 64-bit JVM. I'm guessing that GKusnick's stuff is dependent on or compiled with Java 1.6, and thus won't work with 1.5. Either that, or we're facing a platform dependency in the studio tools or a bug in the 1.5 JVM.

Does anyone who knows enough have a rig they can test this with? I'd love to go mobile with my development.

It's not a huge showstopper for me, as I can develop on my Macbook and ship my STV over to my PC to export STVis, but there's a lot of convenience lost with the tools not working on my macbook.

Cheers
Ikarius
__________________

SageTV 6.6.2, SageMC+CenterSage Theme
Server: Intel Core2 Q6600, 8gb memory, 3x 1tb WD EACS drives, software RAID5 2tb capacity, 4gb Flash boot drive, Ubuntu 8.0.4 Server edition
Capture: 1x HD-PVR -> Motorola DTC6200
Clients: 1x STX-HD100 1x STX-HD200, Windows & OSX Clients
Reply With Quote
  #163  
Old 02-20-2009, 08:57 PM
GKusnick's Avatar
GKusnick GKusnick is offline
SageTVaholic
 
Join Date: Dec 2005
Posts: 5,083
I use Java 1.6 to build the tools in 1.5 compatibility mode, compiling against the 1.5 JDK. So that shouldn't be an issue.

The popup menu thing is due to a hack in my init code, which needs to simulate a right-click in order to locate the context menu to inject plugin commands into it. There was an issue once before (in Windows) with getting stuck in permanent popup mode due to window size issues; see this post for more info.

I'm not a Mac guy and don't have a way of testing this myself, but here's what I'd suggest: remove gkusnick.sagetv.studio.Inject from your startup classes, start Sage, open the Studio window and resize it to some large size, close the Studio window, quit Sage, and put the Inject class back into your startup classes.

If that doesn't fix it, then something more subtle may be going on, which unfortunately I'm not equipped to diagnose. Full source for the tools is included in the distribution package, so you can in principle do the debugging yourself, if you're up for that challenge. I'll be happy to talk you through it as best I can and incorporate any fixes you come up with back into the mainline dev source.
__________________
-- Greg
Reply With Quote
  #164  
Old 02-20-2009, 09:13 PM
Ikarius's Avatar
Ikarius Ikarius is offline
Sage Advanced User
 
Join Date: Aug 2008
Posts: 84
Thank you for the pointer, it explains a bit of what's going on, but unfortunately it appears to be "something more subtle". I'll read through what debug information you requested from that last user and see if I can discern anything more useful for you, but neither resizing the studio window prior to the launch, nor maximizing it cured the problem.

I'm heading out of town momentarily, so I'll have to take another look at this sometime next week.

Cheers
Ikarius
__________________

SageTV 6.6.2, SageMC+CenterSage Theme
Server: Intel Core2 Q6600, 8gb memory, 3x 1tb WD EACS drives, software RAID5 2tb capacity, 4gb Flash boot drive, Ubuntu 8.0.4 Server edition
Capture: 1x HD-PVR -> Motorola DTC6200
Clients: 1x STX-HD100 1x STX-HD200, Windows & OSX Clients
Reply With Quote
  #165  
Old 03-25-2009, 01:33 PM
Slugger Slugger is offline
SageTVaholic
 
Join Date: Mar 2007
Location: Kingston, ON
Posts: 4,008
Just a friendly nudge to regenerate the API for v6.5, please.
__________________
Twitter: @ddb_db
Server: Intel i5-4570 Quad Core, 16GB RAM, 1 x 128GB OS SSD (Win7 Pro x64 SP1), 1 x 2TB media drive
Capture: 2 x Colossus
STB Controller: 1 x USB-UIRT
Software:Java 1.7.0_71; SageTV 7.1.9
Clients: 1 x HD300, 2 x HD200, 1 x SageClient, 1 x PlaceShifter
Plugins: Too many to list now...
Reply With Quote
  #166  
Old 03-25-2009, 08:11 PM
GKusnick's Avatar
GKusnick GKusnick is offline
SageTVaholic
 
Join Date: Dec 2005
Posts: 5,083
Quote:
Originally Posted by Slugger View Post
Just a friendly nudge to regenerate the API for v6.5, please.
Thanks for the reminder. I knew there was some chore I was forgetting about.

Version 0.7 has been uploaded. Not much new except the regenned wrappers, a couple of bug fixes, and a new Copy Widget Symbol command.
__________________
-- Greg
Reply With Quote
  #167  
Old 03-25-2009, 08:51 PM
Opus4's Avatar
Opus4 Opus4 is offline
Administrator
 
Join Date: Sep 2003
Location: NJ
Posts: 19,624
Is it just me, or is the v0.7 file corrupt/incomplete?

Edit: it must be just me because I was able to download it directly from the server. Anyone else have problems downloading it from the forum's Downloads section? Edit2: It must be an IE7 download issue. Firefox works, which used to have upload issues.

- Andy
__________________
SageTV Open Source v9 is available.
- Read the SageTV FAQ. Older PDF User's Guides mostly still apply: SageTV V7.0 & SageTV Studio v7.1.
- Hauppauge remote help: 1) Basics/Extending it 2) Replace it 3) Use it w/o needing focus
- HD Extenders: A) FAQs B) URC MX-700 remote setup
Note: This is a users' forum; see the Rules. For official tech support fill out a Support Request.
Reply With Quote
  #168  
Old 03-25-2009, 08:59 PM
GKusnick's Avatar
GKusnick GKusnick is offline
SageTVaholic
 
Join Date: Dec 2005
Posts: 5,083
I just did a test download without issues, then dropped the JAR into my SageTV\JARs folder and it seems to work.
__________________
-- Greg
Reply With Quote
  #169  
Old 03-25-2009, 09:02 PM
Opus4's Avatar
Opus4 Opus4 is offline
Administrator
 
Join Date: Sep 2003
Location: NJ
Posts: 19,624
I probably added my last edit about when you were posting. IE7 seems to have download issues for me, but Firefox works. Strangely, it used to be Firefox that had issues when people tried to upload files with it. I'll have to see if some other IE7 download option works, for future reference. Edit: the IE7Pro addon's download manager doesn't deal well with the Downloads section here.

- Andy
__________________
SageTV Open Source v9 is available.
- Read the SageTV FAQ. Older PDF User's Guides mostly still apply: SageTV V7.0 & SageTV Studio v7.1.
- Hauppauge remote help: 1) Basics/Extending it 2) Replace it 3) Use it w/o needing focus
- HD Extenders: A) FAQs B) URC MX-700 remote setup
Note: This is a users' forum; see the Rules. For official tech support fill out a Support Request.
Reply With Quote
  #170  
Old 03-29-2009, 01:56 PM
Slugger Slugger is offline
SageTVaholic
 
Join Date: Mar 2007
Location: Kingston, ON
Posts: 4,008
API Throwing Excepion

This call, using API wrapper 0.7:

Code:
		AiringAPI.List titles = null;
		if(title != null && title.length() > 0) {
			titles = API.apiNullUI.database.SearchSelectedFieldsRegex(Pattern.compile(title), true, false, false, false, false, false, false, false, false, "T").FilterByRange("GetAiringStartTime", start, max, true);
			matches.add(titles);
		}
Causes this exception:

Code:
java.lang.ClassCastException: java.util.Vector cannot be cast to [Ljava.lang.Object;
	at gkusnick.sagetv.api.Database.SearchSelectedFieldsRegex(Database.java:744)
	at com.google.code.sagetvaddons.sagerss.SearchShows.doGet(SearchShows.java:91)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:707)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
	at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:487)
	at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:362)
	at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
	at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)
	at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:729)
	at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:405)
	at org.mortbay.jetty.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:206)
	at org.mortbay.jetty.handler.HandlerCollection.handle(HandlerCollection.java:114)
	at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
	at org.mortbay.jetty.Server.handle(Server.java:324)
	at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:505)
	at org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:829)
	at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:513)
	at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:211)
	at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:380)
	at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:395)
	at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:488)
Where line 91 of SearchShows.java is the titles = API.apiNullUI.SearchSelectedFieldsRegex(...) call.

Is SearchSelectedFieldsRegex() returning a vector instead of sage.Airing[] as documented or is this an error with the generated wrapper API?

Help appreciated.
__________________
Twitter: @ddb_db
Server: Intel i5-4570 Quad Core, 16GB RAM, 1 x 128GB OS SSD (Win7 Pro x64 SP1), 1 x 2TB media drive
Capture: 2 x Colossus
STB Controller: 1 x USB-UIRT
Software:Java 1.7.0_71; SageTV 7.1.9
Clients: 1 x HD300, 2 x HD200, 1 x SageClient, 1 x PlaceShifter
Plugins: Too many to list now...
Reply With Quote
  #171  
Old 03-29-2009, 04:20 PM
GKusnick's Avatar
GKusnick GKusnick is offline
SageTVaholic
 
Join Date: Dec 2005
Posts: 5,083
Quote:
Originally Posted by Slugger View Post
Is SearchSelectedFieldsRegex() returning a vector instead of sage.Airing[] as documented or is this an error with the generated wrapper API?
It appears to be returning a Vector. (You can test this yourself with Expression Evaluator.) Not clear whether this counts as a documentation error (doc doesn't match implementation) or a bug in the API (implementation doesn't match spec). There is a precedent (GetAiringsThatWontBeRecorded) for an API method that returns a Vector instead of a sage.Airing[].

If it's a documentation error, I can fudge the wrapper generation to use the correct type instead of the documented type, but unfortunately you then won't get automatic wrapping of the result as an AiringAPI.List; you'll just get back the raw Vector of unwrapped Airings. Personally I would prefer that the API be more consistent in the use of arrays rather than Vectors, but obviously that's not under my control.
__________________
-- Greg
Reply With Quote
  #172  
Old 03-30-2009, 09:52 AM
Slugger Slugger is offline
SageTVaholic
 
Join Date: Mar 2007
Location: Kingston, ON
Posts: 4,008
AiringAPI.Airing missing methods

IsShowReRun() and IsShowFirstRun() are missing from AiringAPI.Airing. I suspect this is due to the fact that these methods are in the Sage API under the Show API, but both methods are documented as taking Airing objects as parameters.

I've unwrapped the AiringAPI.Airing objects and called the underlying Sage API methods for now.
__________________
Twitter: @ddb_db
Server: Intel i5-4570 Quad Core, 16GB RAM, 1 x 128GB OS SSD (Win7 Pro x64 SP1), 1 x 2TB media drive
Capture: 2 x Colossus
STB Controller: 1 x USB-UIRT
Software:Java 1.7.0_71; SageTV 7.1.9
Clients: 1 x HD300, 2 x HD200, 1 x SageClient, 1 x PlaceShifter
Plugins: Too many to list now...
Reply With Quote
  #173  
Old 03-30-2009, 11:37 AM
GKusnick's Avatar
GKusnick GKusnick is offline
SageTVaholic
 
Join Date: Dec 2005
Posts: 5,083
Quote:
Originally Posted by Slugger View Post
I suspect this is due to the fact that these methods are in the Sage API under the Show API, but both methods are documented as taking Airing objects as parameters.
Correct; the rule is that the wrapper generator will push methods down a level (e.g. from AiringAPI.method to AiringAPI.Airing.method) if the first argument matches the group's "this" type. But it does not automatically migrate methods from one API group to another based on their argument type.

What I can do for the next release (whenever that may be) is add extension APIs to AiringAPI.Airing that mimic the ShowAPI methods.

Quote:
Originally Posted by Slugger View Post
I've unwrapped the AiringAPI.Airing objects and called the underlying Sage API methods for now.
You shouldn't need to do that; you should be able to pass in the wrapped AiringAPI.Airing directly to api.showAPI.IsShowFirstRun() and api.showAPI.IsShowReRun().
__________________
-- Greg
Reply With Quote
  #174  
Old 03-30-2009, 12:36 PM
Slugger Slugger is offline
SageTVaholic
 
Join Date: Mar 2007
Location: Kingston, ON
Posts: 4,008
Quote:
Originally Posted by GKusnick View Post
You shouldn't need to do that; you should be able to pass in the wrapped AiringAPI.Airing directly to api.showAPI.IsShowFirstRun() and api.showAPI.IsShowReRun().
Good call, thanks. I just incorrectly assumed that the methods were completely MIA since they weren't defined in AiringAPI.Airing, never thought about looking in showAPI. I went back and was able to remove the direct calls to sage.SageTV.api, which made me remember how tedious all of this was prior to discovering your API.
__________________
Twitter: @ddb_db
Server: Intel i5-4570 Quad Core, 16GB RAM, 1 x 128GB OS SSD (Win7 Pro x64 SP1), 1 x 2TB media drive
Capture: 2 x Colossus
STB Controller: 1 x USB-UIRT
Software:Java 1.7.0_71; SageTV 7.1.9
Clients: 1 x HD300, 2 x HD200, 1 x SageClient, 1 x PlaceShifter
Plugins: Too many to list now...
Reply With Quote
  #175  
Old 03-31-2009, 05:15 PM
Slugger Slugger is offline
SageTVaholic
 
Join Date: Mar 2007
Location: Kingston, ON
Posts: 4,008
So I have an AiringAPI.List and I want to filter the list to include only those that are first runs. Can this be done with API.apiNullUI.database.FilterByBoolMethod()?

Is there a way to tell this method to call a static method with an AiringAPI.Airing as the only argument and use that result? Basically I want to call API.apiNullUI.showAPI.IsShowFirstRun(AiringAPI.Airing) on each item of the list and filter that way. Is there a way to do this without having to unwrap the List, filter it by some other means, and then wrap it back up into a new List for use elsewhere?
__________________
Twitter: @ddb_db
Server: Intel i5-4570 Quad Core, 16GB RAM, 1 x 128GB OS SSD (Win7 Pro x64 SP1), 1 x 2TB media drive
Capture: 2 x Colossus
STB Controller: 1 x USB-UIRT
Software:Java 1.7.0_71; SageTV 7.1.9
Clients: 1 x HD300, 2 x HD200, 1 x SageClient, 1 x PlaceShifter
Plugins: Too many to list now...
Reply With Quote
  #176  
Old 03-31-2009, 06:18 PM
GKusnick's Avatar
GKusnick GKusnick is offline
SageTVaholic
 
Join Date: Dec 2005
Posts: 5,083
Yes, with some caveats. Database.FilterByBoolMethod(), like the underlying core API method, can take a List<T> for any type T and return a filtered List<T>, given a filtering method with the appropriate signature (i.e. boolean F(T)). AiringAPI.List is a subclass of List<AiringAPI.Airing>, so it will work in any context that takes a List<T>, including this one.

Unfortunately ShowAPI.IsShowFirstRun(AiringAPI.Airing) does not have the right signature, since it requires a "this" instance of ShowAPI in addition to the AiringAPI.Airing argument. AiringAPI.Airing.IsShowFirstRun() would have the right signature if it existed (which it does now in my local build, but not in the 0.7 release). You could write your own static wrapper method that takes an AiringAPI.Airing and calls API.apiNullUI.showAPI.IsShowFirstRun() as you suggested.

However this may not be the most efficient approach, since it entails a call to AiringAPI.Wrap() each time an element is fetched from the list. A better solution is probably to use AiringAPI.List.FilterByBoolMethod(), which calls the underlying FilterByBoolMethod() on the unwrapped list, does the filtering on the unwrapped elements, and then wraps up the result. So for this approach the filtering method you'd want to pass in is the core IsShowFirstRun() method, not my wrapped version.

By the way, all the wrapped *API.List types have a full set of type-specific sorting and filtering methods, which you should probably use in preference to the Database sorting and filtering methods where applicable. (But not, obviously, for generic lists and arrays that aren't part of the wrapper API.)
__________________
-- Greg
Reply With Quote
  #177  
Old 03-31-2009, 06:49 PM
Slugger Slugger is offline
SageTVaholic
 
Join Date: Mar 2007
Location: Kingston, ON
Posts: 4,008
Quote:
Originally Posted by GKusnick View Post
However this may not be the most efficient approach, since it entails a call to AiringAPI.Wrap() each time an element is fetched from the list. A better solution is probably to use AiringAPI.List.FilterByBoolMethod(), which calls the underlying FilterByBoolMethod() on the unwrapped list, does the filtering on the unwrapped elements, and then wraps up the result. So for this approach the filtering method you'd want to pass in is the core IsShowFirstRun() method, not my wrapped version.
Ok, it all makes sense and it's what I've been doing except for one detail that is confusing me in the above paragraph. How do I tell FilterByBoolMethod to use the core IsShowFirstRun() method as opposed to your wrapped version? While I'm at it, how do I (or is it possible to) use some static method, that perhaps I've written to do some crazy computation or whatever, as the parameter for FilterByBoolMethod? My current strategy in all my other plugins has been: If the method I want to filter by isn't an instance method of AiringAPI.Airing [in this example], then I create a new, empty instance of List<AiringAPI.Airing>, iterate over the current list, add the ones I want to keep to the List<AiringAPI.Airing>, wrap this new List up in a new AiringAPI.List and overwrite the reference to the original and move on with my new filtered list. I've got to believe there's a better way, and what you're saying tells me there is, I'm just not seeing the light quite yet. Hopefully you can turn that light bulb on for me and I can do this right starting with this new RSS feed project I'm working on.

Let's say I've defined a static method that examines every property of an AiringAPI.Airing then returns a boolean, which means something somewhere else. So in the class "my.package.utils.CrazyComputations" I've defined this static method:

static public boolean digestAllPropsAndDecide(AiringAPI.Airing a)

Is this possible to use as the parameter for FilterByBoolMethod? If so, what's the argument string for the method name? Would it just be "my.package.utils.CrazyComputations"?

I'm sure it's not as difficult as I'm making it out to be? But I just don't see the details in the Sage API docs and I've been starring at this for the better part of two evenings (which obviously isn't helping the cause any). I think once someone explains it to me the light will flip on and all will be good.
__________________
Twitter: @ddb_db
Server: Intel i5-4570 Quad Core, 16GB RAM, 1 x 128GB OS SSD (Win7 Pro x64 SP1), 1 x 2TB media drive
Capture: 2 x Colossus
STB Controller: 1 x USB-UIRT
Software:Java 1.7.0_71; SageTV 7.1.9
Clients: 1 x HD300, 2 x HD200, 1 x SageClient, 1 x PlaceShifter
Plugins: Too many to list now...
Reply With Quote
  #178  
Old 03-31-2009, 06:57 PM
GKusnick's Avatar
GKusnick GKusnick is offline
SageTVaholic
 
Join Date: Dec 2005
Posts: 5,083
You pass in the string name of the method. For core API methods, it's just the documented method name, e.g. "IsShowFirstRun". For general Java methods (static or not), it's the Sageified fully qualified method name, e.g. "my_package_utils_CrazyComputations_digestAllPropsAndDecide", just the same as you'd use when calling it directly from Studio code.
__________________
-- Greg
Reply With Quote
  #179  
Old 04-01-2009, 10:54 AM
Slugger Slugger is offline
SageTVaholic
 
Join Date: Mar 2007
Location: Kingston, ON
Posts: 4,008
Ok, it all makes sense now. My problem was that I was trying to use a method defined in my WAR file that I'm deploying within the Jetty plugin. The various Sage core filter methods cannot see the classes from my WAR and that's why I was getting class not found exceptions thrown all over the place.

So instead I'm doing the filtering myself in static methods by iterating over the list and filtering into a new list. For the sake of completeness, I'll also mention that the alternative would be to create a utility JAR that contains all the sorting, filtering, etc. methods you want and put that JAR in SageTV\JARs\ so that the core will load the classes at startup and are therefore available through the various API calls.
__________________
Twitter: @ddb_db
Server: Intel i5-4570 Quad Core, 16GB RAM, 1 x 128GB OS SSD (Win7 Pro x64 SP1), 1 x 2TB media drive
Capture: 2 x Colossus
STB Controller: 1 x USB-UIRT
Software:Java 1.7.0_71; SageTV 7.1.9
Clients: 1 x HD300, 2 x HD200, 1 x SageClient, 1 x PlaceShifter
Plugins: Too many to list now...
Reply With Quote
  #180  
Old 04-08-2009, 01:29 PM
GKusnick's Avatar
GKusnick GKusnick is offline
SageTVaholic
 
Join Date: Dec 2005
Posts: 5,083
I've just uploaded version 0.71. There are no new features in this release; the only changes are as follows:

* Slugger's issue with Vectors has been fixed. API methods that are incorrectly documented as returning a sage.Airing[] but actually return a Vector now handle the returned Vector correctly and wrap it as an AiringAPI.List.

* I've addressed the confusion with IsShowFirstRun(sage.Airing) and similar methods by fixing the wrapper generator to detect such cases and generate two wrapped versions of the method: one in the group where it's documented (e.g. ShowAPI.IsShowFirstRun(AiringAPI.Airing)) and one in the class to which it applies (e.g. AiringAPI.Airing.IsShowFirstRun()). So you now have a choice of which way you prefer to call it. There are about 18 such cross-referenced methods in this build.

* There seem to be a few new methods that appeared in the online API docs since the last build, so those are now reflected in the wrappers as well.
__________________
-- Greg
Reply With Quote
Reply


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -6. The time now is 02:25 AM.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2023, vBulletin Solutions Inc.
Copyright 2003-2005 SageTV, LLC. All rights reserved.