Main

March 14, 2011

Slides for the upcoming iPhone iPad Devcon Talks

I'm talking at the upcoming iPhone iPad Devcon in Boston from April 4 through 6 and today is the day we all get to share our slides! I'm honored to be talking with Noah Gift and Jonathan Blocksom again. This time, Jonathan and I are doing a full day on Augmented Reality!

The latest version of the slides for the Augmented Reality Full day class is here. (Last Mod: 20110314)
There will be a whole packet of code and other goodness given out on the day of the class.

The latest version of the Open Source UI talk is here. (Last Mod: 20110314)

The latest version of the Caching and performance talk is here. (Last Mod: 20110314)

The latest version of the touchengine talk is here. (Last Mod: 20110314)

October 06, 2010

iPhone iPad Devcon sample code and downloadable slides

Hi everybody. I'm hearing from the conference organizers that slideshare is requiring a login to download the slides. I've put them up on my server along with sample code.

The downloadable pdf version of the Augmented Reality talk is here. Sample code is here. Videos are here. The latest version of the code can always be found on Google Code here.

The downloadable pdf version of the Open Source UI talk is here. Sample code is here. Please see the presentation for various links to the open source project it references.

The downloadable pdf version of the Caching and performance talk is here. Sample code is here.

The downloadable pdf version of the touchengine talk is here. Sample code is here. The latest version can always be found on Google Code here.

August 04, 2010

I'm giving four (!) classes at iPad/iPhone DevCon

saggau_speakerbadge.png

The iPad/iPhone DevCon will be held in San Diego from September 27 through 29 and I've been invited to give four classes! If you put my last name, SAGGAU, in when you register, you will automatically save a hundred bucks ($ 100.00) -- and it's combinable with their other promotional discounts, like Early Bird Specials and so-on.

The conference program at iPhone/iPad DevCon includes more than 40 full-day workshops, half-day workshops and technical classes over three days – in addition to keynotes by Mike Lee and Aaron Hillegass.

CLASS DATES AND TIMES

My courses are currently scheduled as follows:
103 Optimizing Data Caching for iPhone App Responsiveness
Tuesday, Sept. 28, 8:30 — 9:45 am

203 Is It Real or Is It Virtual? Augmented Reality on the iPhone with Jonathan Blocksom (most recently of Google)
Tuesday, Sept. 28, 11:15 am — 12:30 pm

303 TANSTAAFL: Using Open Source iPhone UI Code
Tuesday, Sept. 28, 2:00 — 3:15 pm

403 Connecting Apple's iPhone to Google's Cloud with Noah Gift (of AT&T Interactive)
Tuesday, Sept. 28, 3:45 — 5:00 pm

September 30, 2009

My Deck for 360idev

Thanks to all who attended my talk at 360idev. I think it went rather well and I am grateful to all who attended; the audience makes the talk. Here are the slides and the sample code as promised. Please read the readme file.

I'll also take some time on the plane home tomorrow night to make versions of this sample code without blocks for those who like to kick it old school. I'll post those here as soon as I can.

UPDATE: I've changed the last example to remove the blocks requirement for those who wish to avoid them. Same download location here as before.

Note: Be aware that the slides are on a pretty slow internet connection.

October 01, 2008

iPhone NDA -- some thoughts

When the news came out today that Apple has chosen to lift the iPhone NDA, I (like many developers) breathed a sigh of relief. I would like to take a moment to thank my peers for being so outspoken and to thank Apple for finally deciding to make my life as an iPhone developer excedingly easier by allowing the members of the development community to do as they so often and so unselfishly do to help one another with various recurring difficulties that crop up in our craft. The Mac OS X software community that I've had the pleasure of getting to know over the last couple of years continues to astound me. I'm proud to count myself among them. They are, to a person, a wonderful, well-meaning, honest, and interesting group of people who, as evidenced by the recent brouhaha over the aforementioned NDA, are very vocal about their beliefs and try to treat others as they expect to be treated. I've decided to take a page from that book and voice a belief of mine: A contract is a contract.

Having had the pleasure of arguing over contracts (including several of my own), intellectual property, personal liberty, and many similar topics with more than a few software developers, attorneys, students, musicians, my astonishingly intelligent parents, and various other people I have admired over the years, I've come to a few conclusions. One of the fundamental principals I try to follow in my own dealings with others is, I'm told, a basic brocard of civil law -- Pacta sunt servanda ("agreements must be kept").

