Monday, July 26, 2010

Share Chrome web apps with DropBox, use them in Launchy

Lets see if we can kick this blog back to life a little bit.

I have a nasty habit of leaving tabs open for a very long time in my main browser window. I have 12GB of RAM in my main machine, and usually only boot once a month or so (whenever I finally give in and install the critical Windows updates etc), so this isn’t a problem as such. However, I thougth there must be a better way to handle this. Bookmarks are where URLs go to die for me – how can I stay up to date on the sites I use all the time? This is compounded by the fact that I spend much of my time on three different PCs – my main home machine (Windows 7), my personal laptop (Vista for now), and my workstation at work (Vista for now as well).

Most people familiar with the applications mentioned in the headline will probably see where I am going with this just by reading that line. For the rest, however, here is a short intro to each of them:

Google Chrome is my current browser-of-choice. It is fast, appears to be light-weight, has some nice extensions (Adblock and other lifesavers), is very fast (especially on the javascript side) and quite free. I am fairly browser agnostic, so I have them all, but Chrome is the one I keep using. It has a nice feature where you can create a “web app”. This basically makes a shortcut on the desktop to this web app, which then opens in a window by itself without the URL bar etc.

DropBox gives you one or more folders on your computer that will be synced between the machines you install it on. Cool for keeping ebooks, common configs, works-in-progress etc. up-to-date even when moving between machines. A 2GB account is free. You can also pay a modest sum for larger accounts.

Launchy is probably the most-used (measured in number of invocations) utility I have. I try to be mouseless to be more effective (and save my wrists), and Launchy takes me there. By pressing a quick keyboard shortcut (mine is alt-escape, the default is something different) I get a window where I type what I want to run. It is relatively smart about finding the right thing based on what you type. You can use it as a calculator etc. And I can start applications a LOT faster than mousing through the start menu. Get it. You’ll be glad you did.

Okey, so we got all three installed. See where this is heading? The basic idea is to define Chrome web apps for sites I use a lot (Stack Overflow and the ever increasing amazing sister sites, GMail, Google Reader / Feedly, LinkedIn, Facebook, GitHub, AgileZen, FogBugz, etc.), share them in a DropBox folder, and then have Launchy scan that folder and use what it finds there as shortcuts. So whenever I need to check my GMail account, I press Alt-Esc – G – M – Enter, and the window is there. Quickly and – dare I say it – with a minimum amount of pain.

There really isn’t much to it. There is only one small trick you have to do, and one very minor thing I didn’t figure out yet.

1. Go to the site you want to turn into a web app in Chrome.

2. Push the document-looking button top right and choose to create a web application (currently the top choice in my Chrome).

3. Choose to create the shortcut on the desktop.

4. Find the shortcut on the desktop. Open the properties window for it.

5. Open a Windows Explorer window (Windows-E). In the address bar, type %localappdata% and press enter.

6. Notice that the start of the value in the “Target” field in the properties window for the shortcut and the address bar in the Explorer window now are the same. Replace the part in the properties window that is the same as the address bar of the Explorer window with %localappdata%. This could turn out to be very important, as Chrome doesn’t install in the Program Files folder – rather, it installs in your local app data folder so that anyone can install it without being an admin. This is nice and all, but if you’re sync’ing with dropbox to computers where the local app data folder is different (different username, different OS), the shortcut won’t work.

7. Store the updated shortcut by clicking OK in the properties window.

8. Create a folder in your DropBox – I called mine Apps – and move the shortcut there.

9. Configure Launchy to scan this folder. To do this, press your Launchy shortcut, then Ctrl-, (control comma). Go to the Catalog tab, press the + button, and add the DropBox\Apps folder. In the “File Types” group, add “*.lnk” as a pattern. Rescan the catalog and press OK to escape the Launchy options window.

10. Repeat pt. 9 for each computer that you’re syncing via DropBox.

So what did we achieve with this? Whenever you start using a new web site regularly, create a shortcut as instructed here, and it will be available on each computer you work on. You will of course have to log in to the web app / site on each computer.

The one small thing I mentioned that I didn’t figure out yet is how to get the icons for the web apps across – but Chrome takes care of that after the first run (i.e. second time you open that web app on a computer, Launchy will also display the correct favicon), so it wasn’t worth angsting over.

I hope this is useful to someone besides myself. :)

Saturday, March 07, 2009

