DOPA is like locking your kids in the basement

I’ve been thinking about the moronically shortsighted DOPA doowackie that got passed South of the Border. Basically, if I understand correctly, it attempts to protect children from online predators (which is a Good Thing To Do�). But, it wants to do this by banning minors from websites that let them contribute. They won’t be able to use MySpace. Or Blogger.com. Or Wordpress.com. Or Flickr.com. Or any other social “Web 2.0” stuff. Kids will be protected by locking them out.

Which is akin to protecting your children from harm by locking them in the basement.

Sure, they’ll be safe, but they’ll be completely isolated and unable to function in a connected, online world once they reach the arbitrarily decided “safe” age of 18 or 21 or whatever silly number got picked from the hat.

You don’t protect kids by locking them away from danger. You cripple them.

And, this assumes the clever kids aren’t aware of anonymizing proxies, or something as difficult as clicking the wrong/right box on a web form, to gain access to verboten sites. Groups are working hard to provide these freedom tools to the oppressed civilians of China, unfairly locked behind the Great Firewall. While simultaneously allowing their government to impose the same arbitrary limitations on their own children.

Thankfully, there has been no word of a Canadian copycat legislation. Yet.

There are better ways to protect kids. The best, and most effective (but most difficult) way is to actually educate them. If they are aware of the issues (in whatever age-appropriate manner) they will be better able to safely cope with dangers. There’s already a handy group forming around this issue.

It’s better to teach kids to swim, than to trust a fence around the swimming pool. Or the lock on the basement door.

I’ve been thinking about the moronically shortsighted DOPA doowackie that got passed South of the Border. Basically, if I understand correctly, it attempts to protect children from online predators (which is a Good Thing To Do™). But, it wants to do this by banning minors from websites that let them contribute. They won’t be able to use MySpace. Or Blogger.com. Or WordPress.com. Or Flickr.com. Or any other social “Web 2.0” stuff. Kids will be protected by locking them out.

Which is akin to protecting your children from harm by locking them in the basement.

Sure, they’ll be safe, but they’ll be completely isolated and unable to function in a connected, online world once they reach the arbitrarily decided “safe” age of 18 or 21 or whatever silly number got picked from the hat.

You don’t protect kids by locking them away from danger. You cripple them.

And, this assumes the clever kids aren’t aware of anonymizing proxies, or something as difficult as clicking the wrong/right box on a web form, to gain access to verboten sites. Groups are working hard to provide these freedom tools to the oppressed civilians of China, unfairly locked behind the Great Firewall. While simultaneously allowing their government to impose the same arbitrary limitations on their own children.

Thankfully, there has been no word of a Canadian copycat legislation. Yet.

There are better ways to protect kids. The best, and most effective (but most difficult) way is to actually educate them. If they are aware of the issues (in whatever age-appropriate manner) they will be better able to safely cope with dangers. There’s already a handy group forming around this issue.

It’s better to teach kids to swim, than to trust a fence around the swimming pool. Or the lock on the basement door.

Vancouver überpano

While we were on the 35th floor of the Coast Plaza Hotel in Vancouver for a session at BCEdOnline2006, I snapped a dozen or so photos of the panoramic view. I was thinking I’d stitch them into separate panos to capture the view, but I just spent a few minutes in Photoshop manually stitching each of the 3 autostitch panos into one überpano, spanning approximately 300˚ of a panoramic view of downtown Vancouver. The full image is 27 megapixels, so if you’ve got a few 30″ Cinema Displays tied to your system, check out the high res. version.

The colour on the left is wonky because I took those shots from inside a conference room, through the tinted glass. The rest of the shots were taken out on the balconies in the other conference room.

Vancouver Uberpano

While we were on the 35th floor of the Coast Plaza Hotel in Vancouver for a session at BCEdOnline2006, I snapped a dozen or so photos of the panoramic view. I was thinking I’d stitch them into separate panos to capture the view, but I just spent a few minutes in Photoshop manually stitching each of the 3 autostitch panos into one überpano, spanning approximately 300˚ of a panoramic view of downtown Vancouver. The full image is 27 megapixels, so if you’ve got a few 30″ Cinema Displays tied to your system, check out the high res. version.

