Tasting Coffee Better : Food

I love drinking coffee. Recently I was told to drink more coffee by my dental hygienist. Ok, so she actually told me that coffee was a better choice the the diet pop I had been habitually drinking in the afternoons and evenings. So I have been drinking lots more coffee, about 7-10 cups per day up from 3-4.

By accident I found a new way to enhance my appreciation of coffee. Some of the Halloween candy we bought this year was salty butter caramels and we have lots left over. I happened to be eating one of these caramels when I took a sip of some fresh brewed coffee. Wow! I was amazed at how eating a caramel at the same time brought out flavours from the coffee that I hadn't been able to distinguish drinking the coffee by itself. I could taste the roast much better and the specific bean flavours were much more discrete than they had been. I am not sure if it's just the salt in the caramel or something else. I tried adding cream and a bit of salt to black coffee as an experiment to see if that had the same effect but it just tasted salty and disgusting.

I'm now having fun trying all of my favourite roasts again with a caramel to see what I learn about them. I'm also finding that once my palate has been "trained" by tasting with a caramel I can pick out the same flavours without the caramel. Using a caramel seems to be an excellent training tool for coffee tasting. I am really glad I made this discovery!


 

Video of Shelley : Java

The photo of Shelley in my last post was just a taste. Here's more!

This footage was taken primarily at the Bonneville salt flats in September. Notice at the end of the salt flats segment how she has drifted out the Audi logo at 95 KM/H. There's probably not very many human drivers who could drive with this accuracy. With more time Shelley could just as easily drift out a picture of Duke, the Java logo or the Mona Lisa... try that puny human!


 

Fastest Hardware I Have Ever Worked On! : Java

Image of 'Shelley', an autonomous Audi TTS on the Bonneville Salt Flats at Sunset

Photo credit: Marcial Hernandez

Probably not what you thought you'd be seeing when you came to this page!

"Shelley" is the newest VW ERL test vehicle and will be conquering Pike's Peak in 2011. Yes, that's a Java logo and she is indeed "Java Powered"! Shelley will be using Java Realtime and Solaris for her driving control, GPS integration, telemetry logging and portions of her safety system.

My part, thus far, has been to provide a Solaris CAN bus driver. Which I, unfortunately, had to write in C.


 

Updated Java Store LRM Sample : Java Store

As Octavian mentioned in his recent blog entry, Java Store and License Management, the Java Store will soon offer a simple license rights management system to developers. Octavain's post was based upon early work and, because there have been questions about it, I'm posting updated sample source code for the license management feature. Enjoy!

Java Store License Rights Management Sample
package com.sun.javastore.licenserightsapp;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.security.Signature;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.Date;
import java.util.Map;
import java.util.Properties;

