30 September 2008

Social Bookmarking Howto for Blogger

Attentive readers will have noticed the shiny new social bookmarking icon links around the bottom of my entries. I'm catching up with 2005 here. Last month I caught up with 2004 by including ads. You can't imagine how rich I'm feeling. Actually, you can ... but anyway. In 5 years, I'll add a flickr widget and be fully up to date with 2006. For that, I'll need something called a "photostream".

... You know, it's horrible when everyone thinks you're a geek but in fact you haven't a clue what's going on on the internet?

Anyway, I followed Enrico Suarvé's howto for adding these icons to a Blogger template. For someone who claims to be a hopeless blogger, he does an excellent job. Read his howto because I'm not going to repeat it here.

I was able to make only one little improvement: instead of making my own "submitbuttons" CSS class as he recommends, I used Blogger's "item-action" and "icon-action" classes. So I have a little less work to do, and my Blogger template code looks like this:


<span class='item-action'>
  <a Title='digg it' expr:href='"http://digg.com/submit?phase=3&url=" + data:post.url + "&title=" + data:post.title'>
    <img alt=' Digg ' border='0' class='icon-action' src='path/to/digg.png'/>
  </a>
 
  <a Title='delicious' expr:href='"http://del.icio.us/post?url=" + data:post.url + "&title=" + data:post.title'>
    <img alt='Delicious' border='0' class='icon-action' src='http://path/to/delicious.png'/>
  </a>
 
  <a Title='reddit' expr:href='"http://reddit.com/submit?url=" + data:post.url'>
    <img alt='Reddit' border='0' class='icon-action' src='http://path/to/reddit.png'/>
  </a>
 
  <a Title='SlashDot' expr:href='"http://slashdot.org/bookmark.pl?url=" + data:post.url + "&title=" + data:post.title'>
    <img alt='SlashDot' border='0' class='icon-action' src='http://path/to/slashdot.png'/>
  </a>
</span>

Paste this into your Blogger html template somewhere sensible. Tweak it until you like it. And upload the relevant icons somewhere so you can link to them.

At first I thought I should include furl and fark and magnolia and a zillion other SB sites I'd never even heard of, but in the end I figured that was kind of immodest (and you should know that I'm the modestest person you're ever likely to meet), so I retained only sites that I use: reddit and delicious, and occasionally: digg, and slashdot. (Hey, I even have an account on reddit and delicious, now that's so 2007! I'm getting there!)

Damn. I've just broken my resolution to not blog about blogging. Again!

29 September 2008

<center> is deprecated: use CSS instead!

Being from the 1990's, I like to use tables and the good ol' <center> tag to control my layout. Apparently, that's not polite any more. When I get my CSS Guru 9th-Dan Black Belt certification, I'll let you know why.

In the meantime, the totally modern way to centre a block, I learned today, is to give it a fixed width and set left and right margins to "auto". Thus:

.centred {
  margin-left: auto;
  margin-right: auto;
  width: 10em;
}
The block containing this text is centred relative to its parent. Note that the text itself isn't centred. Use text-align:center for that.

The difference, afaict, is that nowadays the element to be centered is responsible for its centredness, whereas in the old days, the element's parent decided how the child would behave. Very modern, them dudes at w3c. I try to let my children decide how to behave, too. Who would have thought CSS teaches family values?

26 September 2008

Keystroke Strikes Again

I wanted to preview my last blog entry just to check everything was ok and I hit control-F9, my intellij shortcut for "build project". This is very, very grave. It's like when I take out my bus pass to get into my house. Or this: image copyright ??? please let me know!

One from the archives

Ten years ago I wrote a little java applet (yes, an applet. Imagine that!) that plays Reversi, aka Othello - as an exercise for a Game Theory course I was taking.

I dug it up, and amazingly it compiles, runs and even works!

