Begin main content

Extracting detailed Time Slip data from Billings

Similar to a previous post about Extracting invoice data from Billings I hit another limitation with Billings exporting ability today. Each "Slip" in Billings can have multiple time records - I might do 5 minutes on a task now, 10 minutes after lunch and a further 25 tomorrow. There is no way, I can see, to export this data—but armed with our knowledge of Billing's sqlite3 schema we can get it for ourselves.

echo "select TimeSlip.name, datetime(TimeEntry.startDateTime, 'unixepoch', 'localtime'), datetime(TimeEntry.endDateTime, 'unixepoch', 'localtime') from TimeSlip, TimeEntry where projectID = 1400 and TimeEntry.timeSlipID = TimeSlip._rowID;" | sqlite3 -separator ' ' "$HOME/Library/Application Support/Billings/Database/billings.bid"

This will output the detailed timing data for all slips that are un-invoiced for the given projectID (look that up in the Project table - it's _rowid).

07:08 PM, 22 Nov 2010 by Mark Aufflick Permalink | Short Link | Comments (0)

Making a fat static library for iOS device and simulator

Some third party iOS library providers (I'm looking at you Omniture) provide separate static library archives for simulator (i386) and device (armv6 and or armv7).

That's a pain since you either change them manually or set the linking flags on different Xcode targets to use the appropriate library (whereas normally with libraries and frameworks you just drag it into your project and you're done).

Instead, you can build your own fat (multi-architecture) library from the provided archives and Xcode will link against the appropriate architecture segment (flagrantly ignoring Erik's dire predictions about testability and your personality ;)

We achieve this using the lipo tool, eg:

lipo -output libOmnitureAppMeasurement-fat.a -create -arch armv6 libOmnitureAppMeasurement-iPhoneDevice.a -arch l386 libOmnitureAppMeasurement-iPhoneSimulator_4_0_GM.a

Update:

The latest Omniture libraries, available via the Omiture SiteCatalyst admin console, now contains armv6 and armv7 architectures. Oddly, that means that they provide two archives—one regular i386 archive (with no fat header) for the simulator and one fat archive for the device with armv6 and armv7 segments. Since the device archive headers now specify the archives already, we don't need to tell lipo anything other than the archive file name.

lipo -output libOmnitureAppMeasurement-fat.a -create libOmnitureAppMeasurement-iPhoneDevice.a -arch i386 libOmnitureAppMeasurement-iPhoneSimulator.a

03:43 PM, 19 Nov 2010 by Mark Aufflick Permalink | Short Link | Comments (2)

Extracting invoice data from Billings

I use the excellent Billings 2 from MarketCircle for tracking my time and issuing invoices. There are some things it doesn't do well though, and one is exporting or interacting with external systems*

I knew from the also excellent Workload widget for Billings that all the billings data is in an sqlite3 database at the following path:

$HOME/Library/Application Support/Billings/Database/billings.bid

So getting my Q3 invoice data is as simple as:

echo "select date(invoiceDate, 'unixepoch', 'localtime'), '', invoiceNumber, company, totalCached from Invoice, Client where Client._rowid = Invoice.clientID and invoiceDate > strftime('%s', '2010-07-01') and invoiceDate < strftime('%s', '2010-10-01');" | sqlite3 -separator ' ' "$HOME/Library/Application Support/Billings/Database/billings.bid"

This gives me what I need to paste into my BAS spreadsheet (I've set the separator to the tab character). The tax fields in the Invoice table don't seem to be used, but I can easily calculate the flat 10% GST afterwards so I didn't bother investigating the Tax tables.

* I do note that their FAQ for Billings Pro says about any forthcoming API: "We do have the ability to run FScript scripts (or FScript wrapped within AppleScript), but we have not documented the potential calls and methods." which is pretty interesting, but I'm a little nervous about doing that with my billing system until they document which methods are safe!

02:02 PM, 22 Oct 2010 by Mark Aufflick Permalink | Short Link | Comments (0)

Pixar videos

Not quite what the title might suggest ;) These are some of the Pixar University videos André Pang mentioned in his keynote address at this weeks AUC /dev/world conference.

The Dean of Pixar University, Randy Nelson, on the Collaborative Age

Mastery, Breadth, Communication, Collaboration, "Plussing" and more! 9 minutes.

CEO of Pixar Ed Catmull on Keeping your Crises Small

CEO of Pixar (and all round computer graphics genius) Ed Catmull speaking to Stanford Graduate School of Business. 53 minutes.

04:37 PM, 30 Sep 2010 by Mark Aufflick Permalink | Short Link | Comments (1)

Aquamacs copying styled text

Some time ago I switched from X11 GNU emacs to Aquamacs - the Aqua Mac native port of GNU emacs. The latest version of Aquamacs has a neat Edit menu item "Copy as HTML" which basically makes a convenient way to use the htmlize.el package to put a colourised version, in HTML format, of the current selection on the Mac clipboard.

That's great for posting into, for example, a blog post—but what about into other Cocoa apps? For that you still only need html, but it has to have the correct UTI on the clipboard to be recognised. The Aquamacs/GNU Emacs copy internals for the Mac nearly work flawlessly, and the following slightly hacky function will put a "Copy as Styled Text" into your edit menu:


(defun copy-as-styled-text (beg end)
  "Copies the region as HTML styled text into the clipboard."
  (interactive "r")
  (when (or (not transient-mark-mode) mark-active)
    (let ((x-select-enable-clipboard t)
      (buf (aquamacs-convert-to-html-buffer beg end)))
      ;; the copy as html is more reliable if we've copied plain text first
      ;; (which seems to clear the clipboard of all types)
      (with-current-buffer buf
    (copy-region-as-kill (point-min) (point-max)))
      (with-current-buffer buf
        (ns-store-cut-buffer-internal 'PRIMARY (buffer-string) 'html))
      (kill-buffer buf))))

(define-key-after menu-bar-edit-menu [copy-styled]
  '("Copy as Styled Text" . copy-as-styled-text) 'copy-html)

07:33 PM, 24 Sep 2010 by Mark Aufflick Permalink | Short Link | Comments (0)

Speaking at /dev/world 2010

/dev/world is a conference run by the Australasian Apple University Consortium (AUC). The AUC has been around since the Mac was launched in 1984 to promote and foster development of Apple platforms.

This year the AUC conference is in Melbourne on September 28th-29th and I will be one of the speakers. Here's my bit in the program:

Push Notifications - Device, Protocol and Server
Speaker: Mark Aufflick
Target Audience: Intermediate

Apple Push Notifications are an integral part of many applications, from games like "Words With Friends" to VOIP call notification, but for the non-expert developer they can be a source of mystery. Apple's "Local and Push Notification Programming Guide" provides details of the binary protocol, SSL certificates and other details which are hardly beginner material. Additionally the guide makes little mention of correct UTF encoding and other small details which create more difficulty for those unfamiliar with data encodings etc. And finally a persistent server is required which can handle the protocols. This talk will take attendees through: an understanding of the service overall; the protocol and its limitations; responding to notifications in the iOS application; approaches to implementing a server in Perl, Python or Ruby.

Bio:
Mark Aufflick has been involved in the Apple industry since his first job in 1995 and finally put his Computer Science degree to use becoming a freelance developer in 2000. Since then he has developed back end, web and gui applications for various Unix platforms, MacOS and iOS - for both corporate giants and small businesses. Mark has presented on programming topics in fora such as Sydney University's Web Engineering Group and CocoaHeads. These days Mark is an iOS and Mac developer with his company Pumptheory as well as the convenor of Sydney CocoaHeads.

I'm really looking forward to meeting the other presenters and delegates! If you're attending, let me know on twitter - I'm @markaufflick.

02:36 PM, 06 Sep 2010 by Mark Aufflick Permalink | Short Link | Comments (0)

Work Ethic

In Guy Kawasaki's first book, The Macintosh Way (see below), he ascribes this great quote to Michael Jackson:

Nobody could duplicate Mr. Astaire's ability, but what I never stop trying to emulate is his total discipline, his absolute dedication to every aspect of his art. He rehearsed, rehearsed, and rehearsed some more, until he got it just the way he wanted it. It was Fred Astaire's work ethic that few people ever discussed and even fewer could ever hope to equal.

Being a fan of both Michael Jackson and Fred Astaire this rings true—now to try to emulate!

Guy Kawasaki is also someone who keeps rehearsing and refining what he does (which he does very well). You can get a fun insight into his earlier days and also a great read now that The Macintosh Way is a free* download. Free here means that you have to follow Guy on Twitter. If you lack the patience to filter his feed you can always unfollow later ;)

10:32 AM, 25 Aug 2010 by Mark Aufflick Permalink | Short Link | Comments (0)

Quickly add PDFs to iTunes/iBooks

Being able to transfer PDFs to iBooks on your iPad and iPhone is really handy. But sometimes it's a pain to either make or track down an actual PDF file. Here's how to do it painlessly.

For any non-PDF document, you can print to PDF and open it in iTunes. But you can collapse that with this neat tip from MacWorld.

If you want to quickly add a document or a web page to your 'Books' collection in iTunes, all you need to do is to create an alias of iTunes and drag it to ~/Library/PDF Services. Now, when you're browsing the web or viewing documents and you decide that you want to read them later on a portable Apple device just hit Print, click the PDF button on the bottom left corner of the window and choose iTunes. iTunes will launch and receive the PDF. Next, sync your device and you're ready to go. Source

But what about when you've got a PDF already open in Preview (say you clicked a PDF download link)? Sure you could save to desktop, drag into iTunes, delete it. Or find 18e3764.pdf in your download folder etc. But if you're any kind of Mac commandline nerd, you will already have DTerm installed (if you don't - do yourself a favour and go check it out).

So you have a PDF open in Preview (or any other PDF app) - just hit your DTerm shortcut key combo (mine is Command-Shift-Enter), then type open -a iTunes then hit Command-Shift-V. (this pastes the path of the current window's file into the DTerm commandline) and hit Enter.

Now your PDF is in iTunes, already highlighted ready for you to change the title if needed.

12:30 PM, 19 Aug 2010 by Mark Aufflick Permalink | Short Link | Comments (0)

Filtering Growl notifications

Now that I work full time on my Mac I have Skype, Notify and any number of other apps telling me stuff via Growl. One of the great things about having everything centralised through a single notification mechanism is that you can easily choose what notifications you want to see.

Growl already has a great way to choose notifications by turning Apps on or off and notification types as registered by the Apps. But it doesn't have any way to filter based on the content of the notification—e.g. if I want to see when some Skype users log on but not others.

So since Growl is open source I took matters into my own hands. I don't have a UI yet, and haven't forked the repository, but for now here's a quick patch.

The UI is you use Apple's Plist editor to add an array with key "GrowlIgnorePredicates" to com.Growl.GrowlHelperApp.plist in your Library/Preferences directory :) Here are the keys, see NSPredicate docs for predicate string syntax. If you have no idea what I just said you'll have to wait for the UI I'm afraid!

  • ApplicationName
  • NotificationTitle
  • NotificationDescription
And here is the patch:

diff -r 9f9a8561261a Core/Source/GrowlApplicationController.m
--- a/Core/Source/GrowlApplicationController.m	Sun Aug 01 10:35:51 2010 -0400
+++ b/Core/Source/GrowlApplicationController.m	Wed Aug 04 13:18:37 2010 +1000
@@ -592,6 +592,21 @@
 		[pool release];
 		return GrowlNotificationResultDisabled;
 	}
+    
+    GrowlPreferencesController *preferences = [GrowlPreferencesController sharedController];
+    
+    // Mark Aufflick hack - needs UI    
+    NSArray *ignorePredicates = [preferences objectForKey:GrowlIgnorePredicates];
+
+    if ([ignorePredicates isKindOfClass:[NSArray class]]) {
+        for (NSString *predString in ignorePredicates) {
+            NSPredicate *p = [NSPredicate predicateWithFormat:predString];
+            if ([p evaluateWithObject:dict]) {
+                NSLog(@"ignoring notification due to predicate: %@", p);
+                return GrowlNotificationResultDisabled;
+            }
+        }
+    }
 
 	NSMutableDictionary *aDict = [dict mutableCopy];
 
@@ -642,8 +657,6 @@
 		value = [NSNumber numberWithInt:priority];
 	[aDict setObject:value forKey:GROWL_NOTIFICATION_PRIORITY];
 
-	GrowlPreferencesController *preferences = [GrowlPreferencesController sharedController];
-
 	// Retrieve and set the sticky bit of the notification
 	int sticky = [notification sticky];
 	if (sticky >= 0)
diff -r 9f9a8561261a Core/Source/GrowlPreferencesController.h
--- a/Core/Source/GrowlPreferencesController.h	Sun Aug 01 10:35:51 2010 -0400
+++ b/Core/Source/GrowlPreferencesController.h	Wed Aug 04 13:18:37 2010 +1000
@@ -39,6 +39,7 @@
 #define LastKnownVersionKey			XSTR("LastKnownVersion")
 #define GrowlStickyWhenAwayKey		XSTR("StickyWhenAway")
 #define GrowlStickyIdleThresholdKey	XSTR("IdleThreshold")
+#define GrowlIgnorePredicates       XSTR("GrowlIgnorePredicates")
 
 CFTypeRef GrowlPreferencesController_objectForKey(CFTypeRef key);
 CFIndex   GrowlPreferencesController_integerForKey(CFTypeRef key);

01:47 PM, 04 Aug 2010 by Mark Aufflick Permalink | Short Link | Comments (0)

Template::Plugin::Haml caveats

Including other templates is tricky. Either you have to indent the included template as if it was pasted inline (eg. with a bunch of spaces in front of every line instead of the first level being column zero) or you have to format the include appropriately.

For example, let's say you have a content variable which was made by rendering some templates, you'd like to do something like:

%html
  %body
    #content
      [% content %]

You want the embedded content to be location neutral, ie. start at column zero. Something like:

#myDiv
  %ul
    %li foo

Except this will be rendered AFTER the closing html tag since the combined haml will look like:

%html
  %body
    #content
#myDiv
  %ul
    %li foo

I'm going to try to think of some better way to resolve this, but for now I'm using the Template::Toolkit built in indent filter like so:

%html
  %body
    #content
      [% content | indent('      ') %]

The only downside (apart from the pain of keeping it in sync) is that you end up with the rendered html having some funky indentation after the newlines are stripped, but I can live with that. You can use a number instead of a string as an argument to indent, and it will pad by that many spaces which may turn out to be easier to keep in sync.

I'll let you know if I have any flashes of genius and will also contact the Template::Plugin::Haml and Text::Haml authors.

10:00 PM, 29 Jul 2010 by Mark Aufflick Permalink | Short Link | Comments (0)

Using Haml with Catalyst

Thanks to Viacheslav Tykhanovskyi's Text::Haml, we can now enjoy the good clean fun of Haml markup in Perl. Much Perl web templating is done with Template::Toolkit, and using Haml within TT is also now possible thanks to Template::Plugin::Haml by Caleb Cushing. The trouble is, you need to wrap every template in some boilerplate:

[%- USE Haml ; FILTER haml -%]
...
[%- END -%]

So I hacked up a quick solution to using .haml templates directly in Catalyst. First, create a MyApp::View::Haml class:

package Hello::View::Haml;

use strict;
use warnings;

use base 'Catalyst::View::TT';

use Template::Plugin::Haml;

__PACKAGE__->config(
    TEMPLATE_EXTENSION => '.haml',
    render_die => 1,
);

sub render {
    my ($self, $c, $template, $args) = @_;

    $c->log->debug(qq{Rendering Haml/TT template "$template"}) if $c && $c->debug;

    # args may be passed in or be in the stash
    $args = { %{ $c->stash} }
        if ref $args ne 'HASH';

    # let the master haml template know which template to render
    $args->{haml_template} = $template;

    # do the normal TT render
    return $self->SUPER::render($c, 'haml_master.tt', $args);
}

1;

Then you need a haml_master.tt template:

[%- USE Haml ; PROCESS $haml_template | haml -%]

And finally set your config to use the Haml view by default:

default_view => 'Haml'

Et voila - .haml template rendering albeit with only TT style variable interpolation. Getting haml interpolation working might need some change to how the stash is passed to the Text::Haml module.

A controller method might look like this:

sub foo :Global {
    my ($self, $c) = @_;

    $c->stash(foo => 'bar');
    $c->stash(template => 'foo.haml');
}

And foo.haml:

!!! HTML
%body
  %p This is haml inside TT rendering your variables: [% foo %]

Becomes rendered as:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<body>
<p>This is haml inside TT rendering your variables: bar</p>
</body>

06:35 PM, 29 Jul 2010 by Mark Aufflick Permalink | Short Link | Comments (0)

Cauliflower, Potato and Carrot Puree

Our weekly fruit and veg delivery from Doorstep Organics arrived today which meant we had to use up some older produce with todays dinner. We had a fair amount of cauliflower and some carrots so I decided to make a puree. I started with an idea from New Larousse Gastronomique for a carrot and parsnip puree and came up with the following:

  • 200g potato
  • 100g carrot
  • 2 small onions
  • 600g cauliflower
  • 1-2 garlic cloves
  • 2 cups stock (I used chicken, but I think vegetable would be better)

Loosely chop all the ingredients. Melt some butter and olive oil in a pan. Saute carrott and potato, seasoning lightly. Add onion and garlic, then cauliflower. Cook for a while then partially cover with stock and vigorously simmer with the pan loosely covered (e.g. with a wok lid). When vegies are becoming soft, remove lid and continue cooking until almost all the liquid has evaporated. Puree until smooth in a blender.

I served it with some delicious organic sausages and steamed broccoli. This would be enough for at least six, or you can refrigerate and use over a few days.

09:27 PM, 26 Jul 2010 by Mark Aufflick Permalink | Short Link | Comments (0)

Where'd everybody go?

Where'd everybody go?

Our neighbour has a great deciduous tree that attracts loads of birds in summer. Some birds seem not to mind when all the leaves disappear (into our yard)

Series home: http://mark.aufflick.com/a-day-in-sydney

Taken with Canon EOS 400D DIGITAL and EF24-85mm f/3.5-4.5 USM on 2010:07:25 15:28:15

  • Exposure: 1/160
  • Aperture: f22.0
  • ISO speed: 100
  • Exposure program: Aperture-priority AE
  • Exposure compensation: -2
  • Flash: Off, Did not fire
  • File: _MG_3822.jpg

04:57 PM, 25 Jul 2010 by Mark Aufflick Permalink | Short Link | Comments (0)

Sun at last

Sun at last

We haven't had too much sun this winter in Sydney, so it's always a welcome friend

Series home: http://mark.aufflick.com/a-day-in-sydney

Taken with Canon EOS 400D DIGITAL and EF24-85mm f/3.5-4.5 USM on 2010:07:25 15:25:50

  • Exposure: 1/125
  • Aperture: f22.0
  • ISO speed: 100
  • Exposure program: Aperture-priority AE
  • Exposure compensation: 0
  • Flash: Off, Did not fire
  • File: _MG_3811.jpg

04:54 PM, 25 Jul 2010 by Mark Aufflick Permalink | Short Link | Comments (0)

Buttermilk Pancakes with Caramelised Pear

Purple Bridge

Yesterday I bought some buttermilk so I could try out Lauren's Buttermilk Pancakes. I liked the sound of her recipe since it minimised the use of butter—making them, in her words, healthy...

I was short on plain flour so I used half plain and half self raising and left out the baking powder. I normally use butter in the pan to make the pancakes crispy and golden with buttery goodness, but in light of the "healthier" approach, I used olive oil spray.

The pancakes worked out great, as you can see above, and you can visit Lauren's site Coffee Muffins for this and other tasty recipies.

Here is how I made the, oh so healthy, caramelised pears to go on top:

  1. Firstly start with good, in season, organic fruit. Kath and I have all our in season organic fruit and veg delivered by Doorstep Organics;
  2. Peel and slice the fruit, then brown it in a little unsalted butter in a frying pan. I prefer Lurpak Danish butter, but any good butter will do;
  3. When the fruit has started to brown, add some brown sugar (maybe a tablespoon for one pear). Monitor the heat and stir a little to avoid burning the sugar, but it doesn't need too much care. You can be doing it while cooking your pancakes to ensure freshly warm fruit.

And that's it!

04:48 PM, 06 Jun 2010 by Mark Aufflick Permalink | Short Link | Comments (0)

Using blocks to simplify custom view drawing

Commonly when you are drawing a custom Cocoa view, you will be creating paths, filling and stroking them etc. You might even be drawing a similar shape a number of times. A naive approach to drawing five round rects with shadows might look like this:

#define DDOFFSET 10
#define DDWIDTH 50

- (void)drawRect:(NSRect)dirtyRect {

    [NSGraphicsContext saveGraphicsState];

    for (int i=0 ; i < 5 ; i++)
    {
        // offset and put onto pixel boundary
        CGFloat top = [self frame].size.height - 0.5 - DDOFFSET;
        CGFloat left = 0.5 + (DDWIDTH * i) + (DDOFFSET * i) + DDOFFSET;
                
        NSRect borderRect = NSMakeRect(left,
                                       DDOFFSET,
                                       DDWIDTH,
                                       top - DDOFFSET);
        
        NSBezierPath *borderPath = [NSBezierPath bezierPathWithRoundedRect:borderRect
                                                                   xRadius:5
                                                                   yRadius:5];
        
        NSColor *borderColor = [NSColor grayColor];
        
        NSShadow *borderShadow = [[NSShadow alloc] init];
        [borderShadow setShadowOffset:NSMakeSize(2.0, -2.0)];
        [borderShadow setShadowBlurRadius:2.0];
        [borderShadow setShadowColor:[[NSColor blackColor] colorWithAlphaComponent:0.3]];
        
        NSColor *fillColor = [NSColor whiteColor];
        
        // do the drawing
        [borderColor set];
        [borderShadow set];
        [borderPath stroke];
        [fillColor set];
        [borderPath fill];
    }
    
    [NSGraphicsContext restoreGraphicsState];
}

(Note these examples are all using garbage collection).

Hopefully, it should occur to you that, amongst other issues, this is needlessly inefficient because a bunch of objects are being created and destroyed each time the view is dirtied. So we want to move the creation of objects into a separate method that is called when the view is created, store the paths in an array and the drawRect would then just have to set the colours, stroke the paths, etc. Something like this:

@interface DrawDemo2View : NSView {
    NSColor *borderColor;
    NSShadow *borderShadow;
    NSColor *fillColor;
    NSMutableArray *borderPaths;
}

@end
@implementation DrawDemo2View

#define DDOFFSET 10
#define DDWIDTH 50

- (id)initWithFrame:(NSRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        borderColor = [NSColor grayColor];

        borderShadow = [[NSShadow alloc] init];
        [borderShadow setShadowOffset:NSMakeSize(2.0, -2.0)];
        [borderShadow setShadowBlurRadius:2.0];
        [borderShadow setShadowColor:[[NSColor blackColor] colorWithAlphaComponent:0.3]];
        
        fillColor = [NSColor whiteColor];
        
        borderPaths = [[NSMutableArray alloc] initWithCapacity:5];
        
        for (int i=0 ; i < 5 ; i++)
        {
            // offset and put onto pixel boundary
            CGFloat top = [self frame].size.height - 0.5 - DDOFFSET;
            CGFloat left = 0.5 + (DDWIDTH * i) + (DDOFFSET * i) + DDOFFSET;
            
            NSRect borderRect = NSMakeRect(left,
                                           DDOFFSET,
                                           DDWIDTH,
                                           top - DDOFFSET);
            
            NSBezierPath *borderPath = [NSBezierPath bezierPathWithRoundedRect:borderRect
                                                                       xRadius:5
                                                                       yRadius:5];
            
            [borderPaths addObject:borderPath];
        }
    }

    return self;
}

- (void)drawRect:(NSRect)dirtyRect {

    [NSGraphicsContext saveGraphicsState];

    for (NSBezierPath *path in borderPaths) {
                
        // do the drawing
        [borderColor set];
        [borderShadow set];
        [path stroke];
        [fillColor set];
        [path fill];
    }
    
    [NSGraphicsContext restoreGraphicsState];
}

@end

That's mildly painful, and disconnects the meaning of the above code somewhat, but it's not too bad. What, though, if there are other shapes that require different handling - well they will need their own array and drawing code. Then we want to subclass the view and the subclass wants to draw circles, etc. etc. Your view will become messy and very specific. Also in a real example I'd probably need more save/restore graphics states, but here the shadow on the fill isn't important.

Thankfully we can use blocks, which are what some other languages call closures, to keep the efficiency of separating the execution time of the drawing code while keeping it all together in a very general way. We end up with something almost identical to the first naive implementation, but the drawing section at the end goes into a block in an array, and the drawRect simply executes all those blocks:

@interface DrawDemoBlocksView : NSView {
    NSMutableArray *drawingBlocks;
}

- (void)addRoundRect: (int)num;

@end
@implementation DrawDemoBlocksView

#define DDOFFSET 10
#define DDWIDTH 50

- (id)initWithFrame:(NSRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        drawingBlocks = [[NSMutableArray alloc] initWithCapacity:5];

        for (int i=0 ; i < 5 ; i++)
            [self addRoundRect:i];
    }
    return self;
}

