Skip to content

Toronto Java Users Group, 4th year!


The Toronto Java Users Group is back for its fourth great year. Things are going well, we have a nice steady group of reg­u­lars. We still meet at the Free Times Cafe, and the meet­ings have a nice social aspect. Present­a­tions are short and sweet, and we try to avoid blatant product pitches.

If you’re into Java, and you’re in the GTA, you should totally join us. Third Thursday of each month, Free Times Cafe, 7pm start.

Check out the TJUG site for more info!

Programmers are Objects

This is a dis­turb­ing thread from my email (names have been changed to pro­tect the innocent):

From: John Smith
To: Dan

Dan,
I got your email from your blog, linked from the Toronto Java Users Group.
Won­der­ing if you or any of your friends / con­tacts may be inter­ested in
Java Developer oppor­tun­it­ies in down­town Toronto?

Do you have any con­tacts you could send my way or for­ward this email to?

Thank you,
John Smith
416−555−1212

My very snarky, sar­castic reply:

From: Dan
To: John Smith

If I sell you my friends, do I get a cut of your commission?

John seemed to miss my snark and replied with a ser­i­ous reply:

From: John Smith
To: Dan

Dan,

I’m defin­it­ively open to that.

Just to be com­pletely hon­est and open you should know, I’m only start­ing out and am a sourcer for another Recruiter. Which means I’ll get about $400 for a suc­cess­ful place­ment that the Recruiter gets $5000 for.

But of course, out of my $400, you can get a piece, and hope­fully in time when I become a full-fledged Recruiter our rela­tion­ship will con­tinue to produce.

John

You learn some­thing new every day.

Review: Insteon LampLinc Dual-Band 2457D2

I am extremely dis­ap­poin­ted with this product. It has ser­i­ous design and qual­ity flaws.

I’ve been invest­ig­at­ing put­ting some Insteon devices in my house to con­trol my lights and appli­ances, so I ordered a few samples. I ordered a wire-in dim­mer (2876DB), a 2-wire wire-in dim­mer kit (2474D), a power­line modem/computer inter­face (2413U) and the above-mentioned plug-in lamp module.

My first hint of the qual­ity prob­lems with this lamp mod­ule came when I first plugged a lamp into it. The plug just didn’t fit right. It seemed to bot­tom out long before it was com­pletely inser­ted. Com­plete inser­tion was pos­sible with a bit of wig­gling and force, but then the plug didn’t make a proper con­nec­tion. The plug only con­nec­ted prop­erly when it was inser­ted about 2/3 of the way, which is not a safe condition.

I took the device apart to invest­ig­ate (luck­ily this was easy — just remove four screws on the back). I was quite sur­prised by what I found! The reason the plug didn’t fit was clear — the screws hold­ing the con­tacts to the device’s case were inter­fer­ing with the plug! Check it out:

This is a totally puzz­ling design flaw. Didn’t they ever try actu­ally insert­ing a plug? How could this product even get past a pro­to­type stage? It’s pos­sible that my unit is defect­ive or built incor­rectly, but I don’t see any other way it could be put together.

When I showed it to my friend Andrew, he noticed another crit­ical flaw. The alu­minum heat­sink for the dim­mer triac inside could touch one or both out­put ter­min­als, caus­ing a short cir­cuit. This could eas­ily hap­pen if the device was dropped or shaken when powered on, and it would def­in­itely cause the device to be des­troyed. I got out a mul­ti­meter and tested it, put­ting one probe on the out­put ter­minal and the other on the heat sink, and a slight press on the heat sink caused a short cir­cuit. Take a look:

I added a small piece of high-temperature Kapton tape to the under­side of the heat sink so I could feel bet­ter about this device and reas­sembled it. I’ll prob­ably use it, but I cer­tainly won’t buy another one. It’s total junk. For $50, I didn’t expect excel­lent qual­ity, but I at least expec­ted to get some­thing safe and reliable.

Hope­fully my other Insteon devices will be better.

Rotate This RSS Revisited

About five years ago, I wrote a script to scrape the web­site of Rotate This and repub­lish their con­cert ticket list­ing as an RSS feed. Every six hours for five years I’ve hit their site and updated my data­base. The RSS feed has quite a few users, using Feed­Burner, Google Reader, Bloglines and a few other mis­cel­laneous RSS view­ers. It’s one of the most fre­quently hit pages on my site.

I wanted to try out the new Google AppEn­gine ser­vice, and was look­ing for a simple pro­ject, so I figured I could port my little scraper. It seemed like per­fect fit.

Google AppEn­gine is a unique applic­a­tion host­ing ser­vice. It’s not really clas­sical web host­ing, and it’s not really a vir­tual server. You gen­er­ate a Java web applic­a­tion, bundle it as a .war file, and deploy it to AppEn­gine. Google’s magic voo­doo makes sure that your app is hos­ted on at least two serv­ers, that it will scale auto­mat­ic­ally for load, that it will start up quickly, and that it will always have access to its data. There are some restric­tions, how­ever: no request to your app can take longer than a few seconds to pro­cess, and there are strict size lim­its for data stor­age access and request/response size. It can’t start threads, it can’t access the disk, it can’t use too much memory.