The colour on the left is wonky because I took those shots from inside a conference room, through the tinted glass. The rest of the shots were taken out on the balconies in the other conference room.

Vancouver Uberpano

Google can see my house!

When I first started playing with maps.google.com, I thought it was freaking amazing. Then, I wondered out loud if the Keyhole team was talking to the Maps team.

Apparently, the answer was “yah huh!”

OK. Let’s see if this still works. Google, if you’re listening, you should drive a big ol’ Brinks truck full-o-cash into my garage. You already know where it is…


UPDATE: this is just a blog post. if you want to see your house, go to Google Maps, or Bing Maps, or any of a bunch of other places. This site can’t show you your house. Stop putting your home addresses into the search field on my blog in the hopes of seeing a satellite photo of your house. Seriously. People. Stop.


When I first started playing with maps.google.com, I thought it was freaking amazing. Then, I wondered out loud if the Keyhole team was talking to the Maps team.

Apparently, the answer was “yah huh!”

OK. Let’s see if this still works. Google, if you’re listening, you should drive a big ol’ Brinks truck full-o-cash into my garage. You already know where it is…

JAI vs. ImageMagick image resizing

Part of the functionality of the Pachyderm authoring application is the dynamic and on-the-fly resizing of images to whatever dimensions are required by the flash templates that are used to display a screen in a presentation.

I wrote the first version of the image resizing code using Java Advanced Imaging (JAI), and it worked quite well. But, during the authoring of the Mavericks prototype, it became apparent that the quality of the resized images wasn’t quite up to snuff. I tried setting JAI to use bicubic interpolation (InterpolationBicubic and InterpolationBicubic2) instead of the default nearest-neighbour (InterpolationNearest) method. Still produced inconsistent results.

I had looked at using ImageMagick, using the java JMagick bridge, but that was just plain funky. It relies on a JNI bridge that apparently doesn’t compile well on MacOSX (I never got it compiled, and Google only turned up one person in the history of the internets that had success – on an older version of the OS).

Fast forward to last night. I decided to try an ImageMagick solution using java’s Runtime.exec() – and it works perfectly. Image quality is MUCH better. The memory issues we were seeing with JAI disappeared (JAI was barfing on Very Large Images, where ImageMagick chews through them with ease). The downside is that it takes considerably longer to process the resized images, and since ImageMagick can only work with local files (not URLs), I have to download the image from the web each time I want to process it (this can be done more intelligently – I just haven’t done that yet).

Compare the output of the two resize methods:

JAI vs. ImageMagick Resizing in Pachyderm

Update: I get asked by email every now and then for some sample code to show how we used Runtime.exec() in this case. For the Googlers out there, here ‘s the goods…

	/**
	 * Uses a Runtime.exec()to use imagemagick to perform the given conversion
	 * operation. Returns true on success, false on failure. Does not check if
	 * either file exists.
	 *
	 * @param in Description of the Parameter
	 * @param out Description of the Parameter
	 * @param newSize Description of the Parameter
	 * @param quality Description of the Parameter
	 * @return Description of the Return Value
	 */
	private static boolean convert(File in, File out, int width, int height, int quality) {
		System.out.println("convert(" + in.getPath()+ ", " + out.getPath()+ ", " + newSize + ", " + quality);

		if (quality < 0 || quality > 100) {
			quality = 75;
		}

		ArrayList command = new ArrayList(10);

		// note: CONVERT_PROG is a class variable that stores the location of ImageMagick's convert command
		// it might be something like "/usr/local/magick/bin/convert" or something else, depending on where you installed it.
		command.add(CONVERT_PROG);
		command.add("-geometry");
		command.add(width + "x" + height);
		command.add("-quality");
		command.add("" + quality);
		command.add(in.getAbsolutePath());
		command.add(out.getAbsolutePath());

		System.out.println(command);

		return exec((String[])command.toArray(new String[1]));
	}


	/**
	 * Tries to exec the command, waits for it to finsih, logs errors if exit
	 * status is nonzero, and returns true if exit status is 0 (success).
	 *
	 * @param command Description of the Parameter
	 * @return Description of the Return Value
	 */
	private static boolean exec(String[] command) {
		Process proc;

		try {
			//System.out.println("Trying to execute command " + Arrays.asList(command));
			proc = Runtime.getRuntime().exec(command);
		} catch (IOException e) {
			System.out.println("IOException while trying to execute " + command);
			return false;
		}

		//System.out.println("Got process object, waiting to return.");

		int exitStatus;

		while (true) {
			try {
				exitStatus = proc.waitFor();
				break;
			} catch (java.lang.InterruptedException e) {
				System.out.println("Interrupted: Ignoring and waiting");
			}
		}
		if (exitStatus != 0) {
			System.out.println("Error executing command: " + exitStatus);
		}
		return (exitStatus == 0);
	}