- (void)drawRect:(NSRect)dirtyRect {

    for (void *(^block)(void) in drawingBlocks)
    {
        [NSGraphicsContext saveGraphicsState];
        block();
        [NSGraphicsContext restoreGraphicsState];
    }
}

- (void)addRoundRect: (int) num
{
    // offset and put onto pixel boundary
    CGFloat top = [self frame].size.height - 0.5 - DDOFFSET;
    CGFloat left = 0.5 + (DDWIDTH * num) + (DDOFFSET * num) + DDOFFSET;
    
    NSRect borderRect = NSMakeRect(left,
                                   DDOFFSET,
                                   DDWIDTH,
                                   top - DDOFFSET);
    
    NSBezierPath *borderPath = [NSBezierPath bezierPathWithRoundedRect:borderRect
                                                               xRadius:5
                                                               yRadius:5];
    
    NSColor *borderColor = [NSColor grayColor];
    
    NSShadow *borderShadow = [[NSShadow alloc] init];
    [borderShadow setShadowOffset:NSMakeSize(2.0, -2.0)];
    [borderShadow setShadowBlurRadius:2.0];
    [borderShadow setShadowColor:[[NSColor blackColor] colorWithAlphaComponent:0.3]];
    
    NSColor *fillColor = [NSColor whiteColor];
    
    [drawingBlocks addObject:[^{

        // do the drawing
        [borderColor set];
        [borderShadow set];
        [borderPath stroke];
        [fillColor set];
        [borderPath fill];
        
    } copy]];
}

