Hello

Brad Dominy


Selected Work

The following are projects I have written and designed, most of which are based on Cocoa for MacOSX. I have also written AppleScripts and used other languages like Python, PHP, Perl, C, and Java.

Digits of π

In celebration of Pi Day, here is an AppleScript I wrote that outputs the digits of π until the machine runs out of memory and crashes horribly.

(*

From the paper "An Unbounded Spigot Algorithm for the Digits of Pi"
http://web.comlab.ox.ac.uk/oucl/work/jeremy.gibbons/publications/spigot.pdf

*)

property MINUS : -1
property PLUS : 1

set q to {1}
set r to {0}
set t to {1}
set k to {1}

repeat

    set n to divide(add(multiply({3}, q), r), t)

if compare(divide(add(multiply({4}, q), r), t), n) = 0 then

    log n
    set q to multiply({1, 0}, q)
    set r to multiply({1, 0}, subtract(r, multiply(n, t)))
else

    set r to add(multiply(q, add(multiply({4}, k), {2})), ¬
                           multiply(r, add(multiply({2}, k), {1})))
    set q to multiply(q, k)
    set t to multiply(t, add(multiply({2}, k), {1}))
    set k to add(k, {1})
end if
end repeat

on divide(a, b)

set c to {}

if (count of a) = 1 then
    if item 1 of a = 0 then
        return {0}
    end if
end if

if (count of b) = 1 then
    if item 1 of b = 0 then
        return c
    else if item 1 of b = 1 then
        return a
    end if
end if
if item 1 of a < 0 then
    set a_signbit to MINUS
else
    set a_signbit to PLUS
end if

if item 1 of b < 0 then
    set b_signbit to MINUS
else
    set b_signbit to PLUS
end if

set item 1 of a to (item 1 of a) * a_signbit
set item 1 of b to (item 1 of b) * b_signbit

set row to {}

repeat with i from 1 to count of a

    set the end of row to item i of a
    set row to trim_zeros(row)
    set n to 0
    repeat while compare(row, b) ≠ PLUS
        set n to n + 1
        set row to subtract(row, b)
    end repeat
    set the end of c to n
end repeat

set item 1 of a to (item 1 of a) * a_signbit
set item 1 of b to (item 1 of b) * b_signbit

set c to trim_zeros(c)

set item 1 of c to (item 1 of c) * a_signbit * b_signbit

return c
end divide

on multiply(a, b)
set c to {0}

if (count of a) = 1 then
    if item 1 of a = 0 then
        return c
    else if item 1 of a = 1 then
        return b
    end if
end if
if (count of b) = 1 then
    if item 1 of b = 0 then
        return c
    else if item 1 of b = 1 then
        return a
    end if
end if

if item 1 of a < 0 then
    set a_signbit to MINUS
else
    set a_signbit to PLUS
end if

if item 1 of b < 0 then
    set b_signbit to MINUS
else
    set b_signbit to PLUS
end if

set item 1 of a to (item 1 of a) * a_signbit
set item 1 of b to (item 1 of b) * b_signbit

copy a to t --fast but uses more memory
set b_count to count of b
repeat with i from b_count to 1 by -1
    repeat (item i of b) times
        set c to add(c, t)
    end repeat
    set t to shift(t, 1)
end repeat

set item 1 of a to (item 1 of a) * a_signbit
set item 1 of b to (item 1 of b) * b_signbit

set item 1 of c to (item 1 of c) * a_signbit * b_signbit
set c to trim_zeros(c)
return c
end multiply

on shift(n, d)
repeat d times
    set the end of n to 0
end repeat
return n
end shift

on subtract(a, b)
set c to {}

if item 1 of a < 0 then
    set a_signbit to MINUS
else
    set a_signbit to PLUS
end if

if item 1 of b < 0 then
    set b_signbit to MINUS
else
    set b_signbit to PLUS
end if

if a_signbit = MINUS or b_signbit = MINUS then

    set item 1 of b to (item 1 of b) * MINUS
    set c to add(a, b)
    set item 1 of b to (item 1 of b) * MINUS

else if compare(a, b) = PLUS then

    set c to subtract(b, a)
    if item 1 of c > 0 then set item 1 of c to (item 1 of c) * MINUS

else
    set borrow to 0
    set v to 0

    set a_count to count of a
    set b_count to count of b

    set i to a_count
    set j to b_count

    repeat while i > 0 and j > 0

        set v to (item i of a) - borrow - (item j of b)
        if item i of a > 0 then set borrow to 0

        if v < 0 then
            set v to v + 10
            set borrow to 1
        end if

        set the beginning of c to v mod 10

        set i to i - 1
        set j to j - 1
    end repeat

    repeat while i > 0

        set v to (item i of a) - borrow
        if item i of a > 0 then set borrow to 0

        if v < 0 then
            set v to v + 10
            set borrow to 1
        end if

        set the beginning of c to v mod 10

        set i to i - 1

    end repeat

end if
return trim_zeros(c)
end subtract

