Face to Face
Back in December, we lured a black squirrel onto our porch by putting a line of nuts onto the railing so that Christophe could watch him eat.
Back in December, we lured a black squirrel onto our porch by putting a line of nuts onto the railing so that Christophe could watch him eat.
posted at
8:30 PM
posted at
10:20 AM
Labels:
development,
google,
google i/o,
google web toolkit,
gwt,
web,
web development
I was curious about how the iPad plans that were announced by Bell, Rogers and Telus compared, where the break points were, and so forth. So I threw together a Google Spreadsheet to do some quick math on the plans. Assuming I read the plan rules correctly, I think the lessons are as follows:
Marco Arment on iPhone Multitasking:
One of my most common feature requests is for Instapaper to periodically download articles in the background. A lot of people forget to launch the app to let it download content before going underground or boarding a plane.
I’ve already received multiple emails from people who are excited for iOS 4’s multitasking because they can’t wait for this to finally stop being an issue, because they think Instapaper will be able to download articles periodically in the background.
It’s painful to respond, crushing their hopes, to tell them that the iOS multitasking system doesn’t allow me to do that.
posted at
8:59 AM
Labels:
ios,
ipad,
iphone,
multitasking
I was pleased to see that Telus announced and rolled out Visual Voicemail, as was implied in the Carrier Update file I received and analyzed.
posted at
2:39 PM
Labels:
carrier update,
iphone,
telus,
visual voicemail
Safari 4.0.4, when it came out, had an issue with respect to GWT development, causing the GWT hosted mode browser to crash on load. As a result, I didn't take the Safari 4.0.4 update. When Safari 4.0.5 came out, reports indicated that it wasn't any better, despite the fact that some of the interim builds of WebKit had been used successfully, so I didn't take that update either.
posted at
1:08 PM
Labels:
development,
google web toolkit,
gwt,
mac os x,
os x,
safari,
software
This morning, iTunes warned me that there was a carrier update available for my iPhone. The 'more info' button opened a link that explained the process, but didn't offer any details about what the update contained, other than updates with regard to my settings for my carrier, Telus.
$ mkdir ~/telus
$ cp ~/Library/iTunes/iPhone\ Carrier\ Support/Telus_ca.ipcc ~/telus/telus.zip$ cd ~/telus$ unzip telus.zip
Archive: telus.zip
creating: Payload/
creating: Payload/Telus_ca.bundle/
inflating: Payload/Telus_ca.bundle/carrier.plist
inflating: Payload/Telus_ca.bundle/Default_CARRIER_TELUS.png
inflating: Payload/Telus_ca.bundle/FSO_CARRIER_TELUS.png
inflating: Payload/Telus_ca.bundle/Info.plist
inflating: Payload/Telus_ca.bundle/version.plist
$ plutil -convert xml1 *.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>BookmarkURLs</key>
<array>
<dict>
<key>BookmarkName</key>
<string>TELUS Web</string>
<key>BookmarkURL</key>
<string>http://m.telusmobility.com/homepage</string>
</dict>
</array>
<key>CarrierBookmarks</key>
<array>
<dict>
<key>Title</key>
<string>Web TELUS</string>
<key>URL</key>
<string>http://m.telusmobility.com/homepage</string>
</dict>
</array>
<key>CarrierName</key>
<string>TELUS</string>
<key>IntlDataRoamingSwitch</key>
<true/>
<key>MMS</key>
<dict>
<key>GroupModeEnabled</key>
<false/>
<key>MMSC</key>
<string>http://aliasredirect.net/proxy/mmsc</string>
<key>MaxRecipients</key>
<integer>20</integer>
<key>Proxy</key>
<string>74.49.0.18:80</string>
</dict>
<key>MaxBluetoothModemConnections</key>
<integer>1</integer>
<key>MyAccountURL</key>
<string>http://m.telusmobility.com/homepage</string>
<key>MyAccountURLTitle</key>
<string>TELUS Web</string>
<key>Services</key>
<array>
<dict>
<key>ServiceCode</key>
<string>#411</string>
<key>ServiceName</key>
<string>Directory Assistance</string>
</dict>
<dict>
<key>ServiceCode</key>
<string>#411</string>
<key>ServiceName</key>
<string>Assistance-annuaire</string>
</dict>
<dict>
<key>ServiceCode</key>
<string>#8294</string>
<key>ServiceName</key>
<string>TAXI</string>
</dict>
<dict>
<key>ServiceCode</key>
<string>#2886</string>
<key>ServiceName</key>
<string>Roadside Assistance</string>
</dict>
<dict>
<key>ServiceCode</key>
<string>#2886</string>
<key>ServiceName</key>
<string>Assistance Routière</string>
</dict>
</array>
<key>ShowCallForwarded</key>
<false/>
<key>ShowCallForwarding</key>
<false/>
<key>ShowDialAssist</key>
<false/>
<key>ShowTTY</key>
<false/>
<key>StatusBarImages</key>
<array>
<dict>
<key>AllowPrefixMatching</key>
<false/>
<key>CarrierName</key>
<string>TELUS</string>
<key>DefaultImage</key>
<string>Default_CARRIER_TELUS.png</string>
<key>FullScreenOpaqueImage</key>
<string>FSO_CARRIER_TELUS.png</string>
</dict>
<dict>
<key>AllowPrefixMatching</key>
<false/>
<key>CarrierName</key>
<string>TELUS UMTS</string>
<key>DefaultImage</key>
<string>Default_CARRIER_TELUS.png</string>
<key>FullScreenOpaqueImage</key>
<string>FSO_CARRIER_TELUS.png</string>
</dict>
</array>
<key>StockSymboli</key>
<array>
<dict>
<key>symbol</key>
<string>T.TO</string>
</dict>
<dict>
<key>symbol</key>
<string>TU</string>
</dict>
</array>
<key>SupportedSIMs</key>
<array>
<string>302220</string>
</array>
<key>SupportsNITZ</key>
<true/>
<key>SupportsUserBusyCauseCode</key>
<true/>
<key>VVMIgnoresIntlDataRoaming</key>
<false/>
<key>VisualVoicemailServiceName</key>
<string>IMAP</string>
<key>apns</key>
<array>
<dict>
<key>apn</key>
<string>sp.telus.com</string>
<key>password</key>
<string></string>
<key>signature</key>
<data>
...
</data>
<key>type-mask</key>
<integer>7</integer>
<key>username</key>
<string></string>
</dict>
<dict>
<key>apn</key>
<string>isp.telus.com</string>
<key>password</key>
<string></string>
<key>signature</key>
<data>
...
</data>
<key>type-mask</key>
<integer>48</integer>
<key>username</key>
<string></string>
</dict>
<dict>
<key>apn</key>
<string>sp.telus.com</string>
<key>password</key>
<string></string>
<key>signature</key>
<data>
...
</data>
<key>type-mask</key>
<integer>6</integer>
<key>username</key>
<string></string>
</dict>
</array>
<key>com.apple.voicemail.imap</key>
<dict>
<key>BeaconAddress</key>
<string>474663</string>
<key>ClientManagesTrash</key>
<false/>
<key>GreetingNotification</key>
<true/>
<key>MaxGreetingDuration</key>
<integer>60</integer>
<key>MaxPINLength</key>
<integer>10</integer>
<key>MinPINLength</key>
<integer>4</integer>
<key>UsesMWI</key>
<true/>
<key>UsesSSL</key>
<false/>
</dict>
<key>voicemail_context</key>
<integer>0</integer>
</dict>
</plist>
posted at
9:02 AM
Labels:
carrier update,
investigation,
iphone,
telus
In my previous entry, I wrote up a class for displaying Input Prompts in GWT. As I started to fold that code into my project, I realized that I didn't expose the handler registrations, which would make it impossible to remove the event handlers if and when the text fields for which input prompts were displayed were created and removed during the lifecycle of the application.
Because the Input Prompt registers handlers for both Blur and Focus, there are two registrations. It's not easy to return two values from a single method, and frankly, I don't think a class using InputPrompt should have to know or care what events it's employing in great detail. As a result, I've created a composite event handler registration to return:
package com.codiform.gwt.event;
import java.util.ArrayList;
import java.util.List;
import com.google.gwt.event.shared.HandlerRegistration;
public class CompositeHandlerRegistration implements HandlerRegistration {
private Listregistrations;
public CompositeHandlerRegistration() {
registrations = new ArrayList();
}
void add( HandlerRegistration registration ) {
if( registration instanceof CompositeHandlerRegistration ) {
CompositeHandlerRegistration composite = (CompositeHandlerRegistration) registration;
registrations.addAll( composite.getRegistrations() );
composite.clear();
} else {
registrations.add( registration );
}
}
private ListgetRegistrations() {
return registrations;
}
public void removeHandler() {
if ( registrations.size() > 0 ) {
for ( HandlerRegistration item : registrations ) {
item.removeHandler();
}
clear();
} else {
throw new IllegalStateException( "Composite handler registration is currently empty, and cannot remove handlers." );
}
}
private void clear() {
registrations.clear();
}
}
For a GWT project I'm working on, I've reached a point where I wanted to apply input prompts to a text box; this doesn't seem to be something that's built in to the basic GWT framework, or an easily-located extension. For that matter, I couldn't find anyone who'd done it and blogged about it, although it might be that they've used different terminology.
I thought it was worth a quick experiment to see how easy they would be to apply, and this is what I came up with:
package com.codiform.gwt.widget;
import com.google.gwt.event.dom.client.BlurEvent;
import com.google.gwt.event.dom.client.BlurHandler;
import com.google.gwt.event.dom.client.FocusEvent;
import com.google.gwt.event.dom.client.FocusHandler;
public class InputPrompt implements BlurHandler, FocusHandler {
private String promptText;
public InputPrompt( String text, TextBox... inputs ) {
this.promptText = text;
for( TextBox item : inputs ) {
apply( item );
}
}
public void apply( TextBox input ) {
input.addBlurHandler( this );
input.addFocusHandler( this );
applyPrompt( input );
}
public void onBlur( BlurEvent event ) {
TextBox blurred = (TextBox) event.getSource();
applyPrompt( blurred );
}
private void applyPrompt( TextBox input ) {
if( input.getText().isEmpty() ) {
input.setText( promptText );
input.addStyleName( "inputPrompt" );
}
}
public void onFocus( FocusEvent event ) {
TextBox focused = (TextBox) event.getSource();
if( promptText.equals( focused.getText() ) ) {
focused.setText( "" );
focused.removeStyleName( "inputPrompt" );
}
}
}
Ran into an interesting issue this morning:
mysql> drop table RELATIONSHIP_TYPE;
ERROR 1051 (42S02): Unknown table 'relationship_type'
mysql> CREATE TABLE `RELATIONSHIP_TYPE` (`relationshipTypeId` INT UNSIGNED AUTO_INCREMENT NOT NULL, `name` VARCHAR(10) NOT NULL, `code` VARCHAR(2) NOT NULL, CONSTRAINT `PK_RELATIONSHIP_TYPE` PRIMARY KEY (`relationshipTypeId`)) ENGINE INNODB;
ERROR 1050 (42S01): Table 'relationship_type' already exists
$ mysqladmin flush-tables
posted at
10:15 AM
Labels:
error,
mysql,
mysqladmin,
table
I've written up a small script for displaying Maven build notifications using Growl, and put it up on Github.
posted at
2:25 AM
Labels:
development,
growl,
maven,
software
Like many developers, I’ve used a large number of open-source projects over the years to get my work done. Also like many developers, I’ve worked for companies that were wary of contributing to open-source projects to any significant degree. Worse, several of these companies attempted to claim the rights to any software built while employed by them, without regard to whether this was built for them, or on their time. These attitudes are common, suspect, and should probably be the subject of another post.
I’ve returned to doing freelance software development and software consulting this year (and, hey, if you need someone to help you with software development, drop me a line). Although working for yourself has some drawbacks, it does come with a lot of freedom. That includes the freedom to work on open-source projects in unbillable time (or, if you have an understanding with your client, even potentially in billable time).
I’ve been taking advantage of that recently, by building a project to map objects to objects, called Moo. I’ve been on projects that have needed something like this a number of times, and teams I’ve been on have built something very similar to this twice before. I’m really hoping this is the last time I’ll have to write this particular piece of code, because from now on I’ll be able to adopt my own code, even if I’m working for another company.
In order to increase the odds that I’ll be able to adopt it, and to help as many other teams as I can, I’ve used the BSD license. That means you can bury Moo inside your own work and you don’t have to pay me, or adjust the license of your project. If you want to credit me in some way, that’d be cool, but mostly I just want to make sure that, if Moo is useful to you (or to me!) there aren’t any obstacles to that.
posted at
1:45 AM
Labels:
contract,
freelance,
mapping,
moo,
objects,
open-source,
oss,
serialization,
web services
The first Ignite Toronto went off on Tue 25-Aug-2009 at the Drake Hotel Underground. I was able to shoot a few photos:
All in all, the ignites were enjoyable, although I do wish the ignites had started sooner. There was ample time to drink and discuss in advance, but I'd like time to see all the ignites, and then talk some more afterwards without wishing I were home, asleep.
I'm getting old, I know.
Of particular amusement was when the Creemore Springs tap decided to fail very publicly with a bit of a Beersplosion:
posted at
2:10 AM
Labels:
ignite,
ignite toronto,
ignite toronto 1,
oreilly,
photo,
photography,
toronto
Ben Vinegar presented Guestlist at DemoCamp Toronto 21 (Velma Rogers Theatre; 333 Bloor Street East; 28-Jul-2009):
If you'd like to see the large/HD version, click through to YouTube. I also recorded the Q&A that followed (YouTube):
Ben had a self-deprecating style which initially made me wonder if the presentation was going to bomb, but he pulled it off with aplomb, and it ended up being one of the more entertaining demos of the night.
Guestlist is one of the more polished and promising applications I've seen at DemoCamp, and I expect this won't be the last time you hear something about it. I'd say it has a relatively bright future in front of it. It's not a unique product, it's just very well executed.
Apparently the Guestlist folks mostly (all?) work at FreshBooks.
posted at
12:43 PM
Labels:
#dct21,
Ben Vinegar,
bentlegen,
demo,
DemoCamp,
DemoCamp Toronto,
DemoCamp Toronto 21,
Guestlist
I've been doing some experimentation with Scala lately, mostly by reading the Wampler / Payne Programming Scala in O'Reilly Labs. Learning a language by reading about it is deceptive, so I've been looking for an excuse to write some non-trivial Scala code with which to better exercise and test my knowledge of the language.
class KnightsTour(val dimensions : Pair[int,int], val startPosition : Pair[int,int] ) {
val relativeMoves = List( Pair(2,1), Pair(2,-1), Pair(-2,1), Pair(-2,-1), Pair(1,2), Pair(-1,2), Pair(1,-2), Pair(-1,-2) )
val xPositions = 0 until dimensions._1
val yPositions = 0 until dimensions._2
val tourLength = dimensions._1 * dimensions._2;
var closedTours = 0;
var openTours = 0;
def printPaths() : Unit = {
printChildPaths( List(startPosition) )
println( "There were " + ( openTours + closedTours ) + " tours (" + openTours + " open, " + closedTours + " closed)." );
}
def printChildPaths( path : List[ Pair[int,int] ] ) : Unit = {
val moves = getMoves( path.first );
if( path.size == tourLength ) {
if( moves.contains(startPosition) ) {
closedTours += 1
println( "Found a closed tour: " + path )
} else {
openTours += 1
println( "Found an open tour: " + path )
}
} else {
moves.filter( move => !path.contains(move) ).foreach( move => printChildPaths( move :: path ) )
}
}
def getMoves( position: Pair[int,int] ) : List[Pair[int,int]] = {
relativeMoves.map( move => Pair(position._1 + move._1, position._2 + move._2 ) ).filter( withinDimensions )
}
def withinDimensions( position: Pair[int,int] ) : boolean = {
return xPositions.contains( position._1 ) && yPositions.contains( position._2 )
}
}
val tour = new KnightsTour( Pair(3,4), Pair(0,0) )
tour.printPaths();
posted at
12:30 AM
Labels:
knight's tour,
learning,
praxis,
scala
Dan Wood and Martin Pietrzak presented WeGoWeGo at DemoCamp Toronto 21 (Velma Rogers Theatre, 333 Bloor Street East; 28-Jul-2009):
I also captured the Q&A session that followed:
As always, you can feel free to click through to YouTube (presentation, Q&A) to watch the larger HD stream.
They do a user-generated content site for listing things to do. They attempt to differentiate through the search model ("faceted search categorization"). I have to say, this just didn't seem like it was currently differentiated enough to grab my attention. There's a lot of web sites in this space, and I'm not convinced the search is sufficient, particularly in a world where network effects create a sort of lock-in, giving the first-movers a bit of an edge.
That said, I'm happy to be proven wrong.
posted at
8:56 AM
Labels:
dan wood,
demo,
DemoCamp,
democamp 21,
DemoCamp Toronto,
DemoCamp Toronto 21,
martin pietrzak,
wegowego
Shaun MacDonald presented Mashup Arts at DemoCamp Toronto 21 (July 28th, 2009; Velma Rogers Theatre; 333 Bloor Street East):
If you'd like to see the video larger in HD, feel free to click through to YouTube.
MashupArts is essentially rich media e-cards whereby you load videos and photos from the web into your card and then share it, and get others to collaborate with you on the card before sending it to the victim/recipient.
The concept seems sound, although I think there's still a fair ways to go before this is a polished, fully-featured application. There are features that I'd like to see added, and parts of the interface felt like they needed further work, but as long as it continues to improve, this seems like something that has potential to succeed.
posted at
8:49 AM
Labels:
demo,
DemoCamp,
democamp 21,
DemoCamp Toronto,
DemoCamp Toronto 21,
mashup arts,
shaun macdonald,
toronto
Alan Lynse of Cascada Mobile presented Breeze at DemoCamp Toronto 21 at the Velma Rogers Theatre (333 Bloor Street East) on July 28th, 2009. Breeze is a platform for building mobile applications using web technologies that run on a wide array of mobile phone platforms (iPhone, Android, etc.):
In this case, not only can you click through to YouTube, I recommend that you do, since part of this demonstration involves coding in Eclipse, which is a lot easier on your eyes if you switch to the larger HD mode.
Seems like a good way for companies to build simple applications that cross all handsets. If you want the polish of a fully native application that's tailored to the capabilities and design of a particular device, this probably won't cut it, but not everybody needs that, particularly for the first pass.
I don't see this surplanting native mobile application development any time soon, but it's a useful option to keep in mind.
posted at
4:17 PM
Labels:
#dct21,
#democamp,
Alan Lynse,
android,
breeze,
cascada,
cascada mobile,
DemoCamp,
DemoCamp Toronto,
DemoCamp Toronto 21,
development,
iphone,
mobile,
phone
Brian Sharwood presented HomeStars.com at DemoCamp Toronto 21 (July 28th, 2009; Velma Rogers Theatre, 333 Bloor Street East):
Feel free to click through to YouTube to see it in full-size HD.
Some good anecdotes, and the site functionality /sounds/ good, but there wasn't much in the way of a demo here. More demo, less presentation would have been good.
That said, I would check out the site if I needed some work done and wasn't going to do it myself.
posted at
1:08 PM
Labels:
#dct21,
brian sharwood,
DemoCamp,
democamp 21,
DemoCamp Toronto 21,
home,
homestars,
homestars.com,
renovation
I've recently redone my twitter background (which you can see on my twitter page), and in so doing used a few images that, while creative-commons-licensed, should be attributed. Because twitter pages can't easily hold credit links, it seemed worth doing here, rather than there.
Accordingly, you can find the images I used here:
posted at
9:11 AM
Labels:
attribution,
credits,
image,
photo,
photography,
twitter