Kip

Accented memories

Written by Kip on Monday, August 30, 2010 at 8:49 pm (EDT)
Tagged as:

Over the weekend I went to my ten-year high school reunion, and I noticed something interesting when catching up with people. When I haven’t talked to someone in a long time, I forget that they speak with an accent. I guess it’s because I don’t remember their voice, and my brain fills it in with “accentless” Midwesterny broadcast English. Then they talk and I’m thinking “oh wow, you have a southern accent that I totally don’t remember1.” Which shouldn’t surprise me, most of these people spent most of their childhood in North Carolina.

1 Not that there’s anything wrong with that, I have one too
Kip

Just for my cousin Kaylor

Written by Kip on Saturday, August 28, 2010 at 1:46 am (EDT)
Tagged as:

I’ve been asked to post more pictures and video of Grayson, as it has been over a month since I last shared anything. The problem is that he’s still at the age where he doesn’t particularly do anything... besides eat, sleep, poop, and cry. But we tried. I’ve also posted eleven new photos of Grayson and Emma from the past month. And I also have two videos. The first is a rather lengthy video of Emma playing with Grayson, and the second is actually a video of me coming home from work to be greeted by Emma two days before Grayson was born.

No Comments | Add Comment
Kip

Mexican food

Written by Kip on Wednesday, August 25, 2010 at 10:41 pm (EDT)
Tagged as:

I have devised a very simple scale for evaluating Mexican restaurants. There are only two points of evaluation:

1. Are the fajitas sizzling when they are brought to your table? If so, the restaurant gets 25 points.

2. Are the tortillas there as soon as the fajitas are brought to the table? If so, the restaurant gets 75 points. (Score no points if you have to sit there and watch your fajitas sizzle out (assuming they were sizzling in the first place) waiting on the waiter to bring out the tortillas.)

For those of you who aren’t mathematically inclined, the only scores possible are 0, 25, 75, and 100.  0 and 25 are equivalent to an F-.  75 is a C. 100 is an A+.

No Comments | Add Comment
Kip

How to programmatically update your Twitter status using OAuth in PHP

Written by Kip on Thursday, August 12, 2010 at 10:22 pm (EDT)
Tagged as:

Earlier this week I was informed that Twitter will soon be ending its support for “BasicAuth” in the Twitter API, in favor of OAuth authentication. This affects me because I use the API to automatically post a “just blogged!” link to Twitter after every new blog post. Using BasicAuth, this was super simple:

1
2
3
4
5
6
7
8
9
10
11
function postStatus($status, $username, $password)
{
  $ch = curl_init();
  curl_setopt($ch, CURLOPT_URL, 'http://www.twitter.com/statuses/update.xml');
  curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 2);
  curl_setopt($ch, CURLOPT_POST, 1);
  curl_setopt($ch, CURLOPT_POSTFIELDS, 'status=' . urlencode($status));
  curl_setopt($ch, CURLOPT_USERPWD, $username . ':' . $password);
  
  return curl_exec($ch);
}

OAuth is a little more complicated, but I got it to work after about four or five hours of banging away it with the help of this article.1 Since I couldn’t find anywhere that this was described in detail, I decided I would document the whole process here on my blog. I don’t claim that this code is great, but it gets the job done. If you couldn’t care less about the workings of OAuth, and just want a give-me-teh-codez solution, then this is for you.

The first thing you have to do is register a new app. This sounds scary but it’s actually very easy. When filling out the form, note the following fields:

  • Application Name: this is what will show up under your tweets. In my case, I chose “vacantnebula.com” since all tweets from my app are announcements of new posts on this site.

  • Application Website: this is the URL that application name will link to.

  • Application Type: I’m not sure if it matters, but I chose “client”.

  • Default Access Type: you must select “read & write” to be able to update status (i.e. “write”).

After registering your application, you can view application details. Here you will see your consumer key and your consumer secret. You will need these keys later.

For a single-user application (which is what I’m describing), you will need to click on my access token. This will give you the access token (oauth_token) and access token secret (oauth_token_secret). Again, you will need these later.

And without further ado, here is the code:

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
<?php

class twitter
{
  //FILL IN THESE VALUES!!
  private $consumerKey      = '???';
  private $consumerSecret   = '???';
  private $oauthToken       = '???';
  private $oauthTokenSecret = '???';
  
  /**
   * Posts status to a twitter account. Returns true if successful, result
   * of curl_getinfo() if failure. 
   */ 
  function postStatus($status)
  {
    return $this->apiCall('https://api.twitter.com/1/statuses/update.xml', array('status'=>$status));
  }
  
