Macport and mono

Just a heads-up: Macport quit working on my machine. Link errors, missing architecture in sqllite3 dynamic libs or something. After much agonizing, I began to suspect mono, especially since the sqllite3 library port wanted to link against was in the mono path. There’s a shell script in mono called uninstallMono.sh that does a fine job of getting rid of it. Run that, and things work fine again.

I’m guessing the mono libraries are simply put in too early in paths, which may cause the problem, but since I’ve got actual work to do, I’ll just roll my eyes and get on with life.

Update: the above did solve most of my problems, but not all. After perusing more forums than I’d like to peruse, I hit on a remark from one of the Macport developers that you should always reinstall the entire Macport system after every major OSX upgrade. In other words, I installed my Macport under Leopard, then upgraded to Snow Leopard, so it got unhinged. The solution is to entirely remove the /opt/local directory contents, then reinstall Macport from source. Personally, I find it a little bit scary (like, is Macport really the only system using opt/local?) so I tarballed the directory first, just in case. But I don’t think that is necessary, but time will tell.

Anyway, after reinstalling Macport this way, the rest seems to have straightened itself out.

Lecture

I was invited to give a lecture to the International Masters Programme in Health Informatics at Karolinska Institute, and we recorded a video of the entire lecture, in total around 3.5 hours. The last part is about iotaMed, our open source project for a “new and improved” electronic health care record, which is knowledge support, medical record, and national registries all rolled into one.

The rest of the lecture is about a lot of different things I have opinions about, and as there is no lack of things I feel strongly about, it went almost an hour longer than it should have.

The full lecture consists of 12 chapters (“parts”), each 1-4 video segments (YouTube limits videos to max 15 minutes, and that makes for a lot of dividing of videos). You can find the lecture notes here. Oh, by the way, the site for the iotaMed project is here. The playlist with all 20 videos is on YouTube here.

If all else fails, try Preview

I’m totally amazed at all the things Preview does in OSX Snow Leopard. I already use it for knocking out backgrounds, using the “Instant Alpha” tool in the “Select” dropdown. But what happened today is more interesting.

To my everlasting regret I got me a Canon Lide 60 scanner a couple of years ago. Canon’s hardware is pretty nice, but their driver support stinks, especially for OSX. This scanner costs me on average much more work than it should to keep going. Same for my Pixma 5200 Canon printer, by the way. Awful.

Anyway, I needed to scan a page from a mag to show on a slide. Hooked up the scanner, tried Canon Toolbox, and sure enough “Failed to open driver”. Internet next, user groups, downloads, complicated shit about uninstalling, reinstalling, rebooting the Mac Pro ten times. No joy. After a few hours (!) of this, I got an inspiration: hey, since I saw “Twain” mentioned, maybe Acrobat Pro 9 (CS4) could import it, instead of using Canon Toolbox? Sure enough, Acrobat found the scanner, looked it over, and promptly crashed.

And then I got my second inspiration: check out OSX Preview. And yes, that one worked. Not only that, but it automatically calibrated the scanner, proceeded to analyze the page, divided it into sections, scanned it, and served it up already partitioned into useful chunks. See the screenshots below. All the time I was just sitting there watching, doing nothing. The only thing I had to do was select the image and hit cmd-R twice to turn it the right way up.

Jeez, that innocent looking little Preview app is becoming mighty useful for any number of things.

I probably should mention that the driver I installed came in a file called “lide60osx11131en.dmg” to be found, somehow, on Canon’s support site. It installs both the drivers and the toolbox, but the toolbox doesn’t work.

Don’t do parts.parts

I just found another weirdness in Apple’s Objective C. If you have the same name for several components of an object path, the runtime starts stuttering and behaving very badly. Intermittently, you can’t scroll, or only extremely slowly, everything turns into molasses. No errors, mind, just mindbogglingly slow.

This stuttering and slowness seems to affect the simulator, mainly, not so much if you run code on your device (in my case the iPad). Also, if you run under instruments, things work better (Murphy strikes again), except I had it stutter under “Allocations” but not under other instruments.

I had these repeat names in two places in my code and resolving those two seems to have fixed the stuttering entirely. To illustrate what I mean, see this code snippet:

for (IDRBase *idr in self.parts.parts) {
   if ([idr isSuperCell]) break;
   CGRect newFrame = myCGRectDown(hugeFrame, verticalOffset);
   UIView *view = [idr getAsView:newFrame];
   if (view) {
      [returnView addSubview:view];
      verticalOffset += view.frame.size.height;
   }
}

(Yes, it’s the same snippet as in the previous example with nil or not nil. Coincidence. My code does indeed consist of more than just this.)