You can play against my little Reversi here (and it's totally free).

The program is a fine example of alpha-beta game tree pruning, using an evaluation function which takes into account the positions of the stones as well as the mobility of each player.

I'm sure one could write a much more sophisticated Reversi player, but even with low lookahead (4) it crushes me.

Download and play with the source code too - I'm releasing it open-source (under GPL). Just don't judge me by it - it was ten years ago, ok? There are member variables with names starting with uppercase letters ... there are ... ugh ... comments ... and all sorts of other atrocities in there. OMG there was even a new String("foo"); in there. I got rid of those, but it was too much effort to clean it up entirely. I don't write like that any more. I would like to say I never did, but I wasn't born perfect either ...

24 September 2008

Expand div to contain floated child elements

I am sure I am one among many thousands who will be eternally indebted to Quirksmode for its wealth of browser wisdom. Today I learned how to make a container expand to surround all of its floated child elements. On the container, put

style="overflow:auto;"
That's all! At least, for firefox - other browsers need width as well.

19 September 2008

A simple Javascript function to move elements

The proper way to drag divs or images or other html elements using javascript is, of course, to use a well-known and established framework for doing it - scriptaculous, for example. Even better would be to use Firefox's fancy new drag/drop handlers (as soon as they work, that is). But if you suffer, as I do, from NIH Syndrome, here's a roll-your-own version.

Just so we agree on what dragging is: the user clicks on an object, and while moving the mouse, the object follows the mouse around, until the user releases the mouse button. In the version below, we distinguish between the target (the thing to be moved), and the handle (the thing the user clicks on in order to move the target. A titlebar, for example).

The following has been tested on FF3 and almost certainly won't work on Exploder. But there are plenty of resources out there on hacking IE until it works.

Enough talking, here's the good stuff:

var makeMovable = function(target, handle) {
  target = $(target);

  $(handle).onmousedown = function(event) {
    var initialXOffset = target.offsetLeft - event.pageX;
    var initialYOffset = target.offsetTop - event.pageY;

    document.onmousemove = function(event) {
      target.style.left = event.pageX + initialXOffset;
      target.style.top = event.pageY + initialYOffset; 
    }

    document.onmouseup = function() {
      document.onmousemove = null;
      document.onmouseup = null;
    }

    return false;
  }
}

Once your HTML elements are defined, all you need do is call makeMovable with the relevant params:

<div id="myContent" style="position:absolute;left:100px;top:100px;">
  <img id="myHandle" src="/images/move_handle.png" />
  you can move this text by dragging the handle
</div>

<script type="text/javascript">
      makeMovable("myContent", "myHandle");
</script>

(Of course, you might prefer to take an unobtrusive approach and have all movable elements wired up using identifiers and class names. Exercise for reader).

So here's what's going on. The principle is simple: makeMovable sets a "mousedown" listener on the handle - since that's what we're waiting for our user to click on. Once mousedown is triggered, we calculate how far away the mouse click was from the corner of the target. This gets stored in initialXOffset and initialYOffset. The goal now is just to make sure that the target is always this distance from the mouse, as the mouse moves around.

So we need a mousemove listener. Curiously, mousemove has to be on document - you would think it should go on the handle instead because the mouse is necessarily over the handle when we get the initial mousedown - but unless it's document.onmousemove, Firefox gets all confused and thinks you're trying to select text at the same time as moving stuff around.

The mousemove listener does the real work: it sets the top and left style elements of the target so as to maintain the original offset from the mouse position. Note that the original style declaration of the target div includes position:absolute. Without this, the top and left style elements are completely ignored, and you won't be able to move anything.

Remember to return false; at the end of onmousedown. Without this line, it mostly works, but FF also initiates its internal drag handler as well as yours, resulting in angry users tearing at their screens in frustration, and the resulting drag behaviour isn't at all intuitive or pleasant.

The last word goes to onmouseup: once the user lets go of the mouse, we should restore document.onmousemove and document.onmouseup to whatever they were before. I'm being lazy here and setting them to null. Umm ... exercise for reader ...

If you're not using Prototype, replace $(...) with document.getElementById(...).

You can write similar code for resizing an element - you would adjust the width and height style elements instead of top and left.

Leave a comment if this works for you, or more importantly, if it doesn't. Leave a comment even if there's some other javascript question bugging you. I'm curious.

On Learning and Falling

Pascal Pratmarty's comment in a recent article on conflict resolution triggered some painful yet fond memories of learning ice-skating.

"Remember this: to be a learner, you’ve got to be willing to be a fool."

This will sound very odd if you've only tried skating once or twice: it's very difficult to fall. Once you figure out balance, your body clings to it, not letting your delicate elbows and knees hit that hard, cold ice.

I had learned to go forward, but people all around me were spinning, coasting backwards, jumping, and doing those awesome screech-skid stops. Envy filled me.

Your body learns these moves, not your mind, and can learn only by experiencing them. I had to push my reluctant flesh beyond what it was comfortable with. I had to force myself to fall.

It worked. Now, I can wiggle backwards around the rink, mostly avoiding collisions. I have yet to learn stopping though ...

Curiously, the pain of falling is not what inhibited me the most - you get over that fast. It was the eyes of all those people. I knew they were looking at me thinking: the fool.

I try hard, but I wish I could be a better fool.

17 September 2008

Hosting in France

It's hard to find a decent hosting provider. I used Textdrive for a while, but my rails processes kept on getting killed due to some limitation on memory consumption. I'm sure I was doing something awfully wrong (besides using fcgi), but I switched to slicehost (with apache mod-load-balancer and mongrel, a big improvement already). Still, it feels horribly slow, and again, being a bit of a rails newbie, I'm sure I'm doing something wrong.

So, to get to the point, I looked for a hosting provider in France to see if I could blame the network instead of me. Ouch. One look at the webhostingtalk review discouraged me from ever going near OVH. Dedibox, on the other hand, didn't seem to have such reputation issues, and their offer looks really good (physical dedicated server, 2GB RAM for EUR30/month compared to Slicehost's 256MB RAM VPS at $20/month). They have an absurd restriction on selling only to French residents, but I have a workaround for that. So I started the signup process, expecting to type in my name, email, credit card number, and choice of plan, and then be up and running in a few minutes. Slicehost sets the bar very high in this area. But no - they needed my phone number too, which they needed to confirm by sending me an SMS with a code I needed in order to proceed with signup.