Continue reading "iPhone NDA -- some thoughts" »

November 26, 2007

Likely in store. Likely? WTF?

So I went to Borders on Wall street today, thinking "hey, let's have a look at Fake Steve's book." I go to their little search engine kiosk, punch in the title and see "Humor" under section and "Likely in store" under availability. Hmmm. Ok. So the kiosk isn't hooked into their inventory. Fair enough, as a friend of mine likes to say. I go to the little help desk and ask "where's humor?" (they didn't get the joke...It was a dumb joke). I head in the direction of the pointing and grunting. I seek. I do not find. I approach another help desk, this one nearer to the section in question. I follow the nice Borders "associate" (when did we stop using "employee" and "clerk," by the way?) over to the section I was just examining, where she proceeds to look for Fake Steve's book on the same shelf I was. Apparently, alphabetical order is still alphabetical order. Glad I'm not crazy. "Let me go ask if anybody has seen it," she says. "Um. Okay," I reply. Now I don't think that I'm expecting miracles. I just want to know if they have a certain book. After about five minutes the (ahem) "associate" comes back with a "I don't think we have it, but we can order it for you." ...to which I reply (admittedly snidely) "If I had wanted to order it, I would have done so from the comfort of my own home from Amazon. Thanks for looking."

I have questions. Why do the Borders associates clearly have no access to inventory numbers? Why could she not tell me "we have two copies." I can understand having difficulty finding a specific volume, what with the abundance of end caps and special tables in the book stores these days. How hard is it to track inventory? Isn't that what those neat shiny computer doodads they have scattered all over the store are supposed to be good at? Grrrrr.

Shipley! Make a distributed version of Delicious Library or something. These people need help.

August 26, 2007

iPhone theft is teh suck

Poof. Phone gone. 'twas a real pro. I carry my iphone in a case with a very difficult to remove clip attached to the inside of the front strap of my computer bag, which I always hang diagonally across my chest to make it more difficult for someone to run off with my stuff. Doing this places the iphone in its case between my chest and a somewhat tensioned strap. During the afternoon on Thursday, I vaguely registered that I was bumped into a couple of times while walking through the WTC "Viewing Area." I'm accustomed to this as navigating through there without screaming at slow-moving Midwesterners (of which I was once one, so I try to be nice) sometimes proves difficult. I don't think I'll be taking my subway shortcut any more.

If you're wondering what's the absolute worst part about getting an iPhone stolen, it's not that creepy feeling of violation that comes from having one's personal property lifted, it's transferring service to a new iPhone through AT&T. I had originally opted to avoid the two-year AT&T suck customer service lock-in with a "Go Phone" plan, gambling that somebody would come out with a hack that would allow me to use (say) T-Mobile with my iPhone. Until that happens, though I would just love to be able to use the device in the same way I have been. When I got my new iPhone, I thought perhaps the option to transfer my current AT&T number to a new phone would be the logical one to choose. Nope. Apparently, AT&T/Apple never thought that anyone would want to transfer service from one iPhone to another (at least not on the "Go Phone" plan). Long story short: as of right now I'm out the 78(ish) dollar balance I had in my "Go Phone" prepaid account as well as a new activation fee. Why? The only way I could get an activation (according to AT&T customer service) is to go through the "I want a new contract" activation process (without the "all nines" hack). Since my credit doesn't suck, I have a two - year AT&T contract to try to get out of now. That is a pickpocketing I'm going to fight.

For those waiting for iPong, I was expecting to have it ready for public consumption by tonight, but have just jailbroken my new phone. The network error handling and preference code was coming together nicely before my little adventure. I should be able to release something fairly stable during the week.

The way-too-adventurous among us can find the code as it stands now on google. I moved the repository there a few nights ago in anticipation of the release.

August 14, 2007

iPhone Native Pong Application: the real "sweet" SDK

The native iPhone hack I put together for the C4[1] conference is in the process of a "wow, I hope somebody can read this code someday" cleanup. I will release the source in the coming days. Stay tuned for a download link.

In the meantime, here are a couple of teasers.

Screenshots:

scrnsht1.jpg


scrnsht2.jpg


