A blog about Modern Perl, bioinformatics and anything else that I feel like rambling about.

Wednesday, November 25, 2009

Embedding images in POD

Gabor's post lamenting the lack of image examples in image-related modules (like charting) reminded me that once I bumped into a module that did show images in its documentation. They weren't links to images, but actual images, showing there in the CPAN search page.

I couldn't find that module again to see how it was done, but after a little googling and talking to some freenode #perl folks, we came up with a way to do it.

Behold:

=head Title

This module is awesome because it deals with pretty pictures, like this one:

=begin html

<img
src="data:image/gif;base64,[gibberish here]"
alt="foo" width="42" height="42"
/>

=end html

So the trick involves escaping the image source for non-html readers of pod (surrounding the img tag with =begin html and =end html), and using a base64 version of the image. I found this service to convert binary images into their base64 representation, which even lets you choose the column width of the resulting string.

It's a workaround, but having an example picture or two in some of the many plotting and charting modules out there might be very well worth the effort.

Here's a complete example, with an actual image. Copy it to a pod file, run pod2html, and see the resulting .html document in your browser:


=head Title

This module is awesome because it deals with pretty pictures, like this one:

=begin html

<img src="data:image/gif;base64,
R0lGODlhTwBGAOf/AEsvHV8/KXNML3lKMm1NOXFNNH1PLoVPMXZTOXZTQINSOINTPotRPX5ZP31a
R5tVQIpcOZNaO5VZRJFdQ49eSYVhTYliR7FZRIZlVa5cRYVmW6dfRoFqSpFmX8BcR8NfP6VoR85c
SN5YR6JpUpptRLhlS5JvX75kS5FvZZhvWZlwUIx0U5BzV5BxbbRqTrdrRcxlTYt6U5h4TYx8TtFp
SdlmUuRkUd1nTbN1U515cqh6SaV6W7h3RqV6ZKN+RKF+SpSCSbF3Ybh3Tax6U6R6bM5yV52DRa5+
R5KGS9hwV8R4RZiFRpOFVaSDQJmEV8V4VpWIR8J5YZuIQvNrYJ+GTvFwXpuOTKGNTbaHUaOOSMaD
UvF2VcKDYa6MQ/B2W5+QSLuGXOR6XpiRW6+MTbeIZcCHVqmPTO94ZNSBYL2KTayOWqORV6GRXrSQ
QKqPaaCUV6+TR6yVSKqVT6WXTuODYp6YYKiYScOQTLOWRLqPeciOfPWFXtiMdciVUK+eT6qgT9WS
XfSIZbKdXK2fV7ubWNOSbsmVbr2cUuOPabafUfaJcMebTbafWL+eSaiiac2YYbydZ7OgZs6bTq+j
ZbikT7alVbWlXLGnVbCnXK2naPeUcburYdmkVr+sVb6sXLmuXcOrX82pW/eaddalb9CnbsCsb9Sp
UtekfLaxXsmqbLyubuKhgbawb9+laMiuVrKycOKmY76yWbu1W/GhiMa0VcezXMWzY8C1YvWjfO6o
dc+xjdutl/Oomc26ad20etS6ZO6tmsq+XtC8ZeyyeO2zbsq+a9K9X/Svi8y/ZtS+WeqykMy+edm9
Ydq6ft66c9a9ctO9fc3Bdf24ifu4keTFW/i4ptTJfNzIcNvGh+DHfvy+idvJfuDKZ+fEkdHNfuvF
huTJddXOdPjCidbNhtzObdvOdNvMi9XPjubJofvFmvTGqfbKf9rSl+TUc+TVfOvUdN7VoePXid7W
qObWqu7SvN7YsOXYsvzVmOTZufzZpf/atf3cre/huv/lvv7v0v324ywAAAAATwBGAAAI/gDt4Rto
T6DBeQUT2pOn0B7Chg3rwbNmzZvFixSXWVu2TJWqSKVCelQ1iY0TJo4meWTF6lUmVpliOqpTZ95A
ghBz6iz4sKA8eByjVfRG8WK4aCNDqiylMhKbp0ycsFHF8lXLmK9czsSGTyC+evbA7lTYM6HYemCD
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
QNiKTdagLdNWfdh8fcnl3AQBAQA7"/>

=end html


Update: confound told me that apparently data tags don't work with IE6, so if you are planning to do this in your module, take it into consideration.

Tuesday, November 24, 2009

Baby Haskell and Good Old Perl

I finally drank the functional, immutable and pure koolaid and started reading some Haskell books. And to exercise a bit, I began to tackle some of the problems from project Euler.

Problem 10 states: "Find the sum of all primes less than 2,000,000".

After finding out that it's only necessary to check for divisors less than the square root of the number, I blatantly stole this version from the Haskell Wiki:


If this doesn't give you a nerdgasm, I don't know what will. It creates an infinite list of primes by filtering an infinite list of odd numbers with the isPrime function. This function, in turn, uses the primes list itself to look for potential divisors. So basically, the list is defined recursively.

The solution then boils down to getting all primes smaller than two million from the infinite list, summing them and outputting the result.

Anyway, this beautiful solution got me wondering how the perl version would look. Here is my first attempt:


Ugh. I mean, it's not that bad, it has some interesting things going on like having an infinite stream of primes, but after being embelished by the Haskell version, this seems uninspired at best.

But then I thought that being CPAN (and not syntax) Perl's strength, I should take a look there. After no more than 30 seconds of searching, I found Math::Primality. Look how the Perl 5 version looks now:


This put a smile on my face. Perl may not be the most beautiful language around, but it has a JFDI attitude that I have yet to find elsewhere.