Archive for November, 2008

Song of the Day 30/11/08

Sunday, November 30th, 2008

Song of the day is Moment, by Lena Park.

I’ve liked Lena Park for a long time, but a friend recently reminded me of Moment, from the 6th album, and it was exactly what I wanted to hear. Don’t you love it when that happens?

I love the ultra-high accompaniment on the chorus, and it suits my mood perfectly.

Moment (순간), Lena Park (박정현), from 6th album “Come To Where I Am”. MP3 format 7.3M

Lyrics below.

(more…)

Weird output from Digest::MD5 in ruby

Monday, November 24th, 2008

Any Ruby programmers who are reading this, I’m experiencing a strange issue regarding Digest::MD5. Let me show you:

>> require 'digest/md5'
=> true
>> Digest::MD5.digest "Les Rhythmes Digitales"
=> "\213U\3601\260%\267-\343(\213I\030\347"

What the fuck is that huge escaped thing? A unicode issue?

Check out the same from bash:

$ md5 -s "Les Rhythmes Digitales"
MD5 ("Les Rhythmes Digitales") = 8b55f031b0253c6ab72de3288b4918e7

Now that looks more like what I expect from an MD5 hash. Is Digest::MD5 mangling the text into some kind of weird invalid unicode?

Let’s try with $KCODE set:

>> $KCODE = "UTF8"
=> "UTF8"
>> require 'digest/md5'
=> true
>> Digest::MD5.digest "Les Rhythmes Digitales"
=> "\213U?1?%\267-?(?I\030\347"

Great. Any different in 1.9?

irb(main):003:0> Digest::MD5.digest "Les Rhythmes Digitales"
=> "\x8BU\xF01\xB0%\xB7-\xE3(\x8BI\x18\xE7"

Different again. At least I can see the characters in there, though. This is causing some pain.

Am I doing something hopelessly wrong? Somewhere in all these, some character encoding crap is going down. I can’t believe I’m the only one having these problems, and they render it difficult to use hashed passwords. I am working around the issue by shelling out to bash for now, but would like to get it fixed.

UPDATE: About 2 minutes after writing that, I realised I need to use Digest::MD5.hexdigest, not plain digest. I have no idea what the difference is supposed to be, but oh well, lesson learned. Apparently writing complaints on this blog helps me solve problems, so expect it to continue.

>> Digest::MD5.hexdigest "Les Rhythmes Digitales"
=> "8b55f031b0253c6ab72de3288b4918e7"

Milliseconds Since Epoch UTC

Friday, November 21st, 2008

That’s it! I have had enough. I have had enough of DateTime, time strings, datetime strings, Time.parse(), MySQL time, JSON time, CouchDB time, Ruby time, system time and all the rest of it.

I have come to realise that there is one, and only one, appropriate way to store time so everything can understand it without endless string conversion problems, and that is in a numeric format of milliseconds since Epoch UTC.

The only appropriate time to convert from milliseconds into a human-readable string is upon presentation to an actual human – ie, in the View. Or, if you like, store a second time field in any records you save or pass around – just make sure your program doesn’t care about those.

This revelation comes from YET ANOTHER journey into ISO document land as I realised that not only do I have no idea how to store milliseconds in a JSON date/time string, but neither does anyone else. RIGHT!! THAT IS IT! From now on, dates are an integer.

Maybe.

Anyway, here’s some notes on getting millisecond-precision time references in and out of Ruby and JS, both of whose time classes I am no fan of, more for me than anything else..

Ruby example:

 
# Getting milliseconds since Epoch out of Ruby:
 
time_float = Time.now.to_f
time_ms = (1000* time_float).to_i
 
#writing
 
>> t = Time.now.utc
=> Thu Nov 20 23:01:32 UTC 2008
>> time_float = t.to_f
=> 1227222092.50133
>> time_ms = (1000* time_float).to_i
=> 1227222092501
 
#reading
 
>> n = Time.at(time_ms / 1000.0).utc
=> Thu Nov 20 23:01:32 UTC 2008
>> t
=> Thu Nov 20 23:01:32 UTC 2008
 
# check we retained usec through the process
 
>> n.usec # note we lost microsecond precision, this is intended
=> 501000
>> t.usec
=> 501333

Reducing Ruby Time.now to millisecond precision:

time_float = Time.now.utc.to_f
time_msp = ("%0.3f" % time_float).to_f

That doesn’t have much to do with time, I just thought it was cool. Note that apparently doing precision reduction with strings is faster.

Javascript

// Reading an ms-since-epoch time:
js> date_from_above = new Date(1227222092501)
Fri Nov 21 2008 10:01:32 GMT+1100 (EST)
js> date_from_above.toUTCString()
Thu, 20 Nov 2008 23:01:32 GMT // note same as above 
 
// Make a new current date
js> t = new Date
Fri Nov 21 2008 10:28:12 GMT+1100 (EST)
 
// Output date object in milliseconds-since-epoch format
js> t.valueOf()
1227223692041

Review: Scaling Ruby by Envycasts / Gregg Pollack