There is no real “backend” access to your app either; all access must hap­pen though a URL. The Cron ser­vice simply calls a spe­cified URL within your applic­a­tion on reg­u­lar intervals.

A big advant­age to AppEn­gine is that their basic ser­vice is free. The quotas for requests, data trans­fer and CPU time under the free ser­vice level are very high. Any­thing that exceeded them I would call a very suc­cess­ful app — it is unlikely I will ever have to buy more capa­city. The free ser­vice includes over a mil­lion requests and a giga­byte of data trans­fer per day.

I spent a couple of days work­ing on it — AppEn­gine was easy to learn but had a few quirks. My older code was in Perl (the scraper) and PHP (the RSS gen­er­ator) using MySQL as a backend. The AppEn­gine code is all Java, using Google’s data­store through Java Data Objects. I had never used JDO before, so there was a bit of a learn­ing curve there. Everything else was straight for­ward, using the URL Fetch ser­vice to get the Rotate This ticket page, and using the Cron to sched­ule the scrape every six hours.

On the out­put side I was able to take advant­age of the rich Java eco­sys­tem, using ROME to gen­er­ate the RSS feed, and using ICal4J to gen­er­ate the new iCal feed that I was adding on. Both worked fine on AppEngine’s restric­ted Java runtime.

So, here are the links, give it a try!

Rotate This Tick­ets RSS Feed: http://rotatethisrss.appspot.com
Rotate This Tick­ets iCal Feed: http://rotatethisrss.appspot.com/ical

Let me know how it goes!

p.s. I redir­ec­ted the old link to AppEn­gine — if you were using this before, you shouldn’t have to change anything.

Roomba 560 Repair!

My Roomba 560 was mak­ing clunk­ing noises as it drove around… I think it was the safety clutch some­where in the brushes driv­etrain. I took out the brushes and cleaned as much cat hair as pos­sible, but there was some jammed in one of the square drives in the side of the brush hous­ing. I couldn’t get that out, so I decided to take apart the Roomba and its brush mod­ule and see what was going on.

Dis­as­sembly was easy. There are quite a few different-sized screws, so keep them organ­ized… but take it easy, don’t force any­thing, and you should have no trouble get­ting into the gears. I lub­ric­ated things with some Tri-Flow syn­thetic grease (which is safe for plastic) and put it back together.

Here’s a little video I made of the pro­cess:
YouTube Preview Image

Watch it in HD for best res­ults! Note the screw that got away when I pulled off the spin­ning brush at the front… I found it again, but take some pre­cau­tions so this doesn’t hap­pen to you as well.

Social Network Downsizing

A few days ago, I got a sud­den feel­ing that I was on too many social net­works and my inform­a­tion was spread too far out of my con­trol on the inter­net. I was also read­ing a lot about Face­book’s pri­vacy prob­lems and their erosion of user con­trols in order to bet­ter mon­et­ize their inform­a­tion 1, 2, 3. Dur­ing the pro­cess of quit­ting Face­book, the site showed me pic­tures of my friends, and told me that they would miss me. It said “your 153 friends won’t be able to com­mu­nic­ate with you any­more!” Scary.

I was also reg­u­larly using Foursquare, which is a social net­work­ing applic­a­tion that lets you “check in” at vari­ous phys­ical loc­a­tions and see who else is there. If you check in to a place more than any­one else, you become “Mayor,” and if you check in at the right sequence or num­ber of places, you can win “badges.” This was fun for a while, I was Mayor of sev­eral places, and I had lots of badges, but I didn’t feel I was get­ting any­thing out of it, and Foursquare was get­ting a lot of valu­able inform­a­tion. I for­got to “check in” at work for a few days, and when I real­ized this, it was time to fin­ish with Foursquare.

I also had sev­eral near-dormant accounts with Instant Mes­sage ser­vices. I had an MSN account, a Yahoo account, an AIM account and a Google Talk account. I’m on LinkedIn, and Twit­ter, Last.Fm, You­Tube and Vimeo, and who knows what other ser­vices I don’t remem­ber at this point. Too many.

I have been using Passpack to organ­ize my online pass­words, which I’ve been happy with. They have a very strong secur­ity policy, a sane pri­vacy policy, and I pay for ser­vice, which feels a bit more safe as well. As I’ve been chan­ging pass­words and enter­ing them into Passpack, it has given me a view of just how many accounts I have! I have over 40 entered so far, and there are a lot more to go.

So, I’ve been clean­ing this up a bit. I’ve decided that I want to focus on my blog/website, my Twit­ter, and my Google Talk. I’m going to share videos with You­Tube, at least until Vimeo improves their iPhone sup­port. Almost everything else, I’m going to get rid of. If you happened to talk to me on one of the ser­vices I’ve deleted, you can always find me here. Check the “Con­tact Info” box on my blog, or just call me on the phone.

