Reviving an old calendar script

Sometimes things work out better than you had any reason to hope. My older son’s swim season just started, which means it’s time to enter his meet schedule into my calendar. Given that all the team parents have smartphones, and all the teachers and administrators have laptops with coordinated calendar software, you’d think we’d be sent a link to a swim-schedule.ics file that would automatically populate our calendars. You’d think that, at least, if you’d never dealt with school IT staff before. These are people who think they’re doing us a big favor by putting the schedule up as a table on a web page.

When I was using TextMate, I had my own calendar events bundle that would, among other things, convert a Markdown table-like description of events into an .ics file for importing into iCal. I described the first iteration of it here and the later, bundled version here. The input is a series of lines that look like this:

Swim meet|12/07/2013 05:30 PM|3.00|Evanston Township HS|vs. ETHS
Swim meet|12/08/2013 01:00 PM|3.00|NCHS|vs. Hinsdale Central
Swim meet|12/10/2013 05:00 PM|3.00|NCHS|vs. W. Aurora/Glenbard Coop


where the pipe-separated fields are the event name, start date and time, duration in hours, location, and notes. The advantage of doing it this way is that entering a schedule in this form usually takes less time than entering it into iCal or my phone one event at a time. Even better, when the schedule is presented as a table in a web page or (shudder) a Word document, it can be copied, pasted into a plain text file, and massaged into the pipe-separated format with just a few find-and-replaces.

Since leaving TextMate last year, I haven’t had this bundle available to me. During last year’s sports seasons, I just did without a calendar because I thought redoing the commands for BBEdit would be difficult. I was wrong.

What I’d forgotten was that TextMate commands typically use standard input and standard output, just like a BBEdit Text Filter. All I had to do was copy the code from the bundle plist file on GitHub

paste it into a new document, and save it in BBEdit’s Text Filters folder. I didn’t have to make a single edit to the script:

python:
1:  #!/usr/bin/env python
2:  import sys
3:  from dateutil.parser import parse
4:  from dateutil.relativedelta import *
5:
6:  print '''BEGIN:VCALENDAR
7:  VERSION:2.0'''
8:
9:  for line in sys.stdin:
10:    # Assign the fields; skip if there aren't 5 fields.
11:    try:
12:      event, sdtime, dur, place, desc = line.strip().split('|')
13:    except:
14:      print '!' * 20 + ' This event has the wrong number of fields'
15:      continue
16:    # Parse the start time; skip if it's not formatted correctly.
17:    try:
18:      start = parse(sdtime)
19:    except:
20:      print '!' * 20 + ' This event has a bad start time'
21:      continue
22:    # Distinguish between timed and all day events; skip if the duration is bad.
23:    if dur == 'all day':
24:      end = start + relativedelta(days=+1)
25:      dtstart = ';VALUE=DATE:' + start.strftime('%Y%m%d')
26:      dtend   = ';VALUE=DATE:' +   end.strftime('%Y%m%d')
27:    else:
28:      try:
29:        end = start + relativedelta(hours=+float(dur))
30:        dtstart = start.strftime('%Y%m%dT%H%M00')
31:        dtend   = end.strftime('%Y%m%dT%H%M00')
32:      except:
33:        print '!' * 20 + ' This event has a bad duration'
34:        continue
35:
36:    print '''BEGIN:VEVENT
37:  DTSTART:%s
38:  DTEND:%s
39:  SUMMARY:%s
40:  LOCATION:%s
41:  DESCRIPTION:%s
42:  END:VEVENT''' % (dtstart, dtend, event, place, desc)
43:
44:  print 'END:VCALENDAR'


I could look at how easy this was and think what a dummy I was for not doing it sooner. I prefer, in my Panglossian way, to look forward to the time I’ll be saving from now on.

It’s a trap!