Scaling images while keeping aspect ratio and max size

In an application I am writing, I recently came across the need to accept uploaded pictures and scale them to a set size for inclusion in a table. Simple stuff, just a “let’s make all pictures the same size for easier layout” kind of deal. Say the “target” size was 800x600, and given a size originalSize, the function needs to figure out a new size for the image that meets the following demands:

1. The entire image must fit inside the target size.

2. The image must keep its’ aspect ratio.

3. The size of the new image must never be larger in either direction than the original (no upscaling)

4. The image must be as large as possible without breaking the three other rules.

After a few days of wrapping my head around this (and doing other stuff), I realized it was all the aspect ratio – which way we used to calculate the width/height that should be returned, depends entirely on which of the aspect ratios are larger; That of the original image, or that of the target size.

I of course started with the unit tests – a MbUnit RowTest with 20 rows of different combinations of picture sizes, new sizes, and expected result sizes. I had done all the calculations on paper in advance and was pretty sure they were correct.

After a little bit of experimentation, I ended up with this method:

  1: public static Size GetRenderSize(Size originalSize, Size targetSize)
  2: {
  3:     float targetRatio = targetSize.Width / (float)targetSize.Height;
  4:     float imageRatio = originalSize.Width / (float)originalSize.Height;
  5: 
  6:     if (imageRatio < targetRatio) // Target ratio is wider than the source ratio, scale by height
  7:     {
  8:         var smallerY = Math.Min(originalSize.Height, targetSize.Height);
  9:         return new Size((int)Math.Round(smallerY * imageRatio,0), smallerY);
 10:     }
 11:     // Target ratio taller than source ratio or the same - scale by width
 12:     var smallerX = Math.Min(originalSize.Width, targetSize.Width);
 13:     return new Size(smallerX, (int)Math.Round(smallerX / imageRatio,0));
 14: }


A lot simpler than I thought, and seems to give correct results on each and every calculation. :)

Wednesday, February 25, 2009

Silverlight vs. FireFox

After struggling with getting some Silverlight (2.0) apps working in FireFox (v3), I thought I’d post the solutions here so that I can find them easily in the future.

The first problem was getting the application to load in the first place. In one of the parameters to the <object> that will represent your application, you pass in a ‘data’ parameter, like this:

data="data:application/x-silverlight-2,"

See that pesky little comma after the “2”? Well, without it, your app probably won’t show up in FireFox, at least mine wouldn’t. It works fine in IE and Chrome, but no way the ‘fox would love it.

The second issue seems to be that if you give your app a percentage height, and the outer elements don’t have a set height themselves, you could end up with an application with a height of 0 pixels – which means there is nothing to show. Fortunately other people have already figures this out, such as this here guy, who I thank for saving me some gray hairs. :)

That’s it!

Sunday, January 11, 2009

Making a dropdownlist in ASP.Net MVC from an enum

Some times your business objects use a simple enum to indicate something, for instance a status. For one of my projects I have a TaskStatus defined like this:

public enum TaskStatus
{
    NotStarted,
    InProgress,
    Waiting,
    Finished,
    Cancelled
}

Nothing exciting here. Now I want to turn this into a SelectList that can be used with the Html.DropDownList helper. Turns out this is embarrassingly easy using LINQ and anonymous methods:

  1: var statuses = from TaskStatus s in Enum.GetValues(typeof(TaskStatus))
  2:                select new { ID = s, Name = s.ToString() };
  3: ViewData["taskStatus"] = new SelectList(statuses, "ID", "Name", task.Status);


Now I can just use it in my view using the helper method:



  1: <td><b>Status:</b></td><td><%=Html.DropDownList("taskStatus")%></td></tr> 


Easy peasy. :)

Monday, December 01, 2008

You can’t do that in WPF?

One of the things that virtually everyone talks about whenever they start learning WPF is how amazing the experience is – there are virtually no limits to the amazing stuff you can do. Or put in a different way; The hard becomes easy, the impossible becomes possible.

However, one thing I have not found a way to do (and which is apparently not currently possible, according to the answer I got on StackOverflow.com), is how to handle databinding in the case where you want to bind to an interface, and not the actual object.

In my case, I have a list of business objects that represent the ItemsSource for a ListBox. Each of these objects contains two other objects. These objects can be one of several different types, the only thing they have in common is that they implement a specific interface. The problem here is that the ItemTemplate I use cannot refer to the Interface properties – the binding engine will only see the object as the type it really is, not the interface.

