Michael Angstadt - Home

Home

July 25, 2010


Many laptops will automatically dim the screen when running on battery power in order to conserve energy. But does this significantly increase the battery life? How much power is actually saved when the screen's brightness is turned down? My guess has always been that the energy savings are negligible, that a darkened screen might give the laptop 10 more minutes of battery life, nothing more.

To discover the answer, I ran a small experiment. I ran a script which polled the battery data on my netbook every 5 seconds. I monitored this data for 2 minutes with the screen on its brightest setting and 2 minutes with the screen on its darkest setting. I disabled my netbook's wireless network card and muted the speakers to avoid any interference in the data. The results were marginally better than I expected:

 Avg. mABat. life
(4200 mAh battery)
Brightest1120.83h 42m
Darkest1018.64h 7m

If kept on its darkest screen setting, my netbook battery would last about 25 minutes longer. If the brightness were to be set somewhere in between the two extremes to a level where the screen would actually be readable, the energy savings would probably be about half that--12.5 minutes.

The battery data was collected from "/proc/acpi/battery/BAT0/state". The script used to poll the data was written in PHP and is shown below:

<?php
while(true){
$state = file_get_contents('/proc/acpi/battery/BAT0/state');

preg_match('/present rate:\\s+(\\d+)/', $state, $matches);
$presentRate = $matches[1];

echo date('M d G:i:s'), ' ', $presentRate, "\n";

sleep(5);
}
?>
July 21, 2010

If you are having trouble running the UNetbootin Linux binary, you can try installing it using apt-get. This will automatically download and install any required dependencies.

1. Add the following lines to "/etc/apt/sources.list".
deb http://ppa.launchpad.net/gezakovacs/ppa/ubuntu [name] main
deb-src http://ppa.launchpad.net/gezakovacs/ppa/ubuntu [name] main
Where "[name]" is the name of your Ubuntu version:
VersionName
10.04lucid
9.04jaunty
9.10karmic
8.10intrepid
8.04hardy

2. Add the GPG key.
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 72D340A3
3. Get the list of packages from the newly added source.
sudo apt-get update
4. Install UNetbootin. It will appear in the "System Tools" menu.
sudo apt-get install unetbootin
Resources:
1. How to install UNetbootin in ubuntu
June 1, 2010
So I made some improvements to my developer forum flair!

Firstly, I added a Sun Forums flair, which displays your username, number of posts, and number of Dukes.


The background image to the left changes depending on how many "Dukes" you have, which are like these special points you can get for answering questions. It will also put a star next to your name if you are a moderator.

This one was a little more complicated because I couldn't pass the HTML directly into a DOMDocument object like with JavaRanch. I had to use tidy to clean up the HTML before passing it to DOMDocument:
//tidy the page
$tidy = new tidy("http://forums.sun.com/profile.jspa?userID=$id");
$tidy->cleanRepair();
$tidy = preg_replace('/<\/?nobr>/', '', $tidy); //<nobr> tags must be removed for DOMDocument

//load the page
$html = new DOMDocument();
$html->loadHTML($tidy);
I also had to pretty much do all development on the mangst.com server because the PHP installation on my iMac doesn't have tidy installed and it doesn't support all of the GD graphics functions.

Secondly, I added the ability to view the flair as a dynamically created image (nerdgasm!!!). Just change the "type" parameter to "png" or "jpeg":
<img src="http://www.mangst.com/flair/sun?id=1071155&type=png" />


I was actually surprised how easy this was. I had this fear that generating an image programmatically would be hugely complicated, but it wasn't really. The hardest part was keeping track of the pixels to make sure everything lined up right. I tried to make it look as close as possible to the Javascript and HTML versions, but for some reason the bold version of Verdana comes out looking a lot less bold in the image.
May 25, 2010
Check out my JavaRanch flair!



I was so inspired by the flair over at Stackoverflow that I thought it would be fun to create my own! It basically works just like Stackoverflow's does. You have three options for how to include it in your webpage:

  • Javascript - You can include it using a <script> tag, which injects the flair into the DOM via Javascript.
    <script
    src="http://www.mangst.com/flair/javaranch?id=209694&type=js"
    type="text/javascript">
    </script>
  • HTML - You can include it using an <iframe>, which loads the flair as HTML into the frame.
    <iframe
    src="http://www.mangst.com/flair/javaranch?id=209694&type=html"
    marginwidth="0"
    marginheight="0"
    frameborder="0"
    scrolling="no"
    width="220"
    height="100">
    </iframe>
  • JSON - You can get the raw data with JSON and handle the data however you wish with Javascript.
    JSON URL: http://www.mangst.com/flair/javaranch?id=209694&type=json
On the backend, what it does is it screen scrapes your JavaRanch profile page, plucking out the information that it needs. It uses a PHP DOMDocument object to load the HTML, then uses XPath to get the data fields.
$html = new DOMDocument();
$html->loadHtmlFile("http://www.coderanch.com/forums/user/profile/$id");
$xpath = new DOMXPath($html);
$username = $xpath->query("//span[@id='profileUserName']")->item(0)->textContent;
//...

