Cory O'Daniel – These are just words Software development, thoughts, and randomness

27Jul/101

My Genius Invention to revolutionize using the iPhone 4.

So, I'm an Apple Fanboi, so I don't mind finding ways to make their products MORE AWESOME. It's needless to say that the iPhone 4 is revolutionary, but I have made a draft of an invention I am working on that will make the iPhone 4 a truly genius piece of technology.

You'd better sit down.

Your iPhone 4 can do all sorts of cool things like fling angry birds at pigs, help you cook an awesome hamburger, take pictures of girls buts in line at starbucks and send them to your friends, but imagine if you could use the iPhone 4, wait for it, as a phone.

Imagine if you could call people on it and have a conversation without being interrupted by ear muting, ear hangups, holding it wrong and hanging up, or accidentally conference calling your ex girlfriend into a conversation with your current girlfriend with your ear.

Yeah, it'd be a utopian life. So I decided I was going to revolutionize this revolutionary device and low and behold here is what I came up with.

Now, this is just a rough draft. I'm still working on the technicalities. I'm hoping since the internet is a trustworthy place none of you will find this and beat me to the punch on creating this device.


View Full Size Here

Apple, if you would like to buy my patent please feel free to contact me. Steve, I know you are completely intrigued by the idea of being able to use the iPhone as a phone. It blew me away too.

Update - Initial reports are in from my prototype. It turns out if you have hair and use the headset it actually shorts out the antenna. So for now its just for bald people. I'm working on a bumper for the head band.

Post to Twitter Post to Digg Post to Facebook Post to Reddit Post to StumbleUpon

Filed under: Random 1 Comment
24May/102

Lost finale – did i get it?

I think I understood the lost finale? What I understood was that everything that happened on the island was REAL. It all happened. The monster, the time travel, the dharma initiative. Everything. As the losties died off they went to the side world where they could meet up and "move on" together. So when we saw the plane leave, those people left the island, went on to have lives and eventually died. Hurley and Ben stayed on the island for however long and eventually died.

This is supported by the following statements I think?

Hurley to Ben - you were a good #2

Christian to Jack - everybody dies some die before you some die way after you

Christian to Jack - the time on the island was the most important part of your life

Am I on the right track?

Post to Twitter Post to Digg Post to Facebook Post to Reddit Post to StumbleUpon

Tagged as: 2 Comments
23Feb/100

Why the hell can’t Apple fix this bug? – Snow Leopard Keyboard hangs when changing spaces

Everyone knows about this bug, except apparently Apple.

In Snow Leopard the keyboard hangs occasionally when changing spaces. Sometimes for only a few seconds, sometimes forever. All sorts of people are talking or reporting about this issue.

Why isn't it being fixed? Hallo there, Apple? Are you there?

There are currently about 100 posts in the Apple support thread dating back from Sep 15, 2009. You know whats annoying? Killing your Dock constantly while you are working.

Apple: SrSLy 4real. Fix this. Its equivalent to working really hard and someone smacking you in the forehead randomly. It kinda sucks, and its really irritating.

(Note: My keyboard only hung once during this post).


Update: March 3, 2010

After some further research, at least for me and a few others, this bug is tied to an application called Cinch. If you have Cinch installed, try uninstalling it and seeing if this problem goes away. A pretty useful app, but I'd rather resize my windows manually than 'get interrupted' when I'm in my workflow.

I uninstalled Cinch 5 days ago, and the problem has gone away for me. I was having my keyboard hang 4 or 5 times a day with it installed.

Post to Twitter Post to Digg Post to Facebook Post to Reddit Post to StumbleUpon

4Feb/101

How to close (get rid of) the Google Analytics Site Overlay

So, the google analytics site overlay is pretty cool. It's nice to see where people click. I googled around and some people say to clear the cookies. The funny thing is there is actually a 'close' button, but you can't see it if your page's background is white. Duh, it's in the top right corner. Just click close.