And here is some code for playing a sound file from your native iPhone Application's bundle (with the class-dump'd headers you'll need, too). The iPhone, as was mentioned by everyone with a native hack at C4, has some really intelligent API. Hats off, ladies and gentlemen, to the iPhone team. They must be having a grand ol' time internally playing with this thing.



//
// PongAudio.h
//
// Created by Jonathan Saggau on 2007-08-12.
// Copyright (c) Jonathan Saggau All rights reserved.
//

#import <Foundation/Foundation.h>
@class AVItem;
@class AVController;
@class AVQueue;

@interface PongAudio : NSObject
{
AVItem *bounce;
AVItem *loser;
AVQueue *q;
AVController *controller;
}

-(void)playBounce;
-(void)playLoser;

-(void)stop;
@end

//
// PongAudio.m
//
// Created by Jonathan Saggau on 2007-08-12.
// Copyright (c) 2007 __MyCompanyName__. All rights reserved.
//

#import "PongAudio.h"
#import "AVItem.h"
#import "AVController.h"
#import "AVQueue.h"

//From Aaron hillegass
#define LogMethod() NSLog(@"-[%@ %s]", self, _cmd)

@interface PongAudio (PrivateAPI)
-(void)play:(AVItem *)item;
@end

@implementation PongAudio


- (id)init
{
self = [super init];
if (nil!= self)
{
NSError *err;
NSString *path = [[NSBundle mainBundle] pathForResource:@"PongBounce" ofType:@"wav" inDirectory:@"/"];
bounce = [[AVItem alloc] initWithPath:path error:&err];
if (nil != err)
{
NSLog(@"err! = %@ \n item = [[AVItem alloc] initWithPath:path error:&err];", err);
exit(1);
}

path = [[NSBundle mainBundle] pathForResource:@"PongLose" ofType:@"wav" inDirectory:@"/"];
loser = [[AVItem alloc] initWithPath:path error:&err];
if (nil != err)
{
NSLog(@"err! = %@ \n item = [[AVItem alloc] initWithPath:path error:&err];", err);
exit(1);
}

controller = [[AVController alloc] init];
[controller setDelegate:self];
q = [[AVQueue alloc] init];
[q appendItem:bounce error:&err];
if (nil != err)
{
NSLog(@"err! = %@ \n [q appendItem:item error:&err];", err);
exit(1);
}

[q appendItem:loser error:&err];
if (nil != err)
{
NSLog(@"err! = %@ \n [q appendItem:item error:&err];", err);
exit(1);
}
}
return self;
}

- (void)dealloc
{
[bounce release]; bounce = nil;
[loser release]; loser = nil;
[q release]; q = nil;
[controller release]; controller = nil;
[super dealloc];
}

-(void)playBounce
{
[self play:bounce];
}

-(void)playLoser
{
[self play:loser];
}

-(void)play:(AVItem *)item;
{
[controller setCurrentItem:item];

//play NOW
[controller setCurrentTime:(double)0.0];
//should probably check this eventually, too.
//- (BOOL)isCurrentItemReady;
NSError *err;
[controller play:&err];
if(nil != err)
{
NSLog(@"err! = %@ [controller play:&err];", err);
exit(1);
}
}

-(void)stop;
{
[controller pause];
}

- (void)queueItemWasAdded:(id)fp8
{
LogMethod();
}
@end


//AVController.h
/*
* Generated by class-dump 3.1.1.
*
* class-dump is Copyright (C) 1997-1998, 2000-2001, 2004-2006 by Steve Nygard.
*/


#import <Foundation/Foundation.h>
#import "CDStructures.h"

@interface AVController : NSObject
{
struct AVControllerPrivate *_priv;
}

