Solving Slow start up for ASP.NET websites

ASP.NET websites, especially those that don’t get a steady stream of traffic suffer from slow startup.  For sites that might get 12 evenly spaced visits a day, presumably from highly interested users, you can expect all of them to get a 15 to 60 second delay before the first page loads.

This can be mitigated by:

Pre compiling the entire web site using a web deployment project. 

Turning off debugging in web.config

Update your solution configuration to compile for “Release”

Somehow pinging the site (see below)

I did that I start up was still slow, which proves that while compiling and removing debug symbols is probably good, its not going to be noticable, at least not for startup purposes.  I think it has to do with some extremely expensive to create object, maybe the Application object or maybe some IIS object, it isn’t obvious.

Obviously, we can’t let these applications get garbage collected or your web site will appear to be down to all but the most patient of visitors.

RSS to the Rescue

To restore performance you your website, you will need to add an RSS feed to it.  Add that feed to bloglines.  The ideal RSS feed reports back the time, so that the content will change on each retrieval.  The feed should be as small as possible with no optional sections and most required sections blank or minimally filled in.

You can get the real RSS Toolkit (with asxh handlers) here (for some reason the copy I keep downloading from CodePlex lacks the ashx pattern.  Things may have changed by the time you read this)

All this page does is return the time.  Subscribe with Bloglines.com and they will ping your site every hour.

<%@ WebHandler Language=”VB” Class=”RssHTenpo” %>

Imports System
Imports System.Web
Imports System.Collections.Generic
Imports RssToolkit.Rss
Imports System.Globalization

Public Class RssHTenpo
    Inherits RssToolkit.Rss.RssDocumentHttpHandler
    Protected Overloads Overrides Sub PopulateRss(ByVal channelName As String, ByVal userName As String)
        Rss.Channel = New RssChannel()
        Rss.Version = “2.0″
        Rss.Channel.Title = “tenpo”
        Rss.Channel.PubDate = DateTime.Now.ToUniversalTime().ToString(“r”, CultureInfo.GetCultureInfo(“en-US”).DateTimeFormat) ‘”Tue, 10 Apr 2007 23:01:10 GMT”
        Rss.Channel.LastBuildDate = DateTime.Now.ToUniversalTime().ToString(“r”, CultureInfo.GetCultureInfo(“en-US”).DateTimeFormat) ‘”Tue, 10 Apr 2007 23:01:10 GMT”
        ‘Rss.Channel.WebMaster = “webmaster@email.com”
        Rss.Channel.Description = “tenpo ni”
        Rss.Channel.Link = “~/tenpo.ashx”

        Rss.Channel.Items = New List(Of RssItem)()
        If Not String.IsNullOrEmpty(channelName) Then
            Rss.Channel.Title += ” ‘” + channelName + “‘”
        End If
        ‘If Not String.IsNullOrEmpty(userName) Then
        ‘Rss.Channel.Title += ” (generated for ” + userName + “)”
        ‘End If

        Dim item As New RssItem()
        item.Title = “tenpo ni”
        item.Description = DateTime.Now.ToUniversalTime().ToString(“r”, CultureInfo.GetCultureInfo(“en-US”).DateTimeFormat) ‘”Tue, 10 Apr 2007 23:01:10 GMT”
        item.Link = “~/tenpo.ashx”
        Rss.Channel.Items.Add(item)
    End Sub
End Class

 

‘ Slow startup— be gone!

The file ‘/foo.aspx’ has not been pre-compiled, and cannot be requested.

If you put a compiled ASP.NET application into a sub folder of a virtual directory/application, you get this error accessing the child application. Compiled apps don’t like to be in a hierarchy. Create an IIS ‘application’ for the compiled website.

If you are missing a reference, you might get this error message. Think back to what the most recent DLLs that were added to your project. GAC’d dlls are a likely candidate because deployment projects and msi installer projects assume the destination has the same GAC’d file as the development machine.

 

Pedagogical API’s

This summer my project was to teach my son to program, (as it was last summer).  We created a SMS text message translator, (eg. CU L8R=see you later), a version of Hammurabi, a primitive predator-prey population simulator, and got started on an MMO as a way to explore object oriented programming.  This year, we wrote our programs from scratch, as opposed to–mostly–copying them from a book.  Last year, we translated code from an old VB for kids book into C#

Whilst writing these programs with my son, I realized I didn’t have quite the API’s I wish I had.