on trim_zeros(a)
set a_count to count of a
set i to 1

repeat while i ≤ a_count
    if item i of a ≠ 0 then exit repeat
    set i to i + 1
end repeat

if i ≤ a_count then
    set a to items i thru -1 of a
else
    set a to {0}
end if
return a
end trim_zeros

on add(a, b)
set c to {}

if item 1 of a < 0 then
    set a_signbit to MINUS
else
    set a_signbit to PLUS
end if

if item 1 of b < 0 then
    set b_signbit to MINUS
else
    set b_signbit to PLUS
end if

if a_signbit ≠ b_signbit then
    if a_signbit = MINUS then
        set item 1 of a to (item 1 of a) * a_signbit
        set c to subtract(b, a)
        set item 1 of a to (item 1 of a) * a_signbit
    else
        set item 1 of b to (item 1 of b) * b_signbit
        set c to subtract(a, b)
        set item 1 of b to (item 1 of b) * b_signbit
    end if
else
    set carry to 0
    set a_count to count of a
    set b_count to count of b

    set i to a_count
    set j to b_count

    set item 1 of a to (item 1 of a) * a_signbit
    set item 1 of b to (item 1 of b) * b_signbit

    repeat while i > 0 and j > 0

        set n to (carry + (item i of a) + (item j of b))
        set the beginning of c to n mod 10
        if n < 10 then
            set carry to 0
        else
            set carry to 1
        end if

        set i to i - 1
        set j to j - 1
    end repeat

    repeat while i > 0

        set n to (carry + (item i of a))
        set the beginning of c to n mod 10
        if n < 10 then
            set carry to 0
        else
            set carry to 1
        end if

        set i to i - 1

    end repeat

    repeat while j > 0

        set n to (carry + (item j of b))
        set the beginning of c to n mod 10
        if n < 10 then
            set carry to 0
        else
            set carry to 1
        end if

        set j to j - 1

    end repeat

    set item 1 of a to (item 1 of a) * a_signbit
    set item 1 of b to (item 1 of b) * b_signbit

    if carry > 0 then set the beginning of c to carry

    set item 1 of c to (item 1 of c) * a_signbit

end if

return c
end add

on compare(a, b)

if item 1 of a < 0 then
    set a_signbit to MINUS
else
    set a_signbit to PLUS
end if

if item 1 of b < 0 then
    set b_signbit to MINUS
else
    set b_signbit to PLUS
end if

if a_signbit = MINUS and b_signbit = PLUS then return PLUS
if a_signbit = PLUS and b_signbit = MINUS then return MINUS

set a_count to count of a
set b_count to count of b
if b_count > a_count then return PLUS * a_signbit
if a_count > b_count then return MINUS * a_signbit

set r to 0
set item 1 of a to (item 1 of a) * a_signbit
set item 1 of b to (item 1 of b) * b_signbit

repeat with i from 1 to a_count
    if item i of a > item i of b then
        set r to MINUS * a_signbit
        exit repeat
    end if
    if item i of b > item i of a then
        set r to PLUS * a_signbit
        exit repeat
    end if
end repeat
set item 1 of a to (item 1 of a) * a_signbit
set item 1 of b to (item 1 of b) * b_signbit

return r
end compare

Randomize Last Names

A script to randomize the last names of all of my Address Book contacts. Useful for protecting the innocent when taking screenshots of some of my other projects.

DON'T USE THIS WITHOUT MAKING A BACKUP FIRST!

Copy and paste into AppleScript Editor if you want to try it out.

set name_url to "http://names.mongabay.com/most_common_surnames.htm"

set t to do shell script "curl \"http://names.mongabay.com/most_common_surnames.htm\" -o /tmp/temp.html; cat /tmp/temp.html"

set name_list to {}
set the_lines to get every paragraph of t
set grabNamesFlag to false
set row_count to 0
repeat with this_line in the_lines

    if this_line begins with "<table" and this_line contains "table1" then
        set grabNamesFlag to true
    end if

    if grabNamesFlag then
        if this_line begins with "<tr" then
            set row_count to row_count + 1

            if row_count > 1 then
                set o1 to offset of "<td>" in this_line
                set o2 to offset of "</td>" in this_line

                set lname to text (o1 + 4) thru (o2 - 1) of this_line
                set the end of the name_list to capitalizeString(lname)
            end if
        else if this_line begins with "</table>" then
            exit repeat
        end if
    end if

end repeat

--return name_list
set out to ""
tell application "Address Book"

    set person_list to get every person

    repeat with this_person in person_list
        set old_lastname to last name of this_person
        if old_lastname is not equal to "Dominy" then
            set new_lastname to old_lastname
            repeat until new_lastname is not equal to old_lastname
                set new_lastname to some item in name_list
            end repeat
            set out to out & "replacing " & old_lastname & " with " & new_lastname & return
            set the last name of this_person to new_lastname
        end if
    end repeat

    save addressbook
end tell
return out

