« April 2008 | Main | July 2008 »

June 2008

June 20, 2008

The irony of the FF3 NoScript plugin and Google Ads

I saw the following comical juxtaposition today while viewing the release notes page for the wonderful FF3 Plugin FlashGot.

Ironic_2

The developers of FlashGot also develop NoScript, which in its default configuration disables virtually all JavaScript. And when you disable JavaScript, you also fully disable most Google Text Ads, as seen to the right of the NoScript emblem. I had to laugh when it dawned on me that the developers of these free (as in no cost) FF Plugins support themselves at least partly with Google ad revenue and were more  of their users to install the NoScript plugin they would end up disabling their own source of revenue.

Did the CEO of Ford Motor Co. just admit to peak oil?

In the press release accompanying Ford's announced production cutbacks was this little gem from Ford CEO Mulally:

"We view the move to smaller, more fuel-efficient vehicles as permanent, and we are responding to customer demand," Ford CEO Alan Mulally said in the statement.

Permanent? I read this as an indicator that Ford believes the price of fuel is going to remain high for the foreseeable future. In the automotive industry, for which product cycles are in the half-dozen-year range, this statement implies that Ford does not see gas prices dropping any time in the next decade. The only thing missing from this announcement is any mention of a next-generation vehicle from Ford - plugin-hybrid, hydrogen fuel cell  or all-electric.  By the time Ford figures this out I should be driving my Aptera Typ-1!

June 19, 2008

Looks like the all-electric Aptera will be first to ship

A few months ago I decided to make good on my threat ("My next vehicle will be zero emissions!") by sending off a down payment for an all-electric Aptera Typ-1. At the time the payment was made, I was informed by email that I was  #2506 in line. According to the Aptera website, they are planning to go into production sometime around 'Late 2008'. I guessed at the time that it would be late 2009 by the time I received mine.

This morning I received an email from Aptera letting me know that they are splitting their waiting list into two groups: Those who selected the all-electric model and those who selected the gas-electric hybrid. The most interesting line from the email was this:

switch to the all-electric and potentially be driving an Aptera a year earlier than they would otherwise

That is a one year lag time between the introduction of the all-electric vs. the gas-electric hybrid models. Not entirely surprising I suppose - building a vehicle with two motors is more complicated than building a vehicle with just one.  Hopefully though I'll be moved up in the queue now that they are dividing the current list into two parts. Who knows, I might get mine before the lease on my current car expires.

June 14, 2008

Serendipity RSS export to MovableType Import Format Converter

Having made the recent decision to no longer host my own server/weblog, one of the conditions of that transition was to preserve all of my existing weblog entries. That is one of the reasons why I chose to host this at TypePad - the ability to perform bulk imports of weblog entries. I have been using the Serendipity weblog server software for several years, accumulating about 250 entries. One of the admin features of s9y is the ability to export all entries as an RSS2.0 feed.

With that XML file saved to my local drive, I then had to go about converting that content into the MovableType Import Format. I figured there must be decent Java library for parsing RSS XML feed documents, which I could then use to output an MT-import compatible file. After a bit of searching, I came across the Rome project that looked like it had all the features I might need (download v0.9 from here). You'll also need the 'content' plugin (which you can download here) and the dependent JDOM library (download from here).