Removed so far:

  • Face­book
  • Foursquare
  • Microsoft Live Messenger
  • Yahoo Mes­sen­ger
  • AOL Instant Messenger
  • Last.fm
  • LinkedIn
  • MySpace

… and more to come.

So far, this feels pretty good! I’ve been focus­ing on ser­vices that feel less evil, don’t try to col­lect as much per­son­ally identi­fy­ing inform­a­tion, and who are at least more subtle about their attempts to mon­et­ize me.

Controlling MasterConsole IP 116 with Groovy

At work we have a KVM switch for our test rack, the very nice Mas­ter­Con­sole IP 116, from Rar­itan. The switch has a com­pet­ent web user inter­face, but no pub­lished auto­ma­tion API. I guess it’s reas­on­able to assume that nobody would want to auto­mate a KVM switch, but once in a while, you might find a need.

We have a large screen hooked into the switch’s video out­put, and we want to switch which input we’re watch­ing on a fairly reg­u­lar basis. One click access would be ideal, but the web UI forces you to log in, select the desired input from a drop­down menu, and click a “switch input” button.

I wrote a small Groovy script using the Htm­lUnit test­ing frame­work to auto­mat­ic­ally nav­ig­ate the web UI, which was totally pain­less and didn’t require any reverse engineering.

Check out the script… you might find the concept use­ful for auto­mat­ing your own interactive-only device.

package com.onestopmedia.kvmcontrol

import com.gargoylesoftware.htmlunit.WebClient
import com.gargoylesoftware.htmlunit.html.*

class KvmControl {
  public static main(args) {
    def cli = new CliBuilder (usage: "KvmControl")
    cli.u(longOpt: "username", "set username", args: 1)
    cli.p(longOpt: "password", "set password", args: 1)
    cli.i(longOpt: "input", "set input (0-15)", args: 1)
    cli.q(longOpt: "query", "query current input only")
    cli.h(longOpt: "help", "usage information")

    def opt = cli.parse(args)
    if (!opt) return
    if (opt.h) cli.usage()

    def webClient = new WebClient();
    def page = webClient.getPage("http://192.168.7.3/auth.asp") as HtmlPage
    def loginForm = page.getForms().get(0) as HtmlForm

    loginForm.getInputByName("login").setValueAttribute(opt.u)
    loginForm.getInputByName("password").setValueAttribute(opt.p)
    def button = loginForm.getInputByName("action_login") as HtmlImageInput
    def page2 = button.click() as HtmlPage

    def dataFrame = page2.getFrameByName("data")
         .getEnclosedPage() as HtmlPage
    def selectForm = dataFrame.getForms().get(0) as HtmlForm
    def inputSelect = selectForm.getSelectByName("ECG_kvm_active_port")
        as HtmlSelect
    if (opt.q) {
       def currentlySelected = inputSelect.getSelectedOptions()[0] as HtmlOption
       println ("currently selected: "+currentlySelected.getText()
          +" ["+currentlySelected.getValueAttribute()+"]")
    } else {
       inputSelect.setSelectedAttribute(opt.i,true) as HtmlPage
       def switchButton = selectForm.getInputByName("action_switch")
       def page3 = switchButton.click() as HtmlPage;
    }
  }
}

Ever wonder why your Wi-Fi is slow?

I can see 62 dif­fer­ent access points from my apart­ment. Only two or three are carrier-grade hard­ware, the rest are just people’s home routers. I can only see three that are on 5GHz though, and one of those is mine. If you’re in a really WiFi-dense area (ie, any­where down­town) you will get quite a bit of bene­fit from a 5GHz (802.11n) upgrade, at least for a while…

OS X Chrome Bookmarks Export

google_chrome_logo
Chrome for OS X is lack­ing a book­mark export fea­ture. I’m sure it will have one in the future, but it doesn’t have it yet. It will hap­pily import your moz­illa book­marks and let you get star­ted using the browser, but even­tu­ally you will notice that your book­marks are locked in. It only recently got a very rudi­ment­ary book­mark man­ager in the latest nightly builds, but there is still no export.

The Chrome book­mark file in OS X is a simple JSON data­base, so I whipped up a quick tool in Groovy to do the export. This was really a single-use pro­ject but I figured I would post the source and bin­ar­ies in case someone else needs it.

Usage: java -jar ChromeExport.jar > mybookmarks.html

By default it will find the cur­rent user’s “Default” Chrome pro­file. Since Chrome doesn’t seem to have any UI for man­aging pro­files, I don’t see why you’d have a dif­fer­ent one.

Require­ments to build/run:
* Groovy 1.6+
* Commons-Lang (for the StringEs­ca­peUt­ils)
* json-simple (for the JSON parser)

Here is a link to the source: ChromeExport.groovy
Here is a link to the fully bundled bin­ary (which prob­ably breaks somebody’s license agree­ment some­where, but com­pli­ance is not worth the annoy­ance): ChromeExport.jar

Enjoy! Let me know what you think, or if it works for you!