Here it is, sneakily hidden.

Where the hell is the close button?

Here it is with the click-n-drag (TM) revealing tool.

Oh, magic!

You may be saying "duh". But with a white background, its a bit tricky to find, and clearing cookies constantly is retarded (technically speaking).

Post to Twitter Post to Digg Post to Facebook Post to Reddit Post to StumbleUpon

30Dec/090

DataMapper and Merb, sharing your errors via the merb display API.

This is a quick little snippet. At Vokle all of our products are built using our core API, which thanks to merb, was a piece of cake. The thing that sucks is sometimes we return objects as JSON via the display API and the "errors" are missing in the event that validation failed. How to fix that?

Throw this somewhere:

1
2
3
4
5
6
7
8
9
10
module DataMapper
  module Validate
 
    class ValidationErrors
      def to_json
        @errors.to_hash.to_json
      end
    end
  end
end

Now in your merb controllers, when you are displaying an object that may have errors:

1
2
3
4
5
6
7
8
class People < Merb::Controller
 
  def create(person)
    #... *SNIP* ...
    display @person, nil, {:methods => [:errors]}
    #... *SNIP* ...
  end
end

And whatever is getting your data back in XML or JSON (yeah or YAML, right) will get the errors on your object as well. Cool.

Yay, users give you invalid data. Congrats.

Post to Twitter Post to Digg Post to Facebook Post to Reddit Post to StumbleUpon

30Dec/090

Deploying apps stored in Git to Rightscale – easy peasy (Git archive to S3, nothing but net)

Since I started using Rightscale for all my application needs I've found that I don't need things like Capistrano, Chef, or WarningShot. Rightscale has a really cool feature called "Rightscripts" that let you apply little snippets to a server at boot time, any time or decommission time.