I wish there were some API’s that were domain specific, like Hammurabi-type-game specific.  Most of the games were easy, but had one or two damn hard parts. For example, creating a Dice class that works in ASP.NET turned out to be a major distraction from the more relevant task of understanding the difference between fields, methods, if blocks, for blocks, as so on.

If there was such a pedagogical API, it would have a bunch of functions suitable that would have desirable quantities (going up, peaking, going back down), without a multi-hour detour into how 2nd degree polynomials work. 

Anyhow, if I ever get the time I re-write these mini-applications, factor them into the hard parts and the easy parts and publish them as pedagogical API’s.

I can tell you as a geek who learned programming as a child, I’d rather have had API’s in C#, than a funky kid specific language.  Even as a ten year old I knew that logo was for sissies and real code was in Atari Basic.

Blowery Compression and MaintainScrollPositionOnPostback Errors

The blowery ASP.NET gzip module deals poorly with axd files. The axd files aren’t really files on the disk and they often are already compressed.

I don’t completely understand it, but these are the exclusions I used to get Maintain Scroll Postion On Postback to work. WebResource is related to the scroll position code, scriptresource is an ajax thing, and ebresource, I think that is yet another frameworks piece of code.

<excludedPaths>

    <add
path=ebResource.axd/>

    <add
path=ebresource.axd/>

    <add
path=*.axd/>

    <add
path=webresource.axd/>

    <add
path=WebResource.axd/>

    <add
path=ScriptResource.axd/>

    <add
path=scriptresource.axd/>

    <add
path=%.axd/>

</excludedPaths>

Portable XAMPP: Potential Uses

XAMPP is like having a little web host company on your thumb drive. If you did have a WAMP (or LAMP) application you wanted to run, it would make more sense to put it on your web host instead of a thumb drive. But since we can, let’s try to rationalize it.

Advantages
Localhost is faster.
Localhost is more private.
Localhost is disconnected.
Localhost doesn’t cancel your account when you go-over your download limit.
Localhost is free. If you are the only one using your web host account, maybe you should just blog to your thumb drive.

The above are all handy for using Zena as a streaming media player, which would be slow, not 100% available and expensive in terms of bandwidth if you put it on your hosted account. On the other hand, given that you still have to use Itunes or Windows Media player to play the streaming files, you might as well use then to read the files direct from the thumb drive—the only difference would be the folder browsing.

I couldn’t bring myself to install any personal information management (PIM) type applications. I’d rather have those on a connected server. If data loss didn’t worry you, then you might consider time trackers, address databases, etc. These PIM apps were never very compelling before web 2.0, now they are much more compelling as multi-user social applications.

Speaking of folder browsing, most web-based file browsing system suck, but if one existed that didn’t suck, it would be nice to have that on portable XAMPP. Right now if you want to search your thumb drive, you are stuck with the host OS’s search. IF you use Fast File Search, you can index your thumb drive—indexing it via the FileZilla FTP server is probably superior, since the drive letter will keep changing if you index file system directly.

XAMPP is handy as a development environment. If you are a typical geek, you spend 8 hours in front of your work machine, but outside of the office you might be at your home machine, a laptop or visiting family when you have time to write code. Install Flyspray to maintain a more secure and better performing bug tracker. I still don’t know of a good portable source control server, but you can use RapidSVN as a portable client. You might not want to program in PHP, the asp classic of the curly braces world, you can get portable ruby or Instant Rails. (Instant rails comes with yet another copy of MySQL and Apache, so if you are already using XAMPP you will have a merging project to do.) And if you are really ambitious, you can try to get ASP.NET to work on XAMPP. Try mod_aspdotnet.mo or Grasshopper.

Disadvantages
You could lose it.
It isn’t globally available like your web host.

Notes: Hosting Multiple ASP.NET Applications in one place

I have a hosted account on a shared machine.  This means I have sub-optimal access to IIS (a web-app control panel that drives buggy and poorly documented asp scripts).

I have two applications I want to host in one place (I’m use the word place on purpose), because I don’t want to double my hosting fees just because I have a tiny application that isn’t thematically connected to my favorite application.  My favorite application is a movie club web site, the other site is a launch page for a custom google search.

I bought two domains and began working on pointing them at my site.  The finally found a separate control panel that let me pick the IP address for my site.  Since I have a static IP, I pointed my new domains at my static IP.  Now I get, “ns5.dnsserver8.com returned (SERVFAIL)”, which may just mean I need to wait two more days.  This could be a very slow bug to trouble shoot. In the meanwhile….

