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.

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.
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?
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.
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.
Here it is with the click-n-drag (TM) revealing tool.
You may be saying "duh". But with a white background, its a bit tricky to find, and clearing cookies constantly is retarded (technically speaking).
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.
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.
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.
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!
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.