@end

You can also see how this would work really well if we subclassed this view - all subclasses could simply push a block onto the array to request some work to be done during the drawRect phase.

You'll note how the block itself isn't added to the array, but a copy of it. That's because by default the storage for the context embodied in the block is only valid for the scope in which it is created. If we want to execute the block after the scope is gone we need to copy it.

If you found this useful you might also like Drew McCormack's excellent article 10 Uses for Blocks in C/Objective-C.

01:36 PM, 30 May 2010 by Mark Aufflick Permalink | Short Link | Comments (0)

Afternoon Fog

Afternoon fog

There was an unusual afternoon fog in Sydney today

Series home: http://mark.aufflick.com/a-day-in-sydney

Taken with Canon EOS 400D DIGITAL and Sigma HSM 30mm f1.4 on 2010:05:25 16:27:40

  • Exposure: 1/160
  • Aperture: f2.5
  • ISO speed: 200
  • Exposure program: Aperture-priority AE
  • Exposure compensation: +1
  • Flash: Off, Did not fire
  • File: IMG_3716.jpg

10:29 PM, 25 May 2010 by Mark Aufflick Permalink | Short Link | Comments (0)

Purple Bridge

Purple Bridge

Daily Shoot #ds190 'Today's color is purple.'

Taken as part of The Daily Shoot project. View all Mark's Daily Shoot photos.

