#!/usr/bin/perl -w =pod You've probably guessed by now that the program "semaphores"; that is, encodes and decodes semaphore, the system for sending text messages by waving pairs of flags. [notice our ambiguous phrasing in README?] It prints "The Perl Journal" by using semaphore over IPC. Letters are encoded as a text drawing of a person (actually just a head and arms) semaphoring that letter. So, . _. \. a <---> / | , b <---> | , c <---> | , etc.. Normal semaphore can only encode the characters a-z0-9. We have extended it to be able to encode arbitrary ASCII text - and indeed arbitrary unicode UTF-8 text. See SOLUTION2 for a full definition of our system, and how we encode into and decode from it. The name of the program is important: - If $0 eq "sink" (or anything else matching /k/), it encodes semaphore. - If $0 eq "swim" (or anything else not matching /[ok]/), it decodes. - If $0 eq "The_Perl_Journal", it forks; the parent prints "The Perl Journal" to the child, in encoded form. The child decodes and prints this message. Notice that we always print to STDOUT, not STDERR. That means we had to use things like "print;exit" rather than "die $_". It took David^H^H^H^H^H us a lot of squeezing to make enough room to do that, but Sebi^H^H^H^H we thought it was worth it because it is The Right Thing to do. Obfuscations include: - Using confusing separators for s/// and y///; - Joining statements with useless void-context operators instead of semicolons; - Writing the code in a confusing order; - Usinging pointlessly big ranges on the LHS of y///; - Using "open" to close a filehandle; - Writing the logic of the fork unclearly - also done to save space; - Encoding/decoding arm positions with maths tricks - also done to save space; - Having no gratuitous obfuscations due to lack of space. Maybe next time ... Here's a de-obfuscated version of the program. See SOLUTION2 to understand how the mathematical lines work. You can run this file; make sure it is symlinked/copied to "The_Perl_Journal", "sink" or "swim"! =cut sub encode { # encodes global variable $_ # encode non- /[a-z ]/ characters as #xxxxj, where xxxx is ascii value s/[^a-z\n ]/"#".ord($&)."j"/ge; # Transcribe into semaphore positions. See SOLUTION2. X never gets used. y/ 0-9k-uyX#jv-xz\n/`ja-|/d; # replace each character with "X.Y", X and Y representing arm positions s!.!for($a=0,$b=-96+ord$&;$b>7-$a;$b-=7-$a++){}$b+=$a;$a>5||$b+$a<5?"$b.$a":"$a.$b"!eg; # from arm positions, derive 2-line semaphore picture representation ($a=$_)=~y!70-6.!\\|/ !; y!2-701!_\\|/_ !; return "$_\n$a\n"; } sub decode { # decodes each line of <> # replace each arm with a number representing its position /\./ ? y!_\\|/!2-5! : y!/|\\!107! for @_=<>; $_=join"",@_; # Merge every pair of lines: change spaces to \0 then use logical or y! !\0!; s!(.*\n)(.*\n?)!$1|$2!eg; # kludge to make right arms, "._", decode correctly s!\.2!.6!g; # derive character from "X.Y" representing arm positions s!(.)\.(.)!chr(96+(0,7,13,18,22,25,27)[$1>$2?$2:$1]+abs$2-$1)!ge; # Transcribe into ascii positions. See SOLUTION2. y/`j-|/ k-uy\b#jvwxz/; # decode #xxxxj as chr(xxxx) s/#([ka-i]+)j/$_=$1;y!ka-i!0-9!;chr/seg; $_; } $_ = $0; # get program's name if (/sink/) { # encode print encode while <>; exit; } elsif (!/Journal/) { # decode print decode; exit; } # print "The Perl Journal" if (open CHILD, "|-") { # parent: send message to child y/-/ /; # change "The_Perl_Journal" to "The Perl Journal" print CHILD encode; close CHILD # close pipe to child, and wait till child finishes } else { # child: recieve message from parent and print it. print decode; }