While this isn’t a HUGE thing, it is a weakness that would be very nice to be able to work around in an upcoming update of WPF.

Thursday, November 06, 2008

WPF ComboBox binding to LINQ to SQL

This is mostly for my own use – I am senile enough to run into this problem again in the future.

Like all controls in WPF, the ComboBox is full of configurability and extensibility. This can get quite hairy quite quickly – and if you set the wrong parameters when you databind to a LINQ to SQL data source, really funky stuff can happen.

So here is something that worked for me:

<ComboBox Grid.Column="1" Grid.Row="1" VerticalAlignment="Center" IsEditable="False"   
          Margin="10,2" 
          ItemsSource="{Binding Path=Produkt.Modeller}"  
          DisplayMemberPath="Modell"  
          SelectedValuePath="Modell"  
          SelectedItem="{Binding Path=ProduktModell}"  
          />
ItemsSource is relatively easy – just point at the collection of options.


DisplayMemberPath is also relatively easy – it just tells WPF what to display in the ComboBox.



But SelectedValuePath and SelectedItem took some experimentation to get right – the above works for me, but with some variation came some pretty strange bugs. Models being renamed and stuff.



So now I know.

Sunday, October 19, 2008

Book impression – Programming WPF

So, I was a complete newbie when it came to WPF, but because of Sloth and other applications, I was curious about what this was, as I must admit that UI programming in Windows has been a serious annoyance. Perhaps that’s the way it has to be when you come from a background of Amiga programming, with som web stuff thrown in for good measure.

I think I can safely say that I now have a pretty good grasp of how I can use WPF for creating better experiences for the users of my software. There are a lot of things I can do now that I couldn’t before, and the whole layout model makes a lot more sense. Declarative programming is definately the way to go when it comes to GUI programming, IMHO.

So, what about the book? Well, like many programming books, it’s hard to just read it without a keyboard and a compiler nearby. You want to try out the stuff as you go along, and the book rightly encourages you to do so. The logical progression of things felt a little off at times, and in places it felt more like a reference book than an end-to-end learning experience. Particularly when it came to look at data binding, I must admit I struggled a bit; Their explanations were very good, but I left those chapters feeling like the authors should have given more attention to databinding towards CLR objects; After all, WPF representing the presentation layer, I would expect most non-trivial applications to have some model data to show; It won’t all be created as part of the XAML.

Other than small gripes like this, I feel like I have a pretty good idea of the things you can do with WPF. Of course it doesn’t touch on features of .Net 3.5 Sp1 such as the possibilities of creating grid views (the book came out long before Sp1), so while this is not the fault of the authors, if you want to learn about the new features of Sp1, you have to look elsewhere.

So, is this brick worth reading through? If you’re stuck with WinForms and want a better way to do things, go for it! There is a lot you can do with WPF that would be very hard with the old ways, and I for one believe that WPF represents the future of UI programming. I will surely use it for my coming client applications, and I will keep this book nearby as a handy reference.

My copy of the book is “Programming WPF, Second Edition”. It is published by O’Reilly, and authored by Chris Sells and Ian Griffiths.

Sunday, August 31, 2008

Collection sorting – when the built-in stuff doesn’t work

C# and the the .Net framework has a lot of excellent support for collections – no more mucking about creating your own linked list structures, hash tables etc. This means you get easy to use lists of your stuff almost for free, saving you a lot of testing/debugging whenever you make a brain fart during tedious boilerplate coding.

The network also has a lot in place for sorting these collections – the Sort() function allows you to plug in your own comparer and will then perform a relatively performant sort for you (QuickSort? I dunno). Isn’t it nice that we can skip this stuff and concentrate on getting the logic unique to our application right?

Well, yes. However, there are cases where the default sort does not work. I recently encountered one of those in one of my applications.

This application keeps a bunch of tags. You know, the del.icio.us kind, that you can use to label your data in different ways. We can mark certain products with a tag, and then, when we search for the tag, we’ll find all producst tagged by it. Simple stuff.

One particular feature here is that each tag keeps a list of “implied tags” – i.e. if you add this tag, you also implicitly have these tags as well. An example will hopefully clarify;

If you have the products ham, bacon and sirloin, you might want a tag for the first two named pork, and a tag for the last named beef. In addition, you would typically have a tag named meat that is implied both by pork and beef. That way, if you search for products that contain meat, you will find any products that contain ham, bacon or sirloin.