I think it's pretty elegant, though it will break if JavaRanch decides to do any site redesigns. I was afraid that it wouldn't be able to load the HTML into a DOM, since webpage HTML tends not to be well formed XML, which would have prevented me from using XPath. The SimpleXMLElement class wouldn't accept the HTML, but the DOMDocument class did.
May 7, 2010
SimpleDateFormat
The Java class SimpleDateFormat converts Dates to Strings and vice versa. For example, the following code converts the String "04/15/2010" to a Date object and back again:
DateFormat df = new SimpleDateFormat("MM/dd/yyyy");
Date d = df.parse("04/15/2010");
String s = df.format(d);
"04/15/2010".equals(s); //true
This class is documented as not being thread-safe, but I decided to see for myself if this was true.

Thread-safety proof
I created a program that proves that SimpleDateFormat is not thread-safe. It creates X threads which run concurrently. Each thread generates Y random Dates, then formats each Date in two ways: using a local instance of SimpleDateFormat that no other thread has access to, and using a static instance of SimpleDateFormat which all threads use. The Strings created by the local instance are added to one List and the Strings created by the static instance are added to another List.

If everything is synchronized properly, then these two lists should be identical. But because SimpleDateFormat is not thread safe and all threads use a shared static instance, the lists do not always come out identical (I've found that around ten threads and ten dates-per-thread consistently produce different lists).

If the call to "staticDf.format()" is wrapped in a synchronized block, then the lists always come out identical, which shows that SimpleDateFormat needs to be manually synchronized and is therefore not thread-safe.

Usage
The following command will create ten threads, each of which will generate twenty dates:
java SimpleDateFormatThreadSafe 10 20

Source code
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
* Proves that SimpleDateFormat is indeed not thread safe (as documented in the
* javadocs).
* @author mangstadt
*/
public class SimpleDateFormatThreadSafe {
private static final String format = "MM/dd/yy";
private static final DateFormat staticDf = new SimpleDateFormat(format);
private static int numThreads = 10;
private static int numLoopsPerThread = 10;

public static void main(String args[]) throws Exception {
//get the arguments
if (args.length > 0){
numThreads = Integer.parseInt(args[0]);
if (args.length > 1){
numLoopsPerThread = Integer.parseInt(args[1]);
}
}

//create the threads
MyThread threads[] = new MyThread[numThreads];
for (int i = 0; i < threads.length; ++i) {
threads[i] = new MyThread();
}

//start the threads
for (MyThread t : threads) {
t.start();
}

//check the results
boolean allIdentical = true;
for (MyThread t : threads) {
t.join();
if (!t.localList.equals(t.staticList)){
System.out.println(t.getName() + " lists are different:");
System.out.println("local: " + t.localList);
System.out.println("static: " + t.staticList);
System.out.println();
allIdentical = false;
}
}
if (allIdentical){
System.out.println("All lists are identical.");
}
}

private static class MyThread extends Thread {
public final List localList = new ArrayList();
public final List staticList = new ArrayList();

@Override
public void run() {
DateFormat localDf = new SimpleDateFormat(format);
for (int i = 0; i < numLoopsPerThread; ++i) {
//create a random Date
Calendar c = Calendar.getInstance();
c.set(Calendar.MONTH, randInt(0, 12));
c.set(Calendar.DATE, randInt(1, 21));
c.set(Calendar.YEAR, randInt(1990, 2011));
Date d = c.getTime();

//add formatted dates to lists
localList.add(localDf.format(d));
//synchronized (staticDf){
staticList.add(staticDf.format(d));
//}
}
}
}

private static int randInt(int min, int max) {
return (int) (Math.random() * (max - min) + min);
}
}
April 11, 2010
Typically, an image is included in a web page by referencing an image file:

<img src="take-this.jpg" />


But it's also possible to put the image directly inside the web page source. This is done using a data URI:

<img src="data:image/jpeg;base64,image-data-goes-here" />



The URI contains the content-type of the image ("image/jpeg" in this case, since this image is a JPEG) and the image data encoded in base64.

This is supported by most browsers. Internet Explorer support lags behind, with only version 8 supporting it (to a limited extent).

This technique shouldn't be used on a regular basis, since it bloats the size of the web page considerably and makes it take longer to load. Including images as separate files (the typical way) lets the user explore the page while the more bandwidth intensive images are loading.

Check out my Data URI Generator to generate a data URI from an image of your choosing.
April 9, 2010
One thing to note when working with the HealthVault XML method schemas is that the links to these schemas in the HealthVault Developer Center (http://developer.healthvault.com/methods/methods.aspx), as well as in the GetServiceDefinition response, are not always correct. Some versions of some methods refer to the version 1 schemas, when they actually have their own schemas.

For example, the URL to the GetThings3 request schema is listed as:

https://platform.healthvault-ppe.com/platform/XSD/method-getthings.xsd

This URL incorrectly points to the version 1 schema. The version number must be added to the end of the file name in order to get the correct schema:

https://platform.healthvault-ppe.com/platform/XSD/method-getthings3.xsd

This holds true for the following methods:

CreateConnectPackage2 request
GetServiceDefinition2 response
GetThings3 request, response
OverwriteThings2 request
PutThings2 request
March 28, 2010
I've been doing a lot of work with Microsoft HealthVault at my job lately. I did some experimental work with the platform when I first started working there and since then, I've sort of been the team's HealthVault expert. It's been fun learning all about it and challenging as well, since most of the HealthVault libraries, tutorials, etc are centered around .NET (we use Java). So HealthVault is something I think would be fun to blog about.

This blog post will be about how to use what are called connect-requests in HealthVault. It assumes that you already have some knowledge of HealthVault from a developer's perspective. It includes Java code samples that use the JAX-B classes from the HealthVault Java Library.

Connect-requests are used by non web-based applications to create a connection to a HealthVault record. The process must only be completed once--not every time the application wants to access the record. They work like this:



1 The application prompts the user for the following information:

  • Friendly name - This can be anything, but should be the name that's on the HealthVault record.

  • Question - A question of the user's choosing (such as "What high school did I go to?").

  • Answer - The answer to the above question.

2 The application uses the above information, along with an external-id, to create a connect-request. The external-id can be any value that uniquely identifies the connect-request (the current time in milliseconds works fine). This value must be saved somewhere, as the application will need to use it again later (see step 5). Using these four bits of information, the application sends the request to HealthVault:
//create the request
CreateConnectRequestRequest request = new CreateConnectRequestRequest();
request.setExternalId(System.currentTimeMillis() + "");
request.setQuestion("Question?");
request.setAnswer("Answer");
request.setFriendlyName("Joe Smith");

//send the request / get the response
SimpleRequestTemplate srt = new SimpleRequestTemplate(ConnectionFactory.getConnection());
CreateConnectRequestResponse response = (CreateConnectRequestResponse) srt.makeRequest(request);
String identityCode = response.getIdentityCode();





Note:
Because we're using the JAX-B request classes, be sure to use
com.microsoft.hsg.methods.jaxb.SimpleRequestTemplate
and not
com.microsoft.hsg.request.SimpleRequestTemplate


3 HealthVault returns an identity-code, which is a sequence of 20 random letters separated into five groups of four:
DHLE-ELHP-AQLG-TLPZ-PQKD
The application must show this to the user. It should also show (what I call) the patient connect URL. The user will have to visit this URL in order to validate the connect-request:
https://account.healthvault-ppe.com/patientwelcome.aspx

Remove the "-ppe" when going live of course.

4 The user visits the patient connect URL in a web browser. This page will step the user through a process, requiring her to (1) login to her HealthVault account, (2) enter the identity-code, (3) enter the question/answer, and (4) choose which record in her account to grant the application access to.

5 Once the user has done this, the application is able to retrieve the person-id and record-id of the user's HealthVault record:
String externalId = //retrieve the external-id you saved in step 2
GetAuthorizedConnectRequestsRequest request = new GetAuthorizedConnectRequestsRequest();
SimpleRequestTemplate srt = new SimpleRequestTemplate(ConnectionFactory.getConnection());
GetAuthorizedConnectRequestsResponse response = (GetAuthorizedConnectRequestsResponse) srt.makeRequest(request);
for (ConnectRequest cr : response.getConnectRequest()) {
if (cr.getExternalId().equals(externalId)) {
String personId = cr.getPersonId();
String recordId = cr.getRecordId();
//save to persistent storage (like a database)
break;
}
}
However, the application has no way of knowing when the user will approve the application (when she completed step 4). So, the application must continually poll HealthVault for newly approved connect-requests (e.g. a separate thread which calls GetAuthorizedConnectRequests every 30 seconds or so).




Note:
The CreateConnectRequest method has a "call-back-url" parameter, which is a URL that HealthVault is supposed to call when the connect-request is validated by the user. However, at the time of this writing, it is not supported.
March 22, 2010
If the mouse acceleration settings of Mac OS X ever frustrate you, check out the Mouse Acceleration Preference Pane. This is a utility created by Christian Zuckschwerdt which lets you adjust these settings to your liking.

Apple changed around OS X's mouse API when version 10.6 was released, which made existing mouse acceleration tools useless. However, Christian just recently released an updated version supporting 10.6! My hand feels less cramped already...

March 15, 2010
In order to get Maven to properly recognize Scala code, there are are a number of steps you must take. Included below are pom.xml samples, along with explanations.

1. Name your source directories properly:
<project><build>

<sourceDirectory>src/main/scala</sourceDirectory>
<testSourceDirectory>src/test/scala</testSourceDirectory>

</build></project>

2. Add the scala-tools.org repositories.

These are required in order to download the necessary Scala dependencies (see step #3):
<project>
<repositories>
<repository>
<id>scala-tools.org</id>
<name>Scala-tools Maven2 Repository</name>
<url>http://scala-tools.org/repo-releases</url>
</repository>
</repositories>

<pluginRepositories>
<pluginRepository>
<id>scala-tools.org</id>
<name>Scala-tools Maven2 Repository</name>
<url>http://scala-tools.org/repo-releases</url>
</pluginRepository>
</pluginRepositories>
</project>

3. Add the appropriate dependencies:
<project><dependencies>

<!--
This contains the scala compiler, which Maven will use to compile your code and run your unit tests.
-->
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
<version>2.7.7</version>
</dependency>

<!--
This is Scala's unit testing framework. It's also possible to use JUnit, but when in Rome, right?
-->
<dependency>
<groupId>org.scalatest</groupId>
<artifactId>scalatest</artifactId>
<version>1.0</version>
<scope>test</scope>
</dependency>

<!--
If you want to use scalatest, unfortunately you also need to include JUnit as a dependency (see step #5).
-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.1</version>
<scope>test</scope>
</dependency>

<dependencies></project>

4. Add the scala-tools plugin:
<project><build><plugins>

<plugin>
<groupId>org.scala-tools</groupId>
<artifactId>maven-scala-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>

</plugins></build></projects>

5. Add the @RunWith annotation to each unit test.

If you are using scalatest as your unit testing framework, you must trick Maven into thinking that your tests are JUnit tests. Otherwise, Maven will not run your tests:
import org.junit.runner.RunWith
import org.scalatest.junit.JUnitRunner
import org.scalatest.FunSuite

@RunWith(classOf[JUnitRunner])
class MyScalaTest extends FunSuite{
//...
}

Tip: If you're using Eclipse, you can right click on one of these unit tests and select "Run As > JUnit Test" to manually run the test.
March 11, 2010
XPath is a domain specific language which is used to extract data from an XML document. It's supported by many different general purpose languages like C#, PHP, and Java. Take the following XML document for example:

<library>
<book>
<language>en</language>
<title>Solaris</title>
<author>Stanislaw Lem</author>
</book>
<book>
<language>fr</language>
<title>Le Petit Prince</title>
<author>Antoine de Saint-Exupéry</author>
</book>
<book>
<language>en</language>
<title>Dune</title>
<author>Frank Herbert</author>
</book>
</library>

The following XPath query retrieves the titles of all English-language books:

/library/book[language='en']/title

Java makes working with XPath (and XML in general) kind of complicated, since many different classes are involved. First, the XML document must be loaded into a DOM (Document Object Model).

StreamSource source = new StreamSource(new File("books.xml"));
DOMResult result = new DOMResult();
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.transform(source, result);
Node documentRoot = result.getNode();

This means that the XML text is read into memory and organized into a tree of nodes where each tag is an element node. The top element node would be the <library> element, which would have three child element nodes (<book>), and so on.



To demonstrate the power of XPath, this is what Java code might look like if XPath did not exist. The programmer would have to manually iterate through the entire DOM to get what she needed.

List<String> englishTitles = new ArrayList<String>();
Node books = documentRoot.getFirstChild();
if (books.getNodeName().equals("library")){
for (int i = 0; i < books.getChildNodes().getLength(); ++i){
Node book = books.getChildNodes().item(i);
if (book.getNodeName().equals("book")){
boolean english = false;
String title = null;
for (int j = 0; j < book.getChildNodes().getLength(); ++j){
Node bookChild = book.getChildNodes().item(j);
if (bookChild.getNodeName().equals("language") &&
bookChild.getTextContent().equals("en")){
english = true;
}
if (bookChild.getNodeName().equals("title")){
title = bookChild.getTextContent();
}
}
if (english && title != null){
englishTitles.add(title);
}
}
}
}
for (String title : englishTitles){
System.out.println(title);
}

As you can see, this is very very tedious and error prone! XPath is the better solution by far:

XPath xpath = XPathFactory.newInstance().newXPath();
NodeList nodeList = (NodeList)xpath.evaluate("/library/book[language='en']/title",
documentRoot, XPathConstants.NODESET);
for (int i = 0; i < nodeList.getLength(); ++i){
Node node = nodeList.item(i);
System.out.println(node.getTextContent());
}

Namespaces

XML documents often use namespaces. These are sort of like Java packages--they group related elements together and prevent name collisions from occurring. Let's say that each <language> element belonged to a namespace:

<book>
<language xmlns="http://translate.google.com">en</language>
<title>Solaris</title>
<author>Stanislaw Lem</author>
</book>

Note: While namespaces technically can be anything (like "abc123" for example), they should be globally unique. There's no way to enforce this, so the convention is to use a URI belonging to the person or company creating the namespace. For example, if Oracle wants to use a namespace, they can be fairly certain that no one else in the entire world is using one starting with "http://www.oracle.com".


To make Java aware of namespaces,a NamespaceContext object must be created and added to the XPath object.

XPath xpath = XPathFactory.newInstance().newXPath();
xpath.setNamespaceContext(new NamespaceContext() {
public String getNamespaceURI(String prefix) {
if ("tr".equals(prefix)){
return "http://translate.google.com";
}
return null;
}
public Iterator getPrefixes(String uri) {
return null;
}
public String getPrefix(String uri) {
return null;
}
});

This will assign the prefix "tr" to the namespace "http://translate.google.com". The prefix can be anything, but the namespace must match the one in the XML document.

NodeList nodeList = (NodeList)xpath.evaluate("/library/book[tr:language='en']/title",
documentRoot, XPathConstants.NODESET);
for (int i = 0; i < nodeList.getLength(); ++i){
Node node = nodeList.item(i);
System.out.println(node.getTextContent());
}

To learn more about XPath, you can visit w3schools.com.
March 10, 2010

I just found out about this cool service called Dropbox, which I thought I'd write about. I read a blurb about it in the March issue of Linux Journal.

Dropbox is a free service that lets you store files online. That sounds pretty boring. But it's more than just a free FTP server. What happens is, you install a small app on your computer, which creates a special "dropbox" folder in your home directory (or in My Documents if you're using Windows). The app monitors this folder for any changes and syncs these changes with the Dropbox server. For example, when you copy a file (Word document, MP3, whatever) to this folder, it will immediately upload it to your Dropbox account. If you delete a file, it will delete it from your account.

But the really cool thing is that you can connect multiple computers to your account by installing the Dropbox application on each one (there are Windows, Mac, Linux, and iPhone versions). So if you add a file to your Dropbox folder on your desktop PC, it will immediately download to your MacBook laptop, Linux Netbook, and whatever else.

October 23, 2009
Ok, so I'm a little behind the times. Amazon's Affiliate Program has been around for a while--since 1996 to be exact. Everyone and their grandma must have an account by now, making millions off sales of "The Secret" that they linked to on their blog (this is actually the secret that the book talks about). But incase you happen to be Amish, here's a short tutorial on the whole process of signing up for an account and building affiliate links.

1. Visit https://affiliate-program.amazon.com/ and click the "Join now for FREE!" button. It requires that you create an Amazon account first if you don't already have one.



2. It then asks you for your contact information and has some questions about the website/blog where you'll be putting your affiliate links.



3. And that's all the information they need to get your account set up. You don't even have to submit your payment information (although, you'll want to do this eventually...after all, making a few bucks is why you're here, right?). As you can see in the screenshot, Amazon assigns you a unique "Associates ID". This important identifier will be stuffed into all the affiliate URLs you create so that Amazon knows who give money to when a sale is made. To start making links, click the "Learn More" link in the "Product Links" box.



4. It's really easy to create affiliate links. It just takes a few clicks of the mouse and some copy and pasting. First, search for the product you want to link to. I chose a book I recently read.



5. Next, find the product in the search results and click the "Get Link" button.



6. This will take you to the page that lets you build your link. There's a lot of options here you can play with, so take some time to explore this page on your own. Once you're done crafting the link to your liking, copy the HTML code in the "step 3" box and paste it on your site. It's no secret--it's that simple!

October 7, 2009
I recently redesigned my website and one thing I changed was putting my blog on the front page instead of just linking to it. But what's cool (at least, according to my own geeky tastes) is that my blog is hosted on Blogger--not on my website! In this post, I'm going to walk through how I did this.

1. Blogger setup
First, you need to make sure your Blogger feeds are configured to include the full content of each blog post (as opposed to just the first paragraph or whatever). I think this is the default setting, but to make sure, to go the Settings page and click on the "Site Feed" tab. The "Allow Blog Feeds" option should be set to "Full".



2. Atom feed URL
Now, you must get the URL of your blog's Atom feed. Go to your blog's homepage and view the source (in Firefox, this is under "View > Page Source"). Look for a "link" tag that looks like the one below, and grab the value of its "href" attribute.
<link rel="alternate" type="application/atom+xml" title="mangstacular - Atom" href="http://mangstacular.blogspot.com/feeds/posts/default" />

Note: In this tutorial, I use the Atom feed. The RSS feed also has all the same information--it's just arranged differently.


3. Magpie setup
Download Magpie. This is a wonderfully easy-to-use RSS/Atom parser written in PHP which we'll use to parse the Atom feed.

You'll want to configure Magpie to cache the Atom feed so that it only downloads it when your blog changes in some way (i.e. when there's a new post or a new comment). This way, your website won't have to download the feed from Blogger every time someone visits your page. Open the "rss_fetch.inc" file and add these two lines somewhere at the top:
define('MAGPIE_CACHE_ON', true);
define('MAGPIE_CACHE_DIR', 'cache');

This will turn on caching and instruct Magpie to save the cached Atom file in the directory you specify.

Note: Be sure that the permissions of the cache directory allow your web server to write to it. The way you do this varies from server to server, based on the user that your PHP process runs under, but here are the commands that I had to run:
chmod 775 cache
chgrp web cache

What you do NOT want to do is set the folder to be globally writable. While this would work, it would also allow anyone on the Internet to write to that directory--not a good thing.


4. Parse the Feed
Now you're ready to write the code that fetches and parses the feed. Simply calling Magpie's "fetch_rss" function will parse the feed and return all the data in an associative array (despite "rss" being in the function name, it will also parse Atom feeds). No need to deal with any XML. Below is some sample code.

Note: There are a couple quirks, which may be Blogger-specific--be sure to read the code comments.

require_once('magpierss/rss_fetch.inc');

$atom = fetch_rss('http://mangstacular.blogspot.com/feeds/posts/default');
foreach ($atom->items as $item){
//var_dump($item); //see all the stuff that's in each item

$date = date('F j, Y', strtotime($item['published']));
$title = $item['title'];
$content = $item['atom_content']; //no need to run html_entity_decode() or anything
$url = $item['link'];

//because there are two <link> tags whose "rel" attributes are the same...
//...it stuffs the "href" attributes from both tags into this one string...
//...so you must extract the URL you want...
//...which in my case is the URL to the comments page
$commentsUrl = substr($item['link_replies'], strpos($item['link_replies'], 'https'));

$numberOfComments = $item['thr']['total'];

//generate HTML for the entry
//...
}


And now it looks like you're running fancy Wordpress software! ;)
September 29, 2009
Ever since I started my new job, I've gotten into the habit of turning on the morning news while getting ready for work in the morning. They do reports on rush-hour traffic and this morning, there was one whopper of an accident. A tractor-trailer had slide-lined three cars, completely blocking the flow of traffic in that direction. It was on a road I take everyday to work, but I wasn't sure exactly where on the road it was, so didn't know if it would impact my commute.



Then, I remembered that Google Maps has a live traffic feature that overlays the amount of traffic congestion on the map. I could see where the congestion was and figure out if I needed to find an alternate route. Oddly enough, it reported all roads as being more or less clear, which I knew was not the case. The roadside webcams (another Google Maps overlay) also didn't show any signs of an accident.

It turns out that the data just isn't very "live" after all. Not only was the traffic overlay not reporting the current traffic situation, but the webcam images weren't current either--they were anywhere from 30-60 minutes old. Clicking on the image takes you to the website that operates the webcams, and only going there can you get an up-to-the-minute view of traffic.

So it turned out that my drive wasn't affected. And I learned that, while the traffic overlay on Google Maps is great for seeing general traffic trends, it's not so good for live traffic updates.
August 16, 2009


I just finished making improvements to a PHP/MySQL-powered photo gallery website I had written during college (it kind of felt good to see how much my coding skills have improved since then). Besides moving all the SQL into a DAO, cleaning up the UI, and learning how to do file uploads in PHP, I went through all the code and formally documented all the functions and classes. I decided to use phpDocumentor because the format it requires the comments to be in is nearly identical to Java's Javadoc, which I was already familiar with.

I wanted to set up an Ant target that I could run that would generate the HTML documentation. It was pretty straight-forward--just create a target using the Exec task to run a console command. However, even though I could call the "phpdoc" command straight from the command line, Ant had problems with that. I think this is because "phpdoc" is not an executable, but a PHP script. At any rate, it worked fine once I found the script that the command was linked to and used the "php" command to run the script.

<target name="phpdocs" description="Generates phpDocumentor docs">
<delete dir="${doc.dir}" />
<exec executable="php">
<arg value="/usr/local/PEAR/PhpDocumentor/phpDocumentor/phpdoc.inc" />
<arg value="-f" />
<arg value="*.php" />
<arg value="-t" />
<arg value="${doc.dir}" />
<arg value="-ti" />
<arg value="Photo Gallery Documentation" />
</exec>
</target>
July 15, 2009
I recently read the book A Programmer's Guide to Java SCJP
Certification: A Comprehensive Primer (Third Edition)
by Khalid Mughal and Rolf Rasmussen in order to prepare for the SCJP exam (which I took and passed last week). I sent the authors of list of mistakes that I found and some have made it into the book's online errata!



How cool is that! :-P
July 14, 2009
Sorry, I need to rant a little. >:(

OpenOffice isn't as great as everyone says it is. Or at least as great as I though it was. I'm looking for a job and have been using the open source office suite to update my resume. Most recruiters want resumes in Microsoft Word's ".doc" format, but have no fear! OpenOffice supports that format...

...mostly...sorta kinda.

My resume is pretty basic in terms of features used. It uses two tables, a few bulleted lists, and three drawn lines, along with text of various sizes and fonts. But apparently that's too complex. It can never quite seem to get the bullets in the bulleted lists right:



One time, it used an icon of those things used in movies at the start of a take. Just completely random.

For throw-away documents, this is bearable. But for something important like a resume, you want your .doc to come out exactly right. And OpenOffice fails to do this.
March 2, 2009

If you're familiar with both Netbeans and Eclipse, you'll probably know of one obvious difference which sets the two apart: Eclipse supports "workspaces", while Netbeans does not (or at least, doesn't appear to--read on). A workspace is sort of like the "state" of the IDE--it's a collection of open project folders and IDE settings. Workspaces are useful when you are working on two unrelated projects which use different code and require the IDE to be configured differently.

By default, Netbeans only allows you to have one workspace. That is, when you exit Netbeans, all your open projects and settings will be restored when it is launched again. This is different from Eclipse, which asks you to specify a workspace every time it is launched. There is a way to specify your workspace with Netbeans as well, though it's not through an easy-to-use UI. An extra parameter must be included when invoking the Netbeans executable:

--userdir C:\path\to\workspace

Here is how to do use this parameter in Windows:
  1. Create a shortcut on your desktop to the Netbeans executable: C:\Program Files\NetBeans x.x\bin\netbeans.exe.

  2. Right-click on the shortcut and click "Properties".

  3. In the "Target" textbox, add the extra parameter to the very end:

    --userdir C:\path\to\new_workspace

  4. Click "OK" to exit the Properties window and double click the shortcut. Netbeans will launch and create/load the workspace at that location.

Tip: I like to use my default workspace as a "jumping-off point" for all my new workspaces. This saves me time I would otherwise have to spend resetting all my IDE settings, like SVN and code formatting preferences. Just make a copy of the default workspace folder and create a shortcut pointing to that folder, as shown above. The default workspace is located here:

~/.netbeans/<version>
February 27, 2009
There was a power outage in my apartment building the other day, so I went to reset the clock on my stove.

Instead of making you select the hour and minute in two separate steps like most appliances do, you do it in just one. Press the up/down buttons once, and the clock will increment/decrement by one minute. Hold the buttons down, and it moves in ten minute steps for as long as it's pressed.

I thought that was kind of clever. It keeps the task of "Setting the Time" consolidated into a single step, as opposed to breaking it up into as many as three (setting the hour, minute, and am/pm).

January 18, 2009

Want to see something that will blow your mind? Something that will shoot your brain out the back of your skull, through the window, and onto your neighbor's freshly waxed Pinto?

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="layout/frontpage.xsl"?>
<page lang="en_us">
<frontpage/>
</page>

This is the source code for a website's entire home page (which is that of the upcoming computer game Starcraft 2 by Blizzard Entertainment).

I could be in the minority, but I've never seen XSLT used to transform XML documents into web pages...and I've never realized how powerful it can be. After exploring the source code of the website, here are some advantages and disadvantages of this technique that I've discovered:

Advantage - Separation of concerns

Using XSLT, you can more effectively separate the content of your website from the presentation. The Starcraft 2 website has *all* of its text separated out into XML files (pretty cool!). For example, you can find all the text on the Terran page, in a file devoted solely to storing Terran-related text (terran.xml).

Advantage - i18n

By separating the content from the presentation, another benefit is that it makes it easy to internationalize the website. This is what Blizzard has done. The XML files used to store text are located in their own directory, named according to the language of the text (such as "fr_fr" for French). The language of the guy viewing the website is stored in the "lang" attribute of "page" tag of each individual web page (see the above code snippet). This attribute is used to determine which directory to retrieve the text from.

Also, you can do things that you would normally think could only be done using server-side languages:

Advantage - Access to special functions

Since XSLT uses the XPath language, you get to use all the special functions that XPath comes with. Tasks like string manipulation, date/time formatting, rounding numbers--all things that one might typically associate only with server-side languages, can all be done with XPath. For example, the following code, taken from a shared file called includes.xsl, uses the "concat" function to build a URI that points to a language-specific version of an XML file:

<xsl:variable name="terran" select="document(concat('/strings/',$lang,'/terran.xml'))"/>

Advantage - Avoiding code duplication

Just as you might define a function in a server-side script that performs some task, you can define function-like constructs with XSLT that "output" HTML. If you look at movies.xsl (a file used to generate the Movies page) you can see that for each movie listed on the page, a template is called:

<xsl:call-template name="movies-entry">
<xsl:with-param name="title" select="$loc/strs/str[@id='sc2.labels.movies.movie6.title']"/>
<xsl:with-param name="movieid" select="'6'"/>
... more parameters ...
</xsl:call-template>

The template, defined in a shared file called includes.xsl, contains the HTML code used to display the movie:

<xsl:template name="movies-entry">
<xsl:param name="title"/>
<xsl:param name="movieid"/>
... more parameters ...
... HTML/XSL code used to display the movie ...
</xsl:template>

So instead of having to do a lot of copying and pasting, as you would have to do if using plain HTML, the code stays centralized in one place, making bug fixes and other maintenance tasks easier to handle.

Disadvantage - Backward-compatibility

XSLT didn't become a W3C recommendation until 1999, so any browser created before or around that time probably won't have strong support for the language (this includes IE 5 and earlier). So you have to consider the software your audience is likely to be using before building your site. Blizzard probably thought it safe to use this technology, since gamers tend to use the latest and greatest browsers and are therefore unlikely to run into any compatibility issues.

So in conclusion, I've found that using XSLT to build web sites gives you many advantages that you don't get when developing with vanilla HTML. Perhaps I will use it for my next web development project!
January 11, 2009
I've developed a bit of an addiction recently. Thankfully, it's not alcohol-related. But like drinking, it does take up time and money.

If you're not familiar with the puzzle game Sudoku, you've probably at least seen it either in your daily newspaper or somewhere online. The goal is: given a square board 9 cells high and 9 cells wide, fill each row, column, and 3 by 3 sub-square with all the numbers 1 through 9. No number can be repeated in any of those three places. For example, the number 5 can't appear more than once in the same row. The board starts with some cells already filled in to give you a starting point. The less completed cells you start with, the harder the puzzle is.



After solving enough of these, I thought it would be an interesting exercise to write a program which solves them automatically! As I got deep into creating the algorithm, one data structure stood out as being the keystone--sets.

In mathematics, a set is a collection of numbers where:

  1. the order the numbers are in does not matter and

  2. no number can be repeated.


For example, this is a set:
{ 3, 7, 5, 9 }

Since order doesn't matter, this is the same set as the one above:
{ 9, 3, 7, 5 }

But this is NOT a set because there are two 7s:
{ 9, 3, 7, 5, 7 }

In this algorithm, sets are useful when trying to figure out what number a cell should be. The algorithm can be summarized with this pseudo-code:

while board is not complete
for each cell in board
if cell is empty
possibleValues = findPossibleValues(cell)
if size of possibleValues == 1
cell.empty = false
cell.value = possibleValues[0];

function findPossibleValues(cell)
possibleValues = new set{1,2,3,4,5,6,7,8,9}

for each rowcell in cell's row
if rowcell is not empty
//if possibleValues doesn't contain rowcell.value, then nothing happens
possibleValues -= rowcell.value

for each colcell in cell's column
if colcell is not empty
possibleValues -= colcell.value

for each squarecell in cell's square
if squarecell is not empty
possibleValues -= squarecell.value

return possibleValues

Given a current board state, for each cell in the board, a set containing all values the cell could possibly be is created. If this set only contains one number, then that's the only number the cell can be, so we fill in the cell with that number. This keeps repeating until all cells are filled in. (There are some other tricks that have to be taken into account, but this is the most fundamental part of the algorithm.)

If you'd like to try it out or look at the source code, you can download it here:

http://www.mangst.com/projects/sudoku-solver
May 11, 2008

Somewhere, deep in the bowels of a florescent-lit cubical farm, a battle wages on. A battle that has been fought since the dawn of computer programming. A battle of..."right vs. right"?

This sums up the approach that Michael Lopp, better known as "Rands" in the blogosphere, takes to software engineering. In his book Managing Humans: Biting and Humorous Tales of a Software Engineering Manager, the battle he describes is one of Incrementalists vs. Completionists--those who want to get things done quickly verses those who want to get things done correctly. Both mindsets are equally "right" in Lopp's eyes. It's the balanced combination of the two that makes for a solid software team.

Lopp takes this even-handed, "ying/yang" approach throughout his book, which is mostly made up of posts from his blog, Rands in Repose. As with the incrementalists and completionlists, his characterizations of office personality types are colorful, insightful, and even-handed. In the chapter entitled Meeting Creatures, Lopp takes you on a wild safari, describing the different kinds of people you'll encounter around the conference table at work. These meetings, he describes, are a rich ecosystem made up of unique, but interdependent personalities. You never have any idea what a "Curveball Kurt" is talking about, for example, which is why you need a "Translator Tim" to help out.

In regards to writing style, each one of the short, thirty-four chapters are written in a light, conversational tone that's easy to digest. Being a collection of blog posts, it's easy to pick up and put down without getting involved like you might with a novel.

So, the book is great, but it should be noted that people may find it hard to relate to some of Lopp's stories. Lopp works in the fast-paced, high-energy Silicon Valley, where startups come and go like contestants on American Idol. This can make for some quite stressful times. He talks, for example, about The Monday Freakout which describes the deluge of yelling and screaming that comes pouring out of a project lead after a weekend spent worrying about the project. I think it's safe to say that not everyone works in an atmosphere like this. Many readers may have a job that, while engaging, doesn't keep them stressing over the weekend.

But the bottom line is that no matter where you work, if your job is somehow related to software development, you can learn something from this book. Read on! It's the "right" thing to do.
May 6, 2008
I just recently finished putting together a small utility I had written a while ago for some websites I had designed during college. I spent a few days cleaning it up and turning it into something generic that anyone could download and start using right away. I've called it...**drumroll**

ThumbThru


It's a simple photo gallery utility coded entirely in Javascript and written in such a way so that it takes as little time as possible to get up and running. It's a lot like the galleries you'll find on the In Pictures section of the BBC News website--in fact, you could say that's where I got my "inspiration".

Some things I learned when writing this:

  • How to create a Javascript class

  • The difference between the GPL and the LGPL (I've licensed it under the LGPL, btw)

  • The fact that Ant can create ZIP files (pretty cool!)


All future blog posts perhaps...?

Anyway, feel free to download ThumbThru and give it a try! Or at least check out the live demo!
May 3, 2008
So, I go to check my Gmail account like I do on a regular basis. But when I logged in, I noticed something different.

There was this red bar above my inbox:



It turns out that I did indeed have Firebug (a Firefox extension) enabled! And I wouldn't have known it otherwise. Google probably decided to include this feature after getting complaints from users who didn't realize that it was their own stupid fault their mail was loading slowly. Or maybe Google decided to include it out of the kindness of their hearts. Either way, it's pretty cool to see a huge corporation that certainly doesn't need do something like this, take the time to do it. They could have buried the issue somewhere deep inside a FAQ page and left it at that.

In the short-term, spending time to include something that only benefits a small minority of users a small minority of the time is a waste of money. Some developer might have spent a day designing this feature. Google's stock price certainly won't rise the next day because of it. He should have been working on Adsense or something!

But it's the longer term impact that is affected by small enhancements like this. What this is saying isn't "turn off Firebug". It's saying "I know you want to get to your email quickly and Firebug may interfere with that." Or more simply:

"I understand you."

When another product of equal or better quality comes around, if you've been regularly reminding your users that you understand them, they'll be more likely to stick with you during tough times.