He stood in the shadows, watching, while cold rain dripped from the metal staircase to spot his scuffed leather jacket.

If you ever decide to design and build a house, think very carefully before deciding not to have a crawlspace or an attic and with minimal covered space between floors. Electrical and plumbing take a lot longer when you have to continually drill holes in studs.

Gregory is definitely his father’s son and his grandfather’s grandson. I’m sitting here on the bed with my laptop, doing a bit more work before dinner. Gregory climbed up next to me and sat down. At first he was talking to himself and making various noises - then I realized that it had gotten quiet all of a sudden.

I looked over and he was asleep where he sat - leaning back against our headboard.

See, we Vanderpol males have this innate ability to fall asleep at the drop of a hat, in any setting. It can be at a party, in the middle of a movie or even (if we’re really, really tired) at the table. If I lay in bed and it takes me more than ten minutes to fall asleep, it feels like it’s taking forever. (This used to annoy my wonderful wife, but she’s grown resigned accustomed to it.)

I’m glad you’re a part of our family, Gregory, and you’re keeping the torch alive (even if just in your dreams).

“Whoa, dude, where’d you get the idea to make a bong out of that?”

“Hey lummox, it ain’t done wit a knife!”

The old man stumbled across the moonlit snowfield, straining to hear any sounds of pursuit.

I saw Archive Flagged Items from NetNewsWire into Yojimbo (via) and found it a really neat tool. I've started using it to keep a more permanent record of interesting new articles.

I have lots of news articles flagged and I've had the import crash on me before for various reasons which has resulted in some duplicate web archives being created. The reason for the duplicates is usually because there was a redirect to the actual article that Yojimbo followed, so the URL in NetNewsWire doesn't match the Yojimbo URL and checking for existing items on load doesn't work.

This was a great opportunity for me to explore RubyOSA and continue learning Ruby so I wrote a script to detect duplicate web archives based on name and mark them with a "Duplicate" label.

RUBY:
  1. #!/usr/local/bin/ruby
  2.  
  3. require 'rubygems'
  4. require 'rbosa'
  5.  
  6. yojimbo = OSA.app('Yojimbo')
  7.  
  8. seen = Hash.new(false)
  9.  
  10. # Duplicate label details
  11. duplicateLabelName = 'Duplicate'
  12. # An almost painful red
  13. duplicateLabelColor = [65535, 1536, 4628]
  14. duplicateLabel = nil
  15.  
  16. # See if we already have a label named 'Duplicate' and save it
  17. yojimbo.labels.map  { |l| l.name == duplicateLabelName && duplicateLabel = l }
  18.  
  19. # Make a label if we don't have it already
  20. if (duplicateLabel.nil?)
  21.   duplicateLabel = yojimbo.make(OSA::Yojimbo::Label,
  22.                                 nil,
  23.                                 :color => duplicateLabelColor,
  24.                                 :name => duplicateLabelName)
  25. end
  26.  
  27. yojimbo.web_archive_items.each do |f|
  28.   if (seen.include?(f.name))
  29.     puts "Found a duplicate: #{f.name}"
  30.     f.label= duplicateLabel
  31.     seen[f.name].label= duplicateLabel
  32.   else
  33.     seen[f.name] = f
  34.   end
  35. end

Emma came up and was further into her current Magic Treehouse book than expected.

Amber: You skipped chapter 1?
Emma (slightly exasperated): Chapter 1's are always the same!
Amber: What is chapter 1 like?
Emma: Being at home then going into the tree house.

I'd like to start posting code on my blog so I'm testing out a syntax highlighter plugin. This post will likely go through several iterations as I see what it can do and how to do it.

Here's some ruby:

RUBY:
  1. def addPages(urls)
  2.     return false unless urls
  3.     urls.each{ |u| @queue <<PageFactory.newPage(u) }
  4.     @queue.uniq! # Get rid of dupes.
  5. end

Here's some Perl:

PERL:
  1. my @text = ( 'here', 'are', 'some', 'words' );
  2. my $offset = 0;
  3. print join(' ', map { choppedCase($_) } @text );
  4.  
  5. # Convert a string to "ChOpPeD cAsE"
  6. sub choppedCase
  7. {
  8.     my $word = shift;
  9.     my @chars = split('', $word);
  10.     my $char_count = scalar(@chars);
  11.  
  12.  
  13.     for (my $i = $offset; $i <$char_count; $i+=2)
  14.     {
  15.         $chars[$i] = uc($chars[$i]);
  16.     }
  17.  
  18.     # Track odd length words so we constantly alternate in a string
  19.     if ($char_count % 2)
  20.     {
  21.         $offset = $offset == 0 ? 1 : 0;
  22.     }
  23.     return join('', @chars);
  24. }

Here's some PHP

PHP:
  1. // Pattern to match the directory path that a file is in
  2. $dir_pattern = "@(/.*)/[^/]*$@";
  3.  
  4. // Take a path that's (possibly) relative to the directory that the script is executing in
  5. // and convert it to an absolute path.
  6. function absolutize($path)
  7. {
  8.     global $dir_pattern;
  9.  
  10.     // Only operate on paths that are relative
  11.     if (substr($path, 0, 1) == '.' && preg_match($dir_pattern, $_SERVER['PHP_SELF'], $matches))
  12.         $path = implode('', array($matches[1], '/', $path));
  13.  
  14.     $path_bits = explode('/', $path);
  15.     $elms = array();
  16.     foreach ($path_bits as $bit)
  17.     {
  18.         if ($bit == '' || $bit == '.')
  19.             continue;
  20.         if ($bit == '..') {
  21.             array_pop($elms);
  22.             continue;
  23.         }
  24.         $elms[]= $bit;
  25.     }
  26.     // Push an empty string on top so that we get a leading / when we implode
  27.     array_unshift($elms, '');
  28.     return implode('/', $elms);
  29. }

I just realized that I've coded in all three of these languages this week - plus JavaScript (can't find a good sample to post).

Update
JavaScript

JAVASCRIPT:
  1. // Add commas to a long number to make it more readable.
  2. // Currently only supports whole numbers.
  3. var addCommas = function(aNumber)
  4. {
  5.   // Convert our number to an array and reverse it so that
  6.   // we can easily work from most significant digits down
  7.   // to least significant
  8.   var bitsR = (aNumber.toString().split('')).reverse();
  9.   for (var i = bitsR.length - 1; i>2; i--)
  10.     if (i % 3 == 0)
  11.       bitsR.splice(i, 0, ',');
  12.   // Return our array with commas added back to the proper order
  13.   // for display on the screen.
  14.   return bitsR.reverse().join('');
  15. };

There's just something about changing your own oil, filter and belts that makes one feel like a "real man"...