Taken with Canon EOS 400D DIGITAL and Sigma HSM 30mm f1.4 on 2010:05:25 13:02:35

  • Exposure: 1/160
  • Aperture: f2.5
  • ISO speed: 200
  • Exposure program: Aperture-priority AE
  • Exposure compensation: -1
  • Flash: Off, Did not fire
  • File: IMG_3711.jpg

10:20 PM, 25 May 2010 by Mark Aufflick Permalink | Short Link | Comments (0)

Stairway to Law

Stairway to Law

The new Sydney University Law Faculty building offers many interesting views. This one has a slight Jeffrey Smartt aspect (I like to think!)

Series home: http://mark.aufflick.com/a-day-in-sydney

Taken with Canon EOS 400D DIGITAL and Sigma HSM 30mm f1.4 on 2010:05:24 17:23:15

  • Exposure: 1/20
  • Aperture: f1.4
  • ISO speed: 400
  • Exposure program: Aperture-priority AE
  • Exposure compensation: -1
  • Flash: Off, Did not fire
  • File: IMG_3706.jpg

11:00 PM, 24 May 2010 by Mark Aufflick Permalink | Short Link | Comments (0)

Members Only

Members Only

Can't be too many members - look how small the club house is!

Series home: http://mark.aufflick.com/a-day-in-sydney

