The Daily Parker

Politics, Weather, Photography, and the Dog

Mumbai

Why? Why? Why?

The only thing that makes sense to me: someone wants to start a war. I hope to all humanity India and Pakistan keep their senses over the next few days. So do the Indians and Pakistanis, I expect.

Buy Nothing Day

Today (in North America; tomorrow worldwide) is the 17th Annual Buy Nothing Day, "sponsored" by Adbusters:

Suddenly, we ran out of money and, to avoid collapse, we quickly pumped liquidity back into the system. But behind our financial crisis a much more ominous crisis looms: we are running out of nature… fish, forests, fresh water, minerals, soil. What are we going to do when supplies of these vital resources run low?

There’s only one way to avoid the collapse of this human experiment of ours on Planet Earth: we have to consume less.

It will take a massive mindshift. You can start the ball rolling by buying nothing on November 28th. Then celebrate Christmas differently this year, and make a New Year’s resolution to change your lifestyle in 2009.

It’s now or never!

LINQ to FogBugz fun

Most Daily Parker readers can skip this (long) post about software. But if you're interested in C# 3.0, LINQ, or FogBugz, read on.

I use FogBugz's time tracking tool to provide tracability in my billing. If I bill a client 2.75 hours for work on a bug, I want the client to see the exact times and dates I worked on the bug along with all the other details. And because I track non-billable time as well, and I often work in coffee shops or places like the Duke of Perth, I wind up with lots of tiny time intervals that I have to aggregate to produce a bill.

My time sheet today, for example, looks like this:

Start End Case Title
7:11 AM 7:23 AM 901 Walking the dog (November)
8:18 AM 9:32 AM 950 FogBugz to LINQ project
9:32 AM Stop Work 902 Blogging (November)

But what I need for QuickBooks looks like this:

Case Hours
901: Walking the dog (November) 0.20
950: FogBugz to LINQ project 1.23
902: Blogging (November)  