This is a simple, contrived example, but it should illustrate how implied tags work. It also leads to some limitations on the implementation of this system. Data in this case is to be stored in an XML file, and will be fetched in such a way that when a tag references (implies) another tag, the implied tag will already have to be defined; I.e. an implied tag has to come before the tag doing the implying in the XML file.

In my case, recursive tag implication is not allowed. Tag A can not imply tag B which in turn implies tag A, or any deeper variation of that. Therefore, the solution is simple; In the XML file, we need to make sure that tags that don’t imply anything else come first (there will always be at least one of these, because of the limitation on recursion). Then come the tags that only imply one or more of these first tags, and then in turn the tags that imply the tags we already have. Basically, a tag can only be added to the file once all tags it implies are already in the file.

My first attempt to take care of this was a relatively boneheaded one in retrospect; I implemented a comparer, implementing IComparer<Tag> to figure out the sort order, based on wether or not tag X implies tag Y, or Y implies X (and if they both implied each other, I threw – that’s tag implication recursion right there). Now, in theory this would work, but unfortunately the List.Sort() method was a little to clever for me. The result of one single comparison in my case only says something about the relation between these two elements. However, for the Sort() method, if A comes before B, and B comes before C, then we don’t even bother comparing A and C – we’ve already worked that part out implicitly. It doesn’t take a lot of imagination to come up with a situation where a tag list wouldn’t be sorted in the right order with this kind of sorting. And a quick unit test or two easily demonstrated that this would not handle all cases:

[Test]
public void TestImplicationSortingCreatesCorrectOrder()
{
var t1 = new Tag("Level 1");
var t2 = new Tag("Level 2");
var t3 = new Tag("Level 3");

t2.ImpliedTags.Add(t1);
t3.ImpliedTags.Add(t2);

var list = new List<Tag>() { t3, t2, t1 };
var newlist = Tag.SortTagListByImplication(list);

Assert.AreEqual(t1, newlist[0]);
Assert.AreEqual(t2, newlist[1]);
Assert.AreEqual(t3, newlist[2]);
}


This test would easily fail using the built-in sorting. Tag.SortTagListByImplication( IEnumerable<Tag>) was just a static wrapper that created the correct comparer and performed the sort.

To get this to work properly, however, I had to implement the sorting myself, so I chose to do it in the same method:


public static List<Tag> SortTagListByImplication(IEnumerable<Tag> tags)
{
if (tags == null)
throw new ArgumentNullException();

if (tags.Count() == 0)
return new List<Tag>(tags);

var newlist = new List<Tag>();
var sourceitemlist = new List<Tag>(tags);

do
{
var newbatch = new List<Tag>();
foreach (var t in sourceitemlist)
{
var hasAnyUnresolvedImplications = false;

foreach (var it in t.ImpliserteTags)
{
if (!newlist.Contains(it))
hasAnyUnresolvedImplications = true;
}
if (!hasAnyUnresolvedImplications)
newbatch.Add(t);
}
if (newbatch.Count == 0)
throw new InvalidOperationException("No new Tag items added to list - recursion nightmare!");
newlist.AddRange(newbatch);
foreach (Tag t in newbatch)
sourceitemlist.Remove(t);

}
while (sourceitemlist.Count > 0);

return newlist;
}
This code is very much a “first pass” – i.e. I stopped working on it once the unit test started working. Yes, I am quite sure it can be improved. However, right now, it does what I need it to do, so I will leave it alone.

The point of this post? I just wanted to mention that there are situations where the built in sorting logic is not proper. If it helps someone in the future, great. :)

Saturday, August 30, 2008

Book impression – C# in Depth

I’m calling this an impression, since I have no idea what kind of stuff I have to put in here to justify calling it a review. Smile

The other day I finished reading C# in Depth by Jon Skeet, one of those people with such a deep understanding of how stuff works that you just have to admire them. Small disclaimer; Jon replied to a newsgroup post of mine a few years back and turned out to be a very helpful and friendly guy. So I might be a bit biased.

The title of the book is no lie; We’re really going in depth here. Not through the whole language, mind you, “just” the improvements in version 2 and 3 of the C# language itself (which is versioned separately from the .Net framework). That means we get a lot of information on delegates/lambdas, expression trees, and other would-be headache-inducing low-level (at least from my viewpoint) programming constructs.