Taken with Canon EOS 400D DIGITAL and Sigma HSM 30mm f1.4 on 2010:05:19 16:14:33

  • Exposure: 1/250
  • Aperture: f5.6
  • ISO speed: 100
  • Exposure program: Aperture-priority AE
  • Exposure compensation: 0
  • Flash: Off, Did not fire
  • File: IMG_3689.jpg

09:10 PM, 20 May 2010 by Mark Aufflick Permalink | Short Link | Comments (0)

Roller Skating

Roller Skating

I was sad when they closed down my childhood roller skating rink. I'm not sure this is the same.

Series home: http://mark.aufflick.com/a-day-in-sydney

Taken with Canon EOS 400D DIGITAL and Sigma HSM 30mm f1.4 on 2010:05:19 16:07:29

  • Exposure: 1/15
  • Aperture: f5.6
  • ISO speed: 100
  • Exposure program: Aperture-priority AE
  • Exposure compensation: 0
  • Flash: Off, Did not fire
  • File: IMG_3688.jpg

06:45 PM, 19 May 2010 by Mark Aufflick Permalink | Short Link | Comments (0)

Walkway to St James

Walkway to St James

I was at St James station early enough to find it nearly empty. St James is one of the (very few) genuinely attractive stations in Sydney. Another day I'll take some shots of the cavernous interior of the cut-and-cover underground station.

