Hai’s Blog

August 20, 2009

Replacing My Laptop’s Hard Drive

Filed under: OSX, Tips & Tricks — Hai @ 7:39 pm

I purchased my MacBook in the second half of 2007 with a relatively large hard drive of 60GB. Remember, 60GB is sizable in 2007. I then replaced it with a 160GB drive and even that drive now is full. My hard drive du jour is a 500BG, which should last me a couple of months while waiting for the 5TB version :-)

Backing Up

Last night, my hard drive arrived from NewEgg and I started my upgrade process. The first order of business was to take inventory of the applications I currently have in the system and kept track of this list using a plain text file. I am not going into details on the how part–that’s another topics for later. Next, I went through my list and hunt down the product key (AKA license code) for each application. Since I use 1Password to keep track of my lincense codes, the process was fairly painless.

Next, I fired up iBackup and backed up some application settings and data I would like to carry over to the new system: Address Book, iCal, keychains, and mail. I used one of my external hard drive as backup destination. I also used iBackup to copy over the one application which the installation CD was damaged: Toast Titanium 7. Yes, that ancient version is still working with Leopard and I see no need to upgrade.

Before I turned off the laptop to perform surgery on it, I make a final back up using SuperDuper!. Upon finishing backing up, I restarted the laptop and booted from the backup drive to verify it was bootable and made a few checks to see if SuperDuper! correctly backed my files. Finally, I turned off the laptop and replace the hard drive. Again, I am not going into details of how I did it, there are plenty of help if you search the internet for it.

OS Installation

Once the new hard drive is in place, I used the Leopard installation disc to install Leopard onto the new hard drive. After installation, I immediately ran Software Update to bring my system up to date. This process required one reboot.

Restoring Mail, Address, and Other System Data

Right after the OS installation, I downloaded the latest version of iBackup and restored the data which I backed up earlier. To test how well iBackup performed, I fired up the Mail application and saw that all of my mail settings and messages were still there. I am glad that I donated to iBackup. This software is a must-have.

Another must-have I installed right away was 1Password since it stored all of my software license keys. Finally, I scanned through my application list and classify them as followed:

  • Must have. These are the applications I would need. Examples in this category includes 1Password, Aperture, Backblaze, and SuperDuper!
  • Unwanted. These are applications that either I don’t like or don’t need. For example, I don’t need the EPSON scan application because the built-in Image Capture application can scan just as well.
  • On Demand. These are applications which I rarely need and I will install them when the need arise. Applications such as the Logitech Harmony Remote Software, Garmin and RegExhibit fall into this category.

I am now in the process of installing my must-have applications, one at a time and verifying that they are working correctly. This process should take a day or two to complete.

Conclusion

Replacing a hard drive is not hard, but it does take some planning to reduce the risk of losing data. Imagine having to re-type 250 contacts because you forgot to make backup! I hope you enjoy this post and post any comment, correction, or questions to the blog.

August 7, 2009

Use the Right Data Type for the Job

Filed under: Programming, Tcl — Hai @ 6:33 am

The Problem

In one of my Tcl programming projects, I needed to keep track of a list of child process IDs: When I spawn a new process, I added that process’s ID to a list. When the process finished, I removed its ID from the list.

The Initial Solution

Due to the way I phrased my problem, I naturally chose to use Tcl’s list to keep track of the IDs. Thus, to add an ID to the list, I used the following command:

	lappend idList $id

That was easy enough. However, removing and ID from the list requires more works because Tcl does not have an remove command. I ended up with something like this:

	set index [lsearch -exact $idList $id]
	if {$index != -1} {
		set idList [lreplace $idList $index $index]
	}

Months after I wrote that code, I looked back at my work and did not like it a bit. The code was hard to understand and error prone. There must be a better way.

The Second Solution

While browing the help file for Tcllib, I stumbled upon a package called struct::set and inspiration struck me. Yes, instead of using a list to keep track of my IDs, I could use a set data structure to greatly simplify my task. To add an ID to the “list”, I would issue the following command:

	struct::set include idList $id