Then again, I guess you could point out what a nerd I am when I admit that I read part of this book on the beach in Alicante (Spain) during my summer vacation. Big Grin

I have read quite a few programming books, from basic C introductions to relatively complex stuff on a diverse range of topics. However, I must say that no book has ever triggered the “coding itch” quite as bad as this one, and while I am by no means any less of an amateur programmer now than I was before, I feel that I have a deeper understanding of a lot of what the book explains, and I have also been inspired to take my understanding of the language further; If only every online tutorial and article were written as clearly as Jon’s book.

While I am right now plowing through Programming WPF and jQuery in Action for specific projects, next on my list is LINQ in Action – I suspect I will have an easier time grokking that one thanks to C# in Depth.

If you want to have a deeper understanding of the C# language and learn useful stuff like how to use many of the technologies that make up LINQ separately for other things, this is definately a great book. I recommend it highly!

Wednesday, August 27, 2008

Automatically implemented properties and WPF

This blog hasn’t lived much recently – I’ll try to post a little more, but no promises (since noone reads it anyway).

I’ve been looking into Windows Presentation Foundation lately, and it is very fascinating; It opens up a lot of doors for new UI possibilities, but also quite a few new challenges. If you want to display your object model in the “WPF way”, one of the things you have to do is implement INotifyPropertyChanged. This allows WPF to pick up on object changes and update the user interface accordingly.

One of the very helpful new features in C# 3 (i.e. the language, which confusingly was released with .Net 3.5) is automatically implemented properties. Basically these guys allow you to implement trivial properties on objects without a lot of code, backing fields etc. A one-line property makes code more readable, and you have less possibility of failure in a no-code property than one that contains some code.

These two things put together, however, are currently not compatible by default. If you have an automatically implemented property, it will not notify WPF of changes to its’ value. There are of course ways of doing this using reflection and attributes and such, but wouldn’t it be really cool if the C# compiler knew of INotifyPropertyChanged and actually triggered the PropertyChanged event for you automatically on these autoprops?

I certainly think so, but I can see why some people would disagree.

No matter what, I think it would be really useful.

Saturday, March 01, 2008

Sloth v0.1.1 beta released

Hey "all".

So it is time for another beta, this time we're talking about Sloth v0.1.1 - an exciting new version which again has improved a lot of the internal design in Sloth. This means more unit tests for verifying that code changes does not break existing stuff, optimized code, and a cleaner, more maintainable design. This is of course a great benefit as it makes adding new exciting features a lot easier. But what visible changes does Sloth v0.1.1 give you, the user?

Works on Vista "out of the box"

Vista has gotten a lot of heat, but it won't disappear any time soon, so I thought it was important to support it properly. Sloth now puts log- and configuration files in proper places so that Vista does not go ballistic because it tries to write to Program Files etc. This also means Sloth works well in terminal server environments.

Alert changes

You can now tell Sloth to alert you when a particular show is on - no more tagging or creating a rule manually. Just point to a show, right click, and choose "Notify me of this show". When the time comes, Sloth will let you know. Also, there is now an option (on by default) to tell Sloth not to display alerts while a full-screen application (presentation, video, game) is running.

If your screen resolution or screen working area changes, Sloth will now rearrange any open alerts to reflect this; No more alerts all over the place. When an alert is closed (automatically or manually by the user), any remaining open alerts will be moved to fill the open slot.

Rule handling changes

Rules are now handled in their own unit-tested section of the configuration. Quite a lot has been done internally to work with "delta rules" - i.e. when there is a rule change (a rule has been added, deleted or modified), Sloth will only update with the changes, not all rules as before. For users with significant amounts of rules, this should be noticeable. There is also a new search subsystem, which is currently only used for rule matching. Not yet optimized, but almost as fast as the old system, and vastly more flexible.

Community functionality

There is quite a lot being done to support community functionality; Show ratings, discussions etc. Not a lot of this is visible in the current beta, but more will be seen soon. It is now possible to rate shows in the community, but that won't show up for anyone else yet. The community functionality also includes a simplistic news system and a better Sloth Updater feature.

Better tools for helping me debug problems

A new program - SlothBetaInfo - is now included in the start menu. This will make it easier to locate logs etc. Also, if Sloth should crash somehow, you will now get a window with exception info that I would highly appreciate on the forum along with an explanation of what went wrong.

