Home‎ > ‎

Tom's Ideas And Notes

Interesting things I am working on.

Subscribe via google or directly with RSS...
Add to Google Reader

My Notes Blog Has Moved

posted Apr 11, 2015, 9:14 PM by Tom Gutwin

My new items now live on my own server running Apache Roller.
Roller Logo


Subversion 1.8 on Ubuntu 13.10 (Saucy)

posted Jan 26, 2014, 7:47 PM by Tom Gutwin

Subversion Icon
I needed the latest version of Subversion (client and server) running on Ubuntu 13.10, BUT, no pre-built package. So I built Subversion latest release (1.8.5) from source - here are the steps and packages I used.  If you want to build a later version (or trunk) just update the following steps as needed.

Get the Subversion 1.8.5 source
wget http://archive.apache.org/dist/subversion/subversion-1.8.5.tar.bz2
wget http://archive.apache.org/dist/subversion/subversion-1.8.5.tar.bz2.sha1
sha1sum subversion-1.8.5.tar.bz2
more subversion-1.8.5.tar.bz2.sha1
bunzip2 -c -f subversion-1.8.5.tar.bz2 | tar -xv

Get Latest libserf
and dependencies from the main development branch because the latest version is required by subversion.
The version of libserf in the Saucy repo is too old for Subversion 1.8.5. I had to get the deb files from the development repo.
sudo apt-get install libsctp1 libsctp-dev libaprutil1-dev uuid-dev
wget http://mirrors.kernel.org/ubuntu/pool/main/s/serf/libserf-dev_1.3.3-1_amd64.deb
wget http://mirrors.kernel.org/ubuntu/pool/main/s/serf/libserf-1-1_1.3.3-1_amd64.deb
wget http://mirrors.kernel.org/ubuntu/pool/main/a/apr/libapr1_1.5.0-1_amd64.deb
wget http://mirrors.kernel.org/ubuntu/pool/main/a/apr/libapr1-dev_1.5.0-1_amd64.deb
sudo dpkg -i libserf-dev_1.3.3-1_amd64.deb libserf-1-1_1.3.3-1_amd64.deb libapr1_1.5.0-1_amd64.deb libapr1-dev_1.5.0-1_amd64.deb

Other required packages (mainly dev pkgs)
sudo apt-get  install libsqlite3-dev sqlite libz-dev libgnome-keyring-dev gnome-keyring
sudo apt-get  install libdb++-dev libdb-dev libsasl2-dev libsasl2-2 libmagic1 libmagic-dev apache2-dev

Build Subversion
cd subversion-1.8.5
./configure --with-libmagic --with-gnome-keyring --with-berkeley-db --with-openssl --with-serf --with-apxs --with-jdk=/opt/jdk
make -j 8
sudo make install

Works For me.
Depending on what base packages you have on your system, you might need some other packages.
You also might want to fine tune the configure line - such as removing my non-standard jdk dir.

The above should get you close.

Simple/Basic Java Rest Web Services Client (with source)

posted Jan 21, 2014, 6:36 PM by Tom Gutwin   [ updated Feb 27, 2014, 9:56 PM ]

Rest Services Icon
This blog entry presents the Java code for a basic Rest Web services client I wrote in Java. It also shows how to use it to wrap around ISY REST services.

It is kept as small and lightweight as possible but includes all the code to get a working authenticated service connection with a restful web services server.  Think of it as the "hello world"/getting started How -to Java code to be re-used and extended to wrap around the full processing of any published REST web services.


I am writing an Android app to interact with many of my home Audio/Video devices and need to talk to my Universal-Devices ISY-994 home lighting controller using its REST Web Services. I could (and have) interact with the ISY-994 directly with its full and robust Java SDK but since I am including this in an Android app, I want to keep it as light as possible - without the inclusion of the UDI SDK Java libraries. Calling the REST interface is perfect for this.

I started with a proof-of-concept, to ensure I could communicate and consume Rest services, using the basic classes in the standard JDK.

  1. I wrote a generic class to connect and consume Rest services from any specified Rest Services server.

    • RestRequester.java

  2. I then extended it to focus specifically on my ISY-994, and its set of services (see UDI Wiki for the list of available services).

    • ISYRestRequester.java