Once you have those pieces downloaded, you can dowload my Java implementation named RSS2MTImport.java (source: Download RSS2MTImport.java. If you just want a binary build, you can also download that here: Download rss2mt.jar. To use the Jar file:

java -jar rss2mt.jar http://url/to/rss2feed.xml /path/to/output/mt.export

Of course, if you have the Serendipity RSS XML file saved locally, you can refer to it using a file:/// URL.

Transparent Data Encryption with Java, Hibernate and PostgreSQL

A new feature that I've been developing for Altos Research will require that we store the credit card information of our subscribers. This makes me nervous as hell. I am scared to death of the impact a data security breach would have on the customers whose data is compromised as well as on the financial viability of the company. My first engineering task in all of this was to come up with a reliable method of encrypting the billing information fields that we store in PostgreSQL.

The first part of the solution was fairly straightforward - implementing a utility class that would encrypt and descrupt strings using the AES encryption algorithm. I used various examples from around the net, and put together a basic encrypt/decrypt utility that looks something like this - it takes a BASE64-encoded encrypted string value and returns the unencrypted value using the encryption key provided (and yes, these implementations are not even close to fully optimized):

public static String encryptString ( String pUnencryptedString, String pKey ) {
        Security.addProvider(new SunJCE());
	byte[] keybBytes = Base64.decodeBase64(pKey.getBytes());
	SecretKeySpec sks = new SecretKeySpec(keybBytes, "AES");
	Cipher c = Cipher.getInstance("AES");
	c.init(Cipher.ENCRYPT_MODE, sks);

        byte[] inputBytes = pUnencryptedString.getBytes("UTF8");
        byte[] outputBytes = cipher.doFinal(inputBytes);

        String base64 = new String (Base64.encodeBase64(outputBytes));
        return base64;
}

public static String decryptString ( String pEncryptedString, String pKey ) {
        Security.addProvider(new SunJCE());
	byte[] keybBytes = Base64.decodeBase64(pKey.getBytes());
	SecretKeySpec sks = new SecretKeySpec(keybBytes, "AES");
	Cipher c = Cipher.getInstance("AES");
	c.init(Cipher.DECRYPT_MODE, sks);

	byte[] inputBytes = Base64.decodeBase64(pEncryptedString.getBytes());
	byte[] outputBytes = cipher.doFinal(inputBytes);
	return new String(outputBytes);
}

With the basic encrypt/decrypt utility in place, I then created a Hibernate UserType named EncryptedValueUserType to perform the needed transformations at the time the values are read from (decryption) and written to (encryption) the PostgreSQL database. That UserType class looks like this - the interesting methods being 'nullSafeGet' in which the encryption is done and 'nullSafeSet' which performs the encryption:

public class EncryptedValueUserType 
	implements Serializable, UserType {

    private static final int[] SQL_TYPES = {Types.VARCHAR};
    public int[] sqlTypes() {
        return SQL_TYPES;
    }
    public Class returnedClass() {
        return  java.lang.String.class;
    }

    public boolean equals(Object pObject1, Object pObject2) throws HibernateException {
        if (pObject1 == null && pObject2 == null) return true;
        if (pObject1 == null || pObject2 == null) return false;
        return (( String ) pObject1).equals(( String ) pObject2);
    }

    public int hashCode(Object o) throws HibernateException {
        return ((String) o).hashCode();
    }

    public Object nullSafeGet(ResultSet pResultSet, String[] pStrings, Object o) 
	throws HibernateException, SQLException {
        String encryptedValue = pResultSet.getString(pStrings[0]);
        return pResultSet.wasNull() ? null : decryptString (encryptedValue, "MY_AES_ENCRYPTION_KEY");
    }

    public void nullSafeSet(PreparedStatement pPreparedStatement, Object o, int i) 
	throws HibernateException, SQLException {
        if ( o == null ) {
            pPreparedStatement.setNull(i, Types.VARCHAR);
        } else {
            pPreparedStatement.setString(i, encryptString( (String) o ), "MY_AES_ENCRYPTION_KEY");
        }
    }

    public Object deepCopy(Object o) throws HibernateException {
        return o;
    }

    public boolean isMutable() {
        return false;
    }

    public Serializable disassemble(Object o) throws HibernateException {
        return (Serializable) o;
    }

    public Object assemble(Serializable pSerializable, Object o) throws HibernateException {
        return pSerializable;
    }

    public Object replace(Object o, Object o1, Object o2) throws HibernateException {
        return o;
    }
}
Of course you should not embed the actual encryption key directly in the Java source file as I show above, but you get the idea. Now all you need to do to use this is assign the 'EncryptedValueUserType' to any database field you would like to encrypt in your Hibernate mapping file (hbm.xml):
    <property name="accountNumber" type="com.altosresearch.utils.EncryptedValueUserType" column="account_number" />
And now all your business logic nees to do is call the normal getter/setter methods for this property. All of the security work is done completely transparently. This makes it VERY simple to encrypt lots of different fields besides credit card numbers, such as passwords and even address information.

Pascal's Wager as an Argument for Environmental Responsibility

I came across a comment from a digg.com user today that sounded remarkably like Pascal's Wager applied to environmentalism. The comment was in response to the new TED.org talk by Al Gore in which he updates his now famous Inconvenient Truth slide deck with more recent data. While the talk itself is definitely worth spending 30 minutes to watch, this commenter on digg.com is, in my opinion, doing a disservice to the scientific community and scientific evidence accumulated to date.

Wikipedia does a good job of explaining what Pascal's Wager is and when it was originally made, so I'll not revisit that. Here is what I think the Environmentalist's Wager might look like:

Global Warming is RealGlobal Warming is Not Real
Live as if Global Warming is RealYou Win BigYou lose very little
Live as if Global Warming is not RealYou Lose Big You lose very little

What bothers me about such a formulation is that it cheapens the scientific evidence. The findings are quire clear and unambiguous - the earth is getting warmer. In the most recent IPCC report this assertion was assigned a confidence rating of 'Greater than 99%'. So to argue in favor of being environmentally responsible 'on the off chance that there is a problem' seems to be doing a disservice to the movement. An alternative formulation of this could be based on the more conservative (given a 'Greater than 90%' confidence rating in the IPCC report) and controversial claim that humans are the cause of the warming. A Wager version of that might look like:

Humans Cause Global WarmingHumans Do Not Cause Global Warming
Live as if Humans Cause Global WarmingYou Win BigYou lose very little
Live as if Humans Do Not Cause Global WarmingYou Lose Big You lose very little

So what is the cause of the lack of political motivation among American's to do something significant about this? My guess is that for many people, their version of the wager looks like this instead:

Humans Cause Global WarmingHumans Do Not Cause Global Warming
Live as if Humans Cause Global WarmingYou Win BigYou lose very little
Live as if Humans Do Not Cause Global WarmingEveryone Else But Me Loses BigYou lose very little

Seems like wishful thinking to me.

Listening To

Real Estate Stats

  • Price Trend for Sunnyvale 94086
  • Median Price for All Sunnyvale
  • Median Price for Sunnyvale 94086

GA