Other changes

Loading the XMLTV data file is now a lot faster. The notification and installation of newer versions is a lot more robust. A lot of old code has been cleaned up and refactored. TV data grabbing is less error-prone. Sloth also handles new TV channels showing up in data files without problems.

More statistics

As a follow-up to last time, where we had 92 passing unit tests, we now have 355. Does this guarantee that there are no bugs in Sloth? Of course not. But it means that if I change some code that is covered by a unit test, and break something, I'll know right away. And as I mentioned after v0.1, if a new bug is found in this code, I can add a unit test to check for it - if it comes back, I'll know immediately. Another important metric here is code coverage - how much of the library code that is actually tested by unit tests. The current numbers are:

SlothCommunity 40%
SlothCore 65%
SlothUtil 73%
SlothConfig 76%

While 100% code coverage would be nice, it's not necessarily realistic. However, I will work to improve the testing, making sure it is harder and harder for bugs to slip by.

Summary

Well, perhaps no revolutionary new features, but all of the above contributes to make Sloth a much more mature, stable application. I will try to move into quicker-iteration mode now, adding some nice new features and releasing both alphas and betas at a quicker pace. Happy testing!

Monday, September 24, 2007

Fun with optimalization

Sloth, being written in/towards the .Net Framework (currently 2.0), is an object oriented application. I try to follow a few general principles on how to do stuff. One of the things I try to avoid is premature optimalization - the idea being that you first get it to work, with unit tests as a backing confidence booster, and THEN you optimize.

Just for fun, I thought I would optimize something that has survived since the early days of Sloth v0.0.0.1 - it is well proven code, and it would be very easy to verify if my optimizations break anything, as Sloth would cease to function at all.

The area I chose for this experiment is the Channel object, more specifically the OnNow and OnNext properties. These basically tell the caller which show is on the channel right now, and which one is on next.

A run with a profiler shows me that while this does not affect overall application performance much, it is definately ready for some improvements. These properties have largely gone unchanged after being more or less among the first 20 or so things written in Sloth. Optimizing them should be very easy, but I was eager to see just how much I could squeeze out of it. The routines are used by the main window to determine which shows to list, as well as by the "early warning system" that scores OnNow/OnNext before anything else to get alerts launched ASAP after Sloth starts.

The original OnNow would loop through the collection of shows until it found one whose StartTime was less than/equal to DateTime.Now, and whose StopTime was larger than/equal to DateTime.Now. If a match was found, it was returned. Since Sloth never adds shows that end before the current day to the list, at most this would mean having to traverse a whole day of shows before finding the right one. Didn't take long, but it took long enough - there was a definitive room for improvement here!

The implementation of OnNext was way worse. Keep in mind that this was written in the days where Sloth made no warranty that the list of shows was sorted in chronological order. So basically, OnNext would loop through the collection, and if it found any show with a StartTime larger than DateTime.Now, check if it was lower than what it already had (if anything), and if so, grab it. This meant looping through the whole collection. Large room for improvement.

While these numbers are taking from a single profiling session, and in no way represent any real benchmarks, they give you a good indication of the "savings" possible. What I did was basically profile these two properties from Sloth startup until the UpdateScores routine was finished and all alerts fired.

Original OnNow 67 ms
Original OnNext 82 ms

Wow - together they consume a whopping 0.15 seconds on my PC! Way to pick an important target for optimization! ;)

Well, I'm in it for the lesson, not the ... eh ... something.

So time to try to be clever.

Optimization 1 - Cached objects

So how about we cache the show found to be OnNow, the show to be OnNext, and that way, we don't have to look through the list all the time? Excellent idea! How do we know when we actually have to go looking again? Easy - OnNow.StopTime should tell us when the show currently on is over and the next one is ready. So I added two local variables for onNow and onNext, and a DateTime called cachedOnNowSwitch (yeah, clever name) which would be set to the time it was necessary to run the list again.

OnNow simple optimization 19 ms
OnNext simple optimization 42 ms

That's nice - reducing OnNow by a third and halving OnNext shows that caching the objects was a good plan. If only we could tighten the list traversal a little..

Optimization 2 - Cached DateTime.Now

In the profiler, DateTime.Now suddenly stuck out as a sore thumb. It seems like fetching this from the OS takes a relatively long time. So how about instead of calling DateTime.Now all the time I do date comparison in the list, I create a local DateTime called now that I set at the beginning, and then compare to it instead?