(The last bit has no time because I'm still working on it.)

This is the perfect kind of thing to waste a few hours on while learning some new programming tricks. (Code here.)

First: the entity

To use LINQ to SQL in its pure form, you first have to create entity classes that pretty much exactly mirror the tables you're interested in. My target, the FogBugz timeintervals table, yields an entity that looks like this:

[Table(Name="timeinterval")]
class TimeInterval
{
	[Column(Name="ixInterval",IsPrimaryKey=true)]
	public int Identity;

	[Column(Name = "ixPerson")]
	public int PersonId;

	[Column(Name = "ixBug")]
	public int CaseId;

	[Column(Name = "dtStart")]
	public DateTime StartDate;

	[Column(Name = "dtEnd")]
	public DateTime EndDate;
}

Because I'm interested in the aggregate time spent on each case, I also created a simple structure to hold that info:

struct AggregateInterval
{
	public int CaseId;
	public double TotalHours;
}

Second: the console app

To use LINQ to SQL, you need to include a reference to the System.Data.Linq assembly, and import the appropriate namespaces:

#region Copyright ©2008 Inner Drive Technology

using System;
using System.Collections.Generic;
using System.Data.Linq;
using System.Data.Linq.Mapping;
using System.Linq;

#endregion

namespace InnerDrive.Research.FogBugz
{
	class Program
	{
		static void Main(string[] args)
		{

Next, set up the data context:

DataContext context = new DataContext(" (your connection string) ");
context.ObjectTrackingEnabled = false;
Table<TimeInterval> table = context.GetTable<TimeInterval>();

(I turned off object tracking because this is a read-only application. Setting ObjectTrackingEnabled to false improves performance, but the data context will throw an exception if you call DataContext.SubmitChanges().)

I actually need two queries, one to get the table rows and another to aggregate them. The reason for this is that my aggregation depends on getting the total hours each interval represents; LINQ to SQL won't do that. Here's the first query:

// FogBugz stores time as UTC; I want the time for today in Chicago, not London
DateTime startDate = DateTime.Today.ToUniversalTime();

var intervals =
	from interval in table
	where interval.EndDate <= startDate.AddDays(1) &
		interval.StartDate >= startDate
	group interval by interval.CaseId
	into grouping
	select grouping;

The second query does the aggregation, transforming the first query into an IEnumerable<T> and returning AggregateInterval structs:

IEnumerable<AggregateInterval> aggregation =
	from grouping in intervals.AsEnumerable()
	select new AggregateInterval
	{
		CaseId = grouping.First().CaseId,
		TotalHours = grouping.Sum(t => t.EndDate.Subtract(t.StartDate).TotalHours)
	};

Neither query has fired yet, by the way. That's another cool thing about LINQ. Both queries fire when I output the data, which is trivially simple:

foreach(var item in aggregation)
{
	Console.WriteLine(string.Format("Case {0} = {1:0.00}", item.CaseId, item.TotalHours));
}
Console.ReadLine();

That's it. Share and enjoy.

These just in

I've just gotten from Amazon two of the best movies ever made, worth the extra few bucks for Blu-Ray:

That said, I'm under my dad's orders to finish Deadwood before watching anything else...

Night flight last Sunday

I had to scrutinize my logbook to figure out when I last flew at night: 26 April 2006, in Nashua, N.H. So I took a flight instructor with me this past Sunday to get "recurrent." (Regulations require that pilots make three full-stop landings at night—further defined as 1 hour after sunset until 1 hour before sunrise—within 90 days in order to carry passengers at night.)

I had a good flight, they can use the airplane again, the instructor enjoyed flying with someone who knew how to fly (as opposed to a pre-solo student), and Chicago Center almost flew a jet up my butt. You can see the last bit in the KML, where I do two 360° turns, one of them at a mile-and-a-half short final. The jet got within 4 nautical miles of me before calling Chicago Executive Tower, which isn't illegal, but did make me a bit uncomfortable watching the TCAS. (Yes, the flight school now has a training plane with a TCAS. They are that cool.)

Efail?

Via Jeff Atwood, San Francisco-based programmer Tantek Çelik's definition of Email as "Efail:"

All forms of communication where you have to expend time and energy on communicating with a specific person (anything that has a notion of "To" in the interface that you have to fill in) are doomed to fail at some limit. If you are really good you might be able to respond to dozens (some claim hundreds) of individual emails a day but at some point you will simply be spending all your time writing email rather than actually "working" on any thing in particular (next-actions or projects, e.g. coding, authoring, drawing, enjoying your life etc.) and will thus experience a productivity failure. The obvious solution is to push as much 1:1 communication into 1:many or 1:all forms such as public blogs and wikis. ...

think two specific reasons in combination account for most of the problem. [First,] point to point communications do not scale. ...

The second reason that I think email is becoming a worse and worse problem is directly due to its higher usability barrier, that is: Emails tend to be bloated with too many details and different topics.

The End of Wall Street's Boom

Essay by Liar's Poker author Michael Lewis, in December's Conde Nast Portfolio:

In the two decades since [1989], I had been waiting for the end of Wall Street. The outrageous bonuses, the slender returns to shareholders, the never-ending scandals, the bursting of the internet bubble, the crisis following the collapse of Long-Term Capital Management: Over and over again, the big Wall Street investment banks would be, in some narrow way, discredited. Yet they just kept on growing, along with the sums of money that they doled out to 26-year-olds to perform tasks of no obvious social utility. The rebellion by American youth against the money culture never happened. Why bother to overturn your parents' world when you can buy it, slice it up into tranches, and sell off the pieces?

Word of the Year

Via Calculated Risk, Merriam-Webster has declared "bailout" its word of the year:

The word "bailout," which shot to prominence amid the financial meltdown, was looked up so often at Merriam-Webster’s online dictionary that the publisher says it was an easy choice for its 2008 Word of the Year.

The rest of the list is not exactly cheerful. It also includes "trepidation," "precipice" and "turmoil."

"There's something about the national psyche right now that is looking up words that seem to suggest fear and anxiety," said John Morse, president of Springfield-based Merriam-Webster.

Go figure.

The competition

Because the ParkerCam just isn't enough for some people, I commend to you the Puppy Cam. Yes, they are adorable, I have to admit. And more technologically advanced: live, streaming video vs. a once-a-minute static JPEG. But I have no idea who these puppies are. They might even be Communists, or worse, the way they're all in one bed together like that.