Likewise, to remove an ID from the list, I would issue the following command:

	struct::set exclude idList $id

That was much better. By using the right data type, not only I simplified my tasks, enhanced readability, but also reduced chance of making error. It is time to go back to school and learn about data structure!

July 24, 2009

Adding [Incr Tcl] support to Notepadd++

Filed under: Programming, Tcl — Hai @ 8:59 pm

The Problem

Notepad++ does not support [Incr Tcl]: it does not apply syntax highlighting to *.itcl files.

The Solution

We can tell Notepad++ to treat *.itcl file as Tcl. This is not a perfect solution, but it is very quick to implement. Here are the steps:

  1. Edit the file langs.xml from the Notepad++ dir
  2. Search for ext=”tcl” and replace with ext=”tcl itcl”

That’s all! You can now enjoy syntax highlighting when editing you .itcl file. I am sure there are more throughout solutions, but this one is quick and easy–give it a try.

May 28, 2009

Use lassign to Assign Command-Line Parameters to Variables

Filed under: Programming, Tcl — Hai @ 5:52 pm

The Problem

You need to assign command-line parameters to variables. For example:

    set [lindex $argv 0] server
    set [lindex $argv 1] port
    set [lindex $argv 2] user
    set [lindex $argv 3] password

The problem with this approach is it takes lots of typing. Cut and paste can help reducing some of it, but it is error prone for the user might forget to edit the index numbers after pasting. When the number of command-line parameters increase, so is the chance for making error.

The Solution

One way to deal with assigning command-line parameters to variables is to use the lassign command from the Tclx package:

    package require Tclx
    lassign $argv server port user password

Not only this approach is cleaner and less error prone, it is also easier to understand. The user must make sure argv has enough elements to assign to the variables. If there is more variables than the number of command-line parameters, then the extra variables will be assigned the empty value {}:

    % lassign {1 2} a b c
    % puts "a=$a, b=$b, c=$c"
    a=1, b=2, c=

If there are more command-line parameters than variables, then lassign will return a list of unassigned parameters:

    % lassign {1 2 3 4 5} a b c
    4 5

Conclusion

The lassign command eases the task of assigning command-line parameters to variables. The user must exercise care to ensure the number of parameters matches the number of variables. Lassign can also be used for any list-variable assignment task the user can think of. Please take a look at the document for more usage and behavior notes.

May 14, 2009

Tcl: Use commandloop to Provide Interactive Access to Your Procedures

Filed under: Programming, Tcl — Hai @ 3:16 am

When I wrote text base programs in high-level programming languages, I often need to create a simple menu, get the user’s choice, then dispatch the appropriate procedure. The dispatch code often include lengthy swich (case) statement:

    switch (choice) {
	case 'a':
		function_a();
		break;
	case 'b':
		function_b();
		break;
	}
    ...

This design pattern was fine if the menu is relatively short. As the menu grows, adding a choice to the menu means: 1) Add lines to the menu, 2) update the switch statement, and 3) write another function to handle the new choice.

This design pattern bears several problems:

  1. Adding an additional choice to the menu requires a lot of works as illustrated
  2. Programmer must take care to keep the menu and the switch statement in sync.
  3. As the menu grows, the switch statement can get very long

Fortunately, Tcl offers an easy remedy to this problem: commandloop. I wrote about commandloop before as my way to setup a break point for debugging purpose. Commandloop can do more than that. In this case, I can commandloop to provide dispatch to my procedures. Consider the following simple script:

	package require Tclx

	set stack {}

	proc stack {} { set ::stack }
	proc push {item} { lappend ::stack $item }
	proc pop  {}     {
		set item [lindex $::stack end]
		set ::stack [lreplace $::stack end end]
		return $item
	}

	commandloop

This script simulates a stack; it provides three commands (procedures): stack to display the contents of the stack and the self-explanatory push and pop. The script’s main body consists of a single commandloop command. So how does this works?