Series home: http://mark.aufflick.com/a-day-in-sydney

Taken with Canon EOS 400D DIGITAL and EF24-85mm f/3.5-4.5 USM on 2010:05:18 07:14:36

  • Exposure: 1/100
  • Aperture: f3.5
  • ISO speed: 400
  • Exposure program: Aperture-priority AE
  • Exposure compensation: -1
  • Flash: Off, Did not fire
  • File: IMG_3656.jpg

09:52 PM, 18 May 2010 by Mark Aufflick Permalink | Short Link | Comments (0)

Gloomy

Gloomy

Daily Shoot #ds183 'Black can be dramatic. Go for as much black in a photo as you can with lots of oomph, character, and depth.'

Taken as part of The Daily Shoot project. View all Mark's Daily Shoot photos.

Taken with Canon EOS 400D DIGITAL and EF24-85mm f/3.5-4.5 USM on 2010:05:18 16:47:45

  • Exposure: 1/6
  • Aperture: f4.5
  • ISO speed: 400
  • Exposure program: Aperture-priority AE
  • Exposure compensation: -2
  • Flash: Off, Did not fire
  • File: IMG_3667.jpg

07:10 PM, 18 May 2010 by Mark Aufflick Permalink | Short Link | Comments (0)

Chair Shadow

Chair Shadow

Daily Shoot #ds180 'Find an interesting shadow--any shadow--and make a photograph of it. Consider your framing as you shoot.'

Taken as part of The Daily Shoot project. View all Mark's Daily Shoot photos.

Taken with Canon EOS 400D DIGITAL and Sigma HSM 30mm f1.4 on 2010:05:15 15:02:50

  • Exposure: 1/500
  • Aperture: f5.6
  • ISO speed: 100
  • Exposure program: Aperture-priority AE
  • Exposure compensation: 0
  • Flash: Off, Did not fire
  • File: IMG_3645.jpg

03:36 PM, 15 May 2010 by Mark Aufflick Permalink | Short Link | Comments (2)

Coffee Times

Coffee Times

Daily Shoot #ds178 'Pick an everyday subject and get as close as you can to it.' - This is my daily bootup - a one cup stove top espresso maker.

Taken as part of The Daily Shoot project. View all Mark's Daily Shoot photos.

Taken with Canon EOS 400D DIGITAL and EF24-85mm f/3.5-4.5 USM on 2010:05:13 13:57:10

  • Exposure: 1/30
  • Aperture: f4.5
  • ISO speed: 100
  • Exposure program: Aperture-priority AE
  • Exposure compensation: 0
  • Flash: Off, Did not fire
  • File: IMG_3594.jpg

02:44 PM, 13 May 2010 by Mark Aufflick Permalink | Short Link | Comments (0)

Rusted Poles

Rusted Poles

I've been sick for a few days, hence the pause in photographs. This is another one from the archives, taken at Dee Why beach in Sydney's North. It's a mounted transparency so I can't see what type of film it is.

Series home: http://mark.aufflick.com/a-day-in-sydney

Taken with Canon EOS 400D DIGITAL and EF24-85mm f/3.5-4.5 USM

  • Transparency scanned with: Nikon SUPER COOLSCAN 5000 ED
  • File: rusted poles.jpg

10:54 AM, 13 May 2010 by Mark Aufflick Permalink | Short Link | Comments (0)

Vines on the Rocks

Vines on the Rocks

I found this vine covered facade in one of the anonymous lanes of The Rocks--the oldest part of Sydney

Series home: http://mark.aufflick.com/a-day-in-sydney

Taken with Canon EOS 400D DIGITAL and EF24-85mm f/3.5-4.5 USM on 2010:05:07 14:17:01

  • Exposure: 1/50
  • Aperture: f3.5
  • ISO speed: 100
  • Exposure program: Aperture-priority AE
  • Exposure compensation: -1
  • Flash: Off, Did not fire
  • File: IMG_3540.jpg

10:22 PM, 07 May 2010 by Mark Aufflick Permalink | Short Link | Comments (0)

View from Macquarie Lighthouse

View from Macquarie Lighthouse

Today I had no time for photographing so this is one from the archives. To be honest I can't remember when it was taken, but I do know it was taken with my EOS 30 with EF24-85mm f/3.5-4.5 USM lens using a 400 ISO Kodak C-31 process black and white film.

Series home: http://mark.aufflick.com/a-day-in-sydney

11:57 PM, 06 May 2010 by Mark Aufflick Permalink | Short Link | Comments (0)

Clouds over the harbour

Clouds over the harbour

The weather was pretty changeable today, but even so the Sydney Harbour manages to look beautiful.

Series home: http://mark.aufflick.com/a-day-in-sydney

Taken with Canon EOS 400D DIGITAL and EF24-85mm f/3.5-4.5 USM on 2010:05:05 10:49:53

  • Exposure: 1/250
  • Aperture: f5.6
  • ISO speed: 100
  • Exposure program: Aperture-priority AE
  • Exposure compensation: -1/3
  • Flash: Off, Did not fire
  • File: IMG_3503.jpg

09:55 PM, 05 May 2010 by Mark Aufflick Permalink | Short Link | Comments (0)

The Sacrifice

The Sacrifice

Rayner Hoff's amazing sculpture in the Sydney ANZAC War Memorial

The central motif of the design is ‘The Sacrifice’. It comprises a bronze group of sculptures depicting the recumbent figure of a young warrior who has made the supreme sacrifice; his naked body lies upon a shield which is supported by three womenfolk - his best loved Mother, Wife and Sister and in the arms of one is a child, the future generations for whom the sacrifice has been made.
http://www.anzacday.org.au/education/tff/memorials/nsw.html

Series home: http://mark.aufflick.com/a-day-in-sydney

Taken with Canon EOS 400D DIGITAL and Sigma HSM 30mm f1.4 on 2010:05:04 16:42:02

  • Exposure: 1/25
  • Aperture: f1.4
  • ISO speed: 200
  • Exposure program: Aperture-priority AE
  • Exposure compensation: 0
  • Flash: Off, Did not fire
  • File: IMG_3490.jpg

