Saturday, July 28, 2007

How stupid drug laws get made

I received an email from Sandra Kanck's staff today - it's about the cultivation of controlled plants.
I got it because I was so pissed off about other issues she's raised being completely suppressed and ignored by the state government.

Basically, there's a pollie, Dennis Hood, who's trying to introduce harsher punishments for cultivating marijuana. On the face of it, there's absolutely nothing wrong with that, is there?

In fact I'd have no trouble supporting what Dennis Hood was trying to do if it was based on anything resembling a sensible argument, either.

The problem with it is at least some of the people growing small quantities of majiuana are doing it for medical use - these aren't crime lords.

Dennis' argument is:
  • Other states are 'harsher' than us, so we should come into line with them.
  • Marijuana causes psychosis
The problem with the first is that it's an example of "fit in with everyone, otherwise we're a loser". This kind of high school popularity contest attitude has no place in policy.

The problem with the second is there are many examples of scientific argument which cast doubt on the link between psychosis and marijuana use. I'd be happy to wash my concerns away if Dennis were to provide his own scientific argument on this issue; but instead of doing that, he's relied on The Advertiser as his source of facts.

With that in mind, for him to:
... increase the penalties for cultivation to a fine of up to $10 000, imprisonment for two years, or both, for growing 10 plants or fewer.
seems absolutely stupid.

Back in 2002, the fine for cultivating a plant was $150 per plant. It doubled recently to $300 per plant. Up to $10,000 in total is a huge and almost unreasonable increase - a $7000 increase for the same maximum quantities.

If I were to grow marijuana, and I were to do it for pain alleviation, knowing that I could have to shell out $10,000 and spend two years in jail would scare the bejesus out of me. Sure, I probably wouldn't be growing 10 plants, but the threat still looms.

I wouldn't take the risk, personally - I'd just find someone else to buy it from.

So another issue here is that my money would go directly into the hands of exactly the people Dennis is trying to stop - organized criminals using marijuana as a revenue earner.

It's facts like:
Members may have seen a recent article in the Independ­ent Weekly which highlighted the potential (under the Criminal Assets Confiscation Act) for someone to lose their home, by growing just four marijuana plants.

that really stick in my craw, and make me wish that Family First wouldn't try to blindly apply their beliefs and opinions to everyone - in this case, trying to make it the law.

Read up yourselves, make your own minds up: Read the Wed 25th July's State Parliament Hansard.

Monday, July 23, 2007

Saturday, July 21, 2007

PhotoSynth, Seadragon, BeOS and Jef Raskin's THE

My friend James pointed to TED demo of seadragon/photosynth.

Think of it as a two part thing

  • Seadragon is a rendering engine for images, which is really fast and only needs as much memory as your screen resolution needs

  • PhotoSynth is automatic linking of images to make 3D models



Go and watch the demo if you have no idea what I just said.

There's a live demo too.

The interaction with SeaDragon reminded me of Jef Raskin's zooming user interface (8mb swf)

Pretty sweet.