The commandloop command allow the users to interact with the script, including the ability to call the script’s commands. Let’s take a look at an interactive session:

    $ ./commandloop1.tcl
    %stack
    %push 5
    5
    %push 7
    5 7
    %push -3
    5 7 -3
    %stack
    5 7 -3
    %pop
    -3
    %stack
    5 7
    %set x 0
    %push $x
    5 7 0
    %puts "Stack contents: [stack]"
    Stack contents: 5 7 0
    %exit
    $

After launching the script, we arrive at the ‘%’ prompt. From there, we can issue the script’s commands such as stack, push, and pop. Not only that, we can also set additional variables (such as x). We can all issue other commands such as puts. In short, the commandloop command opens up an interpreter to interact with the script. Finally, the exit command (or Ctrl-D in Linux, Ctrl-Z in Windows) exits the command loop and ends the script.

Commandloop comes with some handy optional flags. The first is the -endcommand flag. This flag specifies a command (or procedure) to execute after commandloop terminates. Note that after commandloop terminates, the script’s execution will stop, ignoring any command that follows. If you want to execute a command after the commandloop terminates, use this flag.

Another flag of interest is the -prompt1 flag. This flag allows the users to customize the prompt if they don’t like the default one. These are the two flags I use most often. For information regarding other flags, you can look up information for commandloop in the Tclx package.

May 12, 2009

Debugging Tcl Script with commandloop

Filed under: Programming, Tcl — Hai @ 6:32 am

Besides using puts to debug my Tcl script, I also like this technique, which set up a break point within my script. There are times when I cannot use that technique, I use the commandloop command to create an impromptu break point.

Before we get started, let me clarify that the purpose of commandloop is not for debugging, but that is what I am using it for. Consider the following block of code:

    # Given a number x, double it
    proc double {x} {
        upvar 1 x xValue
        set xValue [expr {$xValue * 2}]
    }

Those who knows Tcl can spot the bug right away, but for argument sake, let’s pretend that the bug was well hidden and I need to set a break point to debug the procedure double. I can accomplish this goal using the commandloop command:

    package require Tclx

    # Given a number x, double it
    proc double {x} {
        upvar 1 x xValue
        commandloop
        set xValue [expr {$xValue * 2}]
    }

During execution, commandloop will halt the code and display the ‘%’ prompt. At this point, I can execute any Tcl command to debug the problem:

    $ tclsh db.tcl
    %set x
    n
    %set xValue
    Error: can't read "xValue": no such variable
    %exit

    $

In the capture above, the script stopped just after the upvar line and displayed the ‘%’ prompt. I then issue some Tcl commands to debug and finally was able to pinpoint the problem–the upvar line should have been:

    upvar 1 $x xValue

One thing to note, unlike the aforementioned solution, commandloop has one disadvantage: upon typing exit, the script will exit right away, ignoring the rest of the script. However, in a crunch, this command provides a quick way to set break point to debug my script.

Use for_file to Ease Line-by-Line Processing

Filed under: Programming, Tcl — Hai @ 5:52 am

In my job, I often need to open a file, read and process each line until the end. In Tcl, that pattern can be translated as:

	set infile [open file.txt r]
	while {[gets $infile line] >= 0} {
		# do something with $line...
	}
	close $infile

Simple? Yes, but I can still see room for improvements. The Tclx package has a for_file command which can simplify the coding quite a bit:

	package require Tclx
	for_file line file.txt {
		# do something with $line...
	}

Not only I don’t have to worry about openning and closing the file, I don’t have to deal with the lengthy while/gets command, which can be error-prone. Finally, the second construct is much cleaner and easier to understand.

After learning about the for_file command, I discovered that the fileutil package also has a similar command:

	package require fileutil
	fileutil::foreachLine line file.txt {
		# do something with $line...
	}

It seems either one of them will get the job done. Personally, I prefer the for_file command because it is shorter. If you are aware of any differences between the two, please comment.

May 8, 2009

Display Weather from Command Line

Filed under: Tcl, Unix — Hai @ 10:19 pm

Since I work on Linux/OSX command line all day, I prefer to get my information such as stock quote or weather via command line. Here is a script to do that.