10:19 PM, 04 May 2010 by Mark Aufflick Permalink | Short Link | Comments (0)

Alone on Eastern Avenue

Alone on Eastern Avenue

A lone student at night, walking down Eastern Avenue of Sydney University, with the beautiful Anderson Stuart building as the backdrop

Series home: http://mark.aufflick.com/a-day-in-sydney

Taken with Canon EOS 400D DIGITAL and Sigma HSM 30mm f1.4 on 2010:05:03 17:47:55

  • Exposure: 1/13
  • Aperture: f2.2
  • ISO speed: 400
  • Exposure program: Aperture-priority AE
  • Exposure compensation: 0
  • Flash: Off, Did not fire
  • File: IMG_3466.jpg

10:40 PM, 03 May 2010 by Mark Aufflick Permalink | Short Link | Comments (0)

Escalating Queen Victoria

Escalating Queen Victoria

The Queen Victoria Building (QVB) has some shiny new escalators

Series home: http://mark.aufflick.com/a-day-in-sydney

Taken with Canon EOS 400D DIGITAL and Sigma HSM 30mm f1.4 on 2010:04:30 16:31:07

  • Exposure: 1/8
  • Aperture: f3.2
  • ISO speed: 100
  • Exposure program: Aperture-priority AE
  • Exposure compensation: 0
  • Flash: Off, Did not fire
  • File: IMG_3454.jpg

05:45 PM, 30 Apr 2010 by Mark Aufflick Permalink | Short Link | Comments (1)

Opera House roof and sky

Opera House roof and sky

There are seemingly infinite number of angles to admire Jorn Utzon's Sydney Opera House from

Series home: http://mark.aufflick.com/a-day-in-sydney

Taken with Canon EOS 400D DIGITAL and Sigma HSM 30mm f1.4 on 2010:04:28 11:26:07

  • Exposure: 1/1250
  • Aperture: f5.6
  • ISO speed: 100
  • Exposure program: Aperture-priority AE
  • Exposure compensation: 0
  • Flash: Off, Did not fire
  • File: IMG_3400.jpg

04:49 PM, 29 Apr 2010 by Mark Aufflick Permalink | Short Link | Comments (0)

Film shoot outside the Old Sydney Customs House

Film shoot outside the Old Sydney Customs House

There was some sort of film shoot outside the old customs house today. Oddly, they were all holding Donut King drinks - seemed a bit classy for Donut King!

Series home: http://mark.aufflick.com/a-day-in-sydney

Taken with Canon EOS 400D DIGITAL and Sigma HSM 30mm f1.4 on 2010:04:28 11:58:32

  • Exposure: 1/400
  • Aperture: f5.6
  • ISO speed: 100
  • Exposure program: Aperture-priority AE
  • Exposure compensation: 0
  • Flash: Off, Did not fire
  • File: IMG_3435.jpg

08:36 PM, 28 Apr 2010 by Mark Aufflick Permalink | Short Link | Comments (0)

Reflecting on Grosvenor Place

Reflecting on Grosvenor Place

The oversized chrome revolving doors of Grosvenor Place make for some nice reflections. Taken under a gloomy Sydney autumn sky.

Series home: http://mark.aufflick.com/a-day-in-sydney

Taken with Canon EOS 400D DIGITAL and Sigma HSM 30mm f1.4 on 2010:04:27 17:18:57

  • Exposure: 1/30
  • Aperture: f5.6
  • ISO speed: 100
  • Exposure program: Aperture-priority AE
  • Exposure compensation: -1
  • Flash: Off, Did not fire
  • File: IMG_3398.jpg

10:27 PM, 27 Apr 2010 by Mark Aufflick Permalink | Short Link | Comments (0)

A day in Sydney

It's time for a new direction for this blog. I follow a number of photography blogs and have long admired Cyril Genty's work on Un jour à Paris where he simply posts a photo a day taken somewhere in Paris. I thought I'd take a similar approach, but with Sydney, to help break some creative block and hopefully provide enjoyment for others at the same time.

So, starting next week I will be posting a photograph of Sydney every single day week day. I hope for the photos to be fairly contemporaneous, but I won't promise they were taken the very day they were posted.

Here is a sneak peak, taken last Friday at Luna Park Sydney.

Luna Park approach

Taken with Canon EOS 400D DIGITAL and Sigma HSM 30mm f1.4 on 2010:04:22 12:26:06

  • Exposure: 1/50
  • Aperture: f13.0
  • ISO speed: 100
  • Exposure program: Aperture-priority AE
  • Exposure compensation: 0
  • Flash: Off, Did not fire
  • File: IMG_3347.jpg

The main page for this project is http://mark.aufflick.com/a-day-in-sydney - please feel free to leave comments and if I fall behind give me a nudge! At the moment this series is hosted on flickr, but that will probably change so please subscribe to my "A day in Sydney" blog category rather than my flickr feed to make sure you don't miss out

06:52 PM, 24 Apr 2010 by Mark Aufflick Permalink | Short Link | Comments (0)

Code Bubbles - the most important IDE innovation since SmallTalk?

Wow. An IDE concept (with prototype and promise of a beta implementation that you can sign up for) that for the first time makes me want to program in Java. People who know me will know how huge that is.

I loved the SmallTalk IDE's concept of method-level programming ever since I was first exposed to it. Code-folding just isn't the same, you are still conceptually dealing with files on a file system - methods and their interactions aren't presented as first class entities in "modern" editors or IDEs and thus struggle for that place in the minds of most developers.

Code Bubbles, by Andrew Bragdon at Brown University resumes this paradigm from SmallTalk and takes the UI to the logical next level, all with a polish that just invites you to hunt through the code to sqaush any bugs!

Any professional developer, Java or otherwise, needs to check it out.

/via Lambda the Ultimate

06:29 PM, 13 Mar 2010 by Mark Aufflick Permalink | Short Link | Comments (0)

IBM 305 RAMAC

I wouldn't want to be debugging that 'wired format control'!

via Royal Pingdom.

03:41 PM, 19 Feb 2010 by Mark Aufflick Permalink | Short Link | Comments (0)

iPad gets back to the priorities of the first Macintosh