In the very first line you see a property referred to as “self.parts.parts”. That is what screws things up. Even though the two names “parts” refer to entirely different things, and even though the code actually delivers the values it should, this repetition of identical literal names confuses the crap out of the runtime, it seems. The solution is to not name these two things the same, of course. In this case, I changed the innermost “parts” to “aParts”, resulting in “self.parts.aParts”, and hey presto, no stuttering no more.

Fighting the good fight

Comment spam on a site like this is out of this world. Completely nuts. I just looked over the stats and this is what they look like:

Click the image for a better look at it. No, you’re not misreading it, 99.27% of all comments I get are spam. Un-frickin-believable. Only between one and five a month get through and have to be manually removed.

Without Akismet, there’s no way I’d allow comments at all. Killing on average 30 spam comments a day to get one sensible comment a week is not what I’d call a fruitful use of time.

Even the machine agrees

Picture this. I’m a little nervous, not much, but a little, since I’m to present my first running code on an iPad of my own entirely different idea of what a medical record should actually look like. I’m presenting this to a group of industry folks, doctors, and professors of different kinds, a power group. So we park the car at Karolinska Hospital in Stockholm and I swipe my credit card in the parking ticket dispenser and this is what comes out:

Now, seriously, if even the parking ticket dispenser calls you “leet”, how can you lose? It went beyond great, by the way. But I can’t figure out how the machine knew that in advance.

Is it nil or isn’t it?

A bit of Objective-C weirdness I don’t quite get. The weirdness occurs if “view” in the code below is nil, that is if [idr getAsView:newFrame] returns nil. You’d expect the verticalOffset not to be incremented, but it is. Even though view is nil, view.frame.size.height still evaluates to “21” (in this case) and verticalOffset gets incremented. (The first returned view was 21 high, the second returned view was nil in the debug run I’m referring to.)

- (UIView *)getAsView:(CGRect)theFrame {
	CGFloat verticalOffset = 0.0;
	CGRect hugeFrame = myCGRectHuge(theFrame);
	IDVBase *returnView = [[IDVBase alloc] initWithFrame:hugeFrame];
	hugeFrame = myCGRectResetToZero(hugeFrame);
	
	for (IDRBase *idr in self.parts.parts) {
		CGRect newFrame = myCGRectDown(hugeFrame, verticalOffset);
		UIView *view = [idr getAsView:newFrame];
		[returnView addSubview:view];
		verticalOffset += view.frame.size.height;
	}
	[returnView sizeToFit];
	return [returnView autorelease];
}

To avoid the unintended increment, I have to add the conditional if (view) {…} (which is a pretty good idea anyway, since it’s rather pointless, or maybe even bad, to add a nil as a subView):

- (UIView *)getAsView:(CGRect)theFrame {
	CGFloat verticalOffset = 0.0;
	CGRect hugeFrame = myCGRectHuge(theFrame);
	IDVBase *returnView = [[IDVBase alloc] initWithFrame:hugeFrame];
	hugeFrame = myCGRectResetToZero(hugeFrame);
	
	for (IDRBase *idr in self.parts.parts) {
		CGRect newFrame = myCGRectDown(hugeFrame, verticalOffset);
		UIView *view = [idr getAsView:newFrame];
		if (view) {
			[returnView addSubview:view];
			verticalOffset += view.frame.size.height;
		}
		[returnView addSubview:view];
		verticalOffset += view.frame.size.height;
	}
	[returnView sizeToFit];
	return [returnView autorelease];
}

I don’t know what the moral of this story is. I assume that if I should delve into the language reference, this will turn out to be undefined behaviour. Trying to figure out what could have been defined behaviour, I can’t come up with a reasonable answer, so I guess it’s just one of those things you should avoid doing. Maybe a compiler warning would have been nice, though.

An ode to Juniper

I have a Juniper SSG-5 and the school I’m doing the network setup for also got one identical unit on my recommendation. I wanted to set up a fixed VPN between the two but failed miserably, so I logged a support request with Juniper on my machine, which is still in warranty but without any kind of support contract. Oh, boy, do these guys have great service.

After just a day I got an engineer connecting to my system with desktop sharing software and we together went through a number of different configurations. It wasn’t really trivial, since the first config took us nearly three hours. Then I had another question of how to implement more finegrained control over the firewall policies in one direction, but not the other, which had us online another two hours using desktop sharing. The final result was perfect and I’ve learned so much more about the details of autokey VPN tunnels.

