astradele

Archive for February, 2008

On business in Chicago

Posted by GJ on February 29, 2008

I’ll be in Chicago on business March 10th to 12th. Recommendations on places to see, food to eat are welcome. :)

So far, I’ve got the Shed Aquarium and deep dish pizzas. Surely there’s more to do than that in the Windy City though…

Posted in everyday | Tagged: | No Comments »

Restoration of TV

Posted by GJ on February 28, 2008

After six years without a TV (a projector and DVD player sufficed), cable TV has snaked its way back into my home. Thankfully, the installation process was hassle free, although I had to make some temporary hacks with cabling and power bars.

First impressions:

  • 28 channels doesn’t really offer that much palatable variety at any given time.
  • Not being able to skip intros or credits is an irritation.
  • I’m bored during commercials.

Having lived the life of on-demand media (barring a little bit of forethought to procure the DVDs ahead of time), the lack of constant, interesting content is a bit annoying. I may have to upgrade… and so it begins!

Posted in everyday | No Comments »

Time to return to Starbucks?

Posted by GJ on February 28, 2008

I used to drink Starbucks exclusively, and still do from time to time, but on a regular basis I drink Seattle’s Best Coffee, a brewed coffee brand (ironically bought by Starbucks a few years ago, but whatever…).

Perhaps it’s time to visit Starbucks regularly again?

I’m a reporter, dammit, so after reading about today’s all-hands training sessions at all Starbucks stores I walked over to the store at 333 Market in San Francisco’s Financial District and asked my barista to explain, step by step, exactly what’s new.

  1. Richer espresso mix. Starbucks espresso machines have been recalibrated to mix a stronger dose. It’s not as powerful as Peet’s, but it’s more in that direction. My daily triple-shot tastes a lot thicker.
  2. Shot glasses. Instead of pouring directly into your cup, all shots are now dispensed into clear glass shot glasses. The barista must visually approve the shot before pouring it into a cup. This not only checks the mix, it prevents stale, crema-free shots from being served after lying around too long.
  3. Smaller steamer pitchers. No more giant tub-o-foam, but rather smaller batches of steamed milk and foam more tailored and fresh to each order.

Could I taste the difference? Instantly.

http://valleywag.com/361607/whats-new-at-starbucks-3-changes

Posted in everyday | No Comments »

A maze-like flash game: Portal

Posted by GJ on February 17, 2008

If you like Prince of Persia and other puzzle “maze-like” games, you might enjoy Portal: The Flash Version, a third-party derivation of the original game from Valve, Portal.

It’s creative, provides a few hours of mental challenge, and avoids ennui that might ensue from too many levels.

Posted in everyday | No Comments »

Badgering the interviewer is a bad idea

Posted by GJ on February 14, 2008

I don’t interview people often, but when I do, I’m often reminded why I find it such a depressing activity. Candidates are rarely as good as they look on paper, never mind as good as they think they are.

I grind through a stack of resumes, propping my eyelids up with toothpicks, to pick the a few resumes that are sufficiently unusual and positive that some hope wells up.

And then, they’re usually dashed when I meet candidates in person, occasionally in a stunning proof of resume exaggeration. Recently, I had someone dig themselves pretty deep, before we even had the phone interview. The sequence is roughly as follows:

  1. I send emails to the candidates, asking for availability to have an initial phone call in the next two weeks.
  2. Couple days later, I receive a reply that is reasonably coherent, except what appears to be a typo when describing the time of availability. In email, I ask for clarification and suggest a time.
  3. Few hours later, candidate calls me, sounding confused and flustered. I explain I’m trying to book time slots for everyone on the same day. Candidate explains incoherently about his workplace, but I divine that some “sneaking out” is needed for the phone call. Okay, I suggest before work, e.g. 8 AM. Candidate is briefly stunned into confused mutterings, but eventually comes around and agrees to my original mid-day proposal, asserting strongly that the call has to be right on time.
  4. I send candidates meeting requests with time slots, teleconference number, passcode, and copy of their resume that I’m assuming is the latest.
  5. Immediately after, I send emails letting candidates know that they should have received a meeting request. After all, you never know when a meeting request or attachment might get filtered by an overzealous email server.
  6. Several minutes later, the candidate calls me again and expresses confusion over my email.
    • I explain there should have been two emails, and the candidate confirms there were. However, the other one had some “strange numbers”.
    • I realize… “You’ve never used a teleconference, before?”. Nope. “OK, well you just call the teleconference number, and when it asks you for the conference ID, punch in the other numbers.”
    • Candidate expresses some distress, and finally ends with,”You have the number, can’t you just call me like normal?!”
    • I’m tempted to find an “unexpected scheduling conflict” with the candidate’s time slot. “Fine. The number on the resume? OK, bye.”
  7. Mental note: on interview day, try to forget that any of this happened.

Moral of the story? Remove your phone number from your email signature when emailing interview candidates. Thank goodness it didn’t have my cell phone number.

[Update: Candidate emails me at 12:30am, interview day, and asks me to move the booking to next week, as a conflict with a "pre-booked health appointment" was realized "a few minutes ago". Starting to get a little displeased...]

