Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?

The History of Acme::Bleach and Acme::EyeDrops

by eyepopslikeamosquito (Chancellor)
on Apr 25, 2012 at 07:25 UTC ( #967004=perlmeditation: print w/replies, xml ) Need Help??

I wrote this node because jdrago999 asked me the other day: what's the difference between Acme::EyeDrops and Acme::Bleach?

After giving a basic answer in that thread, I thought it would be fun to further chronicle the events behind these two concoctions, so as to give the reader some (hopefully interesting and instructive) insights into how on earth these two bizarre modules made it onto the CPAN.

I well remember what a sensation Acme::Bleach caused when it was first released way back in 2001. People were astonished and bewildered when their script disappeared before their eyes and yet still appeared to work! Impossible! Surely Conway was some sort of magician.

I'm not aware of Damian performing any magic tricks, at least I couldn't find any magic shows on offer at Thoughtstream. Yet he did pull a new and surprising idea out of his hat, namely to encode an entire source code file using just spaces and tabs. After all, code is just ones and zeros, so why not encode all the bits in each source code byte as space (zero) and tab (one)? Then later decode this unorthodox bitstream by converting space back to zero and tab back to one. And then, finally, eval the decoded string, thus resurrecting the original program. A simple and (in hindsight) "obvious" idea.

Yet why on earth was he thinking about such a strange concept in the first place? Well, it seems it was all Tim Maher's fault! Damian described how it came about when I asked him about it last week:

Acme::Bleach was conceived during a car ride with Tim Maher in Seattle. I believe we were on our way either to or from a meeting at which I spoke.

We were talking about Perl Golf and he challenged me to create the shortest possible program for some task I can't remember. I almost immediately realized that I could make a visibly zero-length program by encoding everything as whitespace. By the next day the module was created.

I'm not aware of any earlier work in the whitespace programming domain, though it would not surprise me if there were some. It's an obvious steganographic technique, and has probably been employed in clandestine communications from the earliest uses of digital text. However, I can confirm that I was not (consciously) influenced by any other work when inventing Acme::Bleach. It leapt fully formed into my brain (as so many of my other ideas do). My unconscious mind is clearly vastly smarter and more creative than my meagre consciousness. ;-)

In terms of programming language history, it seems that Bleach was the first to use whitespace alone as a programming language, appearing a full two years before the Whitespace programming language.

Though not the first Perl joke module (see The Lighter Side of Perl Culture for that), Acme::Bleach was pioneering in other respects too: it was the first Acme module, and the first source filter joke module.

As testimony to its enduring influence, there are now more than 400 Acme modules on the CPAN and Acme::Bleach alone has spawned more than twenty variations and tributes over a period of ten years (see "Related CPAN Modules" section below).

Though there had long been joke modules on the CPAN, D'oh by Chris Nandor and Sex by Mick Schwern for example, it wasn't until Acme::Bleach was released in 2001 that joke modules became so popular that they demanded their own namespace. Indeed, it was Damian who came up with the name Acme:

to make it clear when a module was for entertainment purposes only, and was likely to lead to great harm to an unwitting user. Thinking of the many misadventures of Wile E Coyote the obvious namespace for such modules was Acme.
Great idea. Yet, alas, it hasn't stopped people employing Acme modules in production code.

The Acme::Bleach Imitators

In the same year that Bleach was released, four imitators closely followed, as shown below:

Feb 21 2001Acme::BleachDamian ConwayAustralia
Apr 1 2001Acme::BuffyLeon BrocardEngland
Apr 3 2001Acme::PonyDavid CantrellEngland
May 19 2001Acme::SmirchJasvir NagraNew Zealand
Sep 22 2001Acme::EyeDropsAndrew SavigeAustralia

Humour is somewhat culture bound, so I find it interesting that the first five of these type of joke modules came from three countries with a similar cultural background, namely Australia, New Zealand and England.

I recall from private communication with Jas Nagra that he hacked Acme::Smirch to relieve the boredom during a long flight from New Zealand to America.

I assume that Bleach was a huge hit at the lively and mischievous, which probably explains Acme::Buffy and Acme::Pony. If Leon or David are listening, I would love to hear about how these two came to be created.

How did Acme::EyeDrops come about?

While Acme::Bleach was an original work, created in a day, Acme::EyeDrops was essentially a derivative work, created over a period of many months, and tinkered with for many years.

Around that time I was certainly aware of Acme::Bleach and its cousins. I remember showing my workmates how I could make their programs "cleaner" with Acme::Bleach. And fondly remember the look of disbelief on their faces when they realised their "empty" program still worked! Some of them were angry that I had "lost" their hard-earned code.

