@madpilot makes

Two computers, three monitors and some funky software

At Bam, I’ve had a second 19″ Dell LCD sitting idle on my desk for a while. Why has it been idle? Because the video card on my desktop doesn’t support multiple monitors. This was quite depressing as I love dual monitors, but I didn’t have time to find a card that would work for me (My box is half height, and only supports PCI express severely limiting my card choices).

Then I discovered a little piece of software called Maxivista, which allows you to use a second computer as a virtual video card. It just so happens that my laptop supports an additional monitor as well as the built in laptop and since I take it to work most days it was a perfect candidate for the Maxivista treatment. By downloading the Pro version (about $50AU) I managed to set up THREE, count them THREE monitors! The image below shows my setup:

My three monitor setup!

The way it works is simple, yet ingenious – on the host (or server) you install the “virtual video cards”, which is just a software driver. The drivers appear to the host as a normal video card. You need to start a virtual card for each virtual monitor you want to support (I setup two). Then on the client/s you install a small app, which receives the video signal. I run two different instances of the software on my laptop, so I get two different monitors.

The lag is surprisingly low! For day-to-day development work, you don’t notice it at all. I was watching a YouTube video on the second monitor today and it was pretty smooth, although you wouldn’t be able to watch a DVD or play a game, but it is still pretty darn impressive!

I’d also recommend installing UltraMon – it allows you to add a discrete taskbar to each window, which makes organising you desktop even easier. I have my IDE in one window, a test browser in my second and my “Getting stuff done” stuff (time tracking, task lists etc) on my third. It is panoramic bliss! :)

Transparent PNGs in IE6 using nothing more than a conditional statement and stylesheet

First of all, I know that IE 7 supports transparent PNGs out of the box, but it would seem the uptake isn’t as grand as everyone was hoping – out of readers of Bloggy Hell this month, 23% viewed with IE 6 and 2% viewed with IE 7 and the 88 Miles statistics show something pretty similar, so IE 6 support is still a requirement for most web developers.

Background:

PNGs support 128bit transparency, meaning you can using many levels of opaqueness, avoiding ugly “jaggies” that are so common with GIF images. GIFs only support 1 bit, which means only one colour can be transparent – too bad if you are anti-aliasing the image.

However, Internet Explorer 6 doesn’t support transparency without some IE only hacks. Most versions of the hack presented use inline CSS styles or JavaScript, which I always found as an unacceptable solution. The following works with foreground and background images (mostly), doesn’t use JavaScript, allows you to separate you presentation (CSS), behaviour (JavaScript) and content layers (HTML) and is standards compliant!.

1. Assign a class or id name to all the PNG images you need to convert.

<img alt="This image should be transparent" class="my_png" src="my_png.png">

2. Create a separate IE only stylesheet.

img.my_png {
    width: 16px;
    height: 16px;
    filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='my_png.png');
    padding-left: 16px;
}

The crazy, non-standard filter command does the magic – it tells IE that the image needs to be made transparent. There are a couple of notes here though, you MUST include a width and height that matches the source image. It doesn’t matter if you include it in the html tag or the CSS – I put it in the CSS because that is where I think it belongs. The padding-left must be the same as the width – this is REALLY important. What this hack does is overlay the “new” png over the top of the old one, without using padding-left to push the old image out of the way, you would see the old image underneath the new image, rendering the effect useless. By moving it over out of view, you will only be able to see the tranparent PNG.

3. Drop in the IE only conditional statement

<!--[if lt IE 7]>
<link href="ie.css" media="screen" rel="Stylesheet" type="text/css"></link>
< ![endif]-->

This is pretty standard – ie.css is the stylesheet we just created.

As I mentioned at the beginning, this technique works for background images too, except for one small issue – if the element with the background image has text in it, the text disappears, because of the padding-left modifier. It is actually a really simple fix, just change the CSS to say the following:

img.my_png {
    width: 16px;
    height: 16px;
    background-image: none;
    filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='my_png.png');
}

This will turn off the non-transparent background PNG and replace it with the transparent version. It won’t work with a repeating background image though, but hey, you can’t have it all. If you want to see this method in action, go to 88 Miles – all of the buttons use it.

Sorry, the servers down – please proceed to login

I was just logging into my online banking system and was confronted with with error message – besides the typo (possbile?) I find it interesting that there is a button inviting you to login in to a system that is un-available… and yes you can proceed to the login window, and it isn’t until you enter your details again before you get a definitive error message. A good example of what NOT to do.

When is an error message, not really an error message?!

Stuff to do this year

I hope that the first week of 2007 has been fruitful – unfortunately I got hit with a stomach bug late in the week which put the brakes on to my running leap into the year. Oh well, there is always next week :)