Posted in everyday | No Comments »

Windows batch script to find most recently modified file

Posted by GJ on February 14, 2008

I needed to find and operate on the most recently modified file in a directory, but from the Windows XP command line rather than a Linux shell script. Knowing how unexpectedly powerful (but so very arbitrary and convoluted!) the Windows command line can be, I figured it was possible with a bit of help file reading.

And lo, it was good:

 @echo off  :: This temp batch file is used to execute a subroutine. set TMP_RECENT_BAT=%TEMP%\tmp_recent.bat  :: Reset the "output" env var in case something goes wrong set MOST_RECENT_FILE=  :: Create the temp batch file. :: :: This subroutine lists all files in the current directory, :: sorts it in descending last-modified-time order, :: and strips out the topmost file (i.e. most recently modified). :: :: Directories, system files, and hidden files are not considered. :: :: A side-effect of this routine is that the filename has a prefix of "[1]" echo @echo off > %TMP_RECENT_BAT% echo dir /o-d /a-d-h-s /b %1 ^| find ^"^" /v /n ^| find ^"[1]^" >> %TMP_RECENT_BAT%  :: Execute the subroutine above, and grab the output in an environment var. :: We are assuming the subroutine above correctly returns only one line. for /f "usebackq delims=="%%i in (`%TMP_RECENT_BAT%`) do set TMP_RECENT=%%i  :: Strip the first 3 chars of the return value of the subroutine, i.e. "[1]" :: :: If the subroutine didn't return a good value, don't try to set the var, :: b/c we'll get a string like "~3" instead of a good value. if "%TMP_RECENT%" == "" goto skip  set MOST_RECENT_FILE=%TMP_RECENT:~3%  :: This line not really necessary, since script that use this can just access :: the environment variable named "MOST_RECENT_FILE". echo %MOST_RECENT_FILE%  :skip set TMP_RECENT=  :: Delete the temp file del %TMP_RECENT_BAT% 

Posted in techie | No Comments »

10 out of 10 bots say I’m boring

Posted by GJ on February 7, 2008

I visit my blog this morning for some admiration and/or self-critcism, and I discovered that I had votes for my blog entries! Yay, people read and respond to my blog! Except… they all voted “No”, that the entries were not interesting or helpful… for several entries.
BotsVoteNo

It turns out the voting plugin I made for my blog had a major oversight: search engine spiders click on them, too. Oops. And for some reason I can’t fathom, they all prefer the “No” vote.

So there you have it, even software thinks my blog is dull. Normally, I’m a fan of listening to people express their opinion, especially if it runs contrary to mine, but I think this time I’ll have to do something about it. :)

Posted in techie | No Comments »

An evening of databases

Posted by GJ on February 6, 2008

So after getting home and logging on to an open evening, my mind turns towards selecting a database (a software component) for my hobby software project. Yes, this is really how I spend some of my evenings.

I spent several hours on the activity: reading database comparisons, discussions, and the manuals of some of a couple of the lesser known ones (Firebird and Postgresql) that explained how they worked internally. It was pretty satisfying, in a home-cooked meal way.

Reflecting upon it, I realized that I had revisited my tech roots by both:

  1. Spending an enjoyable evening reading about how databases work.
  2. Selecting databases that I’d only “heard” about, rather than staying with the mainstream.

For at least a night, I really missed the technical challenge of building software. Processes and politics are important, too, depending on the organization, but it’s not as satisfying as making something that works.

Posted in everyday | No Comments »

Hacking around in Python for Pyblosxom plugins

Posted by GJ on February 6, 2008

I decided to remove the calendar from my blog’s sidebar, and replace it with a “recent posts” list. I realized that it’s not very helpful, since readers aren’t so much interested in when I posted as what I posted about.

There was no pyblosxom plugin to do this, so I rolled up my sleeves and learned some more Python, referring to the Pyblosxom API documentation along the way. The resultant plugin is simple, although I had to fill in the gaps in the API docs through trial and error.

The code I wrote is below. Note that I hardcoded the flavour type (1024px), but I believe there’s an value in the entry dictionary I could have gotten it from.

 from Pyblosxom import tools from Pyblosxom import pyblosxom import time, re 

 def cb_prepare(args):   request = args["request"]   data = request.getData()   entry_list = data["entry_list"]   config = request.getConfiguration()   root = config["datadir"]   s=""     txt_dict = {}   for txt in tools.Walk(request, root, pattern=re.compile('.*\.txt$')):     timetuple = tools.filestat(request, txt)     txt_dict[time.strftime("%y%m%d%H%M",timetuple)]=txt    keys = txt_dict.keys()   keys.sort()   keys.reverse()   url_list = []   for k in keys:     path = re.sub(root, "", re.sub(".txt$", "", txt_dict[k]))     title = pyblosxom.blosxom_entry_parser(txt_dict[k],request)['title']     url_list.append("<li><a href='" + path + ".1024px'>" + title + "</a>")    url_list = [url_list[x] for x in range(0,19)]   for url in url_list:     s += url    data['recentPosts'] = s 