That said, the primary provocation for creating Acme::EyeDrops was not Bleach, but a thread on the (then lively, now dormant) "fun with perl" mailing list about JAPHs without any alphanumeric characters.

Following on from that thread, I subsequently released Acme::EyeDrops to "prove" that you could, in principle, go further than JAPHs and write any Perl program without using any "unsightly" alphanumeric characters at all. I was not the first to do this, however. Jasvir Nagra deserves the credit for being the first when he released Acme::Smirch in May 2001.

I was new to Perl at that time, and eager to improve my Perl skills by creating my first CPAN module. So I was happy to spend a lot of time on EyeDrops. In particular, I wanted to cleanly define the (sightly) encoding (see the "Sightly Encoding" section in the Acme::EyeDrops documentation) and further develop some original shape pouring algorithms.

How does Acme::EyeDrops differ from Acme::Bleach?

Both EyeDrops and Bleach encode the source code. Bleach does so by converting the stream of bits in each source code character to spaces (0) and tabs (1) as indicated by this snippet from its source code:

sub whiten { local $_ = unpack "b*", pop; tr/01/ \t/; ... }
In contrast, EyeDrops encodes each "unsightly" (i.e. alphanumeric) character by using a bitwise operator on two or more "sightly" (i.e. non-alphanumeric) ones. This is done via a lookup table as indicated by this snippet from its source code:
my @C = ( q Z('!'^'!')Z,q Z('('^')')Z,q Z('<'^'>')Z,q Z('>'^'=')Z, q Z('>'^':')Z,q Z('>'^';')Z,q Z('+'^'-')Z,q Z('*'^'-')Z, q Z('+'^'#')Z,q Z('*'^'#')Z,q Z('!'^'+')Z,q Z('!'^'*')Z, q Z('!'^'-')Z,q Z('!'^',')Z,q Z('!'^'/')Z,q Z('!'^'.')Z, q Z('?'^'/')Z,q Z('<'^'-')Z,q Z('-'^'?')Z,q Z('.'^'=')Z, q Z('+'^'?')Z,q Z('*'^'?')Z,q Z('?'^')')Z,q Z('<'^'+')Z, q Z('%'^'=')Z,q Z('&'^'?')Z,q Z('?'^'%')Z,q Z('>'^'%')Z, q Z('&'^':')Z,q Z('<'^'!')Z,q Z('?'^'!')Z,q Z('%'^':')Z, q Z('{'^'[')Z,q Z'!'Z,q Z'\\\\'.'"'Z,q Z'#'Z, q Z'\\\\'.'$'Z,q Z'%'Z,q Z'&'Z,q Z"'"Z,q Z'('Z,q Z')'Z, q Z'*'Z,q Z'+'Z,q Z','Z,q Z'-'Z,q Z'.'Z,q Z'/'Z, q Z('^'^('`'|'.'))Z,q Z('^'^('`'|'/'))Z,q Z('^'^('`'|','))Z, q Z('^'^('`'|'-'))Z,q Z('^'^('`'|'*'))Z,q Z('^'^('`'|'+'))Z, q Z('^'^('`'|'('))Z,q Z('^'^('`'|')'))Z,q Z(':'&'=')Z, q Z(';'&'=')Z,q Z':'Z,q Z';'Z,q Z'<'Z,q Z'='Z,q Z'>'Z,q Z'?'Z, q Z'\\\\'.'@'Z,q Z('`'^'!')Z,q Z('`'^'"')Z,q Z('`'^'#')Z, q Z('`'^'$')Z,q Z('`'^'%')Z,q Z('`'^'&')Z,q Z('`'^"'")Z, q Z('`'^'(')Z,q Z('`'^')')Z,q Z('`'^'*')Z,q Z('`'^'+')Z, q Z('`'^',')Z,q Z('`'^'-')Z,q Z('`'^'.')Z,q Z('`'^'/')Z, q Z('{'^'+')Z,q Z('{'^'*')Z,q Z('{'^')')Z,q Z('{'^'(')Z, q Z('{'^'/')Z,q Z('{'^'.')Z,q Z('{'^'-')Z,q Z('{'^',')Z, q Z('{'^'#')Z,q Z('{'^'"')Z,q Z('{'^'!')Z,q Z'['Z, q Z'\\\\'.'\\\\'Z,q Z']'Z,q Z'^'Z,q Z'_'Z, q Z'`'Z,q Z('`'|'!')Z,q Z('`'|'"')Z,q Z('`'|'#')Z, q Z('`'|'$')Z,q Z('`'|'%')Z,q Z('`'|'&')Z,q Z('`'|"'")Z, q Z('`'|'(')Z,q Z('`'|')')Z,q Z('`'|'*')Z,q Z('`'|'+')Z, q Z('`'|',')Z,q Z('`'|'-')Z,q Z('`'|'.')Z,q Z('`'|'/')Z, q Z('['^'+')Z,q Z('['^'*')Z,q Z('['^')')Z,q Z('['^'(')Z, q Z('['^'/')Z,q Z('['^'.')Z,q Z('['^'-')Z,q Z('['^',')Z, q Z('['^'#')Z,q Z('['^'"')Z,q Z('['^'!')Z,q Z'\\\\'.'{'Z, q Z'|'Z,q Z'\\\\'.'}'Z,q Z'~'Z,q Z('!'^'^')Z ); push @C, map(join('.', q#'\\\\'#, $C[120], map($C[$_], unpack('C*', sprintf('%x', $_)))), 128..255); sub ascii_to_sightly { join '.', map($C[$_], unpack('C*', $_[0])) }

The big difference between the two approaches lies in the decoding. Because EyeDrops encodes into a form that perl can execute unaided, it simply lets perl decode it via eval and so does not require Acme::EyeDrops to be installed on the target system.

In contrast, perl by itself cannot make sense of a raw stream of spaces and tabs and so requires Acme::Bleach to be installed on the target system to decode and eval the "bitstream" of spaces and tabs.

As a consequence, Bleach has to be involved at compile time (which is why it overwrites the file and fiddles with $0). EyeDrops, on the other hand, does not mangle the original file, simply reads it and writes a new (encoded and shaped) one.

Put another way, Bleach is a source filter while EyeDrops is not. EyeDrops is simply an encoder and shaper of the bytes in a source code file. The hardest part of writing EyeDrops was not the (sightly) encoding, but the heuristics required to pour the encoded bytes into a wide variety of shapes.

Perl Monks References

The two excellent nodes below describe a "converse" encoding to the sightly encoding employed by Acme::EyeDrops. That is, they encode a Perl program to use only alphabetic characters, without any punctuation at all:

External References

Related CPAN Modules

Updated 26-Apr-2012: Corrected release date of Acme::Pony (originally Pony) to Apr 3. Thanks DrHyde. 28-Apr-2012: added DNA module by Schwern and SuperPython module by MJD to "Related CPAN Modules" section. 2-May-2012: Minor improvements to wording.

Replies are listed 'Best First'.
Re: The History of Acme::Bleach and Acme::EyeDrops
by DrHyde (Prior) on Apr 26, 2012 at 10:15 UTC
    Acme::Pony was originally Pony, released on the 3rd of April 2001. The story behind both it and Acme::Buffy is that a few days beforehand, Damian Conway had given a talk to, which covered, amongst other things, Acme::Bleach. At the time, Buffy The Vampire Slayer was wildly popular amongst I disremember where the pony thing came from, but flood-filling an ASCII-art pony with the word "buffy" is clearly an improvement!

      When harvesting the original release dates from backpan, I picked up Bleach, Buffy and Smirch ok but for some reason missed Pony. Sorry 'bout that. I've corrected the root node so that Acme::Pony, in addition to being ridden by Buffy, now has a bronze medal hanging around its neck, albeit still one behind Leon.

      Re the Buffy riding a Pony thing, according to the Acme::Pony docs, seeing Buffy riding a Pony is "Greg, Leon and Dave's fantasy". I'm assuming that's Greg McCarroll, acme, and davorg. I also found the original historic email announcement of Pony on (update: and the original email announcement of acme's Buffy module).

      And at the risk of teaching you about your own culture, and telling you why you chose the name Pony, the FAQ has this to say about ponies:

      If people think you're acting stressed on IRC, then they may well offer you a pony to stroke, since stroking a pony makes it all better. For more extreme times, there may even be a 'pony drop' of many ponies.
      The ill-fated Ponie project didn't arrive until two years later ... announced by Leon I see. Hmmm, I'm starting to see a pattern here. :)

        I blame too much (or maybe just enough) gin for my bad memory and inability to read my own documentation.
Re: The History of Acme::Bleach and Acme::EyeDrops
by eyepopslikeamosquito (Chancellor) on Apr 28, 2012 at 09:45 UTC

    I've had some more time to mine the and (SPUG) mailing lists for more detailed supporting references for this node.

    First, we travel back in time to Feb 19 2001, the date of the historic meeting that Damian was travelling to (or from) in Dr Tim Maher's car when he first thought of Bleach:

    Special February Meeting:
    Title: Whither Perl 6.0?
    Speaker: Aussie Perl Guru Dr. Damian Conway
    Indentured Servant #1 to Perl Community,
    via Development Grant from "Yet Another Society"
    Time: February 19th, 2001 (Third MONDAY), 7:00pm-9pm
    Location: Union Bank of California Bldg, 5th Floor Mtg Room
    NOTE: Usual location and time, but Monday, rather than Tuesday!

    Yes, the truth can finally be revealed: I will actually be travelling *backwards* in time to have given that talk, which I will soon be having written from memory, perhaps at the very moment you will have had been being reading this. (Man, this transtemporal travel is tough on the tenses!)

    Next, forward one week to Feb 26 2001 to attend the "Conway Hall" meeting at which Damian subsequently revealed Bleach: proudly presents my birthday, on 2001-02-26, in the Brockway Room, Conway Hall, Red Lion Square, WC1R 4RL from 7pm. You may all get me very large presents. Oh, and Perl God Damian Conway will be doing his wonderful Quantum::Superpositions lecture there as well. You can meet him on Sunday in the Penderels Oak from 6.30ish too.

    Then a surprise. Just two days later, on Feb 28 2001, one "Matthew Robinson" proposed a Pony module based on Bleach! And even had the temerity to post an implementation:

    Although I didn't make it to the pub after Damian's talk I did hear from my sources that someone thought it would be 'useful' to convert to print pony instead. So here it is, it isn't quite the same as Bleach but it produces a similar result.

    Enjoy, Matt

    package Pony; $VERSION = '1.00'; # MSR - 28 Feb 2001 $magic = "pony " x 4; sub pony { local $_ = unpack("b*", pop); s/0/ /g; s/1/pony/g; $magic.$ +_ } sub depony { local $_ = pop; s/^$magic//; s/pony/1/g; s/ /0/g; pack("b +*", $_) } open 0 or die; ($script = join("", <0>)) =~ s/^(.*^use\s+Pony\s*;\s*?\n)//sm; $header = $1; do { eval depony($script); exit } if ($script =~ /^$magic/); open(0, ">$0") or die; print {0} $header.pony($script);

    Finally, on Apr 1 2001 we learn not only about the Buffy and Pony modules, but also the DNA module by Schwern, and the SuperPython module by MJD, all released on April Fools' Day 2001. With all that global namespace trampling on a single day, no wonder there was such a crying need to create the Acme namespace:

    This week was fairly random, mainly because of April Fool's Day. I released a silly Buffy module (which, a la Bleach, converts modules into "BUffY bUFFY BUffY bUFFY bUfFy buffy..."), with example decss code. Schwern released DNA ("CCAA CCAA AAGT CAGT TCCT CGCT..."), mjd released SuperPython (" ..."), and David Cantrell released (late) Pony, a converter to "a lovely ASCII-art rendition of a pony".

      It's worth pointing out that when Damian demonstrated to the module to, it was simply called "Bleach". BackPan confirms that version 1.000 of was uploaded on 21 Feb 2001. It was only with release 1.012 on 21 May 2001 that it acquired its more recognisable name. So it looks like Acme::Buffy and Acme::Pony both beat it into the Acme namespace.

      All of which makes me wonder if Leon had more to do with the invention of the Acme namespace than Damian says above. After all, he's been using the nick "acme" on IRC since well before this all happened :-)


      See the Copyright notice on my home node.

      Perl training courses

        All of which makes me wonder if Leon had more to do with the invention of the Acme namespace than Damian says above.
        Not as far as I know (though, of course, he may well have been mind-controlling me without my knowledge). I actually wrote to Leon to apologize for having chosen "Acme" and to ensure he was okay with that. He was, as always, extremely gracious and bestowed his most aranciate blessing on the choice.


        Well, I'm gaining the distinct impression that acme was (and remains) a formidable player "behind the scenes" -- I suspect he was egging on DrHyde behind the scenes to upload Acme::Pony, for instance. So perhaps he was similarly urging Damian to please, please choose Acme as the new joke module namespace. :)

        However, I believe that Acme::Bleach was the first uploaded Acme module, at least that's what I see:

        • Backpan DCONWAY shows Bleach released on 21 Feb 2001 and Acme::Bleach on 21 May 2001
        • Backpan LBROCARD shows Buffy released on 1 Apr 2001 and Acme::Buffy on 23 May 2001
        • Backpan DCANTRELL shows Pony released on 3 Apr 2001 and Acme::Pony on 20 June 2001

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlmeditation [id://967004]
Approved by moritz
Front-paged by moritz
erix likes multitail
[afoken]: and tail is part of POSIX, less isn't.
[afoken]: So tail works at every Unix's prompt, less only on a subset.

How do I use this? | Other CB clients
Other Users?
Others cooling their heels in the Monastery: (11)
As of 2017-01-17 20:10 GMT
Find Nodes?
    Voting Booth?
    Do you watch meteor showers?

    Results (158 votes). Check out past polls.