+ (void)setEnableNetworkMode:(BOOL)fp8;
+ (id)avController;
+ (id)avControllerWithQueue:(id)fp8 error:(id *)fp12;
- (id)initWithError:(id *)fp8;
- (void)setAVItemClass:(Class)fp8;
- (id)init;
- (void)dealloc;
- (struct AVControllerPrivate *)privateStorage;
- (BOOL)isNewImageAvailableForTime:(const CDAnonymousStruct1 *)fp8 willNeverBeAvailable:(char *)fp12;
- (long)copyImageForTime:(struct __CVBuffer **)fp8 time:(const CDAnonymousStruct1 *)fp12;
- (void)itemPropertyDidChangeNotification:(id)fp8;
- (void)scheduleQueueSpaceCheck;
- (void)checkQueueSpace;
- (void)queueItemWasAdded:(id)fp8;
- (void)queueItemWasAddedNotification:(id)fp8;
- (void)queueItemWillBeRemovedNotification:(id)fp8;
- (void)cancelPrepareForPlayback;
- (void)setQueue:(id)fp8;
- (id)queue;
- (void)feederRangeWasInserted:(id)fp8;
- (void)feederRangeWasRemoved:(id)fp8;
- (void)feederInvalidatedWithCurrentItemMoved:(id)fp8;
- (void)setQueueFeeder:(id)fp8 withIndex:(int)fp12;
- (void)setQueueFeeder:(id)fp8;
- (id)queueFeeder;
- (BOOL)setRepeatMode:(int)fp8;
- (int)repeatMode;
- (BOOL)havePlayedCurrentItem;
- (id)currentItem;
- (id)currentItemPriv;
- (void)setCurrentItem:(id)fp8 preservingRate:(BOOL)fp12;
- (void)setCurrentItem:(id)fp8;
- (void)makeCurrentItemReady;
- (BOOL)isCurrentItemReady;
- (void)continueAfterRepeatGap;
- (void)cancelContinueAfterRepeatGap;
- (void)doCancelContinueAfterRepeatGap;
- (void)doScheduleContinueAfterRepeatGap:(id)fp8;
- (BOOL)beginRepeatGap;
- (void)itemFailedPlaying;
- (void)itemFinishedPlaying:(id)fp8;
- (void)itemCompletedDecode;
- (BOOL)play:(id *)fp8;
- (void)pause;
- (void)dequeueFirstItem;
- (unsigned int)indexOfCurrentQueueFeederItem;
- (BOOL)setIndexOfCurrentQueueFeederItem:(unsigned int)fp8 error:(id *)fp12;
- (id)addNextFeederItemToQueue;
- (BOOL)playNextItem:(id *)fp8;
- (float)rate;
- (BOOL)shouldBeginPlayingItem:(id)fp8 error:(id *)fp12;
- (BOOL)setRate:(float)fp8 error:(id *)fp12;
- (BOOL)resumePlayback:(double)fp8 error:(id *)fp16;
- (id)errorWithDescription:(id)fp8 code:(long)fp12;
- (void)makeError:(id *)fp8 withDescription:(id)fp12 code:(long)fp16;
- (BOOL)beginInterruption:(id *)fp8;
- (BOOL)activate:(id *)fp8;
- (void)endInterruptionWithStatus:(id)fp8;
- (float)volume;
- (void)setVolume:(float)fp8;
- (double)currentTime;
- (void)setCurrentTime:(double)fp8;
- (BOOL)muted;
- (void)setMuted:(BOOL)fp8;
- (void)setEQPreset:(int)fp8;
- (int)eqPreset;
- (struct OpaqueFigVisualContext *)visualContext;
- (void)setVisualContext:(struct OpaqueFigVisualContext *)fp8;
- (id)outputQTESFilePath;
- (void)setOutputQTESFilePath:(id)fp8;
- (id)lkLayer;
- (void)setLayer:(id)fp8;
- (id)attributeForKey:(id)fp8;
- (BOOL)setAttribute:(id)fp8 forKey:(id)fp12 error:(id *)fp16;
- (struct _LKImageQueue *)lkImageQueue;
- (struct _LKImageQueue *)lkEnsureQueueForWidth:(unsigned int)fp8 Height:(unsigned int)fp12;
- (double)lkServerTime;
- (BOOL)okToNotifyFromThisThread;
- (void)fmpTimeJumped;
- (void)fmpRateDidChange;
- (void)rateDidChangeToRate:(float)fp8;
- (void)repeatModeHasChanged:(int)fp8;
- (void)currentItemWillChangeToItem:(id)fp8 oldItemCurrentTime:(double)fp12;
- (void)currentItemHasChanged:(id)fp8;
- (void)itemHasFinishedPlayingNotification:(id)fp8;
- (void)resynchronizeTiming;
- (id)delegate;
- (void)setDelegate:(id)fp8;
- (BOOL)setItemAttribute:(id)fp8 value:(id)fp12 forKey:(id)fp16 error:(id *)fp20;
- (id)itemAttribute:(id)fp8 forKey:(id)fp12;
- (id)initWithQueue:(id)fp8 error:(id *)fp12;
- (BOOL)isValid;
- (id)initWithQueue:(id)fp8 fmpType:(unsigned long)fp12 error:(id *)fp16;
- (void)applyAttributesFromItem:(id)fp8;
- (void)fmpRelease:(id)fp8;
- (void)failPlayback:(id)fp8 reason:(long)fp12 notifyClient:(unsigned char)fp16;
- (void)prepareForPlaybackReply:(long)fp8;
- (int)instantiateFMPRef:(struct opaqueFigMoviePlaybackRef **)fp8 forItem:(id)fp12;
- (void)maybeDumpPerformanceDictionary:(struct opaqueFigMoviePlaybackRef *)fp8;
- (void)removeFMPRefListeners:(struct opaqueFigMoviePlaybackRef *)fp8;
- (void)shutdownFMPRef:(struct opaqueFigMoviePlaybackRef *)fp8;
- (void)updateTimeMarkerObservations;
- (void)scheduleUpdateTimeMarkerObservations;
- (void)registerTimeMarkerObserver:(id)fp8 forItem:(id)fp12 times:(id)fp16 context:(id)fp20;
- (void)removeObserver:(id)fp8 fromTMOArray:(id)fp12;
- (void)unregisterTimeMarkerObserver:(id)fp8 forItem:(id)fp12;