I thought I might list some of the things I’m going to do this year – I refuse to call them resolutions, but I guess that is what they are. 2006 was a busy year with me leaving freelancing and starting work at Bam, starting work on 88 Miles and becoming chairperson of the WA Web Awards, but I can feel an even busier year coming up.

First on the list is getting a production version of my new project out. I used the time off over Christmas to build the footings for it so now I’m committed to getting something out. I’m hoping to make an announcement about what it is, what it does and how it does it sometime towards the end of the month. I can tell you that is is built on Rails (naturally) and it targeted at web designers and developers, and will be something they will on sell to their clients.

I also want to continue work on 88 Miles. The number of sign-ups have really ramped up in the last couple of months of so, and I’ve been getting really good feedback. I’ve also managed to find a way to integrate with the time tracking system at work, so I’m back to using it constantly which puts me back in the drivers seat.

The WA Web Awards are back again this year, after a really successful event last year, the committee had a big job ahead of them again this year. I plan to use last years experience to really refine the process – having volunteers means time is valuable and wasting it can’t be an option.

I’m the Events officer for AWIA (Formerly Port 80) this year, and I’ve got big plans. I want to instigate quarterly local speaking events where local talent gets a change to talk about what they are doing in a similar vein to Sydney’s webjam. This would be on top of the traditional Port80 speaking events: Ideas4 and Ideas5. If you are from Perth, passionate about what you do and want to tell the world (or at least a group of people in a pub) about it, please drop me a line.

I’m going to find time to go out and see my friends again – I’ve been particularly piss-poor in this area in ’06 – sorry guys.

And lastly, spend as much time as possible with my girlfriend, Giovanna – even though we live together, it is harder to find us time than you think ;)

Phew! That’s a lot of stuff. I need a nanna nap just reading it.

Merry Christmas, Happy new year and all that jazz

As is customary on the last working day for Christmas, the tunes are playing and the drinks are flowing, so it is a good time to say Merry Christmas and have a safe holiday.

Stay tuned for next year, when hopefully I’ll have a new project to announce ;)

Password Generating Bookmarklet

Some how I managed to get lumped with the un-enviable task of creating email accounts for clients at Bam Creative – we currently have to use an archaic web interface and it takes forever. One of the many things that annoyed me about the system, is it can’t generate passwords for you, so I whipped up this little bookmarklet that will generate an eight character password made up of upper and lowercase letters and numbers. It adds a small div to the very top of the page you are viewing. Clicking the password makes it disappear again.

Drag the following link into you bookmarks. Click it now to see it work!

[Password generator][2]

Known issues:

  • It doesn’t play nice with frames, it will throw a JavaScript error.
  • Clicking the link in IE doesn’t make it disappear.

The raw code:

<li class="li1">
  <div class="de1">
    <span class="kw1">for</span><span class="br0">(</span>i=<span class="nu0"></span>; i < <span class="nu0">8; i++<span class="br0">)</span><span class="br0">{</span></div> </li> 
    
    <li class="li1">
      <div class="de1">
        <ins class="in"> </ins> <span class="kw1">switch</span><span class="br0">(</span>Math.<span class="me1">round</span><span class="br0">(</span>Math.<span class="me1">random</span><span class="br0">(</span><span class="br0">)</span> * <span class="nu0">2</span><span class="br0">)</span><span class="br0">)</span> <span class="br0">{</span>
      </div>
    </li>
    
    <li class="li1">
      <div class="de1">
        <ins class="in"> </ins> <ins class="in"> </ins> <span class="kw1">case</span> <span class="nu0"></span>:
      </div>
    </li>
    
    <li class="li1">
      <div class="de1">
        <ins class="in"> </ins> <ins class="in"> </ins> <ins class="in"> </ins> passwd += String.<span class="me1">fromCharCode</span><span class="br0">(</span>Math.<span class="me1">round</span><span class="br0">(</span>Math.<span class="me1">random</span><span class="br0">(</span><span class="br0">)</span> * <span class="nu0">25</span><span class="br0">)</span> + <span class="nu0">65</span><span class="br0">)</span>;
      </div>
    </li>
    
    <li class="li1">
      <div class="de1">
        <ins class="in"> </ins> <ins class="in"> </ins> <ins class="in"> </ins> <span class="kw1">break</span>;
      </div>
    </li>
    
    <li class="li1">
      <div class="de1">
        <ins class="in"> </ins> <ins class="in"> </ins> <span class="kw1">case</span> <span class="nu0">1</span>:
      </div>
    </li>
    
    <li class="li1">
      <div class="de1">
        <ins class="in"> </ins> <ins class="in"> </ins> <ins class="in"> </ins> passwd += String.<span class="me1">fromCharCode</span><span class="br0">(</span>Math.<span class="me1">round</span><span class="br0">(</span>Math.<span class="me1">random</span><span class="br0">(</span><span class="br0">)</span> * <span class="nu0">25</span><span class="br0">)</span> + <span class="nu0">97</span><span class="br0">)</span>;
      </div>
    </li>
    
    <li class="li1">
      <div class="de1">
        <ins class="in"> </ins> <ins class="in"> </ins> <ins class="in"> </ins> <span class="kw1">break</span>;
      </div>
    </li>
    
    <li class="li1">
      <div class="de1">
        <ins class="in"> </ins> <ins class="in"> </ins> <span class="kw1">case</span> <span class="nu0">2</span>:
      </div>
    </li>
    
    <li class="li1">
      <div class="de1">
        <ins class="in"> </ins> <ins class="in"> </ins> <ins class="in"> </ins> passwd += Math.<span class="me1">round</span><span class="br0">(</span>Math.<span class="me1">random</span><span class="br0">(</span><span class="br0">)</span> * <span class="nu0">9</span><span class="br0">)</span>;
      </div>
    </li>
    
    <li class="li1">
      <div class="de1">
        <ins class="in"> </ins> <ins class="in"> </ins> <ins class="in"> </ins> <span class="kw1">break</span>;
      </div>
    </li>
    
    <li class="li1">
      <div class="de1">
        <ins class="in"> </ins> <span class="br0">}</span>
      </div>
    </li>
    
    <li class="li1">
      <div class="de1">
        <span class="br0">}</span>
      </div>
    </li>
    
    <li class="li1">
      <div class="de1">
        <ins class="in"> </ins>
      </div>
    </li>
    
    <li class="li1">
      <div class="de1">
        <span class="kw2">var</span> pDiv=document.<span class="me1">createElement</span><span class="br0">(</span><span class="st0">&#8216;div&#8217;</span><span class="br0">)</span>;
      </div>
    </li>
    
    <li class="li1">
      <div class="de1">
        pDiv.<span class="me1">setAttribute</span><span class="br0">(</span><span class="st0">&#8216;style&#8217;</span>,<span class="st0">&#8216;postion:absolute; top:0px; left:0px; border: 1px solid black; background-color: grey; text-align: center;&#8217;</span><span class="br0">)</span>;
      </div>
    </li>
    
    <li class="li1">
      <div class="de1" />
    </li>
    <li class="li1">
      <div class="de1">
        <span class="kw2">var</span> pClose=document.<span class="me1">createElement</span><span class="br0">(</span><span class="st0">&#8216;a&#8217;</span><span class="br0">)</span>;
      </div>
    </li>
    
    <li class="li1">
      <div class="de1">
        pClose.<span class="me1">setAttribute</span><span class="br0">(</span><span class="st0">&#8216;href&#8217;</span>,<span class="st0">&#8216;#&#8217;</span><span class="br0">)</span>;
      </div>
    </li>
    
    <li class="li1">
      <div class="de1">
        pClose.<span class="me1">setAttribute</span><span class="br0">(</span><span class="st0">&#8216;style&#8217;</span>,<span class="st0">&#8216;color: white&#8217;</span><span class="br0">)</span>;
      </div>
    </li>
    
    <li class="li1">
      <div class="de1">
        pClose.<span class="me1">setAttribute</span><span class="br0">(</span><span class="st0">&#8216;onclick&#8217;</span>,<span class="st0">&#8216;this.parentNode.parentNode.removeChild(this.parentNode);&#8217;</span><span class="br0">)</span>;
      </div>
    </li>
    
    <li class="li1">
      <div class="de1">
        pClose.<span class="me1">appendChild</span><span class="br0">(</span>document.<span class="me1">createTextNode</span><span class="br0">(</span>passwd<span class="br0">)</span><span class="br0">)</span>;
      </div>
    </li>
    
    <li class="li1">
      <div class="de1">
        pDiv.<span class="me1">appendChild</span><span class="br0">(</span>pClose<span class="br0">)</span>;
      </div>
    </li>
    
    <li class="li1">
      <div class="de1">
        body = document.<span class="me1">getElementsByTagName</span><span class="br0">(</span><span class="st0">&#8216;body&#8217;</span><span class="br0">)</span>;
      </div>
    </li>
    
    <li class="li1">
      <div class="de1">
        body<span class="br0">[</span><span class="nu0"></span><span class="br0">]</span>.<span class="me1">insertBefore</span><span class="br0">(</span>pDiv,body<span class="br0">[</span><span class="nu0"></span><span class="br0">]</span>.<span class="me1">firstChild</span><span class="br0">)</span>;
      </div>
    </li></ol> </div> 
    
    <ul />

[2]: javascript:passwd=’’;for(i=0;i<8;i++){switch(Math.round(Math.random()*2)){case 0: passwd+=String.fromCharCode(Math.round(Math.random()*25)+65);break;case 1:passwd+=String.fromCharCode(Math.round(Math.random()*25)+97);break;case 2:passwd+=Math.round(Math.random() * 9);break;}}var pDiv=document.createElement(‘div’);pDiv.setAttribute(‘style’,‘postion:absolute;top:0px;left:0px;border:1px solid black;background-color:grey;text-align:center;’);var pClose=document.createElement(‘a’);pClose.setAttribute(‘href’,’#’);pClose.setAttribute(‘style’,‘color:white’);pClose.setAttribute(‘onclick’,’this.parentNode.parentNode.removeChild(this.parentNode);’);pClose.appendChild(document.createTextNode(passwd));pDiv.appendChild(pClose);body=document.getElementsByTagName(‘body’);body[0].insertBefore(pDiv,body[0].firstChild);void(null);

Latest 88 Miles release…

In between my day-to-day job and being sick (Damn you tonsils), I’ve managed to get some more work done on 88 Miles. This release was mainly an internal update, however there are a couple of important, if not major external changes.

  1. Business accounts are now out of beta – there are a variety of plans which should suit most people and you can easily swap betwen plans at your whim. There is even a discount for paying yearly! Check out the pricing page for more details.
  2. The trial account has now become a free account! There is now no account expiry date, and you can do all the things that regular accounts can do, including adding unlimited staff members. The only catch is that you can’t clock in more than 40 hours per month. All of the expired trial accounts have been re-enabled, so if you have signed up before but ran out of time, login again and see what has changed.
  3. The reporting system has improved – you can now view graphs in the project summary view

I would really love some feedback on the system, so if you haven’t had a play with it in a while, or if you have never had a play with it, go and login and show yourself around :)

/End selfless self-promotion

Welcome to the 21st century

This morning at 2am, Western Australia joined most of the rest of Australia and rolled their clocks forward to begin a three year trial of daylight savings – and about bloody time too!

So far, so good – All of my computers at my house have updated, as have the two work servers, and after a quick patch, 88 Miles also made the transition into the new timezone.

For those of you that weren’t quite so on the ball with your updating, you can download the Windows update here, and the Unix/BSD update here.

The Windows update is pretty self-explainitory, and the Unix/BSD update is just as easy:

  1. Download the update file
  2. Copy it to /usr/share/zoneinfo/Australia (overwriting the existing Perth file)
  3. makes sure /etc/localtime is symlinked to /usr/share/zoneinfo/Australia/Perth

Note that this update works for OSX as well.

So you over-easters, just remember little ol’ Perth is now two hours behind (Unless you are in Queensland, now we are only one hour behind). Adelaidians (!?) we are 1.5 hours behind you and Darwin you are 30 minutes in front.

Three development tools you simply must have… Part II

The second development tool in the “simple must have” category would be Capistrano. Capistrano is a deployment system that was written in ruby and is (not suprisingly) integrates quite nicely with Ruby on Rails. However! you can quite happily use it for any system, because at it’s heart, it is just a remote scripting tool.

When you run capistrano, you call a recipe, which is executed on the remote server or servers via SSH and it works really well.

Installation

The capistrano hand book has the latest installation instructions, so check there, but the basics (at the time of writing) are:

gem install capistrano

This will install the cap application. The tutorial from Simple Complexity – it deals with most of the difficult stuff (it’s actually really easy) and I don’t think I can put it any more eloquently.

Follow the steps and then you too can love the one-command deployment. I use it at MadPilot (for 88 Miles) and at Bam all the time. It’s great.

Next week: Part III

Oo-Ahh, it’s all about line and length

I’m sitting here watching the Poms getting destroyed by the Australians in the first test of the 2006/07 Ashes and just witnessed an interview with the man of the moment — Glenn McGrath. He just pulled a six wicket haul to knock off the fledgling English batting line-up in less that a day.

Anyway, during this interview he said the following when asked about what he thinks about when he is bowling:

It’s a simple game that we complicate. When you’re looking for that first wicket, your process is a little bit out

This sounds like the hype that is going around the web industry at the moment about keeping software simple – it is interesting to see how the theory translates to other facets of life.

The irony, I think, is that it takes much experience to be able to simplify a process down. An in-experienced person will probably see a simple solution, however they may fail to interpret potential problems down the track. semi-experienced people may not have used certain techniques long enough to be able to safely say in a given situation whether the procedure should be dropped or not. It is the experienced person that can see exactly what can be culled.

Previous Next