My family lives in a two-story house with an attached garage. At the junction of the main part of the house with the garage, the slope of the garage’s roof runs up into the eave of the main roof, and for reasons I’ve never understood, there’s an opening in the soffit under the main eave at that intersection. When we first moved into the house twenty years ago, I went up on the garage roof and covered the opening with screen because I was afraid birds would go up through it and nest in our attic. The screen held for twenty years.

In the past few days, however, we’ve heard some suspicious noises. At this time of year, squirrels are always running across our roof as they go into that manic phase before winter hits, but these sounds seemed closer than the roof. I poked my head up in the attic a couple of times and never saw any evidence of animals nesting. Still, the noises were just too close.

When I saw that my protective screen had been pulled out of place, I knew the jig was up. I really don’t feel like climbing the roof at this time of year, so I’m hoping I can trap whatever critters are getting up in there, move them out of the neighborhood, and fix the screen in the spring. Today I put a couple of traps up in the attic, baited with bread and peanut butter. It wasn’t long before I heard frantic metallic rustling.

My expectation was that I’d find a squirrel in one of the traps; my fear was that I’d find a racoon instead. I wasn’t afraid of the racoon itself. Our attic is unfinished with blown insulation over fiberglass batts. To get from one place to another, you have to step carefully on the ceiling joists—a step in the wrong place will put your foot though the drywall. My fear was that I’d lose my balance walking back to the attic entry hole while carrying a cage with a heavy, angry, thrashing racoon.

Luckily, it was just a squirrel, and though he was angry and thrashing, he wasn’t heavy enough to throw me off balance. But when I reached the scuttle hole to come down out of the attic, I had a new fear. The cage, one of Havahart’s medium-sized live-animal traps, was too big to fit through the hole without being tilted.

(Image from Havahart.)

In my imagination, one of the doors would open as I tilted the cage and came down the ladder, and instead of having an angry squirrel in a cage in my attic, I’d have an angry squirrel running all through my house. But thanks to the fine work of Havahart’s engineers, the door held and I got the squirrel out of the house and into the trunk of my car without incident.

My first thought was to take him to the same place I take the chipmunks we trap and release: a nearby entrance to a local prairie preserve that just happens to be adjacent to the house of an old boss of mine. I’ve released countless chipmunks in his yard near that entrance over the years. But that’s only about half a mile from my house, and a squirrel has a bigger brain than a chipmunk, so I decided to play it safe and go to another of the preserve’s entrances a couple of miles away. The squirrel shot off into the preserve as soon as I opened the trap door.

The trap is rebaited and back up in the attic. I know at least one other squirrel has been up there because as I was picking up the cage to take away the first one I saw the bushy tail of another poking up through the now-unscreened opening. I hope it takes the bait before bedtime. If not, I’m going up to remove the trap. The last thing I want is to have my wife punching me awake at 3:00 am to go up and get it.

Dipping my toes into Keyboard Maestro

I know Gabe will laugh at me because of this, but I’ve finally succumbed to the temptations of Keyboard Maestro.

It’s not that I didn’t understand its appeal before, but as I’ve gotten older I’ve gotten more particular about which tools I invest my time in learning. I want them to have a depth that rewards that investment. While Keyboard Maestro isn’t as deep as a programming language, it comes pretty close, a fact I’ve come to learn largely through Gabe’s many posts.

I’m starting out simple. I wanted a set of keyboard shortcuts that would switch between Sort by Name and Sort by Date in both the Finder and Transmit. I use Transmit in a way that may seem odd to most people. Instead of the traditional double-pane view with the remote server in the left pane and my local disk in the right, I use it in single-pane mode, showing only the remote server. I drag files to and from it as if it were a Finder window.

Normally, I have my Finder and Transmit windows configured for List view with the files sorted by Date Modified. Sometimes, though, it’s easier to work with the files sorted by Name, so keyboard combinations that switch between the two—and work the same in both apps—would make my life a lot easier.

Here’s the macro for sorting by date in the Finder, which I have bound to ⌃⌥⌘D:

And here’s the corresponding macro for Transmit, with the same binding:

Simulating a mouse click for the Finder macro is a little dicy. If I hide the sidebar or change significantly the width of the name field (which is the only field I have to the left of the date field), that click will go in the wrong spot and the macro won’t work. There’s an command in the menu, but I don’t like the way it breaks up the list into sections. An advantage of simulating a click is that I can toggle between ascending and descending sort by pressing ⌃⌥⌘D repeatedly.

The Transmit macro is more robust to changes in window geometry because its column headings are recognized as buttons and can be addressed as such.

Update 12/5/13
A few people on Twitter have suggested using the Option version of the Finder’s command (or the keyboard equivalent, ⌃⌥⌘5). This is a robust solution, in that it works no matter how I have my Finder window configured, but it doesn’t allow the ascending/descending toggle. Given that the Transmit version of the macro does toggle and that I want the two macros to work the same, I think I’ll stick with the simulated click for the Finder.

But I thank Frederik, Alex, and Ben for letting me know that the Option key brings back the old, unsegmented behavior. I probably should’ve guessed that, but I didn’t.

As I think about it, I could probably write an AppleScript that would be robust and toggle the sort. It probably wouldn’t be as fast, especially if AppleScript isn’t already in memory, but it’s worth looking into.

I have similar macros for Sort by Name, each bound to ⌃⌥⌘N. I’m sure you can guess what they look like: the Finder macro clicks at an X value of 200 instead of 500, and the Transmit macro presses the Name button.

Don’t worry, I won’t typically waste your time with posts on macros this simple. I know most of you are way ahead of me.

Touch ID

I’ve been using Touch ID since I got an iPhone 5s in mid-October. Generally speaking, I like it, and I find it faster than the old swipe-and-passcode method, but I’ve felt compelled to reteach it my fingerprints twice already. I know this sounds impossible, but its recognition of my prints seems to decay with time.

I rescanned my fingers this weekend, and Touch ID has been amazingly fast and accurate since then. Just as it was when I first got the 5s, and just as it was a few weeks later when I rescanned my fingers for the first time. Just before each rescan, though, I was so frustrated with Touch ID I felt like throwing the phone across the room.

Sometime in early November I turned Touch ID off and went back to my old settings: four-digit passcode, but no need to enter the code if the phone’s been off for less than an hour. I tried this for nearly a week before giving up. Forget about the times I had to enter my code—just having to swipe to unlock was more than I could stand. Even bad Touch ID was better than that.

So am I fooling myself, or is it possible that Touch ID’s recognition gets worse with time? I don’t know enough about how it works to hazard a guess, but if the software is continually updating its internal “picture” of my prints with each scan, decay is at least possible.1 We tend to think that gathering more data always increases our understanding, but it doesn’t always work that way.

Google, the Oliver Twist of data, has had to adjust its Page Rank system because it had been gamed by link farms to give high rankings to shitty websites with weak, derivative content (but lots of ads). Even better, though, is the story of the Google Translate API, which was shut down a couple of years ago, because the indiscriminate use of it had reduced the quality of the corpus Google used to learn from. In a nutshell:

1. Crummy Google translations were being posted to the web.
2. Google would then scoop up those translations and add them to its knowledge base.
3. Google’s translation engine got stupider.

EMpTy Pages, in the aforelinked post, called this “polluting its own drinking water.”

If Touch ID is polluting its own drinking water, I won’t be the one that finds out. There’s no way in hell I’m going to count its successes and failures and collect that data over a long enough period of time to draw any conclusions. But I’m going to be mighty suspicious if I feel like throwing my phone again by Christmas.

1. I’m assuming here that fingerprints themselves don’t change appreciably over a few weeks. If they do, the whole concept of Touch ID is flawed.

Afghanistan, November 2013

Big drop in US and coalition casualties this past month. It’d be nice if this trend lasted longer than it did at the beginning of the year.