@end

//AVExternalAudio.h
/*
* Generated by class-dump 3.1.1.
*
* class-dump is Copyright (C) 1997-1998, 2000-2001, 2004-2006 by Steve Nygard.
*/

#import <Foundation/Foundation.h>
#import "CDStructures.h"

@interface AVExternalAudio : NSObject
{
struct AVExternalAudioPrivate *_priv;
}

+ (id)avExternalAudio:(id)fp8;
- (id)initWithDelegate:(id)fp8;
- (void)dealloc;
- (id)attributeForKey:(id)fp8;
- (BOOL)setAttribute:(id)fp8 forKey:(id)fp12 error:(id *)fp16;
- (void)makeError:(id *)fp8 withDescription:(id)fp12 code:(long)fp16;
- (void)postServerConnectionDiedNotification:(id)fp8;
- (void)fmpServerConnectionDied;
- (BOOL)okToNotifyFromThisThread;
- (BOOL)activate:(id *)fp8;
- (float)volume;
- (BOOL)isActive;
- (void)postUserVolumeChangedNotification:(id)fp8;
- (void)fmpUserVolumeDidChange;
- (void)fmpChangeConnectionActive:(BOOL)fp8;

@end

//AVItem.h
/*
* Generated by class-dump 3.1.1.
*
* class-dump is Copyright (C) 1997-1998, 2000-2001, 2004-2006 by Steve Nygard.
*/

#import <Foundation/Foundation.h>
#import "CDStructures.h"

@interface AVItem : NSObject
{
struct AVItemPrivate *_priv;
}

+ (id)avItem;
+ (id)avItemWithPath:(id)fp8 error:(id *)fp12;
- (id)initWithError:(id *)fp8;
- (id)init;
- (id)initWithPath:(id)fp8 error:(id *)fp12;
- (void)dealloc;
- (BOOL)setPath:(id)fp8 error:(id *)fp12;
- (int)_instantiateItem;
- (id)path;
- (double)duration;
- (struct CGSize)naturalSize;
- (float)volume;
- (void)setVolume:(float)fp8;
- (void)setEQPreset:(int)fp8;
- (int)eqPreset;
- (id)attributeForKey:(id)fp8;
- (BOOL)setAttribute:(id)fp8 forKey:(id)fp12 error:(id *)fp16;

@end

//AVQueue.h
/*
* Generated by class-dump 3.1.1.
*
* class-dump is Copyright (C) 1997-1998, 2000-2001, 2004-2006 by Steve Nygard.
*/

#import <Foundation/Foundation.h>

@class NSMutableArray, NSRecursiveLock;

@interface AVQueue : NSObject
{
NSRecursiveLock *_mutex;
NSMutableArray *_items;
void *_reserved;
unsigned int _flags;
}