OnNow medium optimization 6,8 ms
OnNext medium optimization 28 ms

Okey, now we're talking! But it should be possible to optimize even further...

Optimization 3 - No more OnNext list walking

Since the original code was written, Sloth has started ensuring that the show lists are sorted at all times. It's just more efficient that way. So is it really necessary for OnNext to run through the whole list of shows to find its' target? Of course not.

Since OnNow is cached and these two are always called near each other, lets have OnNext just call showlist.IndexOf(OnNow) and add 1 - that should be our show!

OnNow cool optimization 6,1 ms
OnNext cool optimization 3,2 ms

No special reward for OnNow this time around, just an insignificant brain fart probably. But OnNext is starting to look real good!

Optimization 4 - Cache the IndexOf result

Since we already know via the cached DateTime when our OnNow will be outdated, why don't we just cache the result of the IndexOf call as well? Also, let's add some checking for empty show lists and not doing anything when hitting out-of-bounds conditions.

OnNow super optimization 2,9 ms
OnNext super optimization 0,2 ms

Nice numbers!

So there we have it - I'm not going to try to go further, as there is probably nowhere left to optimize for a developer of my skill level. Most of the fat now is in the looping and date comparison stuff, which I can do very little about. So I am plenty happy with the outcome.

I'm looking forward to seeing what can be done in other time-intensive Sloth loops!

Until next time...

Sunday, August 05, 2007

Sloth v0.1 works in Windows Vista after all

Hey.

So I was fiddling around a little on my Virtual PC with Vista installed - a strange thing that happened was that when you installed Sloth, it would work. However, if you restarted your machine or otherwise stopped Sloth and restarted it, it would no longer work. No specific error message, just a generic "Well, it just stopped working, see..." thingy.