I always wanted to build something like it, after playing with a photo+wireframing tool (It was like a poor man's google sketchup) when I was about 13. You'd get an image, draw a cube, and texture it, get another image, texture, hey presto, easy digital model. Unfortunately, adobe bought it and snuffed it, and I have no freakin' idea on how to build something like they have.

The performance of SeaDragon reminded me of a BeOS demo video - a lot of things going one at once.

Wednesday, July 18, 2007

My Chiropractor

I'm just going to take a moment to make a shameless promotional plug for my chiropractor. He's Dr James Sparrow, of Fullarton Chiropractic Clinic.

The reason I'm doing this is because I'm far too busy to remember his name or business day to day; and every time I've gone there, it's been well worth it. He's a chiropractor I definitely trust - and his fees are very reasonable.

These qualities are what I look for. I've been to one or two other chiropractors before this. Usually, the visits were along the lines of: "We need an x-ray, $X please; and you'll have to make 60 sessions at the very least, $X^2 each; oh and no; we don't even know what's wrong with you yet, and we don't really care."
Suffice to say, I've quickly left, thinking they were simply after my money.

What's upsetting though, is Dr Sparrow is a very good chiropractor - but I can't google him. My efforts of google local have only brought up the dodgy ones. So in an effort to rectify that...


Fullarton Chiropractic Clinic - Dr James Sparrow

Cnr Florence Street & Glen Osmond Road
Fullarton, South Australia, 5063
t. (08) 8379 3044

Sunday, July 08, 2007

The Hardest to Use Site of the Day

Harvey Norman doesn't understand the web.

What's got my goat:

  • Typing harveynorman.com.au doesn't resolve the site.

  • There is no search functionality, so I cannot buy a roomba from them

  • The site is a giant, unusable, junk mail website.

  • Everything I click on appears to be a popup window with a flash movie in it about a product that is featured. I don't care about an action movie featuring a digital camera, I just want to know about the product.

  • There is no Contact Us link of any kind, so I can't even ring someone to answer my questions, or email them in.

  • I do believe I can see a MARQUE tag, filled with text. I don't care about moving text, it just gives me a headache.

  • The catalog section is a flash feature of their current junk mail catalog. I can download it as a PDF, too. Best of all, the detailed text is too small and blurry for me to actually read.


Thank you, Harvey Norman, for giving me a way to experience junk mail on the web like I never have before.

The Catalog

If you don't get what the web is about, stay off of it! You'd never open a brick and mortar store; then provide no staff; have all of your information available only in crappy unreadable catalogs; and plaster advertising all over it.

Wednesday, July 04, 2007

Making Useful PHPUnit results

So you have about eleven billion test results, and you need a pretty way to quickly see failures.
What you need is a continous integration environment, and if you don't want to have to stick things into a database, I have the answer for you.

PHPUnit 3.0.6 provides (the first working) version of test-results as JSON.
Basically, you run:
phpunit --log-json results.js MyTest.php


And out comes JSON.

The next step is pretty simple - you just need a bit of Prototype magic, some css, and some love.
What you end up with is:
Our Tests

Here's the javascript, php, and css behind it. I'll leave it up to you to find nice icons.

<?php
$file = dirname(__FILE__) . '/results.js';
if (!file_exists($file)) {
die("No unit tests have been run?");
}
$json = file_get_contents($file);

//Ugh
$json = '[' . str_replace("}{", "},{", $json) . ']';

?>
<html>
<head>
<script src="/prototype.js"></script>
</head>
<body>
<style>
table {
border: 1px solid rgb(240, 240, 240);
}

.error {
border: 1px solid orange;
}

.fail {
border: 1px solid red;
}

.pass {
border: 1px solid green;
}

.cell {
width: 200px !important;
text-align: center;
padding: 0.5em;
}
.cell img {
display: block;
margin: auto;
}

h4 {
font-weight: normal !important;
font-style: italic;
}
</style>
<script type="text/javascript">
var total_passes = 0;
var total_failures = 0;
var total_errors = 0;
var total_skipped = 0;
var total_incomplete= 0;

function renderSuiteStart(item) {
var h2 = document.createElement("H2");
h2.appendChild(document.createTextNode(item.suite));

var p = document.createElement("p");
p.appendChild(document.createTextNode(item.tests + " tests in suite"));

var div = document.createElement("div");
var table = document.createElement("table");

div.id = item.suite;
table.id = item.suite + "_table";
table.className = '';

div.appendChild(h2);
div.appendChild(p);
div.appendChild(table);

$('main').appendChild(div);
}

function renderTest(item) {
var h3 = document.createElement("H3");
var h4 = document.createElement("H4");
h3.appendChild(document.createTextNode(item.test));

var p = document.createElement("p");
p.appendChild(document.createTextNode(item.time + " tests in suite"));

var tr = document.createElement("TR");
var th = document.createElement("TH");
var message = document.createElement("TD");
var detail = document.createElement("TD");
var time = document.createElement("TD");
var img = document.createElement("IMG");
var backtrace = document.createElement("OL");


time.appendChild(document.createTextNode(item.time));


img.alt = item.status;
message.className = item.status + " cell";

switch (item.status) {
case 'error':
if (item.message == "Skipped Test") {
message.className = "skipped cell";
total_skipped++;
} else if (item.message == "Incomplete Test") {
message.className = "incomplete cell";
total_incomplete++;
} else {
total_errors++;
}
img.src = '/presentation/common/img/emblem-important-small.gif';
break;
case 'fail':
total_failures++;
img.src = '/presentation/common/img/cross.gif';
break;
default:
total_passes++;
img.src = '/presentation/common/img/check.gif';
break;
}

item.trace.each(
function(trace) {
var li = document.createElement("LI");
var text = trace.file + "(line " + trace.line + "): " + trace.class + trace.type + trace.function + "()";
li.appendChild(document.createTextNode(text));

backtrace.appendChild(li);
}
);

h4.appendChild(document.createTextNode(item.test));
detail.appendChild(h4);
detail.appendChild(backtrace);

message.appendChild(img);
message.appendChild(document.createTextNode(item.message));
message.style.width = "300px";

tr.appendChild(message);
tr.appendChild(detail);


$(item.suite + "_table").appendChild(tr);
}

function renderResults() {
var data = $A(<?php print $json; ?>);

data.each(function(item) {
switch (item.event) {
case 'suiteStart':
renderSuiteStart(item);
break;
case 'test':
renderTest(item);
}
});

renderTOC();
}

function renderTOC() {
var fail = $A(document.getElementsByClassName('fail'));
var pass = $A(document.getElementsByClassName('pass'));
var error= $A(document.getElementsByClassName('error'));
var skipped= $A(document.getElementsByClassName('skipped'));
var incomplete= $A(document.getElementsByClassName('incomplete'));

var menu = document.createElement('p');
var checkbox_pass = document.createElement('input');
var checkbox_fail = document.createElement('input');
var checkbox_error = document.createElement('input');
var checkbox_skipped = document.createElement('input');
var checkbox_incomplete = document.createElement('input');

var label_pass = document.createElement('label');
var label_fail = document.createElement('label');
var label_error = document.createElement('label');
var label_skipped = document.createElement('label');
var label_incomplete = document.createElement('label');
var status_image;

menu.style.position = 'fixed';
menu.style.bottom = 0;
menu.style.right = "1.5em";
menu.style.backgroundColor = 'rgb(240, 240, 240)';
menu.style.padding = "1em;";
menu.style.fontWeight = 'bolder';

checkbox_pass.type = "checkbox";
checkbox_fail.type = "checkbox";
checkbox_error.type = "checkbox";
checkbox_skipped.type = "checkbox";
checkbox_incomplete.type = "checkbox";

checkbox_pass.checked = "checked";
checkbox_fail.checked = "checked";
checkbox_error.checked = "checked";
checkbox_skipped.checked = "checked";
checkbox_incomplete.checked = "checked";


checkbox_pass.onclick=function(){toggle(pass)};
checkbox_fail.onclick=function(){toggle(fail)};
checkbox_error.onclick=function(){toggle(error)};
checkbox_skipped.onclick=function(){toggle(skipped)};
checkbox_incomplete.onclick=function(){toggle(incomplete)};

label_pass.appendChild(checkbox_pass);
label_fail.appendChild(checkbox_fail);
label_error.appendChild(checkbox_error);
label_skipped.appendChild(checkbox_skipped);
label_incomplete.appendChild(checkbox_incomplete);

label_pass.appendChild(document.createTextNode("Passed (" + total_passes + ")"));
label_fail.appendChild(document.createTextNode("Failed (" + total_failures + ")"));
label_error.appendChild(document.createTextNode("Error (" + total_errors + ")"));
label_skipped.appendChild(document.createTextNode("Skipped (" + total_skipped + ")"));
label_incomplete.appendChild(document.createTextNode("Incomplete (" + total_incomplete + ")"));

label_pass.style.color = "green";
label_fail.style.color = "red";
label_error.style.color = "#FF6600";
label_skipped.style.color = "blue";
label_incomplete.style.color = "gray";

status_image = document.createElement("IMG");
status_image.style.display = "block";
status_image.style.margin = "auto";
if (total_failures > 0) {
status_image.src = "/presentation/common/img/emblem-unreadable.png";
} else {
status_image.src = "/presentation/common/img/compliance.png";
}
menu.appendChild(status_image);

menu.appendChild(label_pass);
menu.appendChild(label_fail);
menu.appendChild(label_error);
menu.appendChild(label_skipped);
menu.appendChild(label_incomplete);

checkbox_pass.onclick();
checkbox_pass.checked = "";

checkbox_skipped.onclick();
checkbox_skipped.checked = "";

checkbox_incomplete.onclick();
checkbox_incomplete.checked = "";

document.body.appendChild(menu);
}

function toggle(type) {
type.each(function(td) {
if (td.parentNode.style.display != 'none') {
td.parentNode.style.display = 'none';
} else {
td.parentNode.style.display = 'table-row';
}
});
}

function hide(type) {
type.each(function(td) {
td.parentNode.style.display = 'none';
});
}

function show(type) {
type.each(function(td) {
td.parentNode.style.display = 'table-row';
});
}

window.onload = renderResults;
</script>
<div id="main" class="contentbox">
<h1>Unit tests</h1>
<p><a href="results.txt">Raw results</a> | <a href="docs.html">Agile Documentation</a> | <a href="recent.php">Recent changes</a> | Generated: <?php print date("F j, Y, g:i a", filemtime($file)); ?> </p>
</div>
</body>
</html>