Using Rightscripts (which I'm going to start sharing on my blog soon) I can apply a bunch of snippets to a server instance, and it essentially does all the 'dependency' resolution that people put together with things like those mentioned above.

I have a script called "deploy_vokle" which gets a tarball, unpacks it, does testing on it then boots up the server if the test pass. The one thing I was missing was how to get my code from git to my servers without my servers having a github account. Solution - Git archive the revision I want to release, send it to S3 and let my new servers pick it up at boot-time. First install the AWS gem.

1
2
3
4
# First you need aws rubygem.
gem install aws-s3
export AS3_ACCESS_KEY=YOUR_KEY_HERE
export AS3_SECRET_KEY=YOUR_SECRET_HERE

Then, put this script in a file called s3packager.rb and make it executable:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
require 'rubygems'
require 'aws/s3'
 
AWS::S3::Base.establish_connection!(
  :access_key_id     => ENV['AS3_ACCESS_KEY'],
  :secret_access_key => ENV['AS3_SECRET_KEY']
)
 
def git_archive(revision='HEAD', filename = nil, format='tar')
  filename ||= revision
 
  if format == 'tar'
    filename = "#{filename}.tar.gz"
  else
    filename = "#{filename}.zip"
  end
 
  `git archive --format=#{format} #{revision} | gzip > #{filename}`
  if $? == 0
    filename 
  else
    return false
  end
end
 
def s3put(filename, opts={})
  deploy_label = filename
  backup_label = "#{$REVISION}-#{filename}"
 
  file_ref = File.read File.expand_path(filename)
 
  # Push the package twice, once with the revision in the name, and once as the intended package
  #   acts as a sort of back up of what has been pushed...
  [deploy_label, backup_label].each do |file_label|
    begin
      puts "Putting to S3: #{file_label}"
 
      AWS::S3::S3Object.store(
        file_label,
        file_ref,
        $BUCKET_NAME,
        :content_type => (file_label =~ /\.tar\.gz$/i ? 'application/x-gzip' : 'application/x-zip'),
        :access       => :private
      )
    rescue Exception => ex
      puts ex.message
      return false
    end
  end
 
  return true
end
 
 
def s3get(filename)
  local_filename = File.expand_path(filename)
 
  File.open(local_filename, 'w') do |new_file|
    AWS::S3::S3Object.stream(filename,$BUCKET_NAME) do |chunk|
      new_file.write chunk
    end
  end
 
  return File.exist?(filename)
end
 
if ARGV.index('-h') || ARGV.empty?
  puts "============================================================================"
  puts "Packages a git revision w/o git data to Amazon S3"
  puts "package.rb --bucket [BUCKET_NAME] --revision [REVISION|HEAD] --FILENAME [production|experimental|USER_DEF]"
  puts "To see revisions do 'git log'"
  puts "============================================================================"
  exit(0)
end
 
$REVISION = ARGV[ARGV.index('--revision') + 1] rescue nil
$OUT_NAME = ARGV[ARGV.index('--filename') + 1] rescue nil
$BUCKET_NAME   = ARGV[ARGV.index('--bucket') + 1] rescue nil
 
begin
  AWS::S3::Bucket.find $BUCKET_NAME
rescue Exception => ex
  puts "Could not fetch bucket #{$BUCKET_NAME}, did you set $AS3_ACCESS_KEY & $AS3_SECRET_KEY?"
  exit(1)  
end
 
if $REVISION.nil?
  puts "--revision is required"
  exit 3
end
 
arch_file = git_archive($REVISION, $OUT_NAME)
 
if arch_file && s3put(arch_file)
  puts "SUCCESS"
else
  puts "FAILED"
end
# First

Make it executable!

1
chmod +x s3packager.rb

Wanna use it? When ever you want to release something from git:

1
s3packager.rb --revision YOUR_GIT_LOG_REVISION_ID --bucket YOUR_AMAZON_BUCKET --filename THE_NAME_OF_THE_FILE_YOUR_SERVER_IS_LOOKING_FOR

If you need help:

1
s3packager.rb -h

Yay, your up in the clouds. Congrats.

Post to Twitter Post to Digg Post to Facebook Post to Reddit Post to StumbleUpon

30Dec/090

Ruby NYSIIS Implementation

This is another thing in my bag of stuff in my ruby core extensions. NYSIIS is a phonetic algorithm that is a little more accurate than the traditional Soundex algorithm. (Note: if you need a Soundex algorithm for ruby, look here.)

I frequently use this in my ActiveRecord and DataMapper models of people or users. I store a NYSIIS of the first and last names of all users to account for misspellings when others are searching for people.

Examples:
O'Daniel → ODANAL
O'Donnel → ODANAL
Cory → CARY
Corey → CARY
Kory → CARY

So if you were searching for me and spelled my name "Corey ODonnel", me "Cory ODaniel" would still be in your result set.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
class String
  def nysiis
    str = self.upcase
    str.strip!      
    str.gsub!(/[^A-Z ]/,"")
    str.gsub!(/ +(JR|SR)$/,"")
    str.gsub!(/ +(I|V|X|L|C|D|M)+$/,"")
    str.gsub!(/ /,"")
 
    # 1. Translate first characters of name: 
    # => MAC → MCC, KN → NN, K → C, PH → FF, PF → FF, SCH → SSS        
    {
      /^MAC/      => "MCC",
      /^KN/       => "NN",
      /^K/        => "C",
      /^(PH|PF)/  => "FF",
      /SCH/       => "SSS"
    }.each do |r,s|
      break if str.sub!(r,s)
    end
 
    # 2. Translate last characters of name: 
    # => EE → Y, IE → Y, DT, RT, RD, NT, ND → D
    str.sub!(/(EE|IE)$/,"Y")
    str.sub!(/(DT|RT|RD|NT|ND)$/,"D")
 
    # 3. First character of key = first character of name.
    first_char = str[0,1]
    str = str[1,str.length]
 
    # 4. Translate remaining characters by following rules, 
    #    incrementing by one character each time:
    # => EV → AF else A, E, I, O, U → A
    # => Q → G, Z → S, M → N
    # => KN → NN else K → C
    # => SCH → SSS, PH → FF
    # => H → If previous or next is nonvowel, previous.
    # => W → If previous is vowel, previous. (A is the only vowel left)    
    str.gsub!(/EV/, "AF")
    str.gsub!(/[AEIOU]/,"A")
    str.gsub!(/Q/, "G")
    str.gsub!(/Z/, "S")
    str.gsub!(/M/, "N")
    str.gsub!(/KN/, "NN")
    str.gsub!(/K/, "C")
    str.gsub!(/SCH/, "SSS")
    str.gsub!(/PH/, "FF")
    str.gsub!(/([^AEIOU])H/, $1) if $1
    str.gsub!(/(.)H[^AEIOU]/, $1) if $1
    str.gsub!(/AW/, "A")
 
    # 4. CONTINUED
    # => Add current to key if current is not same as the last key character.
    str.squeeze!     #everything was done in place, so squeeze out the duplicates
    str = first_char + str
 
    # 5. If last character is S, remove it.
    # 6. If last characters are AY, replace with Y.
    # 7. If last character is A, remove it.
    str.sub!(/(S|A)$/,"")
    str.sub!(/AY$/,"Y")
 
    return str
  end
 
end

Wanna use it?

1
2
3
# include file from above
"Cory".nysiis #=> "CARY"
"O'Daniel".nysiis #=> "ODANAL"

Yay, now you are NYSIIS. Congrats.

Post to Twitter Post to Digg Post to Facebook Post to Reddit Post to StumbleUpon

30Dec/090

Ruby Levenshtein Distance implementation

Levenshtein distance is a metric for measuring the amount of difference between two sequences or strings, ie how many things have to change to make one word another.

Examples:
kitten → sitten (substitution of 's' for 'k') (distance of 1)
sitten → sittin (substitution of 'i' for 'e') (distance of 1)
sittin → sitting (insert 'g' at the end) (distance of 1)
kitten → sitting (distance of 3)
bonsdale → basilton (distance of 7)
california → cory (distance of 9)

I don't know why I had this in my private ruby core extensions library, but I figured I'd share it in case anyone else needed it. Works in ruby 1.8, haven't tested in ruby 1.9.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class String
  def distance(other_str)
    _self_str = self.downcase
    _othr_str = other_str.downcase
 
    # Shortcuts
    return 0 if _self_str == _othr_str    
    return _self_str.length if (0 == _othr_str.length)
    return _othr_str.length if (0 == _self_str.length)
 
    # how to unpack
    unpack_rule = ($KCODE =~ /^U/i) ? 'U*' : 'C*'
 
    #longer, shorter
    _str_1, _str_2 = if _self_str.length > _othr_str.length
      [_self_str, _othr_str]
    else
      [_othr_str, _self_str]
    end
 
    # get different in length as base
    difference_counter = _str_1.length - _str_2.length
 
    # Shorten first string & unpack
    _str_1 = _str_1[0, _str_2.length].unpack(unpack_rule)
    _str_2 = _str_2.unpack(unpack_rule)
 
    _str_1.each_with_index do |char1, idx|
      char2 = _str_2[idx]
      difference_counter += 1 if char1 != char2
    end
 
    return difference_counter
  end
end

Wanna use it?

1
2
#include the file from above
"kitten".distance("sitting") #=> 3

Yay, now you know how far apart words are. Congrats.

Edit
My implementation is faster than the one on Wikibooks for small differences, it is significantly faster for large differences.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
require 'benchmark'
 
 
class String
  def distance(other_str)
    _self_str = self.downcase
    _othr_str = other_str.downcase
 
    # Shortcuts
    return 0 if _self_str == _othr_str    
    return _self_str.length if (0 == _othr_str.length)
    return _othr_str.length if (0 == _self_str.length)
 
    # how to unpack
    unpack_rule = ($KCODE =~ /^U/i) ? 'U*' : 'C*'
 
    #longer, shorter
    _str_1, _str_2 = if _self_str.length > _othr_str.length
      [_self_str, _othr_str]
    else
      [_othr_str, _self_str]
    end
 
    # get different in length as base
    difference_counter = _str_1.length - _str_2.length
 
    # Shorten first string & unpack
    _str_1 = _str_1[0, _str_2.length].unpack(unpack_rule)
    _str_2 = _str_2.unpack(unpack_rule)
 
    _str_1.each_with_index do |char1, idx|
      char2 = _str_2[idx]
      difference_counter += 1 if char1 != char2
    end
 
    return difference_counter
  end
end
 
def levenshtein(a,b)
  case
    when a.empty?: b.length
    when b.empty?: a.length
    else [(a[0] == b[0] ? 0 : 1) + levenshtein(a[1..-1], b[1..-1]),
          1 + levenshtein(a[1..-1], b),
          1 + levenshtein(a, b[1..-1])].min
  end
end
 
 
n = 50000
Benchmark.bm do |x|
  x.report("Levenshtein Distance (Cory, Small Difference)"){ 
    "kitten".distance("smitten")
  }
  x.report("Levenshtein Distance (Wikibooks, Small Difference)") { 
    levenshtein("kitten", "smitten")
  }
 
  x.report("Levenshtein Distance (Cory, Large Difference)"){ 
    "constantinople".distance("antelope")
  }
  x.report("Levenshtein Distance (Wikibooks, Large Difference)") { 
    levenshtein(    "constantinople","antelope")
  }
end

You'll note running those benchmarks that the wikipedia implementation will actually hang for about 30 seconds (or it did on my MacBook 2.8Ghz Core 2 Duo w/ 4 GB ram).

Edit
I updated my implementation to be a little clearer and squash a bug in calculating distances. If anyone finds any mistakes please let me know!

Post to Twitter Post to Digg Post to Facebook Post to Reddit Post to StumbleUpon

30Dec/090

DM Cutie, et al. 0.4 release (minor updates)

I released dm-cutie, dm-cutie-ui, and dm-cutie-extras with some minor releases on gemcutter.org today.

The minor updates include a lot of help information and some tweaks to dm-cutie-ui to make it easier to use/understand (I hope).
+ add 'help' area describing all the default views
+ MysqlIndex/ Steps column info in help
+ Sort Tables Repo, Gen, Executed, Others by alpha (routes key should be view_name)
+ menu cleanup
+ @records count on page
+ Moved connected to
+ Changed word on relationship link
+ Format of page title
+ Removed duplicate column on mysql_index
+ Sort buttons moved

If you haven't installed DM Cutie, make sure your rubygems is up to date and do:

1
2
3
4
5
gem install gemcutter --source http://gemcutter.org
gem tumble
gem install dm-cutie -v 0.4.0
gem install dm-cutie-ui -v 0.4.0
gem install dm-cutie-extras -v 0.4.0

Information on setting DM Cutie up is in this post.

If you want the source its available on my github page.

I'll be adding some more interesting tracking stuff for MySQL in the next few days. Now that Vokle has officially launched, I find myself with more time to work on my projects.

When I started this project I really wanted it to be a cool way to get information on all your DM storage needs. I am now realizing that DM Cutie should probably only support SQL and DO backed stores, and I'll be pairing down the internals over the next few days with that in mind.

Most of my database experience as far as optimizing goes is in MySQL, if anyone has some PostgreSQL or SQlite awesomeness they'd like to share, I'd really appreciate it.

Post to Twitter Post to Digg Post to Facebook Post to Reddit Post to StumbleUpon

24Dec/092

Switching to wordpress

Tumblr has beyond annoyed me, switching to wordpress.

Post to Twitter Post to Digg Post to Facebook Post to Reddit Post to StumbleUpon

Filed under: Random 2 Comments