Sunday, October 25, 2009

Ninite - bulk installer, potentially useful

This looks useful - it's a bulk installer for a bunch of things I use.  Windows 7 upgrades on a couple machines are in my very near future, so hopefully this will save some time.

http://ninite.com/

Tuesday, September 29, 2009

F# running on the iPhone

I tried F# on the iPhone (via MonoTouch) tonight.  The trivial hello-world code seemed to work just fine.  I used standalone to build the (trivial) fsharp code:

type Foo() =
  do System.Console.WriteLine("This output brought to you by the note F#");
mono ../FSharp-1.9.6.16/bin/fsc.exe -a Foo.fs

And added a line to instantiate a Foo in FinishedLaunching().

Loaded the resulting dll into MonoDevelop, along with FSharp.Core.dll, and it just worked.  Or at least it worked in the simulator, haven't tried the real device yet.

fsharponiphone

Friday, September 18, 2009

Sequence of positions in a sequence (F#)

Steve Horsfield's blog had a post on fold functions that cared about the beginning, middle and ends of the sequence they were operating on.  I think there’s a preprocessing step that simplifies the problem – transform the sequence into a seq<Position<'t>>, where Position tells you if the object is at the beginning, middle, or end of the sequence:

type Position<'t> =
| Beginning of 't
| Middle of 't
| End of 't
| Only of 't

let rec sequenceOfPositionsWithLazyList(existing: LazyList<'t>) =
  seq {
    let rec elementsAfterBeginning(s) =
      seq {
        match s with
        | LazyList.Cons(h, LazyList.Nil) -> yield End(h); ()
        | LazyList.Cons(h, t) -> yield Middle(h); yield! elementsAfterBeginning(t)
        | _ -> ()
      }
    match existing with
      | LazyList.Cons(h, LazyList.Nil) -> yield Only(h); ()
      | LazyList.Cons(h, t) -> yield Beginning(h); yield! elementsAfterBeginning(t)
      | LazyList.Nil -> ()
  }
  
let sequenceOfPositions(existing: seq<'t>) = sequenceOfPositionsWithLazyList(LazyList.of_seq existing)
  
printfn "%A" (sequenceOfPositions [1;2;3])
printfn "%A" (sequenceOfPositions [1;3])
printfn "%A" (sequenceOfPositions [1])
printfn "%A" (sequenceOfPositions [])

The output is:

seq [Beginning 1; Middle 2; End 3]
seq [Beginning 1; End 3]
seq [Only 1]
seq []

I think that makes following steps much easier to write.

Friday, July 10, 2009

error: 'GDataInputStreamLogger' undeclared (first use in this function)

If you're seeing errors like this:

/Users/jamesmoore/dev/mba/gdata170/Source/Networking/GDataHTTPFetcherLogging.m: In function '-[GDataHTTPFetcher(GDataHTTPFetcherLogging) logCapturePostStream]':
/Users/jamesmoore/dev/mba/gdata170/Source/Networking/GDataHTTPFetcherLogging.m:797: error: 'GDataInputStreamLogger' undeclared (first use in this function)
/Users/jamesmoore/dev/mba/gdata170/Source/Networking/GDataHTTPFetcherLogging.m:797: error: (Each undeclared identifier is reported only once
/Users/jamesmoore/dev/mba/gdata170/Source/Networking/GDataHTTPFetcherLogging.m:797: error: for each function it appears in.)
/Users/jamesmoore/dev/mba/gdata170/Source/Networking/GDataHTTPFetcherLogging.m:800: error: expected expression before ')' token
/Users/jamesmoore/dev/mba/gdata170/Source/Networking/GDataHTTPFetcherLogging.m:804: error: expected expression before ')' token

Set this preprocessor macro: STRIP_GDATA_FETCH_LOGGING=0.

(TBD:  An actual explanation.  Unfortunately, it's not high on my priority list right now.)

Monday, June 15, 2009

Merging two sequences in F# using LazyList

Claudio Cherubino  had a post about solving one of the standard Amazon interview questions, and it prompted me to finally figure out how to use sequence expressions and LazyList in F#.

The problem is to merge two arrays into a third array in O(n) time.  I like the F# solution using sequences and pattern matching - it feels like a nice way to write this sort of thing. 
type MergeWithLazyLists() =
static member merge(f, x: LazyList<'t>, y: LazyList<'t>) =
seq {
match x, y with
| LazyList.Cons(xh, xt), LazyList.Cons(yh, yt) when f xh yh ->
yield xh
yield! MergeWithLazyLists.merge(f, xt, y)
| LazyList.Cons(xh, xt), LazyList.Cons(yh, yt) ->
yield yh
yield! MergeWithLazyLists.merge(f, x, yt)
| LazyList.Nil, LazyList.Cons(_, _) -> yield! y
| LazyList.Cons(_, _), LazyList.Nil -> yield! x
| LazyList.Nil, LazyList.Nil -> ()
}

static member merge(f, x: seq<'t>, y: seq<'t>) =
MergeWithLazyLists.merge(f, (LazyList.ofSeq x), (LazyList.ofSeq y))

let result = MergeWithLazyLists.merge((fun x y -> x < y), (seq {2..6}), (seq {1..7..15}))

printfn "%A" (Seq.toArray result)

A sequence in F# is anything that implements IEnumerable<'t>, so arrays and lists both work just fine.

(An earlier version of this post used the older names for some methods – to_seq, to_array.  I updated this to the new methods in 1.9.7.8)

Wednesday, May 27, 2009

Recovering Linux RAID drives

I had a couple drives that used to be part of a Linux RAID setup.  The easiest way I've found to grab the data off them is TestDisk - it's a handy tool that will copy files off a drive that was part of a RAID array.  Even better, you can run it from Linux and Windows.  In my case, my new main machine is a Vista box, so I don't have to figure out how to get my VMware instance of Ubuntu to read drive image files on the Windows box.

I found TestDisk through this article: Mounting Linux drive images

Tuesday, April 21, 2009

GTM test suite for the iPhone - figuring out why it was hanging on startup

[Sorry about the formatting problems. This was posted to my old blog, and I found it again when I was doing a google search for the topic. The old blog posts are lying around somewhere, but I'm lazy so I'll just cut-and-paste from the google cache...] I'm trying to use the GTM test suite, and it's just hanging. The build window shows:
    2008-11-21 09:23:46.996 UnitTests[1794:10b] CFPreferences: user home directory at /Users/jamesmoore/dev/TestPlatform/build/TestPlatform.build/Debug-iphonesimulator/UnitTests.build/iPhone Simulator User Dir is unavailable. User domains will be volatile.    2008-11-21 09:23:47.012 UnitTests[1794:10b] Unable to send CPDistributedMessagingCenter message named SBRemoteNotificationClientStartedMessage to com.apple.remotenotification.server: (ipc/send) invalid destination port
Starting under the debugger (using option-cmd-Y to skip running the test harness shell script) isn't very informative:
(gdb) bt#0  0x964954a6 in mach_msg_trap ()#1  0x9649cc9c in mach_msg ()#2  0x956fd0ce in CFRunLoopRunSpecific ()#3  0x956fdcf8 in CFRunLoopRunInMode ()#4  0x31699d38 in GSEventRunModal ()#5  0x31699dfd in GSEventRun ()#6  0x30a5dadb in -[UIApplication _run] ()#7  0x30a68ce4 in UIApplicationMain ()#8  0x00002a39 in main (argc=1, argv=0xbffff060) at /Users/jamesmoore/dev/TestPlatform/../google-toolbox-for-mac/UnitTesting/GTMIPhoneUnitTestMain.m:30(gdb)
All that looks fine. So, did the tests run at all? GTMIphoneUnitTestMain.m does:
  int retVal = UIApplicationMain(argc, argv, nil, @"GTMIPhoneUnitTestDelegate");
So I set a breakpoint on the first line of applicationDidFinishLaunching, on the call to runTests:
- (void)applicationDidFinishLaunching:(UIApplication *)application {  [self runTests];
And sure enough, it's not hit. So my next suspect is the app delegate for the regular application - inthis case, TestPlatformAppDelegate. Set a breakpoint in itsapplicationDidFinishLaunching, start up, and sure enough that's what'srunning. Why? Turns out I had added MainWindow.xib to the unit test target. For the regular (non-unit-test)application, MainWindow.xib has an instance of TestPlatformAppDelegate.The TestPlatformAppDelegate is attached to the File's Owner delegate.When the nib file is instantiated, it creates theTestPlatformAppDelegate, then sets the File's Owner delegate to be thenewly instantiated TestPlatformAppDelegate. That overwrites theinstance of GTMIPhoneUnitTestDelegate that used to be there, and no tests will run. The next question is can something spit out a warning if this happens? Off the top of my head, I don't know who gets called when nib files areloaded. I'm sitting at a debugger, so I slap in a new init method toGTMIPhoneUnitTestDelegate, set a breakpoint on it, and restart. Here'sthe stack:
#0  -[TestPlatformAppDelegate init] (self=0x44fb80, _cmd=0x96d6c858) at /Users/jamesmoore/dev/TestPlatform/Classes/TestPlatformAppDelegate.m:19#1  0x30c2ca67 in -[UIClassSwapper initWithCoder:] ()#2  0x922a4940 in _decodeObjectBinary ()#3  0x922a42b5 in _decodeObject ()#4  0x30c2c615 in -[UIRuntimeConnection initWithCoder:] ()#5  0x922a4940 in _decodeObjectBinary ()#6  0x922a63cd in -[NSKeyedUnarchiver _decodeArrayOfObjectsForKey:] ()#7  0x922a6849 in -[NSArray(NSArray) initWithCoder:] ()#8  0x922a4940 in _decodeObjectBinary ()#9  0x922a42b5 in _decodeObject ()#10 0x30c2bbeb in -[UINib instantiateWithOptions:owner:loadingResourcesFromBundle:] ()#11 0x30c2dcf8 in -[NSBundle(NSBundleAdditions) loadNibNamed:owner:options:] ()#12 0x30a5df99 in -[UIApplication _loadMainNibFile] ()#13 0x30a65f42 in -[UIApplication _runWithURL:] ()#14 0x922ce5ee in __NSFireDelayedPerform ()#15 0x956fdb45 in CFRunLoopRunSpecific ()#16 0x956fdcf8 in CFRunLoopRunInMode ()#17 0x31699d38 in GSEventRunModal ()#18 0x31699dfd in GSEventRun ()#19 0x30a5dadb in -[UIApplication _run] ()#20 0x30a68ce4 in UIApplicationMain ()#21 0x00002a39 in main (argc=1, argv=0xbffff060) at /Users/jamesmoore/dev/TestPlatform/../google-toolbox-for-mac/UnitTesting/GTMIPhoneUnitTestMain.m:30
The interesting points look like:
#10 0x30c2bbeb in -[UINib instantiateWithOptions:owner:loadingResourcesFromBundle:] ()#12 0x30a5df99 in -[UIApplication _loadMainNibFile] ()
Does one of those have something to hook into? I start reading doc. The Resource Programming Guide has lots ofinformation about nib files, but the only thing I find that seemsrelevant is the bit where it points out that nib instantiation is goingto use setValue:forKey: to set the fields. To see what happens there, I added this to GTMIphoneUnitTestMain.m:
@interface GuardedUIApplication : UIApplication@end @implementation GuardedUIApplication- (void)setValue:(id)value forKey:(NSString *)key{ NSLog(@"Current value for key |%@| is |%@|", key, value); [super setValue: value forKey: key];}@end
And changed the call to UIApplicationMain to use GuardedUIApplication instead of the default UIApplication:
  int retVal = UIApplicationMain(argc, argv, @"GuardedUIApplication", @"GTMIPhoneUnitTestDelegate");
Running it again, I see that the call I expected does in fact happen:
2008-11-21 10:43:09.966 UnitTests[2841:20b] Current value for key |delegate| is ||
Something like this might be a solution:
@interface GuardedUIApplication : UIApplication@end@implementation GuardedUIApplication- (void)setValue:(id)value forKey:(NSString *)key{ NSLog(@"Existing value for key |%@| is |%@|", key, [self valueForKey: key]); NSLog(@"New value for key |%@| is |%@|", key, value); if ([key isEqualToString: @"delegate"] && ![value isKindOfClass: [GTMIPhoneUnitTestDelegate class]]) {  NSException *e = [NSException failureInFile: [NSString stringWithCString: __FILE__]             atLine: __LINE__          withDescription: @"The app delegate must be a GTMIPhoneUnitTestDelegate.  Is MainWindow.nib attempting to use a different application delegate?"];  [e raise]; } [super setValue: value forKey: key];}@end

Monday, April 13, 2009

Objective-C basics for C programmers

Objective-C is C

First, if you want to learn Objective-C and you don’t know C yet, go learn C.  Come back when you’re done.  Objective-C is a set of addons to C – you must know C first.  C is a small language, and it won’t take you that long.  (Learning to use C well is a different problem, of course.)

What to read

The Apple doc for Objective-C is pretty good, but it gets bogged down in places because it's not assuming you already know C.  It's also written as if Objective-C were a new language, instead of just some extra bits on top of C.

(And Chapter 11 of that Apple doc tosses in this shocker: C++ is also included in Objective-C.  It's not usually necessary to use C++ on the iPhone, but it does mean you can use lots of existing C++ code if you need it.)

This article is a stripped-down intro to thinking of Objective-C basics in terms of what they are in C.

Square braces are just macros

The best way to think about Objective-C syntax is that it’s just a new flavor of preprocessor for C.  There are some basic things you care about that are going to spit out normal C, eventually:
  • Messages.  They’re sent using square braces like this: [targetObject theMessage]
  • Class definitions.  They’re blocks that start with @interface @implementation @protocol and end with @end.
  • Selectors.  Selector is the Objective-C term for what most languages call “messages.”  They’re what you send to objects.  (Thinking of them as method invocations is mostly wrong and will get you in trouble later on.)  You’ll see selectors used like this: @selector(theMessage) and in square braces like this: [targetObject theMessage] - that’s just syntatic sugar.  They’re going to compile down to the same thing.

Classes

Classes are structs with some extra fields tacked on.  Here's a trivial class declaration:

@interface SmallClass : NSObject
- (void) helloWorld;
@end

This lays out the class for the compiler.  It allows the compiler to give you useful warnings if you try to send the helloWorld message to this class in the wrong way (so you'll get a warning if you try to call it with a parameter, for example).  It adds a field that's a pointer to the class itself, so at runtime you can dereference the pointer to the class type to figure out which functions correspond to which selectors.   (And yes, this implies that at runtime a class can change its type.  That's nasty, and is used by things like key-value observing.)

The implementation for this would be:

@implementation SmallClass
- (void) helloWorld
{
  NSLog(@"Hello world.");
}
@end
     
The compiler turns this into a helloWorld function that looks something like:

void helloWorldFunctionImplementation (SmallClass *self) {
  NSLog(@"Hello world");
}

To create an instance of SmallClass and send it the helloWorld selector, you'd use the the square brackets syntax:

SmallClass *sm = [[[SmallClass alloc] init] autorelease];
[sm helloWorld];


(For now, ignore the alloc/init/autorelease bits - they're memory management on the iPhone.)

Square brackets are just syntatic sugar that makes sending selectors to objects more pleasant.  What you end up with after square-bracket-procesing is a call to the function objc_msgSend(receiver, selector).  Calling objc_msgSend without the square brackets would do exactly the same thing:

objc_msgSend(sm, @selector(helloWorld));  // same as [sm helloWorld]

Or the same thing in a function:

void sendHelloWorldByHand (SmallClass *target)
{
  objc_msgSend(target, @selector(helloWorld));
}

Notice that the call to @selector(helloWorld) couldn't care less about whether or not there's a method called helloWorld implemented by that object.  It's completely irrelevant - selectors just get translated to numbers by the compiler, and they're not tied to classes in any way.  @selector(helloWorld) becomes an int inside the compiler, and you can send that int to any instance of any class.  Whether or not the target does anything interesting with that message is an unrelated issue.

To put it another way: selectors aren't tied to particular objects; the selector for helloWorld on SmallClass is the same selector that you might send to AnotherClassIHaventImplementedYet.  Selectors are just a lookup mechanism so humans don't have to remember numbers - they get informative tokens to put in code.  But they're just going to turn into numbers when your code is running.

(And you should notice that the Apple doc says not to call objc_msgSend by hand, although I suspect this is widely ignored.)

Sending messages

objc_msgSend(target, selector) goes through these steps to figure out what to call:
  1. Looking at the hidden field in the struct that points to the class of the object. 
  2. Call the function matching the selector.  Classes have lookup tables that specify the selector-to-function mapping, and if there's a matching selector, that's what's called.  If there's no matching selector, check the parent of the class, and so on until you get to the root class. 
  3. If there's no match for the selector, call forwardInvocation:.
#3 is important – it means that you cannot tell by looking at an object's @interface code whether or not it handles a selector.  That decision can't really be made until you're actually sending the selector to the object.  (And since forwardInvocation: is free to do anything it feels like with a selector, there's no guarantee that a selector will do anything the same way twice.)

Monday, April 6, 2009

F# - Converting sequences to lists on the fly

There was a question on StackOverflow about chunking sequences to arrays.  The poster wanted to have the input put into three-element arrays, so something like this:

> seq { for i in 1..10000 -> i} ;;
val it : seq<int> = seq [1; 2; 3; 4; ...]

would become:

> seq { for i in 1..10000 -> i} |> Seq.in_groups_of_n 3;;
val it : seq<int list>
= seq [[1; 2; 3]; [4; 5; 6]; [7; 8; 9]; [10; 11; 12]; ...]
> 

(I usually prefer to have my data in lists rather than arrays, so this isn't quite the answer they were looking for, but it's a trivial conversion from lists to arrays.)

My first solution was something more like iter:

  let in_lists_of_length_n n f (ie : seq<'a>) = 
    use e = ie.GetEnumerator()
    let rec next_with_acc acc =
      match e.MoveNext(), acc with
      | true, a when List.length a + 1 = n ->  
        f(List.rev (e.Current :: a))
        next_with_acc []
      | true, _ -> next_with_acc (e.Current :: acc)
      | false, _ ->
        f(List.rev acc)
      ()
    next_with_acc [] 
 
That's OK, but it's pretty limited.  If what you're doing fits into something like iter, it's good enough.

But what about just transforming the sequence into a new sequence?  That seems like a more general solution.  So:

module Seq =  
  let in_groups_of_n n (s: seq<'a>) =
    let rec in_groups_of_n_with_acc n acc (ie: IEnumerator<'a>) =
      seq {
        match ie.MoveNext(), acc with
        | true, a when List.length a + 1 = n -> 
          yield List.rev (ie.Current :: a)
          yield! in_groups_of_n_with_acc n [] ie
        | true, a -> yield! in_groups_of_n_with_acc n (ie.Current :: a) ie
        | false, a when List.length a > 0 -> yield List.rev acc
        | false, a -> ()
      }
    seq {
      yield! in_groups_of_n_with_acc n [] (s.GetEnumerator())
    }    

That's pretty good - it gets us to the point where we're returning a real sequence, so it's much more useful than the iter-style solution.

But why limit ourselves to lists-of-length-n?  Let's turn the accumulator into a function, so you can get any groups you want:

module Seq =  
  let grouped_by f (s: seq<'a>)=
    let rec grouped_by_with_acc (f: 'a -> 'a list -> 'a list option * 'a list) acc (ie: IEnumerator<'a>) =
      seq {
        if ie.MoveNext()
        then 
          let nextValue, leftovers = f ie.Current acc
          if nextValue.IsSome then yield nextValue.Value
          yield! grouped_by_with_acc f leftovers ie
        else
          if not acc.IsEmpty then yield acc
      }
    seq {
      yield! grouped_by_with_acc f [] (s.GetEnumerator())
    }    

This takes a function that accepts:
  • The next item in the sequence
  • Leftovers from the last run
And returns a tuple:
  • An optional value to yield
  • Leftovers
Here's how its used:

module TestGroupedBy =
  let GroupsOfN n newValue acc =
    let newList = newValue :: acc

    // If we have the right length, return
    // a Some as the first value.  That'll 
    // be yielded by the sequence.
    if List.length acc = n - 1
    then Some (List.rev newList), []
    // If we don't have the right length,
    // use None (so nothing will be yielded)
    else None, newList   
    
  // Note that we're going to pass a curried function - (GroupsOfN 3) is a function
  // taking two arguments, suitable for passing to grouped_by
  let resultWithInts = seq { for i in 1..100 -> i} |> Seq.grouped_by (GroupsOfN 3)
  
  printfn "int result %A" resultWithInts
  
  let resultWithChars = seq { for i in ['a'; 'b'; 'c'; 'd'; 'e'; 'f'] -> i} |> Seq.grouped_by (GroupsOfN 2)
  
  printfn "char result %A" resultWithChars  

The results are:

int result seq [[1; 2; 3]; [4; 5; 6]; [7; 8; 9]; [10; 11; 12]; ...]
char result seq [['a'; 'b']; ['c'; 'd']; ['e'; 'f']]

Let's use this with a more interesting grouping function. Say we want the colors of all the single cows in a list:

module TestGroupedByWithMatching =
  let Cows newValue acc =
    let newList = newValue :: acc
    match newList with
    | "cow" :: color :: "one" :: t -> Some [color], []
    | a :: b :: t -> None, [a; b]
    | l -> None, newList
    
  let someCows = seq { for i in ["one"; "red"; "cow"; "and"; "one"; "white"; "cow"; "and"; "three"; "green"; "cows"] -> i} |> Seq.grouped_by Cows
  printfn "some cows are %A" someCows
  
// This prints:  
// some cows are seq [["red"]; ["white"]; ["cows"; "green"]]
// > 

So there's a problem - at the end, we're yielding the accumulator.  That's what we wanted in the previous examples; we were looking for groups of three, plus the last group of 0, 1, or 2 items.  Here, though, if we don't get a match we don't want to see the leftovers.  Let's create a new method that takes another function that specifies what to do with the accumulator:

  let grouped_by_with_leftover_processing f (f2: 'a list -> list<'a> option) (s: seq<'a>)=
    let rec grouped_by_with_acc (f: 'a -> 'a list -> 'a list option * 'a list) acc (ie: IEnumerator<'a>) =
      seq {
        if ie.MoveNext()
        then 
          let nextValue, leftovers = f ie.Current acc
          if nextValue.IsSome then yield nextValue.Value
          yield! grouped_by_with_acc f leftovers ie
        else
          let rems = f2 acc
          if rems.IsSome then yield rems.Value
      }
    seq {
      yield! grouped_by_with_acc f [] (s.GetEnumerator())
    }    

Now we can specify a function to use for the leftovers.  This time we should get the right cows.

module TestGroupedByWithMatching =
  let Cows newValue acc =
    let newList = newValue :: acc
    match newList with
    | "cow" :: color :: "one" :: t -> Some [color], []
    | a :: b :: t -> None, [a; b]
    | l -> None, newList
  
  let IgnoreLeftovers f = None
  
  let someCows = seq { for i in ["one"; "red"; "cow"; "and"; "one"; "white"; "cow"; "and"; "three"; "green"; "cows"] -> i}
  let cowColors = someCows |> Seq.grouped_by_with_leftover_processing Cows IgnoreLeftovers
  printfn "cowColors are %A" cowColors
  
// This prints:  
// cowColors are seq [["red"]; ["white"]]

But we've got two separate functions (grouped_by_with_leftover_processing and grouped_by) that duplicate most of their code.  grouped_by is just grouped_by_with_leftover_processing so the final code is:

module Seq =  
  let grouped_by_with_leftover_processing f (f2: 'a list -> list<'a> option) (s: seq<'a>)=
    let rec grouped_by_with_acc (f: 'a -> 'a list -> 'a list option * 'a list) acc (ie: IEnumerator<'a>) =
      seq {
        if ie.MoveNext()
        then 
          let nextValue, leftovers = f ie.Current acc
          if nextValue.IsSome then yield nextValue.Value
          yield! grouped_by_with_acc f leftovers ie
        else
          let rems = f2 acc
          if rems.IsSome then yield rems.Value
      }
    seq {
      yield! grouped_by_with_acc f [] (s.GetEnumerator())
    }    

  let YieldReversedLeftovers (f: 'a list) = 
    if f.IsEmpty
    then None
    else Some (List.rev f)

  let grouped_by f s =
    grouped_by_with_leftover_processing f YieldReversedLeftovers s

  let group_by_length_n n s =
    let grouping_function newValue acc =
      let newList = newValue :: acc
      // If we have the right length, return
      // a Some as the first value.  That'll 
      // be yielded by the sequence.
      if List.length acc = n - 1
      then Some (List.rev newList), []
      // If we don't have the right length,
      // use None (so nothing will be yielded)
      else None, newList  
    grouped_by grouping_function s

Tuesday, March 31, 2009

Bluetooth headset winner – the Jawbone 2

I’m using a Jawbone 2 now.  I’ve had it for a couple weeks, and it’s working great.  Good sound quality on both sides, works fine outside and in the car.  (If you’re buying from Amazon, don’t buy the bulk package version.  According to the reviews, it doesn’t come with all the right extra bits.)  And make sure you’re getting a version 2, not the original Jawbone – the original is terrible.

The previous headset I tried was a Plantronics Discovery 925.  Indoors, it was fine.  Outdoors, it was useless.  A slight breeze and the person I was calling said it sounded like I was in a hurricane.

Friday, March 27, 2009

Hello, World in F# + WPF

Here’s the small version of F# + WPF Hello, world.  Note that there’s zero Xaml involved.
#light

open System
open System.Windows
open System.Windows.Controls

type MainWindow(app: Application) as self =
  inherit Window()
  do
    let button = Button(Content = "Bye")
    button.Click.Add(fun f -> app.Shutdown(0))
    self.Content <- button

type App() =
  inherit Application()
  
  static member Go() =
    let app = new App()
    app.Run(new MainWindow(app, Title = "Hello world")) 
    |> ignore

[<STAThread>] App.Go()

The references are very similar to the C# code:
image

Thursday, March 26, 2009

Starting out with WPF in F# – but first, C#

I've started to use F# with WPF, and thought that the best way of going about it would be to start with just bare code for the most stripped-down C# app that would do anything.

Most of the WPF examples out there start with too much Xaml - seems like it's just going to get in the way for now.

Norbert Eder's blog had the meat of this - I just stripped it down even more.

using System;
using System.Windows;
using System.Windows.Controls;

public class App : Application
{
[STAThread]
static void Main(string[] args)
{
Application app = new Application();
app.Run(new MainWindow());
}
}

public class MainWindow : Window
{
public MainWindow()
{
Button button1 = new Button();
button1.Content = "Bye";
button1.Click += new RoutedEventHandler(button1_Click);
this.Content = button1;
this.Title = "Hello world";
}

void button1_Click(object sender, RoutedEventArgs e)
{
Application.Current.Shutdown(0);
}
}

The project only needs a couple references – PresentationCore, PresentationFramework, System, and WindowsBase:

image  

 

Tuesday, March 10, 2009

F# useful links

The spec I use this all the time, for obvious reasons.

Expert F# (I use it on Safari - this is the incomplete/sample Google Books entry)

The basic syntax of F# - classes, interfaces, and members Useful disection of an F# type declaration

F Sharp Programming - Wikibooks, collection of open-content textbooks Occasionally useful, but somewhat out of date.  Better to turn to Expert F#.

hubFS forums Lots of useful information in the hubFS forums.  (Think of this as the F# mailing lists; for whatever reason, the F# community seems to prefer forums to mailing lists.)

Sep 2008 release known issues

Tuesday, March 3, 2009

F#: The type 'MatchCollection' is not compatible with the type 'seq<'a>'.

I was trying to use regular expressions with sequences, and ran across this problem.
(new Regex ".*").Matches("foo") |> Seq.iter (fun s -> printfn "s is %A" s);;
-----------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
stdin(4,36): error FS0001: The type 'MatchCollection' is not compatible with the type 'seq<'a>'.
> (new Regex "f.*").Matches("foo") |> Seq.cast |> Seq.iter (fun s -> printfn "s is %A" s);;
s is foo
val it : unit = ()
>
Turns out MatchCollection implements System.Collections.IEnumerable, not System.Collections.Generic.IEnumerable<T>. You need to cast it with Seq.cast to use it:
(new Regex "f.*").Matches("foo") |> Seq.cast |> Seq.iter (fun s -> printfn "s is %A" s);;
I got the solution from hubfs - it's a good place for F# information.

F# error talking complaining about FSharp.PowerPack.dll

If your F# code compiles, but you see errors like this from fsi:

C:\Users\James\Documents\Visual Studio 2008\Projects\ConsoleApplication1\ConsoleApplication1\FSharpDictionary.fs(108,13): error FS0039: The value, constructor, namespace or type 'contains' is not defined. A construct with this name was found in FSharp.PowerPack.dll, which contains some modules and types that were implicitly referenced in some previous versions of F#. You may need to add an explicit reference to this DLL in order to compile this code.
>

Make sure you add PowerPack to your session:

> #r "FSharp.PowerPack.dll" ;;

My problem was that I had added FSharp.PowerPack to the Visual Studio project, but I had forgotten that fsi doesn't pick that up.

And with the new 2010 release, you're going to need to add the location of PowerPack to your search path in fsi.exe:

  > #r "FSharp.PowerPack.dll" ;;
    > #I "C:\Users\James\Documents\Visual Studio 10\Projects\fspowerpack"

Watch out for quoting backspaces in strings.

Tuesday, February 17, 2009

Humor in Apple documentation

Found in "iPhone Dev Center > iPhone Reference Library > Topics > General > Security Overview > Security Services":
The procedure for signing code is not time consuming and requires few resources. See Code Signing Guide for details.

Friday, February 13, 2009

Yet another bad bluetooth headset

Just got my new Aliph Jawbone bluetooth headset. It's not quite epic fail, but it's bad. I could hear the other person fine, but she said I faded in and out - basically transmission quality was completely unacceptable. It goes into the dustbin along with the Samsung WEP301 (rated "useless junk" for terrible sound quality).

Google for domains sync to iPhone

To configure the new iPhone sync system for your Google for domains setup, use:

https://m.google.com/sync/settings/a/example.com/iconfig/

(Where example.com is replaced with your domain)

Tuesday, February 3, 2009

Building parameters strings for the iPhone from NSDictionary objects

Here's the code I use to build parameters strings for URLs on the iPhone.  It adds a method to NSDictionary to convert a dictionary to a parameters string:



What that mysterious %al means in gdb

If you're looking at Xcode's instruction pane in gdb, and you're on an Intel platform, %al is the least significant byte of the EAX register. So code that looks like this:
0x0000661a  <+0251>  call   0x3c21a <>0x0000661f  <+0256>  test   %al,%al0x00006621  <+0258>  jne    0x6650 < -[ConfCallStatusTableViewController mergeConfCallStatusViaNotification:]+305 >
Translates to:
  1. Call dyld_stub_objc_msgSend
  2. AND the least significant byte of the EAX register with itself. The point of this is the side effect - it sets the bits in the EFLAG register that will be used in the jne instruction that's coming next.
  3. Jump-if-not-equal to -[ConfCallStatusTableViewController mergeConfCallStatusViaNotification:]. jne looks at 'equal' bit that was set in the previous step, and if that bit is set, it jumps. If it's not set, just continue on to the next instruction.
Check out Wikipedia for a decent simple into to Intel assembly. I found the note about what %al in a course tutorial.

Saturday, January 31, 2009

Xcode questions and feature wishes

Things I don't know how to do in Xcode, or that Xcode just doesn't do and should:

• Reindent the entire file? I know you can select text and hit C-Shift-F, that's not quite what I'm talking about. One button, whole file, don't move my cursor. Or even better, just turn on the 'always indent my code' mode so I don't have to spend my time thinking about indentation.

• When I finish with run or debug, switch the Xcode back to project mode from debug mode. Why do I always have to hit C-0?

• Jump through your last N edit locations, across all files? C-q in NetBeans, I use this constantly.

• Move the current selection (or line, if there's no selection) up/down?

• Duplicate the current selection (or line, if there's no selection) up/down?

• Delete the current line? I'm aware that I can hit C-l to select the entire line, and then delete it.

• Select by expressions? One key combo, select my current symbol. One more to expand it to the enclosing expression, etc, and the same thing going the other way. I use this all the time in NetBeans.

• Close all editor windows? Close all closes everything - I just want editor windows to go away, leaving the project window.

• Move to the beginning of the text on a line? I know Cmd-leftArrow moves to character position 0.

• Show line numbers in the gutter? I know the line number is shown next to the filename.

• Show an outline of the current file? I want a navigation pane - show me the methods and fields in the file I'm editing. Xcode has the information - I want the dropdown menu in a pane somewhere that I can see all the time.

• Edit/create properties? Properties are painful right now - you have to touch three different places for a single property.

• Edit/create the signature of a method? Give me one place to edit both the .h and the .m.

• I want vertical editing like TextMate.

• Show me the inheritance tree for the class I'm editing, in a pane. Parents, siblings, children, selectable.

• How do you use the refactoring features without Xcode blowing up? OK, more of a rant than a question. But refactoring crashes Xcode too often - I've stopped using it.

• Refactoring needs to add a 'move' to move methods between classes.

• Transform a method call between all arguments on one line/all arguments on a seperate line.

• In the debugger, if you've set up key value observing on an object, and the object is in an array, you can't see its details. You just get a NSKVONotifying_Whatever object that you can't drill down into. This should be fixed. (If the objects aren't an an array, there's no problem.)

• NSDictionary display in the debugger. There's no way to drill down into an NSDictionary.

• Jump to a method or class. In NetBeans, you hit Cmd-O, and the dialog shows you all the available classes. There's a text box to narrow the list of classes, and you can type #methodName in the box to get methods instead of classes. I use this constantly. [UPDATE - Dan Wright on the Seattle Xcoders mailing list pointed out Cmd-shift-D - very handy]

• Better support for code coverage.  Hunting around for *.gcda files isn't a great user experience.

Tuesday, January 27, 2009

This is not the droid you're looking for. Move along, move along.

These show up on the console doing a full iPhone restore:

1/27/09 11:57:48 PM [0x0-0x7b07b].com.apple.iTunesHelper[1192] MobileDevice: AMDeviceConnect: This is not the droid you're looking for. Move along, move along.
1/27/09 11:57:48 PM [0x0-0x7b07b].com.apple.iTunesHelper[1192] MobileDevice: AMDeviceConnect: This is not the droid you're looking for. Move along, move along.
1/27/09 11:57:48 PM [0x0-0x8f08f].com.apple.iTunes[1288] MobileDevice: AMDeviceConnect: This is not the droid you're looking for. Move along, move along.

Curious.

Monday, January 26, 2009

When you're loading from a nib file, outlets aren't connected until #loadView is called

When you're loading a nib file, the load process is supposed to connect outlets that are set in Interface Builder. And according to the Resource Programming Guide, in the Nib Object Life Cycle section:
When you use the methods of NSNib or NSBundle to load and instantiate the objects in a nib file, the
underlying nib-loading code does the following:
...
3. It reestablishes all connections (actions, outlets, and bindings) between objects in the nib file. This
includes connections to File’s Owner and other proxy objects.
Having read that bit, I assumed that initWithNibName:bundle: would count as one of those "NSNib or NSBundle" methods. Wrong. Instead, the outlets are connected when the view loads. To figure that out, I just wrote the method to set the outlet I cared about (in this case, it's called editableField) and set a breakpoint in the method. It's not until loadView happens - here's the full stack trace:
#0  -[EditTextField setEditableField:] (self=0x10266b0, _cmd=0x2ceb3, f=0x105afd0) at /Users/jamesmoore/dev/CallWrangler/Classes/EditTextField.m:37
#1  0x93ac2cee in -[NSObject(NSKeyValueCoding) setValue:forKey:] ()
#2  0x93b477c1 in -[NSObject(NSKeyValueCoding) setValue:forKeyPath:] ()
#3  0x30c1f907 in -[UIRuntimeOutletConnection connect] ()
#4  0x93e5cc45 in -[NSArray makeObjectsPerformSelector:] ()
#5  0x30c1e455 in -[UINib instantiateWithOptions:owner:loadingResourcesFromBundle:] ()
#6  0x30c204b8 in -[NSBundle(NSBundleAdditions) loadNibNamed:owner:options:] ()
#7  0x30ac6eca in -[UIViewController _loadViewFromNibNamed:bundle:] ()
#8  0x30ac72af in -[UIViewController loadView] ()
#9  0x30ac7421 in -[UIViewController view] ()
#10 0x30acb01d in -[UIViewController(UIViewControllerContentScrollView) contentScrollView] ()
#11 0x30acd415 in -[UINavigationController _startTransition:fromViewController:toViewController:] ()
#12 0x30acdd23 in -[UINavigationController pushViewController:transition:forceImmediate:] ()
#13 0x30acd95d in -[UINavigationController pushViewController:animated:] ()
#14 0x0001f157 in -[SavedListViewController pushEditingViewForListNamed:] (self=0x1035630, _cmd=0x2b9d4, name=0x1040dd0) at /Users/jamesmoore/dev/CallWrangler/Classes/SavedListViewController.m:115
#15 0x0001f72b in -[SavedListViewController tableView:didSelectRowAtIndexPath:] (self=0x1035630, _cmd=0x30c624d0, tableView=0x103a370, indexPath=0x10402f0) at /Users/jamesmoore/dev/CallWrangler/Classes/SavedListViewController.m:182
#16 0x30a8f74d in -[UITableView(_UITableViewPrivate) _sendSelectionDidChange] ()
#17 0x30a96b4c in -[UITableView touchesEnded:withEvent:] ()
#18 0x30a6790f in -[UIWindow sendEvent:] ()
#19 0x30a56ff7 in -[UIApplication sendEvent:] ()
#20 0x30a561d8 in _UIApplicationHandleEvent ()
#21 0x31563dea in SendEvent ()
#22 0x3156640c in PurpleEventTimerCallBack ()
#23 0x93dee5f5 in CFRunLoopRunSpecific ()
#24 0x93deecd8 in CFRunLoopRunInMode ()
#25 0x31564600 in GSEventRunModal ()
#26 0x315646c5 in GSEventRun ()
#27 0x30a4ec98 in -[UIApplication _run] ()
#28 0x30a5a094 in UIApplicationMain ()
#29 0x0001c620 in main (argc=1, argv=0xbffff044) at /Users/jamesmoore/dev/CallWrangler/main.m:33
(gdb)

Useful threads on the Apple developer forum

I'm going to start collecting the URLs of particularly useful threads in the Developer Forums here.

Bug with UITableView, Swipes and Controls in Cells
Loupe in scrolling UITableView
Responding to view controller memory warnings
code signing provisioning profile - information about signing and ad hoc distribution

Problem with copyplist (caused by an Apple bug + Ruby macports install)

I was trying to build a copy of the example code EditableDetailView, and I was getting an error when the build tried to run copyplist: Building target “EditableDetailView” of project “EditableDetailView” with configuration “Debug”Checking DependenciesPBXCp build/Debug-iphonesimulator/EditableDetailView.app/appData.plist appData.plist cd /Users/jamesmoore/dev/EditableDetailView setenv PATH "/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin:/Developer/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin" /Developer/Library/PrivateFrameworks/DevToolsCore.framework/Resources/pbxcp -exclude .DS_Store -exclude CVS -exclude .svn -resolve-src-symlinks /Users/jamesmoore/dev/EditableDetailView/appData.plist /Users/jamesmoore/dev/EditableDetailView/build/Debug-iphonesimulator/EditableDetailView.appCopyPlistFile /Users/jamesmoore/dev/EditableDetailView/build/Debug-iphonesimulator/EditableDetailView.app/appData.plist appData.plist cd /Users/jamesmoore/dev/EditableDetailView setenv PATH "/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin:/Developer/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin" /Developer/Library/Xcode/Plug-ins/CoreBuildTasks.xcplugin/Contents/Resources/copyplist appData.plist --outdir /Users/jamesmoore/dev/EditableDetailView/build/Debug-iphonesimulator/EditableDetailView.apperror: can't exec '/Developer/Library/Xcode/Plug-ins/CoreBuildTasks.xcplugin/Contents/Resources/copyplist' (No such file or directory) The first check I did was to make sure I had copyplist somewhere on the system:
jamesmoore@james-moores-macbook-pro:~$ locate copyplist/Developer/Library/Xcode/Plug-ins/CoreBuildTasks.xcplugin/Contents/Resources/copyplist
That's not in my normal path, but I didn't expect it to be.And anyway, XCode's build is calling copyplist from a specific location anyway - it wants /Developer/Library/Xcode/Plug-ins/CoreBuildTasks.xcplugin/Contents/Resources/copyplist and doesn't care about the path. There's a file at /Developer/Library/Xcode/Plug-ins/CoreBuildTasks.xcplugin/Contents/Resources/copyplist and it looks fine. But when I try to run it, I get the same thing:
[james-moores-macbook-pro:~/dev/EditableDetailView] jamesmoore% /Developer/Library/Xcode/Plug-ins/CoreBuildTasks.xcplugin/Contents/Resources/copyplist/Developer/Library/Xcode/Plug-ins/CoreBuildTasks.xcplugin/Contents/Resources/copyplist: Command not found.
So I open the file, and see the problem immediately on line 1:
#!/usr/bin/ruby
Of course there's no /usr/bin/ruby - I do Ruby development, and since Apple ships a version of Ruby that was current back when dinosaurs roamed the earth, I install the macports version. And that goes in /opt/local/bin, not /usr/bin. It's an Apple bug - hardcoding the location of Ruby is wrong. The line should be:
#!/usr/bin/env ruby
The workaround is just to link the good Ruby to the old, bad location:
sudo ln -s /opt/local/bin/ruby /usr/bin/

Monday, January 19, 2009

Installing mysql gem on MacOS

Chris Bailey's blog had the quick answer for how to install the mysql gem in MacOS when you're using the macports mysql:

sudo env ARCHFLAGS="-arch i386" gem install mysql -- --with-mysql-include=/opt/local/include/mysql5 --with-mysql-lib=/opt/local/lib/mysql5 --with-mysql-config=/opt/local/lib/mysql5/bin/mysql_config

Wednesday, January 14, 2009

screen (as in old-school unix screen) on the mac - UTF8

I finally got around to figuring out screen - should have done it years ago. On a Mac, you're going to get a LANG default like this:
LANG=en_US.UTF-8
You'll need to put this in your ~/.screenrc:
defutf8 on

Sunday, January 11, 2009

How to get symbolic stack traces on an iPhone exception

Very useful post from Gabriel Handford about getting symbolic information in stack traces. Good followup article from Ben Chatelain about some missing pieces. Gabriel said "For me, DEBUG is set in GCC_PREPROCESSOR_DEFINITIONS via the awesome GTM xcconfg files, which you should also be using," but since I'm not using them, I just added DEBUG to the command line. (Cmd-I on the target > Build > Preprocessor macros). I hit the same issue with NSDebug that Ben had, and copying the file over seems to solve the problem with running on the device itself and not just the simulator.

Thursday, January 1, 2009

Don't run your bluetooth headset through the wash

Turns out a Samsung WEP200 doesn't survive a pass through the washing machine + dryer. Second bluetooth headset I've killed that way. You'd think I would have learned by now.