Part of the functionality of the Pachyderm authoring application is the dynamic and on-the-fly resizing of images to whatever dimensions are required by the flash templates that are used to display a screen in a presentation.

I wrote the first version of the image resizing code using Java Advanced Imaging (JAI), and it worked quite well. But, during the authoring of the Mavericks prototype, it became apparent that the quality of the resized images wasn’t quite up to snuff. I tried setting JAI to use bicubic interpolation (InterpolationBicubic and InterpolationBicubic2) instead of the default nearest-neighbour (InterpolationNearest) method. Still produced inconsistent results.

I had looked at using ImageMagick, using the java JMagick bridge, but that was just plain funky. It relies on a JNI bridge that apparently doesn’t compile well on MacOSX (I never got it compiled, and Google only turned up one person in the history of the internets that had success – on an older version of the OS).

Fast forward to last night. I decided to try an ImageMagick solution using java’s Runtime.exec() – and it works perfectly. Image quality is MUCH better. The memory issues we were seeing with JAI disappeared (JAI was barfing on Very Large Images, where ImageMagick chews through them with ease). The downside is that it takes considerably longer to process the resized images, and since ImageMagick can only work with local files (not URLs), I have to download the image from the web each time I want to process it (this can be done more intelligently – I just haven’t done that yet).

Compare the output of the two resize methods:

JAI vs. ImageMagick Resizing in Pachyderm

Update: I get asked by email every now and then for some sample code to show how we used Runtime.exec() in this case. For the Googlers out there, here ‘s the goods…