After reading up a bit online (I don't really use Vista myself yet), I found that the new UAC "feature" of Vista was probably to blame. What happened is that when you started the installer, it asked you for permissions; When you give it the goahead, it installs, then runs Sloth. Sloth sees no config and runs the Wizard. The wizard does it's thing and then starts Sloth. All of this still happening with the permissions you gave the installer that you presumably downloaded off the net.

So, you get sick of Sloth and shut it down, then decide you need to see what's on tonight. You double click it.

"Well, it just stopped working, see..."

Yeah, annoying as hell.

However, if you right click Sloth, and choose "Run as administrator", then it works. What Einstein decided that this was the correct way to handle this issue!? No meaningful error message at all! If it had told me "Well, your program tried to write a log file to \Program files\, which is bad", then at least I could do something about it.

But no, just dying and claiming it was the programs' fault seems like a much better approach.

Anyway, until I get Sloth to behave nicer according to Vista's unknown rules, run it as an admin.

Wednesday, June 20, 2007

Sloth v0.1 beta released

This is the first beta that is announced on this blog - and it is also the first beta that uses the .Net Framework v2.0. All beta testers up to and including v0.0.25 got away with just using .Net 1.1, but now you will all need to upgrade. You can download the .Net 2.0 framework installation here if you don't have it (the Sloth installation will tell you if you need it).

Apart from the move to .Net 2.0, there are a number of changes, fixes and additions to Sloth this time around too. A massive job of refactoring has been undertaken as well - this will not really be visible to users (perhaps except in the form of new bugs), but it has really cleaned up the codebase and will make it a lot easier to add exciting features in the future. The job is not finished, however, so a lot of time will be spent on refactoring for the next betas as well. This really should be reflected in the overall quality of the application.

So apart from boring stuff, what's new this time?

New features in the search window

Instead of just searching for phrases, you can now also perform "all words" searches, as well as search for regular expressions and tags.

image

In this example we have searched for anything that contains both of the tags "babe" and "star" (these tags are defined by my personal rule set, and may or may not be anything like the ones you're using).

As you can see, there is also now a Search button in place. This means no more "I'll start searching if you haven't typed anything for 0.8s" behaviour.

Tags are now clickable in ShowInfo windows

A consequence of the above is that it is now also possible to click the tags displayed in ShowInfo windows such as this:

ShowInfo window for Star Wars III with clickable tags

Clicking a tag would open a search window like in the last paragraph, showing all shows containing the same tag.

Programmable hotkeys

In older versions of Sloth, there were just two hard-coded hotkeys; Win-S for opening the main window, and Win-K for killing all open alerts. It is now possible to define as many of these as you want. The config window GUI is pretty ugly still, but it mostly works.

image

I'm guessing there's room for improvement here. Just like in every single other piece of Sloth GUI. :)

Keep in mind that this means that the two hardcoded hotkeys are no longer there! If you want to keep them, you'll have to add them yourself!

New context menu

Sloth now features a global, semi-intelligent context menu. This menu formats itself according to what the user is clicking. In the future it will also be user extendible, meaning you can add your own options to it. Want to search a certain website for actor information? Or perhaps launch VLC with the IP address of the channel you're clicking? The possibilities are.. eh.. well, several.

Grid view enhancements

The grid view is coming along nicely, although it is still a performance slug and there are a number of bugs living large.

image

You can now right click on individual shows and get the same context menu as in the rest of Sloth (see above).

Find pictures of actors and directors

Don't you just hate it when you recognize a name but you just can't place them? Well, I do, so I made this silly little thing which locates pictures of people off the net and shows them to you. Like this here:

image

You get this function by right clicking on an actor or a director in the ShowInfo window, and then choosing "Find picture(s)..." - please note that this is a web search, not in any way under my control, so the pictures you get may not even be remotely related to the person you're looking for. It could be them, or it could be someone they worked with, a movie poster without them featured, or their stalker.

Alerts rewritten

Alerts have been completely rewritten from the ground up. They may still look almost the same, but they now use much less resources, the close button is bigger, they can be used for much more, and they don't steal focus from other applications when they appear. They also react better when scores change.

Download and install new Sloth from inside Sloth

I know a lot of you - and myself - have wanted this feature for a long time. And more software really should have it. Remember the old, annoying window that would pop up with New Sloth information and not close until you went to the forum? Well, here's the new version:

image

Check out the ugly blue progress bar at the bottom. This appears after the user presses the Install-button. Once it is done downloading, it will start the installer automatically. The installer will in turn shut down Sloth and optionally restart it after the upgrade. All you have to do is click "Next".

This feature will of course not be seen by anyone until it is time to download the next beta after this one.

Minor changes to GUI and other stuff

There is a new date picker control in windows where you can choose what day to watch (individual channel windows, Interesting Shows window, and Grid window). This is currently a simple dropdown list showing the list of dates we have TV data for.

Bug fixes

Unsurprisingly, a number of these bug thingies have also been fixed. The fixes include:

  • Even if Sloth was configured not to play an alert sound, it would try to, throwing an exception in the process.
  • Tags are now case insensitive.
  • In certain conditions, if you added a new rule, alerts would not show up for shows matched by this rule (even if their score was high enough) unless you restarted Sloth.
  • When rule changes led a show with an open alert to drop beneath the alert threshold, the alert was not removed.
  • If the config window was minimized, pressing the Config button (main window) or menu item (systray context menu) did not "unminimize" it.
  • If shows in the XMLTV file are overlapping, Sloth will now clip them so that the first show stops when the second begins.
  • If rule changes cause tags to be added/removed for a show with an open ShowInfo window, the tags display will now be updated properly.
  • If you delete a rule in the config window, the rule list/categories are no longer reset. This caused GUI annoyance.
  • A bug that caused Sloth to screw up config window GUI related to online file checking has been fixed.
  • The wizard could overwrite your rule file if you ran it after the initial install.
  • The wizard could in some cases put the main window outside the screen on low-resolution systems.

Supported operating systems

Currently, Sloth is only verified to work on these versions of Windows:

  • Windows 2000
  • Windows XP

It also installs and runs fine on Windows Vista, but if you end Sloth and then restart it, it won't run. It also won't run after a reboot - in fact the only time you can get it to run is right after the installation. This is being looked into.

Statistics

I am slowly implementing unit testing for the libraries (SlothConfig, SlothCore, SlothUtil) to make sure I can refactor code without breaking existing functionality. That is the idea, anyway. Basically, I am supposed to write a test that runs every piece of the library code with every possible piece of input, and report if it breaks. I am not there yet. But for each test I add, it is less likely something will break as a result of change. And every time I fix a bug, I can write a test to make sure it doesn't come back.

As of Sloth v0.1 beta, there are 92 unit tests passing, and none failing. If some failed, I couldn't really release it.

 Availability

If you're a beta tester, you know where to get it. If not, send me an email, and we'll see about making you one. :)