Thursday, November 20th, 2008

So, there’s been some Internet Drama over the for-profit video release of a presentation from RubyConf 2008 by Gregg Pollack of Envycasts. Here are some reactions and comments collected from various sources over the last ~24 hours.

My own (highly negative) review:

Having watched the offending video yesterday, it is pretty easy to see why the guy can’t make money as a developer and so is trying to jump on the “screencast money train” a la Peepcode. I would question if it’s even worth downloading for free.

It’s nothing but a superficial high level tour of threads, messaging, and profiling, with some mildly interesting speed tips at the end which should really have been a single blog post. The “research” the guy did is evident all right – as in, it’s obvious he just looked it all up for the presentation and has never actually used any of this stuff. The “tips” he gives – when he gets around to giving any – are unremarkable at best and downright wrong at worst – he actually seems to recommend using RSS as an interprocess message queue, which is a really stupid idea.

He also includes a video overlay of himself giving the whole speech down the bottom of the screen, for that little “distracting touch of narcissm”. He pronounces “memoize” to rhyme with “turquoise”, and spends the first 3 minutes of a 40 minute paid presentation making an unfunny joke.

On the whole I think the guy might actually have done everyone a favour by making the video pay-only. The presentation is not even worth the 40 minutes it takes to watch, let alone $9, and the less people who think that RSS is a good way to implement distributed processing the better.

None of this excuses the presenter’s actions re. RubyConf but in this case, I think it will be a self-correcting problem. There is some expectation that someone demanding money for their training videos might at least have some experience working with the subject on which they present. I expect this video to destroy the clown’s professional reputation just as surely as his money-grubbing actions have destroyed his personal credibility.

I am hardly alone in this assessment. Let me quote several other people from a number of sources, anonymous because I have used them without permission. That said, if you have a problem with being quoted anonymously, let me know and I will remove your comment immediately.

Couldn’t even be bothered watching it for free:

Ugh…

Couldn’t get through it. The music was just too annoying. So I skimmed. Probably spent 4 minutes watching it.

Yes, all pretty superficial stuff and nothing really useful in there.

I don’t really like those tutorials which are just a tour of add-ons/plug-ins/gems etc written by other people (and as you know, Ruby people are all too ready to embrace other people’s code). I’m more interested in seeing interesting, original and innovative code.

Another prominent developer is unimpressed:

there is nothing in this talk which cannot be discovered in a couple of minutes using google, or by reading a couple of howtos

An IP sleuth points the finger …

The “speed tips” at the end are stolen directly from igvita.com, without attribution of course, and the ruby threading graphs look suspiciously similar too. This video is basically nothing but a visual presentation of the content from someone else’s blog – unpaid, of course. To pay for it would be to encourage this kind of blatant theft.

Tsk, tsk.

UPDATE: More:

I had a strange feeling of deja vu when I saw this talk. I felt like Id seen it before, somehow, and recently. later that day I logged on and was trying to find out where I’d read it before. Turns out the whole thing was lifted from Igvita.com, with minor changes. No credit given at all. If I was the guy from igvita.com, I would be pissed.

Storage space conscious:

Not only is this video not worth 40 minutes of my time or $9 of my money, it’s not even worth 200M of my hard disk space. Deleted.

A message of support:

I fully support Mr Polack’s actions in this matter. Anyone dumb enough to 1. buy this POS and 2. implement its suggestions (RSS? Are you fucking KIDDING me?) deserves to have their money stolen and their app grind to a messy halt. Polack is doing us all a favour, why so harsh?

A compelling argument there.

UPDATE 2:


Surprise!

Ruby 1.9 Incompatibility Gem Hall Of Shame

Thursday, November 20th, 2008

The following gems are shamefully incompatible with Ruby 1.9, which has now been available for testing for almost a year. These are just the ones which have personally affected me; there are bound to be MANY more.

Mongrel
FasterCSV
LibIDN
EventMachine – pure ruby works but is slow

Authors: please fix your gems!

More to come as I think of them. Suggestions welcome.

Simple validations in CouchRest::Model

Monday, November 17th, 2008

Since I’m having no joy on the CouchRest support forum or in mail to the author, here’s a monkeypatch to implement simple field validations in CouchRest::Model.

module CouchRest
 
  class Model
 
  class_inheritable_accessor :validation_fields
 
  def self.validate *fields
    self.validation_fields = fields.map {|f| f.to_s}
  end
 
  def valid?
    self.invalid_fields.blank?
  end
 
  def invalid_fields
    return [] unless self.validation_fields
    check = self.validation_fields.clone
    self.validation_fields.each do |c|
      check.delete_if {|x| x == c } if !self[c].blank?
    end
    return check
  end
 
  def save
    if new_record?
      create if self.valid?
    else
      update
    end
  end
 
  end # class Model
 
end # module CouchRest

Just throw a line like validate :field1, :field2, :field3 anywhere in the Model and it’ll refuse to save without those fields being present.

Stay tuned for the upcoming $9 screencast on use of this incredible new feature, development of which has taken minutes of my precious, precious time.