The source code for both the base generic class and the ISY994 extended class are included below.

Scope of this Rest Client

  • use as few external libraries as possible - keep it to the standard Java Library (unfortunately Authentication requires the use of Base64 encoding so I used an Apache library for this)
  • provide a extendable class with the basic code to connect, send service requests, and receive responses
  • has a basic set of exposed methods to setup and use published Rest Web Services
  • handles Authentication to the service, if it is needed
  • has a main method to allow testing or calling services from the commandline
  • configurable server url
  • handles all the connections to the web services URL
  • POST requests or GET requests
  • Minimal or no processing of the responses other than returning the results as a StringBuilder (and dumping to System.out when run from the commandLine)

Extending this class to wrap around a specific Server and REST services

The generic class works out of the box on any configured Server URL, however it is easier to create a new class that extends the above base class with specific Rest service parameters, such as

  •   Rest Service Base URL
  •   Authentication username and password
  •   response type - plain XML or JSON
  •   response processing - pull out the useful information from the XML responses and transcode it into whatever
  •   wrap individual service calls into callable Java methods that "do something" with the responses

Java Source Code

The source is released as free and open under the GNU license version 3.

  •  It is available in-line below

  •  The latest version is available at my Subversion repo at http://svn.webarts.bc.ca 

  •  as a zip file at the very bottom of this page

  • ca.bc.webarts.tools.RestRequester

  • ca.bc.webarts.tools.isy.ISYRestRequester

My code depends (NOT Derivative) on a few Java files from the Apache Commons Codec library to perform Base64 encoding required by the http basic authentication. These files are licensed and re-distributed unmodified, as links below, under the Apache License, Version 2.0 - http://www.apache.org/licenses/LICENSE-2.0 .

If you plan on using this (or other REST client) within an Android app, you can use the Android Base64 class in the Android SDK that will handle the Encoding instead of the Apache Commons Codec library files. I commented out the import android.util.Base64 in the source. I tried it it works fine as well.

Base Java Class


 *  Written by Tom Gutwin - WebARTS Design.
 *  Copyright (C) 2014 WebARTS Design, North Vancouver Canada
 *  http://www.webarts.ca
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; version 3 of the License, or
 *  (at your option) any later version.
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without_ even the implied warranty of
 *  GNU General Public License for more details.
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

package ca.bc.webarts.tools;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.File;
import java.lang.StringBuilder;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;

//import android.util.Base64;
import org.apache.commons.codec.binary.Base64;

//import ca.bc.webarts.widgets.Util;