/**
 * A sample application demonstrating how to decode and verify the Java Store licensing rights object. This
 * sample shows the rights code executing within the {@code main()} method that normally starts your
 * application. In a real application you should move this code to wherever your application decides which
 * functions are available.  Note: An application can be run in demo/preview mode, in which case, none of
 * the rights objects are to be set, which is an indicator to the application that it is being run in such
 * mode.
 *
 * You may wish to use several copies of the code in different places in your
 * application to check for different rights. You should try to avoid using a pattern like :
 *
 *  
 *  public boolean featureUnlocked() {
 *     ... rights handling code ...
 *  }
 * 
* * as this is quite simple to replace with a method that simply returns "true" all the time. The more * you spread out the rights processing and checking within your code the harder it will be for attackers * to disable it. */ public class App { /** * The public key which must match the key which was used for signing the rights object. */ private final static byte[] TRUSTED_PUBLIC_KEY = { (byte) 0x30, (byte) 0x81, (byte) 0x9F, (byte) 0x30, (byte) 0x0D, (byte) 0x06, (byte) 0x09, (byte) 0x2A, (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xF7, (byte) 0x0D, (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x00, (byte) 0x03, (byte) 0x81, (byte) 0x8D, (byte) 0x00, (byte) 0x30, (byte) 0x81, (byte) 0x89, (byte) 0x02, (byte) 0x81, (byte) 0x81, (byte) 0x00, (byte) 0x98, (byte) 0x21, (byte) 0xAE, (byte) 0x6C, (byte) 0x80, (byte) 0x97, (byte) 0x6F, (byte) 0xDE, (byte) 0xAD, (byte) 0xC4, (byte) 0x59, (byte) 0x44, (byte) 0x57, (byte) 0xCC, (byte) 0x3D, (byte) 0x7E, (byte) 0x48, (byte) 0x7B, (byte) 0xE2, (byte) 0xEE, (byte) 0xB2, (byte) 0xA3, (byte) 0xF7, (byte) 0x53, (byte) 0x03, (byte) 0x12, (byte) 0x07, (byte) 0x60, (byte) 0x3D, (byte) 0x5E, (byte) 0x5D, (byte) 0xEF, (byte) 0x89, (byte) 0xAF, (byte) 0xA4, (byte) 0x6E, (byte) 0x85, (byte) 0xE3, (byte) 0xB8, (byte) 0xD1, (byte) 0xF1, (byte) 0x4D, (byte) 0x8C, (byte) 0x8C, (byte) 0x10, (byte) 0xE5, (byte) 0x1A, (byte) 0x6F, (byte) 0x70, (byte) 0xE8, (byte) 0xAD, (byte) 0x54, (byte) 0x96, (byte) 0xB1, (byte) 0x61, (byte) 0xC5, (byte) 0xE5, (byte) 0x42, (byte) 0x83, (byte) 0x2B, (byte) 0xB2, (byte) 0xB1, (byte) 0x91, (byte) 0x6F, (byte) 0xB0, (byte) 0xFE, (byte) 0x0D, (byte) 0xAF, (byte) 0x60, (byte) 0xA9, (byte) 0xD5, (byte) 0x64, (byte) 0x82, (byte) 0x8F, (byte) 0x1F, (byte) 0xE5, (byte) 0x47, (byte) 0x45, (byte) 0x76, (byte) 0x00, (byte) 0xC1, (byte) 0x43, (byte) 0x29, (byte) 0x10, (byte) 0x33, (byte) 0x52, (byte) 0x49, (byte) 0x53, (byte) 0x0E, (byte) 0xC8, (byte) 0xD2, (byte) 0x98, (byte) 0x17, (byte) 0x7F, (byte) 0x6E, (byte) 0x8F, (byte) 0x41, (byte) 0x1C, (byte) 0xF6, (byte) 0xE4, (byte) 0x6F, (byte) 0x84, (byte) 0x1C, (byte) 0x39, (byte) 0xA7, (byte) 0x17, (byte) 0x8A, (byte) 0x31, (byte) 0x1A, (byte) 0x90, (byte) 0xD0, (byte) 0xA8, (byte) 0x44, (byte) 0x84, (byte) 0x73, (byte) 0x01, (byte) 0x1F, (byte) 0x51, (byte) 0x19, (byte) 0x43, (byte) 0x35, (byte) 0x2D, (byte) 0x3D, (byte) 0xC6, (byte) 0x2B, (byte) 0x68, (byte) 0x7C, (byte) 0x4F, (byte) 0x02, (byte) 0x03, (byte) 0x01, (byte) 0x00, (byte) 0x01 }; /** * Name of the property containing the encoded rights for this user/device/application. (BASE64) */ private final static String RIGHTS_BLOB_PROPERTY = "jnlp.javastore.appwrapper.rightsBlob"; /** * Name of the property containing the digital signature of the encoded rights object. (BASE64) */ private final static String RIGHTS_SIGNATURE_PROPERTY = "jnlp.javastore.appwrapper.rightsSig"; /** * Name of the property containing certificate of the signer of the encoded rights object. (BASE64) */ private final static String RIGHTS_CERTIFICATE_PROPERTY = "jnlp.javastore.appwrapper.rightsCert"; /** * The ID of the user running the application as provided by the Java Store wrapper. */ private final static String RIGHTS_USER_ID = "jnlp.javastore.appwrapper.UserID"; /** * The Product ID of this application as provided by the Java Store wrapper. */ private final static String RIGHTS_PRODUCT_ID = "jnlp.javastore.appwrapper.ProductID"; /** * The Version ID of this application as provided by the Java Store wrapper. */ private final static String RIGHTS_VERSION_ID = "jnlp.javastore.appwrapper.VersionID"; /** * The system fingerprint for this system as provided by the Java Store wrapper. */ private final static String RIGHTS_SYSTEM_ID = "jnlp.javastore.appwrapper.SystemID"; /** * Clock drift window. This is padding we add in time/date calculations to allow for differences between * the user's clock and the Java Store clock. */ private final static long MAX_CLOCK_DRIFT_WINDOW_MS = /*1sec*/ 1000L * /*1min*/ 60L * /*1hr*/ 60L * /*1/2day*/ 12L; /** * The basic right for purchased applications. If this right is absent or unavailable then the application * is in demo mode. */ private final static String BASIC_PURCHASED_RIGHT = "store:run"; /** * Main entry point. * * @param args command line arguments (if any). */ public static void main(String[] args) { // We will decide if this application should be running in demo mode or not. boolean demoMode = true; try { // Get the current time. long now = System.currentTimeMillis(); // Recover rights info objects from system properties and decode BASE64 data. byte[] rightsBlob = decodeBase64(System.getProperty(RIGHTS_BLOB_PROPERTY, "")); byte[] rightsSig = decodeBase64(System.getProperty(RIGHTS_SIGNATURE_PROPERTY, "")); byte[] rightsCert = decodeBase64(System.getProperty(RIGHTS_CERTIFICATE_PROPERTY, "")); // Ensure that all of the rights info components are available. if (rightsBlob.length <= 0 && rightsSig.length <= 0 && rightsCert.length <= 0) { throw new IllegalArgumentException("Rights objects unavailable."); } // Read in the certificate of the signer. CertificateFactory cf = CertificateFactory.getInstance("X.509"); X509Certificate certificate = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream( rightsCert)); // verify that the public key in the presented signer certificate matches the one know to trust. if (!Arrays.equals(TRUSTED_PUBLIC_KEY, certificate.getPublicKey().getEncoded())) { throw new IllegalArgumentException("Incorrect signer."); } // Verify the signature using the certificate against the rights info blob. Signature signature = Signature.getInstance("SHA1withRSA"); signature.initVerify(certificate); signature.update(rightsBlob); if (!signature.verify(rightsSig)) { throw new IllegalArgumentException("Signature doesn't match."); } // We can now trust that the rights info blob is authentic. // The rest of the processing is devoted to using the rights info. // Read a Properties map from the rights info blob. Properties rights = new Properties(); rights.load(new ByteArrayInputStream(rightsBlob)); // Extract some values from the properties map // The ID of the product to which the rights are applied. int productId = Integer.parseInt(rights.getProperty("productId", "-1")); rights.remove("productId"); // The ID of the user holding the rights. int userId = Integer.parseInt(rights.getProperty("userId", "-1")); rights.remove("userId"); int systemId = Integer.parseInt(rights.getProperty("systemId", "-1")); rights.remove("systemId"); // The ID of the device on which the application is running. String deviceId = rights.getProperty("deviceId", ""); rights.remove("deviceId"); // Timestamp at which this rights info was generated in milliseconds since Midnight Jan 1, 1970 UTC ("the epoch"). long timestamp = Long.parseLong(rights.getProperty("timestamp")); rights.remove("timestamp"); // Print out the core properties of the rights info. System.out.printf("product : %d user : %d system : %d device : '%s' timestamp : %s \n", productId, userId, systemId, deviceId, new Date(timestamp)); // Perform checks upon the properties. // The product ID must be a positive number. int appProductId = Integer.parseInt(System.getProperty(RIGHTS_PRODUCT_ID, "-99")); if (productId != appProductId) { throw new IllegalArgumentException("Invalid product Id"); } // Normally the userID is > 0. If the userID is -1 then this is a preview or demo and we should // not expect any rights. int currentUserId = Integer.parseInt(System.getProperty(RIGHTS_USER_ID, "-99")); if (userId != currentUserId) { throw new IllegalArgumentException("Invalid user Id"); } // The ID of the system on which the application is running. int currentSystemId = Integer.parseInt(System.getProperty(RIGHTS_SYSTEM_ID, "0")); if (systemId != currentSystemId) { throw new IllegalArgumentException("Non-matching system Id"); } // Device ID must be present. This is used to track how many devices the user is installing the // application on. if (0 == deviceId.trim().length()) { throw new IllegalArgumentException("Invalid device Id"); } // Compare timestamp to current time allowing for clock drift. if ((timestamp < 0) || (now - timestamp < -MAX_CLOCK_DRIFT_WINDOW_MS)) { throw new IllegalArgumentException("Invalid time stamp"); } if (!rights.isEmpty()) { System.out.println(); } // At this point all remaining keys in the rights map should be single right descriptors. if ((-1 == userId) && !rights.isEmpty()) { System.out.printf("*** Rights Info should be empty when in demo/preview mode.\n\n"); } // Print out properties for each right in the rights info. for (Map.Entry aRight : rights.entrySet()) { String key = aRight.getKey().toString(); String value = aRight.getValue().toString(); // Not a right entry. if (!key.startsWith("right.")) { System.out.printf("\t** Unexpected property ** :: key : '%s' value : '%s'\n", key, value); continue; } // Process a single right descriptor. Value is a BASE64 encoded property map. Properties right = new Properties(); right.load(new ByteArrayInputStream(decodeBase64(value))); // Read the properties for this right from the property map. // the name of the right (not unique) String name = right.getProperty("name"); // receipt id of the Java Store purchase transaction which acquired this right. (unique) int receiptId = Integer.parseInt(right.getProperty("receiptId")); // payment processor name. String paymentProcessor = right.getProperty("paymentProcessor"); // transaction id from the payment service (unique per payment procesor) String paymentTransactionId = right.getProperty("paymentTransactionId"); // if true then right is currently granted otherwise false (refunded, revoked, etc.) boolean isGranted = Boolean.parseBoolean(right.getProperty("isGranted", "false")); // timestamp in millis since epoch at which the right becomes (or beacame) active. Not present for perpetual rights. long activation = Long.parseLong(right.getProperty("activation", "-9223372036854775808")); // timestamp in millis since epoch at which the right expires. Not present for for perpetual rights. long expiration = Long.parseLong(right.getProperty("expiration", "9223372036854775807")); // Calculate whether this right is currently available. Application functionality for // absent and unavailable rights should be disabled. boolean available = isGranted && // must be granted. (now + MAX_CLOCK_DRIFT_WINDOW_MS >= activation) && // and activated. (now - MAX_CLOCK_DRIFT_WINDOW_MS < expiration) && // and not expired. (userId > 0) && // for a specific user (not preview or demo). (null != name); // and not null; // print out properties for this specific right. System.out.printf("\tright : '%s' receipt id : %d payment : %s '%s' granted: %b \n" + "\t\tTimestamps: %s (activation) %s (expiration)\n" + "\t\t==> %s\n", name, receiptId, paymentProcessor, paymentTransactionId, isGranted, (Long.MIN_VALUE == activation) ? "perpetual" : new Date(activation), (Long.MAX_VALUE == expiration) ? "perpetual" : new Date(expiration), available ? "available" : "unavailable"); // See if we should disable demo mode based upon this right. if (available && BASIC_PURCHASED_RIGHT.equals(name)) { demoMode = false; } } } catch (Exception failure) { System.err.println("Failure processing Java Store Licensing Rights"); failure.printStackTrace(System.err); throw new IllegalStateException("Invalid Java Store Licensing Rights", failure); } // Print out our decision about whether we are running in demo mode. System.out.printf("\nApplication is running in %s mode.\n", demoMode ? "demo" : "purchased"); } /** * Decodes a BASE64 string into a byte array. * * @param encodedBASE64 A BASE64 encoded string with optional whitespace. * @return the decoded bytes. */ private static byte[] decodeBase64(String encodedBASE64) { ByteArrayOutputStream bos = new ByteArrayOutputStream(encodedBASE64.length()); int index = 0; int values = 0; int charsToBytes = 0; int trailing = 0; while (index < encodedBASE64.length()) { char c = encodedBASE64.charAt(index++); int v; // 6 bits if ('A' <= c && c <= 'Z') { v = (c - 'A'); } else if ('a' <= c && c <= 'z') { v = (c - 'a') + 26; } else if ('0' <= c && c <= '9') { v = (c - '0') + 52; } else if (c == '+') { v = 62; } else if (c == '/') { v = 63; } else if (c == '=') { v = Integer.MAX_VALUE; } else if (Character.isWhitespace(c)) { continue; } else { throw new IllegalArgumentException("Bad character in input @ " + (index - 1)); } values <<= 6; charsToBytes++; if (Integer.MAX_VALUE != v) { if (0 != trailing) { throw new IllegalArgumentException("Bad character in input @ " + (index - 1)); } values |= v; } else { trailing++; if (trailing > 2) { throw new IllegalArgumentException("Bad character in input @ " + (index - 1)); } } if (0 == (charsToBytes % 4)) { bos.write((byte) (values >> 16)); if (trailing < 2) { bos.write((byte) (values >> 8)); } if (trailing < 1) { bos.write((byte) values); } values = 0; } } return bos.toByteArray(); } }

And a unit test which invokes the sample code.

Java Store License Rights Unit Test
package com.sun.javastore.licenserightsapp;

import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;

/**
 * Unit test for simple App.
 */
public class AppTest
        extends TestCase {

    /**
     * Create the test case
     *
     * @param testName name of the test case
     */
    public AppTest(String testName) {
        super(testName);
    }

    /**
     * @return the suite of tests being tested
     */
    public static Test suite() {
        return new TestSuite(AppTest.class);
    }

    /**
     * Rigourous Test :-)
     */
    public void testApp() {
        String SAMPLE_RIGHTS_BLOB =
                "I1dlZCBTZXAgMTYgMTc6MzM6NDQgUERUIDIwMDkKc3lzdGVtSWQ9MzU5Nzg3MQpyaWdodC4yPUkx" +
                "ZGxaQ0JUWlhBZ01UWWdNVGM2TXpNNk5EUWdVRVJVSURJd01Ea0taWGh3YVhKaGRHbHZiajB4TWpV" +
                "ek1UVXhNakV5TkRFNENtNWhiV1U5YzNSdmNtVmNPbk4xWW5OamNtbHdkR2x2YmdwcGMwZHlZVzUw" +
                "WldROWRISjFaUXB5WldObGFYQjBTV1E5TWdwd1lYbHRaVzUwVkhKaGJuTmhZM1JwYjI1SlpEMHhN" +
                "alFLWVdOMGFYWmhkR2x2YmoweE1qVXpNVFEzTmpFeU5ERTRDbkJoZVcxbGJuUlFjbTlqWlhOemIz" +
                "STlVR0Y1VUdGc1FWQUsKcmlnaHQuMT1JMWRsWkNCVFpYQWdNVFlnTVRjNk16TTZORFFnVUVSVUlE" +
                "SXdNRGtLYm1GdFpUMXpkRzl5WlZ3NmNuVnVDbWx6UjNKaGJuUmxaRDEwY25WbENuSmxZMlZwY0hS" +
                "SlpEMHhDbkJoZVcxbGJuUlVjbUZ1YzJGamRHbHZia2xrUFRFeU13cHdZWGx0Wlc1MFVISnZZMlZ6" + 
                "YzI5eVBWQmhlVkJoYkVGUUNnXD1cPQp1c2VySWQ9MQpwcm9kdWN0SWQ9Mwp0aW1lc3RhbXA9MTI1" +
                "MzE0NzYyNDYwMwpkZXZpY2VJZD05MzIxRTAyMy1DRUEyLTQxQTItODM1Mi1ERUVFODYxMDA4OEMK";

        String SAMPLE_RIGHTS_SIG =
                "GHNXWheMgBv8NC/jR9rVuwufyLgtirKsFq7C8dWL4Uzb4+3pZmfoqNLrxbXiTErCP4F42UnkP8mF" +
                "i8sFsdO99xGCuaa1zQqZO9zXNScKBxzRlKcSuzIRDynnq0CN9Wz82ibeA+b5S7HpsQ7nUbHb6SEu" +
                "9BqjArTEc8wu7RCcTZo=";

        String SAMPLE_RIGHTS_CERT =
                "MIIE5jCCA86gAwIBAgIQXqXlgX7rylXBGhLidL9EhzANBgkqhkiG9w0BAQUFADCBgzEdMBsGA1UE" +
                "ChMUU3VuIE1pY3Jvc3lzdGVtcyBJbmMxHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsx" +
                "JTAjBgNVBAsTHENsYXNzIDIgT25TaXRlIFN1YnNjcmliZXIgQ0ExGjAYBgNVBAMTEU9iamVjdCBT" +
                "aWduaW5nIENBMB4XDTA5MDgyNzAwMDAwMFoXDTEyMDgyNjIzNTk1OVowbTEdMBsGA1UEChQUU3Vu" +
                "IE1pY3Jvc3lzdGVtcyBJbmMxITAfBgNVBAsUGENvcnBvcmF0ZSBPYmplY3QgU2lnbmluZzEQMA4G" +
                "A1UECxQHQ2xhc3MgQzEXMBUGA1UEAxQOU3VuIEphdmEgU3RvcmUwgZ8wDQYJKoZIhvcNAQEBBQAD" +
                "gY0AMIGJAoGBAJghrmyAl2/ercRZRFfMPX5Ie+LusqP3UwMSB2A9Xl3via+kboXjuNHxTYyMEOUa" +
                "b3DorVSWsWHF5UKDK7KxkW+w/g2vYKnVZIKPH+VHRXYAwUMpEDNSSVMOyNKYF39uj0Ec9uRvhBw5" +
                "pxeKMRqQ0KhEhHMBH1EZQzUtPcYraHxPAgMBAAGjggHtMIIB6TAJBgNVHRMEAjAAMA4GA1UdDwEB" +
                "/wQEAwIHgDBrBgNVHR8EZDBiMGCgXqBchlpodHRwOi8vb25zaXRlY3JsLnZlcmlzaWduLmNvbS9T" +
                "dW5NaWNyb3N5c3RlbXNJbmNDb3Jwb3JhdGVPYmplY3RTaWduaW5nQ2xhc3NDL0xhdGVzdENSTC5j" +
                "cmwwHwYDVR0jBBgwFoAUs0crgn5TtHPKuLsZt76BTQeVx+0wHQYDVR0OBBYEFJHwpfEC3ziinvN3" +
                "8dKlgVR5OrW1MDsGCCsGAQUFBwEBBC8wLTArBggrBgEFBQcwAYYfaHR0cDovL29uc2l0ZS1vY3Nw" +
                "LnZlcmlzaWduLmNvbTCBuQYDVR0gBIGxMIGuMDkGC2CGSAGG+EUBBxcCMCowKAYIKwYBBQUHAgEW" +
                "HGh0dHBzOi8vd3d3LnZlcmlzaWduLmNvbS9ycGEwcQYLYIZIAYb3AIN9nD8wYjAnBggrBgEFBQcC" +
                "ARYbaHR0cHM6Ly93d3cuc3VuLmNvbS9wa2kvY3BzMDcGCCsGAQUFBwICMCsWKU5vdCBWYWxpZGF0" +
                "ZWQgRm9yIFN1biBCdXNpbmVzcyBPcGVyYXRpb25zMBEGCWCGSAGG+EIBAQQEAwIEEDATBgNVHSUE" +
                "DDAKBggrBgEFBQcDAzANBgkqhkiG9w0BAQUFAAOCAQEAPoQ8RWJ6xfnY8YxHL3kEVEPxKyDAa+sG" +
                "Ng5Rw2SaXFek9KMfMvU6DUXdj/BYIuLu9S2cVIHlIyFINzT6gtxsDNTkByMmRys8lsCZhXv767Pe" +
                "b/KW2sZWA8fxSE6JDRpWsE7j4PSr3rBB6YNqCTX0qH5yzumx2Lfk28BILKW7ri4cmakaql+Vi+6q" +
                "QIqhxDu1FzAdbwp/DzAJYtafcAZa381jDH3kwpSXpP15V1jqZgGYs387hQEYDWie4J5sol7g0cN9" +
                "zlRZQMxwU6Rcz/nWiM24mGB/W0NH7ggMS7/AWz6efN534OAxgWuBA96Qwf7TWKdZWzWEdhZar483" +
                "hfmZiw==";

        System.setProperty("jnlp.javastore.appwrapper.UserID", "1");
        System.setProperty("jnlp.javastore.appwrapper.ProductID", "3");
        System.setProperty("jnlp.javastore.appwrapper.VersionID", "3");

        // This value will be calculated by the java store runtime.
        int systemId = "user".hashCode() ^ "os".hashCode();

        System.setProperty("jnlp.javastore.appwrapper.SystemID", Integer.toString(systemId));

        System.setProperty("jnlp.javastore.appwrapper.rightsBlob", SAMPLE_RIGHTS_BLOB);
        System.setProperty("jnlp.javastore.appwrapper.rightsSig", SAMPLE_RIGHTS_SIG);
        System.setProperty("jnlp.javastore.appwrapper.rightsCert", SAMPLE_RIGHTS_CERT);

        App.main(new String[0]);
    }
}

 

The Legacy List & The Two Words : General

The Two Words : Some relevant advice regarding legacy technology from Bob Newhart.

I've been compiling a list for the last couple of months of legacy technologies that I feel are well past their 'Best Before Date' and should be eliminated. Keeping them around in spite of better alternatives makes all of our jobs more complicated. The reasons for keeping the dead technologies alive end up sounding like delusional rationalizations.

I'm looking for suggestions of obsolete technologies which we would all be better off by getting rid of them. I'm not going to share the complete list I've compiled because I want people to come up with their suggestions. Some ideas to get you started:

  • Cylinder/Head/Sector Disk Addressing
  • Telnet/rsh/rlogin
  • Non-UTF character encodings
  • S-Video
  • ...

If there's a technology you're forced to use or support that's best destined for the boneyard please make the case for its obsolescence.


 


« November 2009
SunMonTueWedThuFriSat
1
2
3
4
5
6
7
8
10
11
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
     
       
Today



subscribe in a reader
GeoURL




Today's Page Hits: 334