A couple of notes:

  1. I use curl instead of the TclCurl package because my system does not come with TclCurl
  2. The script employs Google Weather API to retrieve weather data. The rest of the script deals with converting that data from XML format to human-readable format.
  3. I use this script as part of my geek tool output.

Here is a sample output of the script:

$ weather
Seattle, WA 98121 2009-05-08 22:15:09 +0000
  Condition      : Overcast
  Temperature (F): 61
  Humidity       : 47%
  Wind           : NE at 2 mph

  Fri 63 45 Mostly Sunny
  Sat 68 47 Mostly Sunny
  Sun 67 49 Mostly Sunny
  Mon 61 47 Chance of Showers 

Bothell, WA 98012 2009-05-08 22:18:51 +0000
  Condition      : Cloudy
  Temperature (F): 55
  Humidity       : 58%
  Wind           : N at 2 mph

  Fri 59 41 Mostly Sunny
  Sat 63 43 Mostly Sunny
  Sun 65 45 Mostly Sunny
  Mon 58 41 Chance of Showers 

Here is the script itself:

#!/usr/bin/env tclsh

package require tdom

# Provide the default zip codes of none specified
if {$argc == 0} { set argv {98121 98012} }

foreach location $argv {
    set xml [exec curl --silent http://www.google.com/ig/api?weather=$location]

    set doc [dom parse $xml]
    set root [$doc documentElement]

    #
    # Show Forecast Information
    #

    set inf [$doc getElementsByTagName forecast_information]
    set data ""
    append data "[[$inf selectNodes city] getAttribute data] "
    append data "[[$inf selectNodes postal_code] getAttribute data] "
    append data "[[$inf selectNodes current_date_time] getAttribute data] "
    puts "$data"

    #
    # Show Current Condition
    #
    set currentConditions [$doc getElementsByTagName current_conditions]

    set labels {
        condition      "Condition"
        temp_f         "Temperature (F)"
        humidity       "Humidity"
        wind_condition "Wind"
    }

    set longest 0
    foreach {tag labl} $labels {
        set length [string length $labl]
        if {$length > $longest} { set longest $length }
    }

    foreach {tag labl} $labels {
        set node [$currentConditions selectNodes $tag]
        set data [$node getAttribute data]
        regsub {[^:]*: *} $data "" data
        puts [format "  %-*s: %s" $longest $labl $data]
    }

    puts ""

    # Show Conditions for Next Days
    foreach cond [$doc getElementsByTagName forecast_conditions] {
        set data ""
        append data "[[$cond selectNodes day_of_week] getAttribute data] "
        append data "[[$cond selectNodes high] getAttribute data] "
        append data "[[$cond selectNodes low] getAttribute data] "
        append data "[[$cond selectNodes condition] getAttribute data] "
        puts "  $data"
    }
    puts ""
}

May 6, 2009

View Stock Price Using Command Line

Filed under: Finance, Tips & Tricks, Unix — Hai @ 4:21 pm

I live on command line all day, so it is convenience to perform many tasks using the command line. One of those is to check stock price:

curl -s 'http://download.finance.yahoo.com/d/quotes.csv?s=csco&f=l1'

The above command check for the last price (with some delay) of Cisco Systems. If you want to check the price for other tickers, replace ‘csco’ with your ticker symbol. You can query more than one symbols by separate them with commas, but do not leave any space in between.

The f=l1 defines the formatting for the returned information. To find more about formatting, visit this page

Please note this trick requires curl so install it before you try.

May 4, 2009

Locate a File and Go to It

Filed under: Unix — Hai @ 3:58 am

I often need to find a file, then cd to its directory. This command will do both, provide that the file’s name is unique enough:

$ cd $(dirname $(find ~ -name emails.txt))

Please note that the above command works for bash shell, but not csh: csh’s equivalent to the $( … ) construct is the ` … ` construct which the bash shell also understands. However, the “ construct does not allow for nesting.

« Newer PostsOlder Posts »

Blog at WordPress.com.