If I want the domains to resolve to different folders on my server, I have to double my hosting fees.  That isn’t good.  So I moved my applications into two folders and put a Default.aspx file at the root that inspects the requested domain name and forwards the browser to the correct subfolder.

This leads to web.config errors, because the redirection application and my two sub folders also have web.config files.

Single application.  I could put the everything into one visual studio project, with one web.config. I don’t like this solution because the ASP.NET 2.0 application has only one Profile/Membership, etc. object and database per application. 

Multiple applications.  One in the root, two in subfolders.  The root application has a minimal web.config to minimize cascading. 

If an app in a subfolder is precompiled, it just serves the “This is a marker…” message and no compiled pages.  I even tried putting the PrecompiledApp.txt file in the folder and the parent folder, no joy.  I even tried moving the compiled files to the parent bin folder, still no joy.  I so I compiled the parent app, and got the error “The file default.aspx has not been compiled…” This normally means a reference is missing.  So I tried putting the compiled dll’s in the parent folder’s bin, still no joy.  A pre-compiled application, it seems, must be entirely in it’s own IIS application.

Creating IIS “Applications”.  I’m using WebHost4Life, so I use their “Total Control” control panel with command path of : “Site Admin: IIS Manager: Set .NET App: [Go] (my domain) : (click on gear for child folder which hold asp.net apps)”

Finally, joy.  The parent project works, the child projects work and it doesn’t look like there is any significant web.config cascade problems.

Now solving the domain name problem, that will take longer….

[Update!]

Domain name problem solved.  When you buy a domain name, two machines need configuration, the domain name servers of the company that sold the domain and the domain name servers of your web host company.  I initially tried to tell my domain name seller to use my static IP–no joy.  It wasn’t until the script that updates my web hosting companies two domain servers finally succeeded without error that the domain names started to work.  Afterwards, I had to set up an ASP.NET application for each folder for each domain name and voila! They all work.  I have no idea what the isolation is between one ASP.NET application and the next, but that is Okay.

Mod_aspdotnet: Some investigations

