Plain Text Obfuscation
The Code Behind the Harry Potter Theory Post
As regular readers will know, I’m spending a lot of my time at the moment writing a gripping adventure book ‘Ajax in Action’, in which our hero, a young half-ancient greek, half-dutch football player combats the forces of darkness armed only with a bottle of cleaning fluid. Oh, hang on, it’s about web programming, isn’t it? Wrong Ajax, sorry,…
Well, anyway, being along-time Harry Potter fan, I’ve been rather distracted this week, and wanted to post a few musings about the new book here on the blog. At the same time, I didn’t want to give away any plot spoilers to the casual eye. One sees on many movie and book review sites the dire warning Plot Spoilers ahead. Wel, I decided to go one better, by obfuscating my post to the casual reader, so that nothing of any note could accidentally be read. On pressing the ‘reveal’ button, the random words are replaced by their real, significant counterparts, which are also highlighted. Enough explanation, give it a try now.
So how does it work?
Well, I’ve defined a simple javascript object with it’s own cod-Latin Potter-esque name. The Scrutio operates on a paragraph, taking a list of secret words and replacing them with other words randomly drawn from a list of substitutes. (’scrute’ is to see or discern, as in the word ‘inscrutable’.) For example:
[’horcrux’,'amulet’,'replacement’,
’soul’,'ring’,'burnt’,'pensieve’,
’scar’,'parselmouth’,'prophesy’,
’numerical index’,'hand’],
[’bat’,'toothbrush’,'wig’,
’goggle-eyed goose’,'monkey’,'dork’,
’goddamn robot camel jockey’,'doofus’]
);
Any of the words in the second argument will be replaced by one randomly selected from the third argument list.
The first element is the id of the document element to operate upon. The main text of the blog entry is wrapped in a div tag:
which the Scrutio object picks up in its constructor:
this.el=document.getElementById(el);
this.secrets=secrets;
this.subs=subs;
this.hiddens=new Array();
this.cloak();
}
It then obfuscates the contents of the paragraph by calling it’s cloak() method, which replaces the innerHTML of the target element
var origTxt=this.el.innerHTML;
var upper=this.subs.length-1;
for(var i=0;i<this.secrets.length;i++){
var secret=this.secrets[i];
var rex=new RegExp(secret,”gi”);
var randx=Math.floor(Math.random()*upper);
var rand=this.subs[randx];
origTxt=origTxt.replace(rex,
”<span realVal=’”+this.secrets[i]
+”‘>”+rand+”</span>”);
}
this.el.innerHTML=origTxt;
}
First, I use Javascript Regular Expressions to search out all instances of the ’secret’ words in the text, and then wrap them up in SPAN tags, which display a randomly-selected word from the replacements list. So, for example:
becomes:
once the Scrutio has finished with it. (Note that it isn’t clever enough to deal with plurals). The text that the browser displays is now harmless, but the real, secret text is stored in the attribute ‘realVal’.
We pass through the entire innerHTML string this way, and then simply replace it. In this case, its simpler than DOM manipulation, because we’re taking what was a few lengthy text nodes and breaking them up into a mix of smaller text nodes and SPANs.
When we call Scrutio.reveal(), however, to show the hidden meaning of the text, we use DOM methods to traverse the SPAN nodes, replacing their inner content with the hidden realVal attribute that we tucked in there earlier:
var hiddens=this.el.getElementsByTagName(”span”);
for(var i=0;i<hiddens.length;i++){
var hidden=hiddens[i];
var realVal=
hidden.attributes.getNamedItem(”realVal”).value;
if (realVal){
hidden.innerHTML=realVal;
hidden.className=’revealed’;
}
}
}
realVal is a non-standard attribute, and so is unlikely to interfere with any bona-fide SPAN tags that may be inside the targetted element.
To put it together for the blog entry, I wanted the obfuscated text to make some sort of sense, rather than just completely random words, so I create three Scrutio objects, and pass them over the blog entry in turn, transforming proper names, nouns and verbs with suitably silly substitutes.
window.onload=function(){
scrutes={
properNames:new Scrutio(’potterology’,
[’Nagini’,'Borgin’,'Dumbledore’,'Burke’,
’Tom’,'Riddle’,'Voldemort’,'September’,
’July’,'RAB’],
[’bat’,'toothbrush’,'wig’,
’goggle-eyed goose’,'monkey’]
),
nouns:new Scrutio(’potterology’,
[’horcrux’,'amulet’,'replacement’,’soul’,
’ring’,'burnt’,'pensieve’,’scar’,
’parselmouth’,'prophesy’,'numerical index’,
’hand’],
[’bat’,'toothbrush’,'wig’,
’goggle-eyed goose’,'monkey’,'dork’,
’goddamn robot camel jockey’,
’doofus’]
),
verbs:new Scrutio(’potterology’,
[’burnt’,'tried to kill’,'get rid of’,
’colecting’,’seventh’,’stole’,'born’],
[’collywobbled’,
’calmly explained in quiet tomes so as not to frighten’,
’whupped’,'freaked out’,'jellified’,
’organically farmed’,
’instantiated’,'hog-wrassled’]
)
};
}
function reveal(){
for (i in scrutes){
scrutes[i].reveal();
}
}
So, if you want to read my real thoughts about the new Harry Potter book, hit the reveal button. If you like reading semi-random gobbledegook, then keep refreshing the page, and you’ll get served up with a fresh plate of the stuff every time!