/**
* Uses a Runtime.exec()to use imagemagick to perform the given conversion
* operation. Returns true on success, false on failure. Does not check if
* either file exists.
*
* @param in Description of the Parameter
* @param out Description of the Parameter
* @param newSize Description of the Parameter
* @param quality Description of the Parameter
* @return Description of the Return Value
*/
private static boolean convert(File in, File out, int width, int height, int quality) {
System.out.println(“convert(” + in.getPath()+ “, ” + out.getPath()+ “, ” + newSize + “, ” + quality);

if (quality < 0 || quality > 100) {
quality = 75;
}

ArrayList command = new ArrayList(10);

// note: CONVERT_PROG is a class variable that stores the location of ImageMagick’s convert command
// it might be something like “/usr/local/magick/bin/convert” or something else, depending on where you installed it.
command.add(CONVERT_PROG);
command.add(“-geometry”);
command.add(width + “x” + height);
command.add(“-quality”);
command.add(“” + quality);
command.add(in.getAbsolutePath());
command.add(out.getAbsolutePath());

System.out.println(command);

return exec((String[])command.toArray(new String[1]));
}

/**
* Tries to exec the command, waits for it to finsih, logs errors if exit
* status is nonzero, and returns true if exit status is 0 (success).
*
* @param command Description of the Parameter
* @return Description of the Return Value
*/
private static boolean exec(String[] command) {
Process proc;

try {
//System.out.println(“Trying to execute command ” + Arrays.asList(command));
proc = Runtime.getRuntime().exec(command);
} catch (IOException e) {
System.out.println(“IOException while trying to execute ” + command);
return false;
}

//System.out.println(“Got process object, waiting to return.”);

int exitStatus;

while (true) {
try {
exitStatus = proc.waitFor();
break;
} catch (java.lang.InterruptedException e) {
System.out.println(“Interrupted: Ignoring and waiting”);
}
}
if (exitStatus != 0) {
System.out.println(“Error executing command: ” + exitStatus);
}
return (exitStatus == 0);
}

reBeLog » WebObjects thoughts.

David just published a great post on developing with WebObjects. He really boils down the WebObjects development experience into a few bullet points, which I will copy/paste here for searchability…

The last point is really the best one – I’ve come across this so many times on CAREO and Pachyderm. We’ll be building away and I’ll just stop and say something lame like “Wait – this is getting too complicated. There has to be an easier way…”

  1. Don’t fight the tool – WebObjects and EOF are very flexible and rich in capablilites. Get to know the way they work and work with them. Don’t fight them – they will win. Read the sample code from Apple and the source for Project WONDER. When you write your code emulate their style. The really good stuff is just below the surface (Key Value Coding for example). That’s where the power lives, dig a little, you will be rewarded.
  2. Follow the commandments – A few simple rules that will prevent a world of hurt.
  3. Let someone else write the code – I’ve mentioned a number of sources of WebObjects frameworks in my posts (Project WONDER, SwitchableStrings, WOCode ), they provide an amazing amount of functionality that you don’t need to implement yourself, that’s the entire point of OO design isn’t it? Also, when you build something useful, factor it out into your own reusable framework – why would you want to write something twice? Finally, use EOGenerator – no really – use it. There is no excuse not to.
  4. Model it right the first time – Every time I’ve been tempted to cut corners on my model, it’s come back to bite me. A strong Model will allow your App to almost write itself. My general rule of thumb: If I can’t get from one object to a “related” one via KVC, I’m going to be grumpy.
  5. If it is getting complicated, you’re probably doing it wrong
    • You’re fighting the tool aren’t you?
    • Maybe WebObjects is the wrong tool.

    Please, don’t try to hack around the WebObjects architecture. i.e. If you really need multiple concurrent access to your database everywhere in your application – use something other than EOF.

David just published a great post on developing with WebObjects. He really boils down the WebObjects development experience into a few bullet points, which I will copy/paste here for searchability…

The last point is really the best one – I’ve come across this so many times on CAREO and Pachyderm. We’ll be building away and I’ll just stop and say something lame like “Wait – this is getting too complicated. There has to be an easier way…”

  1. Don’t fight the tool – WebObjects and EOF are very flexible and rich in capablilites. Get to know the way they work and work with them. Don’t fight them – they will win. Read the sample code from Apple and the source for Project WONDER. When you write your code emulate their style. The really good stuff is just below the surface (Key Value Coding for example). That’s where the power lives, dig a little, you will be rewarded.
  2. Follow the commandments – A few simple rules that will prevent a world of hurt.
  3. Let someone else write the code – I’ve mentioned a number of sources of WebObjects frameworks in my posts (Project WONDER, SwitchableStrings, WOCode ), they provide an amazing amount of functionality that you don’t need to implement yourself, that’s the entire point of OO design isn’t it? Also, when you build something useful, factor it out into your own reusable framework – why would you want to write something twice? Finally, use EOGenerator – no really – use it. There is no excuse not to.
  4. Model it right the first time – Every time I’ve been tempted to cut corners on my model, it’s come back to bite me. A strong Model will allow your App to almost write itself. My general rule of thumb: If I can’t get from one object to a “related” one via KVC, I’m going to be grumpy.
  5. If it is getting complicated, you’re probably doing it wrong
    • You’re fighting the tool aren’t you?
    • Maybe WebObjects is the wrong tool.

    Please, don’t try to hack around the WebObjects architecture. i.e. If you really need multiple concurrent access to your database everywhere in your application – use something other than EOF.