Around the same time, I had the idea of adding a “voting” mechanism to allow people who don’t have anything to say (comment) to still indicate which entries are interesting. I figured an easy approach would be to add voting buttons that triggered an AJAX-style HTTP request to special URLs, which would show up in the Apache logs and could later be parsed out. Being unfamiliar with Python, I could just focus on reading data in the plugin and save on code to tally votes (I was feeling lazy at the time).

Shortly thereafter, I got a blog comment:

Name: Gunfus
Entry URL: http://blog.astradele.com/life/Why-blog-.2008-02-01-14-50

I don’t think your yes/no is working to well. If you click it it dissapears (this is fine), if you reload the page it shows again (this is aceptable), once you reload, the counter is at 0/0 (this is expected?)

I thought I tested it properly, but… So I got into it again and wrote the solution completely in Python. At least I’m getting more familiar with the language. The solution still uses a custom URL format that don’t resolve to an actual page, but it’s the Pyblosxom plugin that notes the URI, checks to see if it’s similiar to an existing entry, creates files to track the IP addresses of votes on a per entry basis, and generates tallies.

I considered trying to devise a way to auto-refresh the tally instead of just hiding the voting “bar”, but upon consideration I wasn’t up to the effort it would take on the Python side.

The code:

 import sys, StringIO, os, os.path, re 

 def verify_installation(request):     return 1  def include(req, filename):     """     This takes in one argument--a filename.  It opens the file, reads     in the contents, and returns them as the value of this variable.      (It actually takes in two, but one of them is provided by     PyBlosxom.)     """     if not filename.startswith(os.sep):         data = req.getData()         basedir = data["root_datadir"]         if data.has_key("bl_type") and data["bl_type"] == "file":             basedir = os.path.dirname(basedir)          filename = os.path.normpath(basedir + os.sep + filename)      try:         f = open(filename, "r")         lines = "".join(f.readlines())         f.close()         return eval_python_blocks(req, lines)     except:         return ""  def cb_logrequest(args):   import os, time   http = args['request'].getHttp()   config = args['request'].getConfiguration()   request_uri = http['REQUEST_URI']   remote_addr = http['REMOTE_ADDR']   entry_name = re.compile("^/vote_(yes|no)(/.*)\..*$").sub(r"\2",request_uri)   if (os.path.exists(config['datadir'] + entry_name + ".txt")):     try:       os.makedirs(config['datadir'] +           "/votes" + re.compile("^(.*)/.*$").sub(r"\1", entry_name))     except:       pass      if (re.compile("^/vote_yes").match(request_uri)):       vote_file=config['datadir'] + "/votes" + entry_name + ".yes"     else:       vote_file=config['datadir'] + "/votes" + entry_name + ".no"      is_dupe=False     if (os.path.exists(vote_file)):       f=open(vote_file, "r")       for line in f:         is_dupe = is_dupe or re.compile(remote_addr).match(line)       f.close()      if (not is_dupe):       f=open(vote_file, "a")       f.write(remote_addr + "\n")       f.close()  def cb_story(args):   """   """   entry = args["entry"]   request = args["request"]   config = request.getConfiguration()   http = request.getHttp()    entry_filename = entry.getId()   yes_votes_file = re.compile(".txt$").sub(".yes",re.compile("^" + config['datadir']).sub(config['datadir'] + "/votes",entry_filename))   no_votes_file = re.compile(".txt$").sub(".no",re.compile("^" + config['datadir']).sub(config['datadir'] + "/votes",entry_filename))    entry['vote_yes_url'] = "/vote_yes/" + entry['file_path'] + "." + entry['flavour']   entry['vote_no_url'] = "/vote_no/" + entry['file_path'] + "." + entry['flavour']    request_uri = request.getHttp()["REQUEST_URI"]   remote_addr = request.getHttp()["REMOTE_ADDR"]    count=0   if (os.path.exists(yes_votes_file)):     f = open(yes_votes_file, "r")     for line in f:       count += 1     f.close()   entry["yes_votes_count"]=str(count)    count=0   if (os.path.exists(no_votes_file)):     f = open(no_votes_file, "r")     for line in f:       count += 1     f.close()   entry["no_votes_count"]=str(count) 

Posted in techie | No Comments »

Incoming: Head First PMP

Posted by GJ on February 4, 2008

After reading about the joys of international food, it’s time to turn to less flavourful material.

Head First PMP
From Amazon:

Head First PMP offers 100% coverage of The PMBOK(R) Guide principles and certification objectives in a way that’s engaging, not tedious. This book helps you prepare for the PMP certification exam with a unique method that goes beyond answers to specific questions and makes you think about the big picture of project management. By putting project management concepts into context, you will be able to understand, remember, and apply them-not just on the exam, but also on the job.

I have no interest in being a project manager, but as a software architect I butt heads with them on a frequent enough occasion that it’s worth making the effort to understand where they’re coming from. I’ve also heard some good things about the Head First series of books - I picked up their version of Design Patterns as well - and wanted to see whether their “engaging” method was better than other books I’ve read.

I’m about 100 pages in so far, and it’s certainly leisurely reading. With the amount of diagrams and redundancy, one can go pretty fast.

Posted in techie | Tagged: | No Comments »