Credit card? No - they want your bank account. With a severe warning in red that they will sue you if you deliberately offer false details. And then you have to print out your bank details and sign an authorisation for Dedibox to charge your account, and mail it to them. Surprisingly, they don't have an option for payment by sheep or goat. I was a little bit uncomfortable typing in all this bank information without numerous assurances in the surrounding text that no charge would be made unless and until I had my server, but I had little choice if I wanted to give these guys a chance.

Ok ok now you're thinking well what do you expect, that's French bureaucracy for you. Well for once in my life I figured I would click on that pesky "terms and conditions" link that I was about to claim to have read, understood, and accepted. Pretty quickly, I had read, understood, and totally not accepted that they "guarantee" that my server will be ready in a maximum of 35 days.

35 days ???? !!!!

"Wtf?", one might think. And: if they fail to deliver in 35 days, I have the right to cancel the contract - by sending them a registered letter to that effect. Double wtf.

So the long and the short of it is, I didn't click on the "I have read and accept the terms and conditions blah blah blah" box, and I didn't click on "proceed", and I'm not getting a Dedibox. I wonder who does? Do you have to hate your customers in order to be successful in France? Is that what they teach in business schools?

Now that the US is falling to pieces, the rest of the world is going to scramble to take its place on the top of the economic dunghill. Does anyone know where I might get my CV translated into Chinese or Hindi?

16 September 2008

An Incredible Thread

A few weeks ago, I read Halting State by Charles Stross. WARNING: potential spoiler follows - It's a novel set in the future, about a bank robbery in a virtual world, said robbery having far-reaching implications for global cyberterrorisim, including compromise of Europe's root servers and digital certificates, handing control of the continent's core infrastructure (police, transport, banking, everything) to a gang of Chinese hackers who possibly think it's all just a game. The highlight is when Jack looks up to the virtual sky at a flock of virtual birds flying past and realises the bad guys are encoding messages in the detaild of their flight paths.

"The traffic looks like game-play to [...] NSA or whoever's sniffing packets; looking in-game for characters run by Abdullah and Salim holding private chat about blowing up the White House garden gnomes won't get you a handle on what's going on because they're not using the game as a lydic universe to chat in, they're using it as a transport layer! They're tunnelling TCP/IP over AD&D!" (p.299)

Oscar Wilde said "Life imitates Art". And today Wired.com describes US Congress and Pentagon fears of terrorists chatting in World of Warcraft to plot an ATTACK ON AMERICA OMG OMG GET THE DUCT TAPE HONEY WHERES MY .32??!!!1!!

A Credible Threat, in order to be useful to a scaremonger, must be easily understood by the population purportedly under attack. A heavy reliance on popolar stereotypes is customary, but by broadening the stereotype to encompass virtual reality, the threat authors postpone threat fatigue and get better ROI on their fiction investment. The problem with Stross's scenario is that it's far too technical. A politucian wouldn't have a clue how to explain it, while a smart terrorist (bad, bad guys) could do a lot worse, but the guy on the street has mostly figured out online chat.

Those bad, bad terrorists wouldn't even have to go as far as Strosss describes. Combine basic cryptography, steganography, and any of the myriad ways of communicating (internet or otherwise), and you can undetectably send any message you want while it looks like you're only sending a picture of the kids to their grandmother in a village in Saudi Arabia. Or tunnel encrypted instructions through common misppellings or bad grammar in bot-generated chat in any of a million online forums. Wake up, CIA, you can't detect this stuff! The only solution is too shut down the world's entire telecommunications infrastructure - but that would be bad for business.