  //separate function to leave the door open to other API calls...
  private function apiCall($url, $params)
  {
    $method = 'POST';
    
    //postString covers what will *actually* be posted
    $postString = $this->joinParams($params);
    
    //now adding to $params other OAuth properties...
    $params['oauth_nonce']            = sha1(time() . mt_rand());
    $params['oauth_timestamp']        = time();
    $params['oauth_signature_method'] = 'HMAC-SHA1';
    $params['oauth_version']          = '1.0';
    $params['oauth_consumer_key']     = $this->consumerKey;
    $params['oauth_token']            = $this->oauthToken;
    
    ksort($params); //IMPORTANT!
    $paramString = $this->joinParams($params);
    
    $signatureBaseString = $method . '&' . rawurlencode($url) . '&' . rawurlencode($paramString);
    $signatureKey = $this->consumerSecret . '&' . $this->oauthTokenSecret;
    $params['oauth_signature'] = base64_encode(hash_hmac('sha1', $signatureBaseString, $signatureKey, true));
    
    $authHeader = 'Authorization: OAuth realm=""';
    foreach($params as $key => $val)
      $authHeader .= ", $key=\"" . rawurlencode($val) . "\"";
    
    
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 2);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $postString);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); //required for HTTPS URL
    curl_setopt($ch, CURLOPT_HTTPHEADER, array($authHeader));
    
    $content = curl_exec($ch);
    $resultInfo = curl_getinfo($ch);
    curl_close($ch);
    
    if ($resultInfo['http_code'] == 200)
      return true;
    
    $resultInfo['content'] = $content;
    return $resultInfo;
  }
  
  //Join key/value pairs together in url string format, encoding values.
  private function joinParams($params)
  {
    $paramString = '';
    foreach($params as $key => $val)
    {
      if($paramString !== '')
        $paramString .= '&';
      $paramString .= $key . '=' . rawurlencode($val);
    }
    return $paramString;
  }
}

And I assume you know this, but to use the API it’d look like this:

1
2
$twitter = new twitter();
$result = $twitter->postStatus('hello world!');
1 I could have saved myself over an hour by realizing that I had to call rawurlencode rather than urlencode; the former encodes spaces as %20, whereas the latter encodes them as +.
Kip

Photostorm

Written by Kip on Saturday, August 7, 2010 at 6:24 pm (EDT)
Tagged as:

I have uploaded eighty-nine new photos from the first three weeks of Grayson’s life, in addition to the twenty-one I already told you about. All 110 photos can be found in the Grayson is born album.

No Comments
Kip

QuickReplace

Written by Kip on Sunday, August 1, 2010 at 4:55 pm (EDT)
Tagged as:

It’s amazing how often, as a programmer, I find myself pasting something into Notepad, then pressing Down, Home, Ctrl+V, over and over and over. (Or a variant, like Down/End/Ctrl+V, or End/Comma/Delete, or F3/Ctrl+V/Enter, etc.) It gets very tedious, and sometimes requires me to write an adhoc Perl script to do it. Yesterday I had the idea to finally just take a few hours to write a simple tool that I should have written years ago.

I give you: QuickReplace

It’s really simple. Just paste text into the first big text area, and then it will be filtered and displayed in the lower text area. There are three types of filters: text that is prepended or appended to each line; a simple search/replace (with \n and \t allowed), and a full-on regex substitution. And everything is updated as you type it, so you can see the effects of the filters as you enter them. (This really helps when you haven’t written a regex in a month or so.)

Everything is done in Javascript so the page is completely self-contained—you can view source and save a local copy if you wish. (It does require an internet connection, as it uses Google-hosted jQuery.) It’s also kind of a work in progress that might at any time be edited on the fly. Consider yourself warned.

No Comments | Add Comment
Kip

Grayson arrives

Written by Kip on Friday, July 16, 2010 at 6:00 pm (EDT)
Tagged as:

Yesterday morning Grayson Matthew Robinson—the handsome little boy shown below—came into our lives:

Stephanie holds Grayson for the first time

The last time I managed to write about Emma’s birth within a few hours, but this time around I guess I’m a little late. Mark my words, someday when Grayson gets rebellious and I ask him, “Son, why did you drop out of school and get all those tattoos and start a Metallica cover band? I mean come on, no one liked Metallica songs even when Metallica performed them, and even before Lars Ulrich had that gender-reassignment surgery. The only people who ever liked Metallica are in their eighties now. It’s just a poor decision.” And he’ll reply “I did it because I wanted to be first. I always got second best, Dad! Look at the day I was born, you couldn’t even be bothered to write a blog post about it! Emma got a blog post. Emma got to pierce her nose. Emma got to go to Harvard.” Then I’ll tell him, “Son, the only reason you didn’t get a blog post that day was because I was so busy falling in love with you.” Then he’ll say “eww gay.” That’s just how teenagers talk.1

All kidding aside, I actually was somewhat concerned that I would never be able to love him as much as I love Emma. But I quickly learned that your love for your children isn’t meted out in discrete quantities from a finite supply. I already feel like I have just as much love for Grayson as I do for Emma. It is very surreal. It seems to be multiplied somehow when I see how much Emma loves her brother too. The video below shows just that, with Emma holding Grayson for the first time.

It has surprised me just how much I can already tell that Grayson has a different personality than Emma. For one thing, he loves being held much more than Emma did. Even as a baby, being held didn’t do much to console Emma. She’s never been much of a snuggler (except when she’s sick). Grayson, on the other hand, is very content to be held. He’s also generally quieter than Emma was at this point, though it remains to be seen if that trend will continue. Emma I’m sure was a little extra fussy because (as you may recall) she was born with a black eye.