Mod_aspdotnet is an semi-abandoned application. The latest snapshot can run ASP.NET 2.0 on Apache 2.2, I’ve done it once against a DevSide WAMP stack: (http://www.devside.net/ ) It was pretty cool to see ASP.NET run on Apache. Why?

  • Apache can run on a thumb drive, IIS can’t
  • If asp.net ran on apache on a thumb drive, then web apps could be run in a disconnected location off a thumb drive
  • Admittedly, you’d need a host machine with .NET already set up and administrator rights to install the Apache.Web.dll. So you could take home your development environment, but not do development at say a locked down library or internet cafe machine.

I tried to reproduce the trick on a second machine with XAMPP, no joy, permanently stuck with:

[notice] mod_aspdotnet: CorBindToRuntimeEx has loaded version v2.0.50727 of the .NET CLR engine.
[error] (-2146304894)Unknown error: mod_aspdotnet: Could not create the .NET interface for the Apache.Web.HostFactory.
[crit] (-2146304894)Unknown error: mod_aspdotnet: Failed to start Asp.Net Apache.Web host factory

The error happens what appears to be a call to a constructor. So it behaved as if the class couldn’t load. So I tried uninstall/reinstall. No joy. I tried manual regasm/gacutil. That reported success, but still no joy, the error persists. I tried comparing httpd.conf files, no significant difference.

If I removed the “load mod_aspdotnet” from the httpd.conf, apache ran, so I know everything else was working.

I tried theories involving code access policies and ntfs permission, but no luck. I turned off IIS on a theory that IIS was interfering, no luck.

Some factoids I’ve learned: the release files are an MSI. They can be unzipped and examined using TotalCmd. I also checked out the MSI using orca, which wasn’t too illuminating. There is an Apache.Web.Dll, which is a COM object that must be registered with regasm and then put into the GAC with GACUtil. The installer does this for you. The installer also seems to want to know where the apache folder is, so it can put the mod_aspdotnet.mo into the right folder and two more files. The source code can be downloaded, but it doesn’t have enough files to compile by a naïve non-C++ developer like myself. You can also get a view of it using reflector and if you set a reference to it (it is a COM object), you can browse the same with the object browser.

I know, if I had tried to get ASP.NET 1.1 working, I probably would have had more success, but I have no interest in working with 1.1 unless I’m doing maintenance development.

Who are you and who do you know?

This is an interesting problem somewhat related to authentication and authorization. It is screaming for another name starting with ‘a’ and ending in ‘ation’. It asks the question, who are you? Who do you know? Can you prove that you know them through some sort of reciprocal authentication process? What rights do you grant your various relationships?

Why Do We Care Who you Know?

This is a special case of authorization. If you have verifiable claims about who you know, then that information can be used to authorize you see information concerning your friends and collegues. This is part of the trend of putting users in control of their own information. The alternative would be for an overworked administrator to create a authentication group, say a Window group or an Azman group, which has the special right of being able to view your data. This would mean an application of one million users would have one million Azman or Windows groups, an administrative nightmare and the administrator would have to use an out of bound method (like making phone calls) to verify the relationship.

This is also a special case of authentication. A friends list is most interesting when you I know you because you gave me a secret which lets me correlate the person I created the identity with subsequent authentication attempts. I know you know your friends because you gave me a secret which matches the secret I got from one of your friends. For example, if you can tell me the sum of the digits in your email address and your fiends email address, maybe I can believe you without letting you know what the true email address of your claimed friend is. Of course, there are better cryptographic methods for this.

Current Technologies

Current technologies focus on public claims and not much on the verification of the claims.

You try to authenticate me and ask, “Who are you?” I give you my OpenId or InfoCard. I send back some claims and maybe an hCard.

You ask for some claims, “Who do you know?” I give you one of the following: a FOAF document, bunch of XFN links, a XOXO/OPML list. Ugh.

  • FOAF– hard to make by hand, no browsers can read it. This answers, “Who’s in your email address book?”
  • XFN– doesn’t support time, no way to prove relationships short of spidering the links in hopes of finding a reciprocal XFN link. This answers, “Who amongst your friends have a URL that is associated with their identity?” I wouldn’t easily be able to make a meaningful XFN link to my grandmother.
  • OPML is just an hierarchical list structure, not specific to a friends list and is mostly used for blog readers, so a OPML list answers, “Who’s blog do you read?” Somehow this format seems redundant, since XML already is a hierarchical data structure. XOXO is the microformat of the same.
  • hCard — This is a business card, also answers, “Who’s in your address book?” (It is the microformat of the vCard standard)

Proof of Relationship. In FOAF, proving relationships requires knowing something secret about your friend, say their email address. You publish a crytopgraphic hash of your friend’s email address, the friend does the same. In XFN, your friends need to be able to publish html pages with XFN. The relying party would query both domains and see if they match. Authentication is as good as the internet domain name system, so an XFN relationship is really between the users represented by the Whois database, which is mostly minimally authenticated people. Worse, many, many people might have the ability to publish to a given domain. OPML has the same problems as XFN in proving a reciprocal relationship. hCard lacks a way to uniquely link two hCards. I publish my hCard with the name Matthew Martin, which is shared by 100′s of people. To form a link you’d need to do a complicated fuzzy match of address, phone number, name and other address information.

Claims. Out of FOAF, XFN, OPML, hCard, only XFN makes claims about the type of the relationship. OPML implies a bogger-reader relationship. FOAF implies only a friend relationship, the only other category is “not-friend” indicated by leaving someone out of the FOAF file. hCard implies no particular relationship at all. I could publish a list of hCards on my website and there is no way to know what the implied semantic meaning of the relationship is. Maybe it’s just a list of lawn mowing companies I’m considering hiring, maybe they are my best friends.

Rights Granting. None of these say anything about what it means for someone to be a friend, so right now this is handled in an ad hoc fashion. For example, Flickr lets you grant different rights to the public versus your friends list. The rights would have to be simple, maybe Read, Write, Update, Delete. The contexts would also have to be simple, maybe a URL for a context. What would rights granting look like if one of the above were extended?

- Friend List
—– John Doe
———-Friend
—– Jane Doe
———Met
-Rights
—–flickr.com
———Read–(photos)– Friends
———Read–(vacation photos)– Verified Friends
—–blogger.com
——–Write–(comments), Met
——–Write–(posts), Family
—–amazon.com
———Read–(wishlist), Friends, Family
———Write–(recommendations)–Met

The system would have to be extensible to rights that don’t fall into the Read/Write/Update/Delete categories and right would need some domain restrictions. The format would have to be extremely simple to make and robust to validation errors.

Tools. None of these have very good tool support, but the tool support is better than any proprietary technique you can think up. XFN and hCard can be browsed with any browser. FOAF is going to languish until browsers have support for RDF documents in general. In theory, they all can be parsed as XML.

Ubiquity. Formats that rely on domain control mean users need to open accounts on ClaimId or the like to get a page associated with themselves. Email is almost ubiquitous. Cell phone control does a better job of identify one person, but is not as ubiquitous. Domain control is mostly restricted to super users and geeks. SSL is restricted to people with spare cash and are geeks. SSL certificates that actually verify an identity claim to any degree cost a lot more money and require the relying party to check the SSL certificate issuer’s issuance policies, not an easily automatable process. Of these, only ClaimId or email control are in the grasp of my mother.

Privacy of Friends. Maybe I don’t want my friends URL, email address, phone number and address to be misused. FOAF addresses this issue, but doesn’t require users to protect their friends from spam. XFN assumes that the URL of your friend is public. hCard makes no effort to address the privacy issue. A good friends list would let the user decide if he trusts the world with their claims about their friends, a hash of their friends claims, an encrypted copy of the claims (ie. the relying party can store my friends data, but not read it), or maybe I entrust the relying party with the identity but not claims about my friends at all.

Any relationship verification system needs to be able to prevent mischief. Any system that can be exploited, will eventually be overrun with spam and other attempts to get rich quick.

Games people play with the question

Aspirational Claims. Claiming someone is a friend when they are not a friend at all. Fortunately, my best friend Bill Gates doesn’t fall into this category. To prevent this, you’d have to get a friends list from both candidates and find the reciprocal claim.

Misrepresentation. You have a relationship, but you misrepresent it. They met you, but they are not a close friend like you claim. If the relationships fall on a neat continuum, you could pick the minimum relationship claimed by both. For example, if one person claims the other is a brother, but the other only claims they are kin, then the verifiable claim is mere kinship.

No one can be expected to make a claim that will restrict their rights. When an administrator puts people into groups, he has no qualms about putting people in the the “Limited user” group. Who will make claims that will give them less access to the people they know? If I claim I’m a best friend, I get access to the juicy gossip. If I claim I only met someone, I get just the public information. Any one guess what I will claim? This is misrepresentation again. Again, to prevent this you’d have to calculate the minimum reciprocal relationship.

The relying party relies on stale information. They were your friend, but they aren’t any more. Reciprocations are only reliable if friends lists have start and stop dates and a duration that the claim is good for. For example, if John Doe is my friend, I need to record him on my friend list as a friend since 2004 and this claim is good for a year.

Good Manners. No one wants to be hostile, so people will over-reciprocate and claim a stronger relationship than they would want to if you get them to privately explain the extent of their friendship. For example, if John Doe says I’m his best friend forever and I think he’s just an acquaintance and only for the next year, If it is important to know the true extent of a relationship. If you make people rate their relationship on a scale of 1 to 10, people will be biased towards 10. If you ask binary questions, there will be less of a bias due to politeness.

The relying party needs to know the strength of the relationship, but the two claimants don’t want to reveal the fact to the other person. This means public friends lists will be dogged by good manners biases. If the friend list was secret and the user got back limited information on friends list based authorization check, users would be more likely to be honest.

Humor. The XFN romance attributes appear to be used for humorous intent. All developers who write sample XFN links claim they have a crush on Don Box. Surely some of them must be joking. Real developers have a crush on Scott Gu.

Unidirectional claims. These are unverifiable, so what can they be used for? Who can verify if I have or had a crush on Kylie Minogue? If I and Kylie Minogue were in the same database, would she grant extra rights to her account data to people who claim a crush on her? (Or more likely, restrict rights to deter stalkers?)

Unauthenticated Other Friend. You authenticate a user. The user claims he has Kim Cameron as a friend. But this guy claims that Kim Cameron friend list can be found at KimCameron.ru, which is actually a domain controlled by the party claiming to be a friend of Kim Cameron. So no relationship claims should be accepted by the relying party

Some Characteristics Of a Commercial Grade Relationship Architecture

Uses private friends lists. E.g. “If a relying party asks, I will let them know that John Doe is someone I barely know, but please don’t tell John Doe the details, just give him a yes/no on an authorization check”

Uses authenticated friends lists. E.g. “John Doe is my friend, you know, they guy in your authentication store that sent you his friend list”

Relies on reciprocal claims. E.g. “John Doe is my friend, just go check his friends list”

Has time a time dimension. E.g. “John Doe was my co-worker from 2000-2004.” “Jane Doe is a friend since 2000″ “I am willing for these claims to be valid for the next six months”

Has a rights list. E.g. “These are my friends and when I say friend, I mean they can read my blog and comment. When I say family, I mean they can also write blog entries.”

Has a enterprise grade API, maybe a SOA based server based on WCF.

Some Characteristics of a Good Enough Relationship Architecture

Relies on public friends lists. Authenticating friends to a private store is expensive and require co-ordination.
Rights granted based on level of friendship and quality of claim. Most claims will be unreciprocated and unverified. Authenticated friends should be differentiated from unauthenticated. Likewise, unreciprocated are differentiated from reciprocated. If transaction costs are important and it is not important to guarantee that people don’t play games with the system, reciprocated claims based on domain control might be good enough.
Based on plain old semantic HTML. HTML has a universally available data viewer. RDF and XML don’t.
Has a simple API. Maybe a some HTML GET commands (REST) or some Javascript checks. Obviously Javascript would only be useful for data that is already public. For example, a Javascript API might use my friends list to filter a public photo RSS stream down to just my co-workers photo’s.
Works with google and other ‘found API’s. For example, the “who link’s to me” could be used as a way of verifying reciprocal claims.

TimeSnapper: A Review

Free Version
The trial version is not bad, I used it for quite a while to remind myself what time I started working.

Paid Version
I now have the paid version ($40/each). Every day I check my productivity score, which really just is the ratio of time spent in work applications – time spent in browser, time spent in front of the computer and start and stop times.

Benefits
Time spent in front of the computer has a different quality to it and it’s hard to estimate how long you are in various applications. Time spent in front of the computer also has a lot of ‘same-ness’ which makes it hard to remember what you were doing. Time snapper gathers a lot of data from which you can infer what you were up-to.

It is extremely easy to use TimeSnapper data to calculate a billable/not-billable split and total time worked. Doing a spit between time spent on one client vs another is more challenging because you probably use the same set of applications to do work for each client, but with the movie of the day, you can get an hour by hour break down with just 8 clicks.

The customer support is fantastic. The code base is under active development and the developers are responsive to their customers.

There is a side effect to screen recording, namely you can recover lost data. TimeSnapper even has an OCR tool for extracting text from screenshots.

Usage Advice
Put all your time snapper files into an encrypted TrueCrypt disk (or turn on EFS if you have windows XP Pro). Plain text passwords will show on your screen and pose a security risk. Also, having a recording of everything you do will make you look worse than other employees should management get a hold of your recording because there will be proof that you visited a non-work website, while for other employees there will only be a suspicion.

For versions up to 2.4.3.0, watch out for low disk space errors. If TimeSnapper can’t write to disk, it will silently log the problem, but not report that it is no longer recording.

Wish List
I wish I could get multiple computers to record to the same TimeSnapper directory, for example, if I work on three remote desktop sessions and two virtual machines and two different workstations, they should all record to the same shared encrypted folder. Also, there isn’t a clear strategy for profile switching. If I switch from an administrator to limited user profile on one machine, I should be able to record them as a single stream. This may be possible with the free version, but I haven’t tried it. The pro version seems to collect meta-data in addition to the screenshots, so there might be contention for that file.

Encryption should be an automatic option, even if it is just the built in Windows EFS

Internet usage tracking is not usable, but competing products like pageaddict are also usable. What I mean is that a typical browsing session involves visiting dozens of sites for small periods of time, many of which you will never visit again. Individually assigning all of these to billable/not-billable categories or even assigning them to individual contracts is not practical. Some sort of automated split, say between intranet vs internet would be useful, or some report that shows all sites with more than 10 minutes of total usage, vs all sites with less than 10 minutes usage each lumped together would be more usable.

I wish I could view the day in hour by hour screen shots in a single screen, ie. The 8AM screen shot, 9AM screen shot, 10AM screen shot, etc. Then I could visually figure out what client I was working for at hourly intervals.

I wish it could be installed to my USB drive.

Recommendation
Everyone who has to do a time sheet or wants to be more productive should use TimeSnapper. Since getting it, my productivity has gone up.