+ (id)avQueue;
+ (id)queueWithArray:(id)fp8 error:(id *)fp12;
- (id)initWithError:(id *)fp8;
- (id)init;
- (id)initWithArray:(id)fp8 error:(id *)fp12;
- (void)dealloc;
- (int)_instantiateItem;
- (unsigned int)itemCount;
- (id)itemAtIndex:(unsigned int)fp8;
- (unsigned int)indexOfItem:(id)fp8;
- (id)itemAfterItem:(id)fp8;
- (BOOL)appendItemsFromArray:(id)fp8 error:(id *)fp12;
- (BOOL)appendItem:(id)fp8 error:(id *)fp12;
- (void)itemWasAdded:(id)fp8;
- (BOOL)insertItem:(id)fp8 atIndex:(unsigned int)fp12 error:(id *)fp16;
- (BOOL)insertItem:(id)fp8 afterItem:(id)fp12 error:(id *)fp16;
- (void)itemWillBeRemoved:(id)fp8;
- (BOOL)removeItem:(id)fp8;
- (BOOL)removeItemAtIndex:(unsigned int)fp8;
- (void)removeItemsInRange:(struct _NSRange)fp8;
- (void)removeAllItems;

@end

September 25, 2006

Jury duty. It Ain't the DMV...

. ...and neither is the DMV, for that matter.

When I moved to New York, I vaguely expected some of the horror stories to be true. Yes, some of them are. There really is a rather rank-smelling old fellow who badgers passers by for change outside of the deli. One often notes rats chasing garbage in the subway tunnels. And, yes, some parts of New York smell. Bad.

So far, however, my experiences with municipal government have been pleasant. Today I await the call to join a jury. I'm planted on a comfortable pleather chair, sipping a diet Pepsi (a can I bought for a dollah... ahem), and enjoying free wi-fi access. There is a computer lab in an adjoining room sporting 16 little Dell desktops with Internet access and there are public telephones, vending machines, and a clean bathroom. Sure, I can't visit any clients today and it's possible that I will be watching a trial or some other matter for an indefinite period of time. Right now, though, I'm just hanging out with my Mac people watching. Not bad for government work...and neither is the DMV, for that matter.

September 17, 2006

Happy Birthday

Nobody loves me but my mother and she could be jivin' too.
- BB King

(Happy Birthday to MOM!)

September 02, 2006

They do share a first name

While I'm not in the habit of making public political statements. I just can't let this one go by.

NYTImes Article

SALT LAKE CITY, Aug. 31 — President Bush said Thursday that withdrawing now from Iraq would leave Americans at risk of terrorist attacks “in the streets of our own cities,” and he cast the struggle against Islamic extremists as the costly but necessary successor to the battles of the last century against Nazism and Communism.

“The war we fight today is more than a military conflict,’’ Mr. Bush said in a speech to veterans at an American Legion convention here. “It is the decisive ideological struggle of the 21st century.’’


Sound Familiar?

It does not matter whether the war is actually happening, and, since no decisive victory is possible, it does not matter whether the war is going well or badly. All that is needed is that a state of war should exist. The splitting of the intelligence which the Party requires of its members, and which is more easily achieved in an atmosphere of war, is now almost universal, but the higher up the ranks one goes, the more marked it becomes. It is precisely in the Inner Party that war hysteria and hatred of the enemy are strongest. In his capacity as an administrator, it is often necessary for a member of the Inner Party to know that this or that item of war news is untruthful, and he may often be aware that the entire war is spurious and is either not happening or is being waged for purposes quite other than the declared ones: but such knowledge is easily neutralized by the technique of doublethink. Meanwhile no Inner Party member wavers for an instant in his mystical belief that the war is real, and that it is bound to end victoriously, with Oceania the undisputed master of the entire world.

July 04, 2006

Spotted in New Jersey

A fat, helmetless, man on a Harley Davidson with a propane tank balancing on the gas tank... cigarette in hand.

I guess head injury is the least of his worries...

January 23, 2006

Share

Spent some time at Mundial (thanks to Google for the SMS service and the address) Makin' Troublesome Noise with AM (I think I'm the sidekick. I wanted to be the superhero, but...yeah, I'm the sidekick...) and my fellow noise nerds(TM) at share. The guy who hosted the event, Daniel, mentioned that one could do a "featured set," which is sort of a featured performance before all of the geeks crack open their laptops and jam all night. He must have been out of his mind to think the noises our little corner of the room was making are even close to ready for public consumption... but, it seems maybe-not-so-young-anymore Mr. Saggau will be finding his way back to "the stage" again... sort of.

Continue reading "Share" »