-- Translate characters of a text
-- Note: Pass the From and To tables as strings (same length!)
--
on translateChars(theText, fromChars, toChars)
    set the newText to ""
    if (count fromChars) is not equal to (count toChars) then
        error "translateChars: From/To strings have different length"
    end if
    repeat with char in theText
        set newChar to char
        set x to offset of char in the fromChars
        if x is not 0 then set newChar to character x of the toChars
        set newText to newText & newChar
    end repeat
    return the newText
end translateChars

-- Convert a text case to lower characters
-- Note: Requires the translateChars function
--
on lowerString(theText)
    set upper to "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    set lower to "abcdefghijklmnopqrstuvwxyz"
    return translateChars(theText, upper, lower)
end lowerString

-- Convert a text case to upper characters
-- Note: Requires the translateChars function
--
on upperString(theText)
    set lower to "abcdefghijklmnopqrstuvwxyz"
    set upper to "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    return translateChars(theText, lower, upper)
end upperString

-- Capitalize a text, returning only the first letter uppercased
-- Note: Requires translateChars, lowerString and upperString
--
on capitalizeString(theText)
    set firstChar to upperString(first character of theText)
    set otherChars to lowerString(characters 2 thru -1 of theText)
    return firstChar & otherChars
end capitalizeString

vCards to Clipboard

A utility that puts the names of people into the clipboard from vCards. The cards can come directly from Address Book by selecting a group of cards and then dragging them onto the droplet.

Copy and paste into AppleScript Editor and then save as a droplet if you want to try it out.

on open vcards
set out to ""

repeat with this_vcard in vcards

    set p to POSIX path of this_vcard
    set s to "grep \"FN:\" " & encode(p) & "| cut -c 4-50"
    set out to do shell script s
end repeat

set the clipboard to out
end open

on encode(this_path)
set tmp to ""

repeat with i from 1 to length of this_path

    set ch to character i of this_path

    if ch is equal to space then set tmp to tmp & "\\"

    set tmp to tmp & ch
end repeat
return tmp
end encode

iChat Stock Ticker

A fun little script that puts a scrolling stock ticker in your iChat status.


Copy and paste into AppleScript Editor if you want to try it out.

set stockList to {"^DJI", "^IXIC", "AAPL", "AKAM", "TIVO", "SIRI", "AIG", "MSFT", "STEC", "F", "ESLR", "GME", "UAUA", "BAC", "WFC"}
set upCh to "▲"
set dnCh to "▼"

repeat
set m to ""
repeat with daSymbol in stockList

    -- fetch quote page
    set q to do shell script "curl \"http://www.google.com/finance/info?client=ig&q=" & daSymbol & "\" -o /tmp/temp.html ; cat /tmp/temp.html"

    set pq to parse_quote(q)

    set m to m & _t of pq & " " & _l_cur of pq & " "
    set c to _c of pq as number

    if c < 0 then
        set m to m & dnCh
    else if c > 0 then
        set m to m & upCh
    else
        set m to m & "-"
    end if
    set m to m & " " & c & " ( " & _cp of pq & "% )       "
end repeat

set i to 0
set l to length of m

tell application "iChat" --to 
    repeat
        set i to i + 1

        set n to text i thru -1 of m

        if i > 1 then set n to n & text 1 thru (i - 1) of m

        if i ≥ l then
            set i to 0
            exit repeat
        end if

        set the status message to n
        delay 0.1
    end repeat
end tell
end repeat

on parse_quote(q)

set r to {} as record

set li to get every paragraph of q
repeat with thisLine in li

    set o1 to offset of ":" in thisLine

    if o1 > 0 then
        --log clean(thisLine)

        set k to clean(text 1 thru (o1 - 1) of thisLine)
        set v to clean(text (o1 + 1) thru -1 of thisLine)

        if k is "id" then
            set r to r & {_id:v}
        else if k is "t" then
            set r to r & {_t:v}
        else if k is "e" then
            set r to r & {_e:v}
        else if k is "l" then
            set r to r & {_l:v}
        else if k is "l_cur" then
            set r to r & {_l_cur:v}
        else if k is "ltt" then
            set r to r & {_ltt:v}
        else if k is "lt" then
            set r to r & {_lt:v}
        else if k is "c" then
            set r to r & {_c:v}
        else if k is "cp" then
            set r to r & {_cp:v}
        else if k is "ccol" then
            set r to r & {_ccol:v}
        end if
    end if

end repeat
return r
end parse_quote

on clean(t)

set out to ""

if length of t > 0 then
    repeat with i from 1 to length of t
        set ch to character i of t
        if ch is "\"" then

        else
            set out to out & ch
        end if
    end repeat
end if

if character 1 of out is "," then set out to text 2 thru -1 of out

return trim(out)
end clean

on trim(someText)

if length of someText > 1 then
    repeat until someText does not start with " "
        set someText to text 2 thru -1 of someText
    end repeat

    repeat until someText does not end with " "
        set someText to text 1 thru -2 of someText
    end repeat
end if
return someText
end trim

About me

Brad Dominy

Projects

By Language

By Frameworks