The first Mac I ever used was a Mac 128, when my Dad brought one home as part of the ground breaking Apple Test Drive promotion. It booted into the Finder quickly even though it used a floppy. It only ran one program at once, so programs (mostly) started and exited quickly and didn't interact. It had a fixed screen size so everyone's experience was the same. There were desk accessories that gave access to limited functionality while applications were running.

Sounds a lot like the iPad (except bigger and black and white - and of course no 3G ;).

Seriously, it's Steve Job's core vision all over again. Steve Jobs didn't want the Apple ][ to have any expandability, it was Steve Wozniak who convinced him (correctly) that computers were still very much a hobbyist device and need expandability. The original Mac wasn't supposed to have upgradeable ram - it was the engineers (Burrell Smith I think) who secretly made the circuit board easily upgradeable.

Only now, the hardware and connectivity reality has caught up with Jobs' reality: hardware is cheap, expendable and compact - and Apple makes the best. Once again another insanely great device is going to change the place computers have in our lives.

11:08 AM, 28 Jan 2010 by Mark Aufflick Permalink | Short Link | Comments (1)

Debugging release/autorelease issues in Cocoa

So your code crashes with an EXC_BAD_ACCESS in objc_msgSend and there is *none* of your own code in the stack trace. Bummer. Since all we know from objc_msgSend is that it's trying to call a method on an object. Since we got EXC_BAD_ACCESS you can bet your bottom dollar that it's attempting to call a method on a freed pointer, so there's no obvious way of finding out what the object was. We can, though, easily find the method. Read Greg Parker's excellent post So you crashed in objc_msgSend(). For the iPhone simulator on my Mac I need to do this at the gdb prompt to decode the eax register:

(gdb) x/s $ecx
0x980530c4:	 "release"
you can see that the selector in the second argument is "release". Now we're getting somewhere, we know an already freed object is trying to be released. Since there is none of our code in the stack trace it's a fair bet that it's happening when the autorelease pool is releasing.

There are a few tricks in your toolbox for tracking down over-released objects. There's the NSZombieEnabled, NSAutoreleaseFreedObjectCheckEnabled and other environment variables which will give you better logging rather than just crashing.

I've found this is not always reliable (logs from the above builtin debug options showed that the over-release was on an NSCFDate object, when in fact it was an NSNumber). Sometimes you also just want to trace through exactly what is happening with your retain/release/autorelease cycles. That's what we're about to achieve here.

Ok, so you have a unit test that replicates this problem right? I use the excellent GHUnit by Gabriel Handford. If not you'll have to play around a bit to narrow down your problem code. In my case, I wanted to confirm that a particular unit test was failing during the autorelease pool release. Best way is to wrap the offending code in a new autorelease pool. Then it will be freed inside your code, which you will see in the stack trace, and confirm you have found the reason. My unit test now looks like:

(Note that the code examples, embedded in github gists, are not showing up in my RSS feed. I'll fix that later, but for now please read the original post)

Now when I fail with EXC_BAD_ACCESS my stack trace looks like this:

Where line 91 of CJTestCJCard.m is the [pool release] call above. So something is being added to the autorelease pool, and is *also* being fully released, or maybe it's being added to the pool more times than it is being retained. There doesn't seem to be a way to interrogate the contents of the autorelease pool (which is a shame) but we log some really useful info by overriding a few methods, like NSObject's release and autorelease methods, so we can see when things are being added to the pool and when things are being released. This is some funky stuff, but since we're only doing it in our unit test class, not code we're going to release you can sleep soundly at night. Here's how I effected logging in release and autorelease.

Add this to the top of your unit test class, before your current @implementation:

Now in your unit test class @implementation, you can use the setupClass method to effect the method implementation switcharoo:

Now your log will be filled with log lines like:

This can help when tracking down tricky releasing bugs. Note that not all classes seem to comply. For instance I see plenty of log lines for NSCFString, but never any release lines. I assume that NSCFString release implementation is a bit different since it's a toll free bridged object - getting that to log is an exercise left for the reader!

If you're interested in the functions I used above to interact with the runtime, check out the Introduction to The Objective-C Programming Language and Objective-C Runtime Reference. Note that the code above works fine in the iPhone simulator. It should be fine on 64 bit Mac apps, but you may need to diddle the method structs manually in 32 bit Mac apps since they use the legacy Objective-C runtime (which you can read about in the Objective-C 1 Runtime Reference).

Also note it won't work on the iPhone itself, so to save constantly commenting out code, you can wrap the offending code in #if TARGET_IPHONE_SIMULATOR #endif pairs.

12:38 PM, 14 Jan 2010 by Mark Aufflick Permalink | Short Link | Comments (2)

Wow - twitter has sure killed my blogging

I'm not the first to note this, but my blogging sure has taken a huge hit thanks to Twitter (where you can follow me as @markaufflick). It's been a bit over a month since my last post. Contrast that with the fact that in the more than 6 years I've been writing this blog I've only not blogged in April 2008, March 2009 and December 2009.

And that's a shame - because some things I blurt out on twitter, either technical or personal, could stand more thought and word-smithing than 140 characters allow.

So one of my 2010 resolutions is to blog more - even if I tweet first.

I'm even open to topic suggestions.

03:37 AM, 03 Jan 2010 by Mark Aufflick Permalink | Short Link | Comments (0)

XML

Blog Categories

software (39)
..cocoa (21)
  ..heads up 'tunes (5)
..ruby (6)
..lisp (3)
..perl (4)
..openacs (1)
mac (20)
embedded (2)
..microprocessor (2)
  ..avr (1)
electronics (3)
design (1)
photography (25)
..black and white (6)
..A day in Sydney (18)
..The Daily Shoot (6)
food (2)
Book Review (2)

Notifications

Icon of Envelope Request notifications

Syndication Feed

XML

Recent Comments

  1. Unregistered Visitor: An other Script
  2. Unregistered Visitor: A message in there?
  3. Unregistered Visitor: using Amazon S3
  4. Unregistered Visitor: Thank you ! Thank you ! Thank you !
  5. Unregistered Visitor: Umbrello on leopard
  6. Unregistered Visitor: Script gor generate for library
  7. Unregistered Visitor: Similar but different
  8. Unregistered Visitor: Thanks for fixing my problem!
  9. Unregistered Visitor: Pop up once the category is been defined
  10. Unregistered Visitor: smal amendment