I’m totally blown away by the level and quality of support I got for this issue from Juniper. Maybe this particular engineer was exceptionally good and persistent, but I have the impression that it is more of a rule with Juniper. When I bought the SSG-5 I thought it was a little expensive, but after this experience, I’ve totally changed my mind. The support level and quality makes it worth the price hands down.

No, I don’t have shares in Juniper, but after this experience I think I may get some.

Breaking news!

Hania, my woman and wife, was one of the winners of the Benzelius price from the Royal Society of Science in Uppsala, Sweden, for her Ph.D. work in digital geometry and combinatorics on words (she had to help me spell this). She got this on the 300 year anniversary of the society, which was set up by such luminaries as Anders Celcius and Carl Von Linné. The Royal Society of Science in Uppsala is actually the oldest academic society in Sweden.

I’m so proud I’m certain to break some vital organ if I don’t calm down.

Method forwarding in Objective-C

I scraped together the following from a number of sources and got it to work fine and without compiler warnings. Interesting links are, among others:

http://cocoawithlove.com/2008/03/construct-nsinvocation-for-any-message.html
http://macdevelopertips.com/objective-c/objective-c-categories.html

But, I get ahead of myself. The idea here is to have one object forward method invocations to another. Typically, you have a class responding to method A, then you decide to make an instance of that class a member of an outer class and any messages for the methods sent to the outer class should be forwarded to the inner class if that’s where they are to be handled. And, of course, you don’t want to sit and write all these methods again in the outer class just so the inner class gets called. An example:

I have a class I call IotaDOM2TableProxy which has a method “rowsInSection:”. The class IssueWorksheet holds an instance of IotaDOM2TableProxy as a property. I now want any “rowsInSection” messages sent to the outer IssueWorksheet to be forwarded to the inner IotaDOM2TableProxy object without having to declare any “rowsInSection” method for the IssueWorksheet class. This is how you do it.

Firstly: the target, the IotaDOM2TableProxy class, needs no modification at all. It never knows what hit it, or rather, where the invocations come from. So we’ll not say anything more about it than that it contains the declaration of the “rowsInSection:” method (among a load of other stuff):

@interface IotaDOM2TableProxy : NSObject {
...
}
- (NSUInteger)rowsInSection:(NSUInteger)section;
@end

The IssueWorksheet class holds an instance of the IotaDOM2TableProxy, and does not declare any method called “rowsInSection”:

@interface IssueWorksheet : NSObject {
    IotaDOM2TableProxy *dom2tableProxy;
}
@property (nonatomic, retain) IotaDOM2TableProxy *dom2tableProxy;
@end

To make IssueWorksheet forward any calls it doesn’t know about to IotaDOM2TableProxy, we have to override three methods in IssueWorksheet:

- (BOOL)respondsToSelector:(SEL)aSelector {
    return [super respondsToSelector:aSelector] || 
           [self.dom2tableProxy respondsToSelector:aSelector];
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    NSMethodSignature *sig;
    sig = [super methodSignatureForSelector:aSelector];
    if (sig == nil)
        sig = [self.dom2tableProxy methodSignatureForSelector:aSelector];
    return sig;
}

- (void)forwardInvocation:(NSInvocation *)invocation {
    SEL aSelector = [invocation selector];
    if ([self.dom2tableProxy respondsToSelector:aSelector])
        [invocation invokeWithTarget:self.dom2tableProxy];
    else
        [self doesNotRecognizeSelector:aSelector];
}

And this works beautifully for one, two, or any number of methods to forward. There’s just one problem: the compiler complains that IssueWorksheet “may not respond to method…” and we should always eliminate warnings. The easiest way is to declare the forwarded methods in a category, which only mildly defeats the purpose of the exercise. But it works and is safe. You do that by adding the category after the interface declaration of IssueWorksheet, so the header file will now look as follows in its entirety:

//
//  IssueWorksheet.h
//  iotaPad1
//
//  Created by Martin on 2010-06-08.
//

#import 
#import "IotaDOM2TableProxy.h"

@interface IssueWorksheet : NSObject {
    IotaDOM2TableProxy *dom2tableProxy;
}

@property (nonatomic, retain) IotaDOM2TableProxy *dom2tableProxy;

- (id)initFromFile:(NSString *)name ofType:(NSString *)type;


@end

@interface IssueWorksheet (ForwardedMethods) 
- (NSUInteger)rowsInSection:(NSUInteger)section;
@end

In the above, I call the category “ForwardedMethods”, but you can call it anything you like. The name doesn’t matter and isn’t referenced anywhere else, but the category must have a unique name of some sort.

Please note: there is no implementation in the .m file for “rowsInSection”. The category definition suffices to shut the compiler up.