/** A class to encapsulate the calls to Restful Web Services. It is kept very basic with low overhead to live in android apps.
public class RestRequester
  protected static String CLASSNAME = "ca.bc.webarts.tools.RestRequester"; //ca.bc.webarts.widgets.Util.getCurrentClassName();
  public static final String LOG_TAG = CLASSNAME;
  public static boolean debugOut_ = false;

  /**  A holder for this clients System File Separator.  */
  public final static String SYSTEM_FILE_SEPERATOR = File.separator;

  /**  A holder for this clients System line termination separator.  */
  public final static String SYSTEM_LINE_SEPERATOR =

  protected static String baseUrl_ = ""; // http://isy994
  public static boolean authenticating_ = true;
  protected static String username_ = "";
  protected static String password_ = "";
  protected static boolean acceptJSON_ = false;

  public void setUsername(String uName){username_=uName;}
  public void setPassword(String uPasswd){password_=uPasswd;}
  public void setBaseUrl(String url){baseUrl_=url;}
  public void setAcceptJSON(boolean acceptJson){acceptJSON_=acceptJson;}
  public String getUsername(){return username_;}
  public String getPassword(){return password_;}
  public String getBaseUrl(){return baseUrl_;}
  public boolean getAcceptJSON(){return acceptJSON_;}

  public RestRequester()

  public RestRequester(String baseUrl)
    setBaseUrl( baseUrl);

  public RestRequester(String baseUrl,String uName,String uPasswd)
    setBaseUrl( baseUrl);
    setUsername( uName);
    setPassword( uPasswd);

  public boolean isInit()
    boolean retVal = true;
    if( baseUrl_.equals("") ||
        (authenticating_ &&
            (username_.equals("") || password_.equals(""))
    return retVal;

  /** Sends the rest service GET request off and retruns the results.
    * @param serviceName is the service (string) to append to the baseURL - example /rest/sys
    * @return the serviceResult as a stringBuilder, null if error
  public StringBuilder serviceGet(String  serviceName)
  { return callService(serviceName, true);}

  /** Sends the rest service POST request off and retruns the results.
    * @param serviceName is the service (string) to append to the baseURL - example /rest/sys
    * @return the serviceResult as a stringBuilder, null if error
  public StringBuilder servicePost(String  serviceName)
  { return callService(serviceName, false);}

  /** Sends the rest service request off and retruns the results.
    * @param serviceName is the service (string) to append to the baseURL - example /rest/sys
    * @param getNotPost is a flag to tell this method to do a get or post based on this flag - true does a GET, false does a POST
    * @return the serviceResult as a stringBuilder, null if error
  public StringBuilder callService(String  serviceName, boolean getNotPost)
    StringBuilder retVal = null;
        String usrlStr = (baseUrl_+serviceName).replace(" " ,"%20");
        URL url = new URL(usrlStr);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
          conn.setRequestProperty("Accept", "application/json");
          conn.setRequestProperty("Accept", "application/xml");

        //BASE64Encoder enc = new sun.misc.BASE64Encoder();
        String userpassword = username_ + ":" + password_;
        //String encodedAuthorization = android.util.Base64.encodeToString( userpassword.getBytes(), android.util.Base64.DEFAULT );
        String encodedAuthorization = new String(Base64.encodeBase64( (userpassword.getBytes()) ));
        conn.setRequestProperty("Authorization", "Basic "+ encodedAuthorization);

        if (conn.getResponseCode() == 200)
          BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
          if (br!=null)
            retVal = new StringBuilder();
            String output;
            if (debugOut_) System.out.println("Output from Server .... \n");
            while ((output = br.readLine()) != null)
              if (debugOut_) System.out.println(output);
        } // valid http response code
      catch (MalformedURLException e)
      catch (IOException e)
    return retVal;

  public StringBuilder responseIndenter(StringBuilder sb)
    StringBuilder retVal = new StringBuilder("");
    int indent = -1;
    boolean opening = false;
    boolean closing = false;
    boolean lf = false;
    char [] sbChar = sb.toString().toCharArray();

    for (int i=0; i< sbChar.length;i++)
      opening = false;
      closing = false;
      lf = false;
        opening = true;
        for (int j=0;j<indent;j++) retVal.append("  ");
      else if (sbChar[i]=='/'&&sbChar[i-1]=='<')
        closing = true;
      else if (sbChar[i]=='>')
        lf = true;
        for (int j=0;j<indent;j++) retVal.append("  ");

    return retVal;


ISY-994 Extension Java Class


 *  Written by Tom Gutwin - WebARTS Design.
 *  Copyright (C) 2014 WebARTS Design, North Vancouver Canada
 *  http://www.webarts.ca
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; version 3 of the License, or
 *  (at your option) any later version.
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without_ even the implied warranty of
 *  GNU General Public License for more details.
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

package ca.bc.webarts.tools.isy;

import ca.bc.webarts.tools.RestRequester;

public class ISYRestRequester extends RestRequester
  protected static String CLASSNAME = "ca.bc.webarts.tools.ISYRestRequester"; //ca.bc.webarts.widgets.Util.getCurrentClassName();
  private static StringBuffer helpMsg_ = new StringBuffer(SYSTEM_LINE_SEPERATOR);

  public ISYRestRequester()
    setBaseUrl( "http://isy994/rest");
    setUsername( "admin");
    setPassword( "*******");

   * Class main commandLine entry method.
  public static void main(String [] args)
    final String methodName = CLASSNAME + ": main()";
    ISYRestRequester instance = new ISYRestRequester();

    /* Simple way af parsing the args */
    if (args ==null || args.length<1)
      if (args[0].equals("test"))
        System.out.println("Testing ISY Rest Service: "+ "/sys");
        StringBuilder resp =  instance.serviceGet("/sys");
        // Parse the command
        String allcommands = args[0];
        for (int i=1;i< args.length;i++) allcommands+=" "+args[i];
        System.out.print("Sending ISY Rest Service: "+allcommands);
        String passedCommand = (allcommands.startsWith("/rest/") ? allcommands.substring(5) : allcommands);
        System.out.println(" ("+passedCommand+")");
        StringBuilder resp =  instance.serviceGet(passedCommand);
        if (resp!=null)
          System.out.println("Response Error");
  } // main

    /** gets the help as a String.
   * @return the helpMsg in String form
  private static String getHelpMsgStr() {return getHelpMsg().toString();}

  /** initializes and gets the helpMsg_
  class var.
   * @return the class var helpMsg_
  private static StringBuffer getHelpMsg()
    helpMsg_ = new StringBuffer(SYSTEM_LINE_SEPERATOR);
    helpMsg_.append("---  WebARTS ISYRestRequester Class  -----------------------------------------------------");
    helpMsg_.append("---  $Revision:$ $Date:$ ---");
    helpMsg_.append("WebARTS ca.bc.webarts.android.ISYRestRequester Class");
    helpMsg_.append("   java ");
    helpMsg_.append(" test or restCommand");
    helpMsg_.append("Available Commands:");
    helpMsg_.append("see: http://wiki.universal-devices.com/index.php?title=ISY_Developers:API:REST_Interface");

    return helpMsg_;


Have fun. I hope it helps someone else get started.

Updated my eISCP Java code

posted Jan 2, 2014, 10:53 AM by Tom Gutwin   [ updated Jan 2, 2014, 10:54 AM ]

I made some important updates to my Java Integra Serial Control Protocol code ( Java eISCP).

See my Blog post.

Rooting My Android Nexus 7

posted Dec 27, 2013, 9:31 PM by Tom Gutwin   [ updated Dec 30, 2013, 9:16 PM ]

xda dev icon
Successfully rooted my device.

Information Links I Used:

issues/wrinkles I ran into:
  • The adb debug server connection was 'touchy''
    • each time I rebooted into recovery:
      • I had to restart the adb server with adb kill-server;sleep3;adb start-server
      • then unplug and re-plug in the Nexus 7
  • the adb push path-to-zip/SuperSU.zip /sdcard command
    • did not work correctly.  Maybe its because the adb push has changed in the way it works towards symbolic links on the device. I suspect something changed on Android 4.2.  Basically it does not put the zip file where you want it.
    • copy it directly to its real device dir (not symbolic linked)
      • adb push path-to-zip/SuperSU.zip /storage/emulated/0

Very Yummy Lemon

posted Dec 13, 2013, 10:52 PM by Tom Gutwin   [ updated Dec 13, 2013, 10:54 PM ]

1 oz Vodka,
1/2 oz Raspberry Vodka,
1 Squeezed lemon,
1/2 oz simple syrup,
1/2 oz triple sec,

Pour over ice
Martini Glass

Excel VBA Reference to Last Cell in table

posted Nov 20, 2013, 11:10 AM by Tom Gutwin   [ updated Nov 20, 2013, 7:20 PM ]

Excel Icon
How many times have I had to loop through rows in an Excel table until I get to the Last Row.  Too Many times and I always forget the quick reference to the row count.
Well here it is as VBA code...
  Dim numRows As Integer
  numRows = ActiveSheet.Columns("A:A").SpecialCells(xlLastCell).Row

See also the MSDN page http://msdn.microsoft.com/en-us/library/office/aa213567%28v=office.11%29.aspx

Use at will!

Nissan Leaf - Test Drive

posted Jul 2, 2013, 5:16 PM by Tom Gutwin

Me in the Leaf
I took a Nissan Leaf EV for a test drive this past weekend.
I had the car over the Canada Day long weekend to experience what it is like to drive an EV.

It was an enjoyable and enlightening experience. I drove it on the highway, to and from work, around North Vancouver and on an errand.  I had no problems with anything, in fact, it convinced both me, and more importantly, my family that our next vehicle will be an EV.

 The idea of an EV has been in my mind for a few years, based on the economics and environmental benefits; however, I had not actually driven a 100% electric vehicle. The qualities the Nissan Leaf demonstrated were:

  • the constant high torque performance
  • the smoothness of the acceleration
  • the quietness
  • no gas
  • the range
  • the roominess
  • overall how well it handled
  • no $1.42/L gas (or did I mention that)

 It was an enjoyable experience… now to start saving for a Tesla!

Resize Windows 7 BootCamp Partition on a MacMini

posted May 27, 2013, 10:47 AM by Tom Gutwin   [ updated May 27, 2013, 10:49 AM ]

Windows On Apple Icon
How did I resize the Windows 7 ( Win7 ) BootCamp partition on my (kids) MacMini?
I have a 2011 MacMini with a 500GB HD that has a 60GB Partition for Windoze7 created by BootCamp.
It became too small to hold all the games that are getting installed :( AND the Mac partition had lots of empty space.

You will need your windows install disc (or recovery disc)
You will need GParted Live iso

Here are the steps I used to increase the size of the Windoze partition:
It worked with NO data loss; however, there was a couple small tweaks to get the MacMini and the Windoze bootLoader to "see" the partition after the resize - see below.
  1. Download GParted live bootable iso
  2. Get a USB flash drive (a 1GB is big enough)
  3. On a linux box
    1. insert the usb drive
    2. go to a command line
    3. type> dmesg
      • to see the device name it connected as
      • mine came up as /dev/sdd
    4. type> sudo dd if=/path-to-gparted-live.x.y.z-w.iso of=/dev/sdd bs=4M; sync
      • this creates the bootable flashDrive
      • IT OVERWITES the entire drive, so make sure you back up its original files.
      • see GParted Live on USB page for other ways to create the USB drive
    5. Unmount the USB drive if it got mounted
      • sudo umount /dev/sdd
  4. On the MacMini:
    1. Shutdown
    2. insert the newly created USB drive - GParted Live
    3. Re-power on and hold the Option key ('alt' key if you have a non-mac keyboard)
      • this brings up the boot selection screen (Startup Manager)
    4. pick the USB drive
      • mac USB Drive boot selection
      • It shows up as the orange Windows icon
    5.  Wait until GParted starts up
    6. run the GParted app by double clickking its desktop icon
      • Shrink the Mac Partition
      • Move the Recovery partition next to the Mac Partition
      • Grow the Windoze partition to fill the space
      • Apply the changes
      • Go get a beer and wait until its done
    7.  Open a command window and type
      • sudo gptsync /path-to-disk-device
      • Where /path-to-disk-device is the device /dev/sdb
      • Find the device names in the upper right drop down in the gparted app
      • do it for the mac and windoze partitions
      • This is so the partitions show up in the mac after the move (see http://gparted.sourceforge.net/faq.php#faq-21
    8. shutdown the gparted live
      • Click the red shutdown icon on the desktop
  5. You now need your Windoze Install disk (flashed onto a USB drive) to fix the windoze bootloader.
    • See my other blog entry on how to flash it.
    • You could now re-use the gparted live usb drive and overwrite it
  6. Insert the Windoze Install USB drive and start the MacMini
    • Hold the Option key while it boots and boot onto the USB Drive as you did in step 4-4
  7. a black Window install screen should come up
    • select the Repair install selection (or was it recovery)
    • It will suggest fixes to the master boot record.
    • I accepted what it recommended
  8. Restart the MacMini (WITHOUT any usb drives)
    • Hold the Option key while it boots to see what partitions show up
    • All your partitions should show up (as in the picture above in 4-4)
  9. choose windows and you should boot into windoze with a bigger c:\ drive!

Review of a Fiskars StaySharp Max Reel Mower

posted May 25, 2013, 4:07 PM by Tom Gutwin   [ updated May 25, 2013, 4:36 PM ]

Fiskars Stay Sharp Max Mower
I bought a Fiskars StaySharp Max Reel Mower. My old push reel mower (Great States) worked okay for 15 years, but it was finally time to put it out to pasture.
I have only 2 small patches of lawn - maybe 55 m2 .

All I can say about this new StaySharp Max Reel Mower is "Wow".
  • The grass just pumped out of the reels.
  • Nice and clean cuts.
  • Very easy to push.
  • I went over the grass twice, but really would have been able to get away with one pass.

With my old mower, I had to go back and forth in different directions about 5-8 times.

Plus I never have to buy any more gas, electricity , or change batteries every 3 years.

1-10 of 63