In any case, I hope you’ll join me in welcoming Grayson into the world. You can find pictures from his first two hours of life on this very website. I’m sure more will be coming later, but probably not until after we are back home from the hospital.

1 Alternate ending: “Hey, I told people you were born on Facebook!” “What’s Facebook?” “It was this website that everyone sent all their personal information to. It ultimately turned out to be owned by a Russian spy.”
No Comments | Add Comment
Kip

New and improved gradient generator. Now almost as good as Photoshop!

Written by Kip on Wednesday, July 7, 2010 at 10:00 pm (EDT)
Tagged as:

You may recall that the gradients I use on this site (in the background images on the photos pages, and in the header above each comment) are dynamically generated. I made some significant improvements to the code over the holiday weekend, which I will discuss here.

First, the minor things. I’ve added support for If-Modified-Since header, so that no cached image is retrieve and no content is returned to the browser if the user has the image cached. In doing this I learned that PHP’s filectime does not actually return the time the file was created; rather, it returns the last time it was changed. I don’t really understand the difference between this and filemtime (time the file was modified), as they both seem to always return the same time. Oh well.

Next, I added support for 3-character colors (like 000 for black and f00 for red). This just makes sense if you’re used to dealing with them in CSS.

And finally, the big improvement is an implementation of error diffusion.1 Why did I need to do this? In some very gradual gradients, you would see bands of individual colors. Eight bits per channel just isn’t quite enough.  For example, look at this gradient from 0x888888 to 0x444444:

Gradient from 0x888888 to 0x444444, with no dithering

You should be able to see vertical bands somewhere in that gradient. If not, it probably has to do with your monitor’s gamma settings or something. In any case, what I do to prevent this is keep a running sum of how far off each pixel is from its “true” color. When the absolute value of that sum is greater than 1, I adjust the color of the next pixel by one level in the appropriate direction to compensate. This gives a much smoother gradient:

Gradient from 0x888888 to 0x444444, with no dithering

This actually gives better results than Paint.NET and Paint Shop Pro. Here’s a close-up look at what that looks like, with pixel colors exaggerated:

Close-up of gradient with dithering

It’s good, though it’s not quite as good as what you get in Photoshop:

Close-up of gradient generated in Photoshop

Clearly the Photoshop guys are doing some kind of subpixel shading, since there are slightly colored pixels in a monochrome gradient. I guess they know what they’re doing.

Lastly, here is my PHP gradient generator source code, if you want to look under the covers and/or utilize the code.

1 Technically, it’s what I thought error diffusion was. But I read the Wikipedia article on error diffusion when writing this post, and now I’m pretty sure that what I did isn’t actually error diffusion. It’s kind of a similar process that I came up with all on my own.
No Comments | Add Comment
Kip

New photo album: beach trip 2010

Written by Kip on Monday, June 28, 2010 at 11:42 pm (EDT)
Tagged as:

I just put up a new photo album covering our 2010 beach trip. I tried my hand at a panoramic photo again, now that I know what I’m doing a little better. I got much better results than I did with my Hawai’i panoramics five years ago. The main thing I had to learn was to take one picture in auto mode, then put the camera in fully-manual mode (duplicating the settings from auto mode) before taking the pictures you intend to stitch. This keeps the camera from being darker when you’re looking at the sun and lighter when you’re looking away, so that everything can be stitched seamlessly. It seems obvious once you know it, but it didn’t occur to me for a while. On the software side, I used the completely free Microsoft Research Image Composite Editor to stitch the panoramic together, and it worked quite well (thanks for the tip, Jonah). Like magic, really.

Kip

While I’m at it: How to win at the Cracker Barrel peg game

Written by Kip on Wednesday, May 26, 2010 at 11:06 pm (EDT)
Tagged as:

In my last post I discussed the game of hangman, aided by an algorithmic analysis of the winningest words. A few months ago I did something similar with the peg game they have on the tables at Cracker Barrel.  The one where you have a triangle with 15 pegs, with one missing. You remove a peg by jumping over it. The goal is to leave only one peg remaining. I think I won the game the very first time I ever played it, and I don’t think I’ve won since then.

It occurred to me that the game would be easily solved with brute force, and after an hour or two of coding I had done so. However, I never went much farther than that. I had hoped to look for patterns or simple rules that lead to a victory, but never really got very far. But I decided to post what I have here just for the sake of doing so.

         0
       1   2
     3   4   5
   6   7   8   9
10  11  12  13  14

Given the above peg positions, there are four unique starting configurations: you can start with peg 0, 1, 3, or 4 removed. Any other position is a mirror and/or rotation of those four. So I looked at which starting positions were the most likely to win.

Peg 0: 29,760 ways to win of   568,630 games (5.23%)
Peg 1: 14,880 ways to win of   294,543 games (5.05%)
Peg 3: 85,258 ways to win of 1,149,568 games (7.42%)
Peg 4:  1,550 ways to win of   137,846 games (1.12%)

So the moral of the story is: start with a middle edge peg removed, not the traditional configuration of top peg removed. Beyond that, I got nuthin.

No Comments
RSS feeds: Kip's - Stephanie's - Both
Admin