Of course, the online subversion goes he other way, too. Did you know that the CIA runs Facebook? Its Hamming Distance from "FactBook" (as in "The World Factbook") is only 1, so it's much easier for CIA agents to tipe. I don't know whether other Facebook constpiracy theorists had spotted that. Did you spot it?

What is the Truth? Somewhere out there, someone is laughing their arse off. Is it the bad guys, or the badder guys?

Subpixel Rendering

I just read about sub-pixel rendering on good ol' wikipedia. If you've ever needed to draw a vertical line exactly between two pixels, subpixel rendering is what you're looking for.

On an LCD screen, each pixel is three little bars, one red, one green, one blue. All on looks like white, all off like black.

The subpixel trick is to light, for example, the blue bar of one pixel, and the red and green bars of the next pixel to the right. The effect is a white pixel, because you have a red bar, a green bar, and a blue bar, all together, all lit up.

Here's a little image I made with iconfu just now:

Below is how it looks enlarged, so you see each pixel value. Notice that there are no black or white vertical lines. The appearance of black and white is a side-effect of the way sub-pixels are lined up on an LCD screen - and if you're using a CRT or an LCD that doesn't order its subpixels the same way, you'll be wondering what the hell I'm talking about.

Ok, that was the enlarged image, but in case you're having doubts, this is how it looks if you take a traditional screenshot (ie, with your camera). Here you can see how each pixel is lit and where the black and white lines come from.

You can also see that this trick can't work horizontally: there is no alignment of pixels to exploit in this direction. This is the same image, rotated:

And if we rotate it once more, the alignment doesn't work at all, and we lose our black and white lines ...

You can't imagine how many problems this solves. Not world hunger, unfortunately, but let's say you're drawing a vertical arrow in a 16x16 icon. You want a sharp point on your arrow, but if you make the tip 1 pixel wide the arrow won't be centered in the icon. Subpixel rendering is the solution! Similarly, you can control how curvy a curve is by lighting only the pixels that make your curve smoother: a curve going up and right (the top-left corner of a rounded-corners box, for example), would benefit from a little dash of blue on the outside, whereas the curves on the other side would benefit from a little bit of red.

Now, wasn't that fascinating ... back to work ...

please don't fix this

My iPhoto (6.0.6) has an awesome bug (at least I suppose it's a bug) if you adjust exposure down after having fiddled a bit with light levels. Resulting in this magnificent stained glass from St. Merry, next to the Pompidou Centre:

The statue of the saint holding the baby reminds me how intimately connected religion and politics are.

05 September 2008

List foreign key constraints in Oracle and MySQL

Sometimes you want a list of all the associations in your database. You're supposed to know this from your Hibernate mappings, or from your ActiveRecord declarations, but sometimes you just need to dig this stuff out of a legacy database with its cryptic prehistoric naming conventions layered on top of one another like geological rock strata.

Anyway, I digress. As you might imagine, this is a simple select in MySQL, and a four-table join in Oracle.

Suppose you've had the original idea of building a brilliant e-commerce site. You have Clients, Orders, Products, and LineItems, with the usual associations.

This is the kind of output you want:

+-----------------------+-------------+
| foreign key           | references  |
+-----------------------+-------------+
| orders.client_id      | clients.id  |
| line_items.order_id   | orders.id   |
| line_items.product_id | products.id |
+-----------------------+-------------+

With MySQL:

select 
    concat(table_name, '.', column_name) as 'foreign key',  
    concat(referenced_table_name, '.', referenced_column_name) as 'references'
from
    information_schema.key_column_usage
where
    referenced_table_name is not null;

With Oracle (9-ish, probably 10 too, it's ages since I've actually used this)

select
    col.table_name || '.' || col.column_name as foreign_key,
    rel.table_name || '.' || rel.column_name as references
from
    user_tab_columns col
    join user_cons_columns con 
      on col.table_name = con.table_name 
     and col.column_name = con.column_name
    join user_constraints cc 
      on con.constraint_name = cc.constraint_name
    join user_cons_columns rel 
      on cc.r_constraint_name = rel.constraint_name 
     and con.position = rel.position
where
    cc.constraint_type = 'R'

I cry when I behold the beauty of Oracle's meta data model. But we'll hold off the religious wars for another day. I know it's not your fault you're using Oracle.

HTH.

01 September 2008

Faber-Mazlish parenting workshops : coming soon to the capital city of France nearest you

Sabrina will be offering Faber-Mazlish parenting workshops in Paris starting later this year. I have yapped about Faber-Mazlish before, and will again: of all the parenting books we've looked at, this is the only one that is clear, simple, undogmatic, and makes total sense. If you don't want to read the book, then take the workshop. Reserve your place before it's too late !!!