NAME¶
Acme::EyeDrops - Visual Programming in Perl
SYNOPSIS¶
use Acme::EyeDrops qw(sightly);
print sightly( { Shape => 'camel',
SourceFile => 'eyesore.pl' } );
DESCRIPTION¶
"Acme::EyeDrops" converts a Perl program into an equivalent one, but
without all those unsightly letters and numbers.
In a Visual Programming breakthrough, EyeDrops allows you to pour the generated
program into various shapes, such as UML diagrams, enabling you to instantly
understand how the program works just by glancing at its new and improved
visual representation.
Unlike "Acme::Bleach" and "Acme::Buffy", the generated
program runs without requiring that "Acme::EyeDrops" be installed on
the target system.
EXAMPLES¶
Getting Started¶
Suppose you have a program,
helloworld.pl, consisting of:
print "hello world\n";
To convert this little program into an equivalent camel-shaped one, create
cvt.pl as follows:
# cvt.pl. Convert helloworld.pl into a camel shape.
use Acme::EyeDrops qw(sightly);
print sightly( { Shape => 'camel',
SourceFile => 'helloworld.pl',
Regex => 1 } );
Then run it like this:
perl cvt.pl >new.pl
After inspecting the newly created program,
new.pl, to verify that it
does indeed resemble a camel, run it:
perl new.pl
to confirm it behaves identically to the original
helloworld.pl.
Instead of using the API, as shown above, you may find it more convenient to use
the
sightly.pl command in the
demo directory:
sightly.pl -h (for help)
sightly.pl -s camel -f helloworld.pl -r >new.pl
cat new.pl (should look like a camel)
perl new.pl (should print "hello world" as before)
Notice that the shape 'camel' is just the file
camel.eye in the
EyeDrops sub-directory underneath where
EyeDrops.pm is located,
so you are free to add your own new shapes as required.
For the meaning of Regex => 1 above, see the
Just another Perl hacker
section below.
Making Your Programs Easier to Understand¶
If your boss demands a UML diagram describing your program, you can give him
this:
print sightly( { Shape => 'uml',
SourceFile => 'helloworld.pl',
Regex => 1 } );
If it is a Windows program, you can indicate that too, by combining shapes:
print sightly( { Shape => 'uml,window',
Gap => 1,
SourceFile => 'helloworld.pl',
Regex => 1 } );
producing this improved visual representation:
''=~('('.'?'.'{'.('`'|'%').('['^'-').(
( (
( (
( (
( (
( (
'`'))))))))))|'!').('`'|',').'"'.('['^
(
( (
( (
'+'))))
)
)
.('['^')').('`'|')').('`'|'.').(('[')^
( (
( (
'/'))))).('{'^'[').'\\'.('"').( '`'|'(').('`'|'%').('`'|"\,").(
( ( ( (
( ( ( (
( ( ( (
( ( ( (
( ( ( (
'`'))))))))))))))))))))|"\,").( '`'|'/').('{'^'[').('['^"\,").(
'`'|'/').('['^')').('`'|',').('`'|'$').'\\'.'\\'
.('`'|'.').'\\'.'"'.';'.('!'^'+').'"'.'}'."\)");
$:='.'^'~';$~='@'|'(';$^=')'^'[';$/='`'|"\.";$,=
"\("^ (( '}'))
;($\) =( '`')|
"\!"; $: =')'^
"\}"; $~ ='*'|
"\`"; $^ ='+'^
"\_"; $/ ='&'|
"\@"; $, ='['&
"\~"; $\ =','^
"\|"; $: ='.'^
"\~"; $~ ='@'|
"\("; $^ =')'^
'[';$/='`'|'.';$,='('^'}';$\='`'|'!';$:=')'^'}';
($~)= (( '*'))
|'`'; $^ ='+'^
"\_"; $/ ='&'|
"\@"; $, ='['&
"\~"; $\ =','^
"\|"; $: ='.'^
"\~"; $~ ='@'|
"\("; $^ =')'^
"\["; $/ ='`'|
"\."; $, ='('^
"\}"; $\ ='`'|
'!';$:=')'^'}';$~='*'|'`';$^='+'^'_';$/='&'|'@';
$,='['&'~';$\=','^'|';$:='.'^'~';$~='@'|"\(";$^=
')'^'[';$/='`'|'.';$,='('^'}';$\='`'|'!';$:=')';
This is a Visual Programming breakthrough in that you can tell it is a Windows
program and see its UML structure too, just by glancing at the code.
For Linux only, you can apply its
/usr/games/banner command to the
program's source text:
print sightly( { Shape => 'srcbanner',
Width => 70,
SourceFile => 'helloworld.pl',
Regex => 1 } );
The generated program is easier to understand than the original because its
characters are bigger and easier to read.
An Abbreviated History of Perl 6¶
Here is a summary of the Perl 6 development effort so far:
print sightly( { Shape => 'jon,larry,damian,simon,parrot,' .
'buffy3,autrijus',
Gap => 3,
Regex => 1,
Print => 1,
Indent => 1,
SourceString => <<'END_HAIKU' } );
Coffee mug shatters
Larry Apocalyptic
Parrot not a hoax
Design, debate, sift
Prankster Piers pawky precis
Weekly light relief
Gallop Ponie bold!
Beer to gulp, Buffy astride
Orange sky surrounds
Lambda hugs camel
Precocious pup productive
Sixth pearl glorious
END_HAIKU
producing:
''=~(
'('."\?".
'{'.('['^'+'
).('['^"\)").(
'`'|')').('`'|
'.').('['^'/').
'"'.('`'^'#').(
'`'|'/').(('`')|
'&').('`'|'&').(
'`'|'%').("\`"|
'%').('{'^'[').
('`'|('-')).(
'['^"\.").(
'`'|"'").(
'{'^'[').('['^'(')
.('`'|'(').('`'|'!')
.('['^'/').('['^"\/").(
'`'|'%').('['^')').('['^"\(").(
'!'^'+').('`'^',').('`'|'!').('['^')').(
'['^')').('['^'"').('{'^'[').('`'^'!').('['^'+')
.('`'|'/').('`'|'#').('`'|'!').('`'|',').('['^'"').
('['^'+').('['^'/').('`'|')').("\`"| "\#").(
'!'^'+').('{'^'+').('`'|('!')).( '['
^')').('['^')').('`'|"\/").(
'['^'/').('{'^'[').('`'|'.')
.('`'|'/').('['^'/').(('{')^
'[').('`'|'!').('{'^'[').('`'
|'(').('`'|'/').('`'|('!')).(
'['^'#').('!'^'+').('!'^'+').(
'`'^'$').('`'|'%').('['^'(').(
'`'|')').('`'|"'").('`'|"\.").
','.('{'^'[').('`'|'$').("\`"|
'%').('`'|'"').('`'|'!').("\["^
'/').('`'|'%').','.('{'^('[')).(
'[' ^'(').('`'|')').('`'|'&').("\["^
'/').('!'^ '+').('{'^'+').('['^')').(('`')|
'!').('`'|'.' ).('`'|'+').('['^'(').('['^'/'). +(
'`'|'%').('['^')').('{'^'[').('{'^'+').(('`')| ( (
')'))).('`'|'%').('['^')').('['^'(').('{'^'[').( ( (
'['))^'+').('`'|'!').('['^',').('`'|'+').('['^'"'). (('{')^
'[').('['^'+').('['^')').('`'|'%').('`'|'#').(('`')| ')').('['^
'(').('!'^'+').('{'^',').('`'|'%').('`'|'%').('`'|'+').('`'|','
).('['^'"').('{'^'[').('`'|',').('`'|')').('`'|"'").('`'|'(').(
'['^'/').('{'^'[').('['^')').('`'|'%').('`'|',').('`'|')').('`'|
"\%").( "\`"| '&').('!'^'+').('!'^'+').('`'^"'").('`'|'!').(
(( '`'))|',').('`'|',').('`'|'/').('['^'+').('{'
^'[').('{'^'+').('`'|'/').('`'|'.').('`'|')'
).('`'|'%').('{'^'[').('`'|('"')).( "\`"|
'/').('`'|',').('`'|'$').'!'.('!'^'+'
).('`'^'"').('`'|'%').('`'|'%').("\["^
')').('{'^'[').('['^'/').('`'|'/').('{'
^'[').('`'|"'").('['^'.').('`'|',').('['^
'+').','.('{'^'[').('`'^'"').('['^"\.").(
'`'|'&').('`'|"\&").( '['^'"').('{'^'[').(
'`'|'!').('['^"\(").( '['^'/').('['^')').
('`'|')').('`'|'$').( '`'|'%').('!'^'+')
.('`'^'/').('['^
')').('`'|'!').('`'|'.'
).('`'|"'").('`'|'%').('{'^'['
).''. ('['
^'(' ).(
'`'| '+'
).+( ( '['
)^(( ( '"'
)))) .( ( '{'
)^(( ( ( '['
))) )) .( '['
^(( (( ( '('
))) ))). ( '['
^(( '.') ) ).(
'[' ^')' ) .+(
'[' ^(')')).( ( '`'
)|+ (( ( ((
'/' )) ) ))
).( ( ( ((
'[' ) )))^+
'.' ) .(
'`' | '.').('`'|'$').('['^'(').('!'^('+')).(
'!' ^'+').("\`"^ "\,").( ( ( "\`"))| (
'!' ) ) .+( '`' |+ ( ( (( '-' ))) )
).( ( ( '`'))|'"').( ( ( '`'))|'$').( (
'`' ) | ( ( (
(( '!' ) ) ) )) )
.( ( '{')^ ( ( (( (
(( ( ( ( ( ( (
(( ( '[' ))))))))))))))) ) ).('`'|'(').
+( ( ( ( (
( ( ( ( (
( ( ( '[' ) )
) ))) )) )
) ) )^'.').('`'|"'").('[' ^
( ( '('))).('{'^'[').(('`')| (
( ( '#')))).('`'|'!').('`'|'-' )
. ( "\`"| '%').('`'|',') .''. (
( ( '!') ) ^ '+' )
.( '{' ^'+').('['^')'). (((
( (
( (
( (
( ( (
( ( (
( ( (
( ( (
( ( ( (
( ( ( (
( '`' )) )
) ))))))))))) )
)))))))))))))|+
'%').('`'|'#').('`'|
'/').('`'|'#').('`'|')').
('`' |'/'
).+( '['^
'.') .''.
('[' ^'('
).+( '{'^
'[') .''.
('[' ^'+'
).+( '['
^'.' ).+(
'['^ '+').( '{'^
'[') .''. ( '['
^(( '+' ))).('[' ^ ')'
).( ( '`') |(( ( '/'
))) ) .('`'|'$'). ( '['
^(( ( ( '.'
))) ) ) .+(
'`' | ( '#'
)). ( ( '['
)^+ ( ( '/'
)) ) . (((
( (( ( ( ((
( (( ( ( ((
( '`') ))))))))) )))))) )|+
( ')' )). ((( '[' ))^ '-'
) .( (( ('`')))| "\%").( ((
( ( (( (( '!') )) ) )) ))^+ (( (
( ( '+' )))))).''. ( '{'^"\(").( (
( ( (( ( (
( (( ( ((
( '`' ) ))
) ))) ) )))
)))|')' ) .+(
"\["^ ( ( ( '#'
)))). ( ( ( '['
))^'/' ).('`'|'('). ('{'
^'['). ('['
^'+').( '`'|'%').('`'|'!'). ('['
^"\)").( '`'|',').('{'^'[').('`'| "'")
.(('`')| (( ','))).
('`'|"\/").( '['^')').('`'|')') .('`'|
'/').('['^ '.').('['^'(' ).''.
('!'^'+'). ('"').
'}'."\)");$:= '.'^"\~";
$~='@'|'(';$^=')'^'[';$/='`'|'.'
;$,='('^'}';$\='`'|'!';$:=(')')^
'}';$~='*'|'`';$^='+'^('_');$/=
'&'|'@';$,='['&'~';$\=','^'|';
$:='.'^'~';$~='@'|'(';$^=')'
^'[';$/='`'|'.';$,=('(')^
'}';$\='`'|'!';$:="\)"^
'}';$~='*'|('`');$^=
'+'^'_';$/=('&')|
'@';$,='['&
'~';$\=','^"\|";
$:='.'^'~'; $~=('@')|
'(';$^=')'^'[' ;$/='`'|'.'
;$,='('^"\}";$\= '`'|"\!";$:=
')'^'}';$~='*'|'`' ;$^='+'^"\_";
$/='&'|'@';$,='['&'~' ;$\=','^"\|";
$:='.'^'~';$~='@'|"\("; $^=')'^'[';$/
='`'|'.';$,='('^"\}";$\= '`'|'!';$:=')'
^'}';$~='*'|'`';$^='+'^'_' ;$/='&'|'@';$,
='['&'~';$\=','^'|';$:='.'^ '~';$~='@'|'(';
$^=')'^'[';$/=('`')| '.' ;$, ='('^'}'
;$\='`'|'!';$:=')' ^'}';$~
='*'|'`';$^=('+')^ '_';$/=
'&'|'@';$,='['&'~' ;($\)=
','^'|';$:='.'^'~'; $~='@'
|'(';$^=')'^'[';$/= "\`"|
'.';$,='('^"\}";$\= ( '`')
|'!';$:=')'^'}';$~ = '*'
|'`';$^='+'^'_';$/ = ((
'&'))|'@';$,="\["& ( ((
'~')));$\=','^'|'; ( ( ( ( ( ( (
$:)))))))='.'^"\~"; ( ( ( ( (
$~)))))='@'|'(';$^ =')'^ '[' ; (
( $/))='`'|'.';$, ='('^'}' ;($\) = (
( '`'))|'!';$: = (
')')^"\}"; ( $~)
= '*' | (
( ( (
( ( (
( ( (
( ( ( ( ( ( (
( ( ( ( (
( ( ( (
( (
( (
( ( '`')))))) )
) ) )))))))))))))
) ) )))))))) ;
( ( $^))='+'^'_';
( ( ( (
( ( ( (
( ( (
( ( ( ( (
( (
( (
( (
( ( (
( (
( ( ( (
$/)))))))
))))))))))))))
))))))))))='&'|"\@";
$,='['&'~';$\=','^'|';$:=
'.'^'~';$~=('@')| '(';$^=
')'^'[';$/='`'|'.';$, ='('^'}'
;$\='`'|'!';$:=')'^'}';$~='*'|'`';$^
='+'^'_';$/='&'|'@';$,='['&'~';$\="\,"^
'|';$:='.'^'~';$~='@'|'(';$^=')'^('[');$/=
'`'|'.';$,='('^'}';$\='`'|'!';$:=')'^'}';$~=
'*'|'`';$^='+'^'_';$/='&'|'@';$,='['&"\~";$\=
','^'|';$:='.'^'~';$~='@'|'(';$^=')'^ '['
;$/='`'|'.';$,='('^'}';$\='`'|'!';$:= ')'
^'}';$~='*'|'`';$^='+'^'_';$/='&'|'@'
;$,='['&'~';$\=','^'|';$:='.'^'~';$~=
'@'|'(';$^=')'^'[';$/='`'|'.';$,="\("^
'}';$\='`'|'!';$:=')'^'}';$~='*'|"\`";
$^='+'^'_';$/='&'|'@';$,='['&('~');$\=
','^'|';$:='.'^'~';$~='@'|'(';$^="\)"^
'[';$/='`'|'.';$,='('^'}';$\='`'|'!';
$:=')'^'}';$~='*'|'`';$^='+'^"\_";$/=
'&'|'@';$,='['&'~';$\=','^('|');$:=
'.'^'~';$~='@'|'(';$^=')'^"\[";$/=
'`'|'.';$,='('^'}';$\='`'|"\!";$:=
')'^'}';$~='*'|'`';$^='+'^('_');$/=
'&'|'@';$,='['&'~';$\=','^"\|";$:=
'.'^'~';$~='@'|'(';$^=')'^('[');$/=
'`'|'.';$,='('^'}';$\='`'|"\!";$:=
')'^'}';$~='*'|'`';$^='+'^"\_";$/= '&'
|'@';$,='['&'~';$\=','^'|';$:='.'^ (
'~');$~='@'|'(';$^=')'^('[');$/= '`'|
'.';$,='('^'}';$\='`'|('!');$:= ')'^'}'
;$~='*'|'`';$^='+'^'_';$/='&'| '@';$,='['&
'~';$\=','^'|';$:='.'^'~';$~= '@'|'(';$^=')'
^'[';$/='`'|"\.";$,= (( '('))^'}';$\='`'|
'!';$:=')'^('}');$~= ( '*')|'`';$^='+'^'_'
;$/='&'|'@';$,="\["& ( ( '~'));$\=','^'|';
$:='.'^'~';$~='@'|'(' ; $^=')'^'[';$/=
'`'|'.';$,='('^'}';$\ ='`'|"\!";
($:) =')'^'}';$~='*' |'`';$^
=(( '+'))^('_');$/= '&'
|+ '@';$,='['&"\~";
( $\)=','^"\|";$:=
'.'^'~';$~="\@"|
'(';$^=')'^"\[";
$/
='`'|'.'
;$,=('(')^
'}';$\="\`"|
'!' ;$:
= (
( (
')' ))
)^(( '}'
));$~ ='*'
|'`'; ( $^)=
"\+"^ '_';
$/="\&"| '@' ;($,)
= '[' & ( ( (
( ( ( ( (
( ( ( (
( '~')))))))))) )
) );$\=','^'|';$: = '.'^ '~';
( $~)='@'|'(';$^= ( ( ')'))^'[';$/= ((
( '`')))|"\.";$,= ( ( '('))^'}'; (
( $\))='`'|'!'; ( $:)=')'^'}'; $~
= '*'|('`');$^= ( ( ('+')))^ '_'; $/
= '&'|('@');$,= ( '[')&'~' ; ( $\
) =','^"\|";$:= '.' ^+ '~'; $~= ((
( '@')))|"\(";$^= ')' ^+ (( ( (( '['
) ))));$/='`'|('.');$,= (( (( '(')) ))
^ '}';$\='`'|'!';$:=')'^ (( '}'));$~ =(
'*' )|'`';$^='+'^'_';$/='&'| '@' ;$,='['& ((
'~'));$\=','^'|';$:='.'^'~'; $~ ='@' |('(');$^=
(')')^ '[';$/='`'|'.';$,='(' ^(( (( '}')))) ;($\)=
'`' |'!';$:=')'^"\}";$~= '*'|('`');$^= (( (
'+' )) )^"\_";$/= (( '&') )|'@';$, ='['
&'~' ;$\=',' ^'|';$: =( '.')^"\~"; ($~)=
'@'|'(' ;$^ =')' ^(( (( '[' )))
);( $/ )=( (( '`' )) )|'.';$,=
(( (( (( '(')) )) ))^'}'
;( ( $\) )='`' |+ '!'
;( $: )= "\)"^ '}' ;(
$~ )= (( '*'))|'`'; $^= '+'^
'_' ;( $/ )=(( '&'))| (( '@')
);( $, )= '['& '~';$\ ="\,"^
'|' ;( $: )= (( '.'))^'~';$~ =(
(( '@' )) )| (( "\("));$^=
(( ')' ) )^ (( '[')); $/ ='`'
|+ '.' ;$,= ( (( (( ((
(( (( '(') ) )) )) )
)) ))^(( ( ( (( '}'))) ))
); $\ ='`' |+ (( '!')) ;(
$: )=')'^'}' ;( ($~)) ='*' |+
(( '`'));$^ ='+'^'_';$/= "\&"| '@';
$,= (( '['))&"\~";$\= ','^ '|';$:
="\."^ '~';$~='@'|'(';$^=')'^'[';$/=
('`')| '.';$,='('^"\}";$\= '`'|'!';$:=
')'^'}' ;$~='*'|'`' ;$^='+'^ '_';$/='&'
|'@';$,= '['&'~'; $\=','^ '|';$:='.'
^'~';$~= '@'|'(' ;($^) =')'^'['
;$/='`' |"\."; ($,)= '('^'}'
;($\)= '`'| '!';$: =(')')^
"\}"; ($~)= ('*')| '`';$^='+'
^'_' ;$/=('&')| '@';$,="\["&
'~'; $\=','^'|'; $:='.'^"\~";
($~) ='@'|'(';$^ =')' ^'['
;($/) ='`'|'.';$, ='(' ^+
'}';$\ ='`'|'!';$:= ')'^'}';
$~='*'| '`';$^='+'
^'_';$/= ('&')|
'@';$,=
'['&'~'
;$\=','
^('|');$:=
'.'^'~' ;$~='@'|'(';$^
=')'^'['; $/='`'|'.';$,='('
^'}';$\='`' |'!';$:=')'^'}';$~=
'*'|"\`";$^= '+'^'_';$/='&'|"\@";
$,='['&'~';$\ =','^'|';$:='.'^"\~";
$~='@'|'('; $^=')'^'[';$/="\`"|
('.');$,= '('^'}';$\='`'|'!'
;$:="\)"^ '}';$~='*'|'`';$^
='+'^'_' ;$/='&'|'@';$,="\["&
"\~";$\= ','^'|';$:='.'^"\~";$~=
'@'|'('; $^=')'^'[';$/='`'|'.';$,=
'('^'}'; $\='`'|'!';$:=')'^'}' ;$~='*'|'`'
;($^)= '+'^'_';$/='&'|'@' ;$,='['&"\~";
($\)= ','^'|';$:="\."^ '~';$~='@'|"\(";
$^=')' ^'[';$/='`'|'.' ;$,='('^('}');$\=
('`')| '!';$:=')'^'}' ;$~="\*"| "\`";$^=
('+')^ ( '_');$/=('&')| "\@"; $,='['
&"\~"; ( ( $\)) =',' ^+ "\|";
$:='.' ^(( '~') );($~)
="\@"| '(';$^ =( ')') ^'['; $/='`'
|"\."; $,="\("^ (( '}') );$\='`'|('!');$:=
(')')^ '}' ;$~= '*'|'`';$^='+'^'_';$/
="\&"| '@'; ($,) ='['&'~';$\=','^'|';$:
="\."^ '~';$~='@'|'(' ;$^=')'^ "\[";$/=
('`')| '.';$,='('^'}' ;($\) ='`'|'!';
$:=')' ^(( '}'));$~='*'|'`'
;($^) =( '+')^'_';$/=('&')|
'@';$, = ( '[')& '~';$\=','^
'|';$: = ( ( ( '.' )))^'~';$~
="\@"| (( (( '('))));$^
=(')')^ (( ( "\[")));$/=
'`'|'.'; $, =( ( (( '('))))^'}'
;$\='`'| '!';$:=')' ^+ '}';$~=('*')|
"\`";$^= ( "\+")^ ( '_') ;$/='&'|('@');$,=
'['&"\~"; ($\) =','^'|';$:="\."^
'~';$~='@' | ( '('); $^=')'^('[');$/=
'`'|'.';$, = ('(')^ '}';$\='`'|'!';
$:=')'^'}'; ( ( ( ( $~))))= '*'|'`';$^='+'^
'_';$/='&' |'@';$, ='['&'~';$\=','
^"\|";$:= '.'^'~' ;$~='@'|'(';$^=
')'^'['; $/='`'| '.';$,='('^'}';
$\='`'| '!';$:= ')'^'}';$~='*'|
'`';$^ ="\+"^ '_';$/='&'|'@';
($,) ='[' &'~';$\=','^'|'
Just another Perl hacker¶
Let's get more ambitious and create a big self-printing
JAPH.
my $src = <<'FLAMING_OSTRICHES';
open 0;
$/ = undef;
$x = <0>;
close 0;
$x =~ tr/!-~/#/;
print $x;
FLAMING_OSTRICHES
print sightly( { Shape => 'japh',
SourceString => $src,
Regex => 1 } );
This works. However, if we change:
$x =~ tr/!-~/#/;
to:
$x =~ s/\S/#/g;
the generated program malfunctions in strange ways because it is running inside
a regular expression and Perl's regex engine is not reentrant. In this case,
we must resort to:
print sightly( { Shape => 'japh',
SourceString => $src,
Regex => 0 } );
which runs the generated sightly program via "eval" instead. If you
want to use Regex => 1 (to eliminate
all alphanumerics), ensure the
program to be converted is careful with its use of regular expressions and $_.
To produce a
JAPH that resembles the original
Just another Perl
hacker, aka
Randal L Schwartz, try this:
print sightly( { Shape => 'merlyn',
SourceString => 'Just another Perl hacker,',
Regex => 1,
Print => 1 } );
producing:
''=~('('.'?'.'{'.('['
^'+').('['^')').('`'|')').(
'`'|'.').('['^'/').'"'.('`'^'*')
.('[' ^'.')
.('[' ^'(')
.('[' ^'/')
.('{'^ '[').(
"\`"| '!').(
'`'| '.').(
'`'| ( ( '/'))).
('[' ^ ( ( '/'))).(
'`'| ( ( ( ( '('))))).
('`'| ( ( ( ( '%'))))).
('['^ ( ( ( ( ')'))))).
('{'^ '[') .( ( (( ('{'))))^
'+'). ( '`'|'%' ).("\["^ ')').('`'
|',').('{'^ '[').('`'
|'(').('`' |"\!").(
'`'|'#').( ('`')| '+').( '`'|'%')
.('['^')') .(( ',' )). '"' .('}').
"\)");$:= ('.')^ ( "\~"); $~='@'|
('(');$^= (( ')' )) ^ (( '[' )) ;($/)=
'`'|'.'; $,='('^'}' ; $\='`'|'!' ;($:)
=(')')^ ( '}'
);($~) = '*'
|'`'; ( ( ( $^)
) )= ( ( ( '+'
) ) ) ^ ( ( ( '_'
) ) ) ; ( ( ( $/
) ) ) =
( ( ( (
( ( ( (
( '&')))))))))|'@' ; ( (
( ( ( ( ( $,
) ) ) ) ) ))
= ( (( (( ( (
( ( ( (( ( (
( ( '[')) ) )
) ) ) )
) ) ) )
) ) )
) & (
( ( (
( ( (
( (
( (
'~' ))
)))))))))
Buffy Looking in the Mirror¶
Because the
sightly encoding is not very compact, you sometimes find
yourself playing a surreal form of
Perl Golf, where the winner is the
one with the smallest
f.tmp in:
sightly.pl -r -f program_to_be_converted >f.tmp
Apart from reducing the (key-)stroke count, you must avoid regexes and strive to
replace alphanumeric characters with sightly ones, which do not require
sightly encoding.
To illustrate, consider the intriguing problem of creating
Buffy looking in
the mirror. Let's start with
k.pl:
open$[;chop,($==y===c)>$-&&($-=$=)for@:=<0>;
print$"x-(y---c-$-).reverse.$/for@:
Notice that EyeDrops-generated programs, by default, contain no trailing spaces,
which complicates the above program.
Buffy looking in the mirror can now be created with:
sightly.pl -r -f k.pl -s buffy2 >b.pl
cat b.pl (should show Buffy's face)
perl b.pl (should show Buffy looking in the mirror)
Drat. This requires two
buffy2 shapes. What to do? Well, you could use
the "TrailingSpaces" attribute ("-T" switch to
sightly.pl) to append the required number of trailing spaces to each
line, allowing you to write a briefer
kk.pl:
open$%;chop,print+reverse.$/for<0>
and finally produce
Buffy looking in the mirror with:
sightly.pl -Tr -f kk.pl -s buffy2 >bb.pl
Alternatively, the "Compact" attribute ("-m" switch to
sightly.pl) could be used to produce a solution free of any trailing
spaces:
sightly.pl -mr -f k.pl -s buffy2 >buffy.pl
cat buffy.pl (should show Buffy's face)
perl buffy.pl (should show Buffy looking in the mirror)
producing
buffy.pl:
''=~('(?{'.(
'`'|'%').('['^'-'
).('`'|'!').('`'|','
).+ ( '"'
).( ( '`'
)|+ ( '/'
)). ( '['
^(( ( '+'
))) ).('`' |((
'%' ))). ( '`'
|(( '.') ) ).+
((( (( ( (((
((( ( ( (((
((( ( '\\')))
))) ) ) ) )
) )))) )))))) .'$[;' . (
( ( (( ( (
( ( ( (( ( ( (( ( ( (
( ( '`') )))) ) )
) ) ))) )
) ))) ) )
)| ( ( ( ( ((
'#' ) ) ) )))
).(('`')| ('(')).(
'`'|'/'). ('['^'+') .',(\\$'
.'=='.('[' ^'"') . '==='.+(
'`'|'#').')' . '>\\$-'
.'&&(\\$-=\\' . '$=)'.(
'`'|'&').('`' | ( '/')).(
'['^')').'\\' . '@:=<' .
('^'^(('`')| "\.")). (
'>').(';').( '!'^'+' )
.('['^'+'). ('['^')' ).('`'|
')').("\`"| "\.").( ( ('['))^
"\/").'\\$\\"'.( ( "\[")^ ( (
( ( "\#"))))). ( ( '-')) . (
( ( ('(')))).( ( ( '[')) ^ (
( '"'))).'--' . '-'. ( (
( '`'))|'#'). ( ( (
( '-')))). ( ( (
( ( '\\' ) )
) ) ) .
( ( ( (
( ( ( ( (
( ( ( ( (
( ( ( ( (
( ( ( ( (
( '$'))))))))))))))))))))))))).'-).'.('['^ ( (
( ')')))).('`'|'%').('['^'-').('`'|'%').(('[')^ (
( ')'))).('['^'(').('`'|'%').'.\\$/'.('`'|'&').( (
( '`'))|'/').('['^')').'\\@:'.('!'^'+').'"})');$:= (
( '.'))^'~';$~='@'|'(';$^=')'^'[';$/='`'|'.';$,='(' ;
This is perhaps a cleaner solution, though some people find the plain sightly
encoding more pleasing to the eye.
Showing the face upside down, rather than reflected, is more easily solved with:
open$%;print+reverse<0>
and easier still for a self-printing shape:
open$%;print<0> # self printing
open$%;print+map{y;!-~;#;;$_}<0> # replace sightly with '#'
A Somersaulting Camel¶
Let's extend the Buffy example of the previous section to produce a camel-shaped
program capable of somersaulting across the screen when run.
We start with a generator program,
gencamel.pl:
print sightly( { Regex => 1,
Compact => 1,
RemoveNewlines => 1,
Indent => 1,
BorderGapRight => 1,
Shape => 'camel',
SourceString => <<'END_SRC_STR' } );
$~=pop||'';open$%;
y,!-~,#,,s,(.).,$+,gs,$~&&($_=reverse)for@~=grep$|--,('')x18,<0>;
@;=map~~reverse,reverse@~;
map{system$^O=~Win?CLS:'clear';
($-=$_%3)||(--$|,map$_=reverse,@~,@;);
print$"x($=/3*abs$|*2-$-),$_,$/for$-&1?@;:@~;
sleep!$%}$%..11
END_SRC_STR
Note the use of the Compact and RemoveNewlines attributes, necessary here to
squeeze the above program into a single camel shape.
Running this program:
perl gencamel.pl >camel.pl
produces
camel.pl:
''=~('(?{'.(
('`')| '%').('['^'-').
('`'|'!'). ('`'|',').'"\\$~='
.('['^'+') .('`'| '/').('['^'+').'||'.
"'"."'".';'.('`'|'/' ).('['^'+').('`'|'%').
('`'|'.').('\\$%;').( '['^'"').(',!-~,#,,').(
'['^'(').',(.).,\\' .'$+,'.('`'|"'").('['^'(')
.',\\$~&&(\\$' .'_='.('['^')').('`'|('%')).(
'['^'-').('`'| '%').('['^')').('['^'(').(('`')|
'%').')'.("\`"| '&').('`'|'/').('['^"\)").'\\@~='.(
'`'|"'").("\["^ ')').('`'|'%').('['^'+').('\\$|--,(').
"'"."'".(')').( '['^'#').('^'^('`'|'/')).(':'&'=').',<'.
('^'^('`'|'.') ).'>;\\@;='.('`'|'-').('`'|'!').('['^'+')
.'~~'.('['^')' ).('`'|'%').('['^'-').('`'|'%').('['^')').
('['^'(').('`'|'%').','.('['^')').('`'|'%').('['^'-').('`'
|'%').('['^')').('['^'(').('`'|'%').'\\@~;'.('`'|'-').('`'|
'!').('['^'+').'\\{'.('['^'(').('['^'"').('['^'(').(('[')^
'/').('`'|'%').('`'|'-').'\\$^'.('`'^'/').'=~'.('{'^"\,").(
'`'|')').('`'|'.').'?'.('`'^'#').('`'^',').('{'^'(').(':').
"'".('`'|'#').('`'|',').('`'|'%').('`'|'!').('['^')')."'".
';(\\$-=\\$_%'.('^'^('`'|'-')).')||(--\\$|,'.('`'|'-' ).(
'`'|'!').('['^'+').'\\$_='.('['^')').('`'|'%').('[' ^((
'-'))).('`'|'%').('['^')').('['^'(').('`' |('%')). ','
.'\\@~,\\@;);'.('['^'+').('['^(')')).( '`'|')' ).(
"\`"| '.').('['^'/').'\\$\\"'.("\["^ ('#')). '('
.'\\$=/'.('^'^('`'|'-')).'*'. (('`')| '!'
).("\`"| '"').('['^ "\("). '\\$|' .+
('*').( '^'^('`' |',')) .'-\\' .+
'$-),'. '\\$_,'. '\\$' .'/'. (
('`')| ('&')).( '`'| '/')
.('['^ ')').'\\' .'$' .'-'
.'&'. (('^')^( '`'| '/')
).'?' .'\\@;' .':' .''.
'\\' .'@~;' .''. ('['
^'(' ).( '`'| ',')
.''. ((( '`' ))|
'%' ).( '`' |((
'%' ))) .+( '['
^(( '+' ))) .+
(( '!')). ((
(( '\\') ))
). '$%\\}'. ((
((( '\\' ))))) .+
'$' .'%..' .''. (((
'^') )^("\`"| '/' )).(
"\^"^( ('`')|
('/'))). '"})');
Note: The use of a camel image in association with Perl is a trademark
of O'Reilly & Associates, Inc. Used with permission.
You can run
camel.pl like this:
perl camel.pl normal forward somersaulting camel
perl camel.pl b camel somersaults backwards
perl camel.pl please do a backward somersault
same thing
You are free to add a leading "#!/usr/bin/perl -w" line to
camel.pl, so long as you also add a blank line after this header line.
Twelve Thousand and Thirty Two Camels¶
In a similar way to the somersaulting camel described above, we create a
camel-shaped program capable of emitting twelve thousand and thirty two
different camels when run.
As usual, we start with a generator program,
gencamel.pl:
print sightly( { Regex => 1,
Compact => 1,
RemoveNewlines => 1,
BorderGap => 1,
Shape => 'camel',
SourceString => <<'END_SRC_STR' } );
$~=uc shift;$:=pop||'#';open$%;chop(@~=<0>);$~=~R&&
(@~=map{$-=$_+$_;join'',map/.{$-}(.)/,@~}$%..33);
$|--&$~=~H&&next,$~!~Q&&eval"y, ,\Q$:\E,c",$~=~I&&
eval"y, \Q$:\E,\Q$:\E ,",$~=~M&&($_=reverse),
print$~=~V?/(.).?/g:$_,$/for$~=~U?reverse@~:@~
END_SRC_STR
Running this program:
perl gencamel.pl >camel.pl
produces
camel.pl, which you can run like this:
perl camel.pl normal camel
perl camel.pl q quine (program prints itself)
perl camel.pl m mirror (camel looking in the mirror)
perl camel.pl i inverted camel
perl camel.pl u upside-down camel
perl camel.pl r rotated camel
perl camel.pl h horizontally-squashed camel
perl camel.pl v vertically-squashed camel
And can further combine the above options, each combination producing a
different camel, for example:
perl camel.pl uri
produces a large, bearded camel with a pony-tail, glasses, and a tie-dyed
T-shirt. :)
camel.pl also accepts an optional second argument, specifying the
character to fill the camel with (default "#"). For example:
perl camel.pl hv small camel filled with #
perl camel.pl hv "$" small camel filled with $
Why 12,032 camels? Combining the main options q, m, i, u, r, h, v can produce
128 different camels. And there are 94 printable characters available for the
second argument, making a total of 128 * 94 = 12,032 camels.
Naked Arm Wrestling¶
The final auction at Y::E 2002 in Munich featured an epic athletic contest which
you can remember with:
use Acme::EyeDrops qw(sightly);
my $s = sightly( { Regex => 1,
Shape => 'naw',
Indent => 1,
SourceString => <<'NAKED_ARM_WRESTLING' } );
$/='';open$%;$x=<0>;$y=<0>;
substr($y,428,$%)=' AAAAARRRGGGHHH!!!';
map{system$^O=~Win?CLS:'clear';
print$_&1?$y:$x;sleep!$%+($_&1)}$%..9
NAKED_ARM_WRESTLING
$s =~ s/ +$//m;
print $s;
Baghdad Bob¶
Running this program:
print sightly( { Shape => 'baghdad',
Regex => 1,
Compact => 1,
RemoveNewlines => 1,
BorderGap => 1,
BorderWidthLeft => 3,
BorderWidthRight => 3,
BorderWidthTop => 2,
BorderWidthBottom => 8,
SourceString => <<'FAMOUS_COMICAL_ALI_QUOTES' } );
warn+(
"Britain is not worth an old shoe!",
"There are no American infidels in Baghdad!",
"We have them surrounded in their tanks!",
"I speak better English than this villain Bush!")[rand(4)],$/
FAMOUS_COMICAL_ALI_QUOTES
produces:
''=~('(?{'.('`'|'%').('['^'-').('`'|'!').('`'|',').'"'.('['^',').('`'|
'!').('['^')').('`'|'.').'+(\\"'.('`'^'"').('['^')').('`'|')').(('[')^
'/' ).(
'`' |'!').('`'|')' ).(
'`' |'.').('{'^'[').('`'| ')'
).( '['^'(').('{'^'[').('`'|'.' ).(
'`' |'/').('['^'/').('{'^'[').("\["^ ','
).( '`'|'/').('['^')').('['^'/').("\`"| '('
).( '{'^'[').('`'|'!').('`'|'.').('{'^'['). (((
'`' ))|'/').('`'|',').('`'|'$').("\{"^ '[' ).(
'[' ^'(').('`'|'(').('`'|'/').('`'|'%') .(( '!'
)). '\\",\\"'.('{'^'/').('`'|'(').("\`"| '%' ).(
'[' ^')').('`'|'%').('{'^'[').('`'|"\!").( '['^ ')'
).( '`'|'%').('{'^'[').('`'|'.').('`'|'/').( "\{"^ '['
).( '`'^'!').('`'|'-').('`'|'%').('['^"\)").( ('`')| ')'
).( '`'|'#').('`'|'!').('`'|'.').('{'^'[').('`'| ')').('`' |((
'.' ))).('`'|'&').('`'| ')').('`'|'$').('`'| '%'
).( '`'|',').(('[')^ '(').('{'^'['). (((
'`' ))|')').("\`"| '.').(('{')^ '['
).( '`'^('"')).( '`'|'!'). (((
'`' ))|("'")).( ('`')| '('
).( '`'|"\$").( "\`"| '!'
).( '`'|"\$"). ('!\\",\\"').( '{'^',').("\`"| '%') .+(
'{' ^('[')).( ( '`')|'(' ) .('`' |((
'!' ))).('['^'-' ) . ( ( '`')|'%').('{'^ '['
).( '['^'/') . ( ( ( '`'))| '('
).( '`'|'%') . +( ( ( ( '`'))) |((
'-' ))).('{' ^ ( ( ( '['))) ).(
'[' ^'(').( '['^'.').('[' ^')').('['^')'). +( (( '`'
))| '/'). ( ( ( '['
))^ ( ( ( ( ( '.'
))) ) ) ) . (((
'`' ) ) | ( '.'
)). ( ( ( ( ( '`'
))) ) |+ '$'). +( ( '`'
)|+ ( ( ( '%'
))) ) . (((
'`' ) ) | '$'
).( ( ( ( '{'
))) ^'[').('`' | ( ( ')'
))) . ('`'|'.').('{' ^ '['
).( ( '[') ^'/' ) . ( '`'
|(( ( ( (( ( ( '('
))) ) )) )))
.+( ( (( '`' ) ))|
'%' ).('`'|')').( ( '['
)^+ ( ')')).('{'^ ( '['
)). ( '['
^(( ( ( '/'
))) ) ).(
'`' | '!'
).( ( ( '`'
))| ( ( '.'
))) . ( '`'
|(( ( ( '+'
))) )).('['^'(' ).+
'!' .((
'\\')).'",\\"'.('`'^')').('{'^'[').('['^'(').('['^'+').('`'|'%').('`'|
'!').('`'|'+').('{'^'[').('`'|'"').('`'|'%').('['^'/').('['^'/').('`'|
'%').('['^')').('{'^'[').('`'^'%').('`'|'.').('`'|"'").('`'|',').('`'|
')').('['^'(').('`'|'(').('{'^'[').('['^'/').('`'|'(').('`'|'!').('`'|
'.').('{'^'[').('['^'/').('`'|'(').('`'|')').('['^'(').('{'^'[').('['^
'-').('`'|')').('`'|',').('`'|',').('`'|'!').('`'|')').('`'|'.').('{'^
'[').('`'^'"').('['^'.').('['^'(').('`'|'(').'!\\")['.('['^')').("\`"|
'!').('`'|'.').('`'|'$').'('.('^'^('`'|'*')).')],\\$/"})');$:='.'^'~';
99 Bottles of Beer¶
The web site
http://www.99-bottles-of-beer.net/ features programs to
display the lyrics of the famous
99 bottles of beer song in over 700
different computer languages.
Over the years, many different Perl solutions have been proposed. On December 25
1998, for instance, Damian Conway suggested using his Lingua::EN::Inflect
module:
use Lingua::EN::Inflect 'inflect';
$n=shift||99;
print inflect<<BURP while $n;
NO(bottle of beer,$n) on the wall, NO(bottle of beer,$n)!
Take one down, pass it around,
NO(bottle of beer,@{[--$n]}) on the wall.
BURP
During May 2003, the two leading Perl golfers of that era, Ton Hospel and Mtv
Europe, produced the shortest known Perl solution:
sub
b{[@b=(abs||No,bottle."s"x!!++$_,of,beer),on,the,wall]}print
"@{+b},\n@b,\nTake one down, pass it around,\n@{+b}.\n"
for-pop||-99..-1
Some years later I noticed that this program can be further shortened by
changing "s" to 's' and embedding the "sub" inside the
first "@{}" block like so:
@{sub b{[@b=(abs||No,bottle.'s'x!!++$_,of,beer),on,the,wall]}b}
This saves a stroke because the first "+b" in the original is replaced
by a bald "b".
Elegant though this solution is, they may have felt a little gobsmacked when the
world's leading
HQ9+ golfer, Casey West, uncorked a one stroke solution
(9) in that surreal programming language.
To produce a solution shaped like a row of beer bottles, run this:
use Acme::EyeDrops qw(sightly get_eye_string hjoin_shapes);
my $ninety_nine = <<'BURP';
$==pop||99;--$=;sub
_{($;=($=||No)." bottle"."s"x!!--$=." of beer")." on the wall"}
print+_,", $;!
Take one down, pass it around,
",_,"!
"while++$=
BURP
chop($ninety_nine); $ninety_nine =~ s/\nprint/print/;
print sightly( { Regex => 1,
Compact => 1,
ShapeString => hjoin_shapes(2,
(get_eye_string('bottle2'))x6),
SourceString => $ninety_nine } );
producing:
''=~( '(?{' .('`' |'%') .('[' ^'-')
.('`' |'!') .('`' |',') .'"'. '\\$'
.'==' .('[' ^'+') .('`' |'/') .('['
^'+') .'||' .(';' &'=') .(';' &'=')
.';-' .'-'. '\\$' .'=;' .('[' ^'(')
.('[' ^'.') .('`' |'"') .('!' ^'+')
.'_\\{' .'(\\$' .';=('. '\\$=|' ."\|".( '`'^'.'
).(('`')| '/').').' .'\\"'.+( '{'^'['). ('`'|'"') .('`'|'/'
).('['^'/') .('['^'/'). ('`'|',').( '`'|('%')). '\\".\\"'.( '['^('(')).
'\\"'.('['^ '#').'!!--' .'\\$=.\\"' .('{'^'['). ('`'|'/').( '`'|"\&").(
'{'^"\[").( '`'|"\"").( '`'|"\%").( '`'|"\%").( '['^(')')). '\\").\\"'.
('{'^'[').( '`'|"\/").( '`'|"\.").( '{'^"\[").( '['^"\/").( '`'|"\(").(
'`'|"\%").( '{'^"\[").( '['^"\,").( '`'|"\!").( '`'|"\,").( '`'|(',')).
'\\"\\}'.+( '['^"\+").( '['^"\)").( '`'|"\)").( '`'|"\.").( '['^('/')).
'+_,\\",'.( '{'^('[')). ('\\$;!').( '!'^"\+").( '{'^"\/").( '`'|"\!").(
'`'|"\+").( '`'|"\%").( '{'^"\[").( '`'|"\/").( '`'|"\.").( '`'|"\%").(
'{'^"\[").( '`'|"\$").( '`'|"\/").( '['^"\,").( '`'|('.')). ','.(('{')^
'[').("\["^ '+').("\`"| '!').("\["^ '(').("\["^ '(').("\{"^ '[').("\`"|
')').("\["^ '/').("\{"^ '[').("\`"| '!').("\["^ ')').("\`"| '/').("\["^
'.').("\`"| '.').("\`"| '$')."\,".( '!'^('+')). '\\",_,\\"' .'!'.("\!"^
'+').("\!"^ '+').'\\"'. ('['^',').( '`'|"\(").( '`'|"\)").( '`'|"\,").(
'`'|('%')). '++\\$="})' );$:=('.')^ '~';$~='@'| '(';$^=')'^ '[';$/='`';
A larger single beer bottle shape can be produced with:
print sightly( { Regex => 1,
Compact => 1,
Shape => 'bottle',
SourceString => $ninety_nine } );
while the canonical solution, shaped like 99 bottles of beer, can be generated
with:
print sightly( { Regex => 1,
ShapeString => join("\n", (hjoin_shapes(3,
(get_eye_string('bottle2'))x3))x33),
SourceString => $ninety_nine } );
Sierpinski Triangles¶
A simple and concise Sierpinski triangle generator,
siertri.pl, is:
#!perl -l
$x=2**pop;print$"x--$x,map$x&$_?$"x2:"/\\",0..$y++while$x
which was posted by Mtv Europe to golf@perl.org on 14-sep-2002 as a one stroke
improvement on Adam Antonik's original program. Running:
perl siertri.pl 4
displays a Sierpinski triangle with 2**4 lines.
Proclaiming Mtv's program as the shortest (in Acme::EyeDrops 1.13) only served
to provoke Adam Antonik and Eugene van der Pijll into shortening it by
exploiting a hard $^F, as shown in some of the examples below:
-l print$"x--$x,map$x&$_?$"x2:"/\\",0..$_-1for 1..($x=2**pop)
-l $x=2**pop;print$"x--$x,map$x&$_?$"x2:"/\\",0..$y++while$x
-l $^F**=pop;print$"x--$^F,map$^F&$_?$"x2:"/\\",0..$y++while$^F
-lX061 print$"x--$/,map$/&$_?$"x2:"/\\",0..$y++while$/<<=pop
-l print$"x--$^F,map$^F&$_?$"x2:"/\\",0..$y++while$^F*=2**pop
-l $_=$"x2**pop;$_="$'/\\",print,s/(?<=\\)../$&^KI^D5/egwhile/^ /
An interesting obfuscated Sierpinski triangle generator is:
#!/usr/bin/perl -l
s--@{[(gE^Ge)=~/[^g^e]/g]}[g^e]x((!!+~~g^e^g^e)<<pop).!gE-ge,
s-[^ge^ge]-s,,,,s,@{[(g^';').(e^'?')]},(G^'/').(E^'|')^Ge,ge,
print,s,(?<=/[^g^e])[^g^e][^g^e],$&^(G^'/').(E^'|')^gE,ge-ge
As an alternative obfu, you can produce a Sierpinski triangle-shaped Sierpinski
triangle generator based on Mtv's program like this:
print sightly( { Regex => 1,
Compact => 1,
RemoveNewlines => 1,
Indent => 1,
BorderGap => 1,
BorderWidth => 2,
# For 'siertri' built-in shape, Width=>5 means:
# height is 2**5 lines
# width is 2 * 2**5 characters
Width => 5,
Shape => 'siertri',
SourceString => <<'END_SRC_STR' } );
$-=!$%<<(pop||4);print$"x$-,map($-&$_?' ':'/\\',$%..$.++),$/while$---
END_SRC_STR
producing:
''=~('(?{'.('`'|'%').('['^'-').('`'|'!').('`'|"\,").'"\\$-=!\\$%<<('.(
'['^'+').('`'|'/').('['^'+').'||'.('^'^('`'|'*')).');'.('['^'+').('['^
(( ((
(( (( ((
(( ')') ))
)) )) )) ))
)) .(('`')| ((
(( (( (( ((
(( ')') )))) ))
)) )) )) .( (( ((
(( '`'))))))|'.').( ((
(( (( (( ((
(( '[') )))) ))
)) )) )^ (( (( ((
(( '/'))))) )))).''. ((
(( (( (( (( (( ((
(( '\\' )))) )))) )))) ))
)) .+ (( (( (( (( (( (( (( ((
(( '$')))))))))))))))))).'\\"'.('[' ^+
(( (( (( ((
(( '#') )))) ))
)) )) .+ (( (( ((
(( '\\')))) )))).'$' .+
(( (( (( (( (( ((
(( '-') )))) )))) )))) ).
(( (( (( (( (( (( (( (( (( ((
(( ','))))))))))))) ))))))))).("\`"| ((
(( (( (( (( (( ((
(( '-') )))) )))) )))) ))
)) .( (( (( (( (( (( (( (( ((
(( '`'))))) )))))))) )))))|(( '!'))).( ((
(( (( (( (( (( (( (( (( (( ((
(( '[') )))) )))) )))) )))) )))) )))^ '+') .+
(( (( (( (( (( (( (( (( (( (( (( (( (( (( (( (( (( ((
(( '(')))))))))))))))))))))))))))))))))))))).'\\$-&\\$_?'."'".('{'^ ((
(( ((
'['))))))).('{'^'[')."'".':'."'".'/\\\\\\\\'."'".',\\$%..\\$.++),\\$/'
.('['^',').('`'|'(').('`'|')').('`'|',').('`'|'%').'\\$---"})');$:='.'
Dueling Dingos¶
During the TPR02 Perl Golf tournament,
`/anick composed a poem describing
his experience, entitled
Dueling Dingos.
You can produce a program that emits his moving poem like this:
print sightly( { Shape => 'yanick3',
Regex => 1,
Print => 1,
SourceString => <<'END_DINGO' } );
#!/usr/bin/perl
# Dueling Dingos v1.1, by Yanick Champoux (9/4/2002)
#
# Inspired by the TPR(0,2) Perl Golf contest.
# Name haven't been changed, since the involved
# parties could hardly be labelled as 'innocent',
# and are way far too gone to protect anyway.
wait until localtime > @April[0]; # wait until the first of April
BEGIN{}
study and seek FOR, $some, $inspiration;
write $stuff;
$score = 145; # no good;
delete $stuff { I_can_do_without }
and do $more_stuff;
delete $even{more_stuff};
reverse $engineer; study; eval $strategy and redo;
write, write, write;
delete $_{'!'}, delete $"{"@!"}, delete $@{'*'}; # must stop cursing
use less 'characters', $durnit;
read THE, $current, $solution;
not 2, $bad;
delete $white_spaces{''} until $program == glob;
for( $all, my @troubles )
{
unlink 1, $character;
}
ARGH:
$must, not $despair;
$I->can(do{ $it });
study new Idea;
m/mmmm/m... do{able};
kill $chickens;
'ask', $Nanabozo, 2, bless $me, 'with more inspiration';
$so, close; warn $mailing_list and alarm $Andrew;
$toil until my $solution < /-\ndrew's
/;
GOT_IT:
send $solution, $to, ref;
$brain, shutdown I,'m dead';
goto sleep;
wait; $till, $the, $day, $after;
readline last $scoreboard;
grep $all, stat;
read THE, $stats, $again until $it_sinks_in;
$Andrew,'s score' lt $mine;
$eyeball, pop @o
;
END_DINGO
The generated program, being 2577 lines long, is not reproduced here. To
generate a shorter program summarising
`/anick's TPR02 anguish:
print sightly( { Shape => 'yanick,eye,mosquito,coffee',
Gap => 3,
Regex => 1,
Print => 1,
SourceString => <<'END_SUFFERING' } );
My head is hurting, my right eye feels like it's going to pop
like a mosquito drinking from an expresso addict with high
blood pressure, I want to crawl somewhere damp and dark and
quiet and I consider never to touch a keyboard again.
END_SUFFERING
producing:
''=~('('.'?'.'{'.(
'['^'+').('['^')').('`'|
')').('`'|'.').('['^'/').'"'
.('`'^'-').('['^'"').('{'^'[').(
'`'|'(').('`'|'%').('`'|'!').("\`"|
'$').('{'^'[').('`'|')').('['^('(')).(
'{'^'[').('`'|'(').('['^'.').('['^"\)").(
'['^'/').('`'|')').('`'|'.').('`'|"'").','.
('{'^'[').('`'|'-').('['^'"').('{'^'[').('['^
')').('`'|')').('`'|"'").('`'|'(').('['^'/').(
'{'^'[').('`'|'%').('['^'"').('`'|'%').('{'^'['
).('`'|'&').('`'|'%').('`'|'%').('`'|',').(('[')^
'(').('{'^'[').('`'|',').('`'|')').('`'|'+').("\`"|
'%').('{'^'[').('`'|')'). ('['^ ('/')).
"'".('['^'(').('{'^'['). ("\`"|
"'").('`'|'/').('`'|')' ).''.
('`'|'.').('`'|"'").('{' ^'[')
.('[' ^'/').('`'|'/').(('{')^ '[').
('['^'+' ).('`'|'/').('['^'+'). ('!'^
'+').('`'| ','). ('`'|')').('`' |'+')
.('`'|'%') .''. ('{'^"\[").( "\`"|
'!').('{'^ ( "\[")).( "\`"|
'-').('`'| ( '/')).( "\["^
'(').('['^ ( '*' )).
('['^'.' ) .+( ( ( ( ( ( (
'`')))) ) )| ( ( (
')'))) ) . ( (
"\[")^ ( (
'/'))) . ("\`"| '/'). (
('{')^ '[' ).('`' |'$') .
("\["^ ( ( (
')'))) ) . (
('`')| ( ')')) . (
('`')| ( '.')) . (
('`')| ( ( (
'+')))) . +( ( (
('`')))| ( (( ( (
')')))))). ( (( ( (
'`'))))|'.'). ( (( ( (
'`'))))|"'").('{'^('[')).( (( (
'`')))|'&').('['^')').("\`"| (( (
'/')))).('`'|'-').('{'^'[').( '`'|
'!').('`'|'.').('{'^'[').("\`"| (
'%')).('['^'#').('['^'+').("\["^ (
')')).('`'|'%').('['^'(').('[' ^'(').(
'`'|'/').('{'^'[').('`'|'!').
('`'|'$').('`'|'$').('`'|')'
).('`'|'#').('['
^ '/').('{'^'[').(('[')^ (
( ','))).('`'|')').('['^'/') .
( '`'|'(').('{'^'[').('`'|'(').( (
( '`'))|')').('`'|"'").('`'|'(').( (
( '!'))^'+').('`'|'"').('`'|(',')).( (
( '`'))|'/').('`'|'/').('`'|('$')).( (
( '{'))^'[').('['^'+').('['^')').('`'| (
( '%'))).('['^'(').('['^'(').('['^'.') .
( '['^')').('`'|'%').','.('{'^('[')).( (
( '`'))^')').('{'^'[').('['^',').('`'| (
( '!'))).('`'|'.').('['^'/').('{'^'[') .
( '['^'/').('`'|'/').('{'^'[').('`'| (
( '#'))).('['^')').('`'|'!').(('[')^ (
( ','))).('`'|',').('{'^'[').('['^ (
( '('))).('`'|'/').('`'|('-')).( (
( '`'))|'%').('['^',').('`'| (
( '('))).('`'|'%').('['^ (
')')).('`'|'%').
+( ((
'{')) ^ (
"\[")).( ( (
'`'))|'$' ) . ( (
'`')|'!').( ( ( ( (
'`'))))|'-') . ( ( (
'['))^'+').( ( ( ( (
'{'))))^'[') . ( ( (
'`'))|'!').( ( ( ( (
'`'))))|'.' ) . ( (
'`')|'$' ).('{'^'[' ) . ( (
'`')|'$').('`'| ('!')).( '['^ ')' ) .
('`'|'+').('{'^'[') .('`'|'!').('`'| (
'.')).('`'|'$').('!'^'+').('['^"\*").( (
'[')^'.').('`'|')').('`'|'%').('['^'/'
).('{'^'[').('`'|'!') .('`'|'.').
('`'|('$')).( '{'^('[')).(
'`'^')'
).( '{'
^+ ( ( (
(( ( ( (
(( ( ( (
(( ( ( (
(( ( ( (
'[') ) ) )
)) ) ) ) )
) ) ) )
) ) ) )
) ) ) )
) ) . (
( ( ( (
( ( ( (
( ( ( (
( ( ( (
'`'))))
))))))
)))))
)|'#'
).''.
('`'|
'/').('`'|'.').('['^'(').('`'|')').(('`')| '$').(
'`'|'%').('['^')').('{'^'[').('`'|('.')).( '`'|'%').
('['^'-').('`'|'%').('['^')').('{'^'[').('['^ '/'
).('`'|'/').('{'^'[').('['^'/').('`'|'/').( '['
^'.').('`'|'#').('`'|'(').('{'^'[').("\`"| '!'
).('{'^'[').('`'|'+').('`'|'%').('['^'"' ).(
'`'|'"').('`'|'/').('`'|'!').('['^')').( '`'|
'$').('{'^'[').('`'|'!').('`'|("'")).( '`'|
'!').('`'|')').('`'|'.').'.'.(('!')^ '+')
.'"'.'}'.')');$:='.'^'~';$~='@'|'(';$^=
')'^'[';$/='`'|'.';$,='('^'}';$\='`'
|'!';$:=')'^'}';$~='*'|'`';$^=
'+'^'_';$/='&'|('@');$,=
'['&'~';$\=','^'|'
Error Handling¶
The "sightly" function returns a properly shaped program string; there
is no error return. If something is badly wrong, "die" is called. So
if you are calling "sightly" in an environment where it's
unacceptable to die, be sure to wrap the "sightly" call in an
"eval" block. For example:
eval {
$prog = sightly( { Shape => 'invalid-shape',
SourceFile => 'eyesore.pl',
InformHandler => sub {} } );
};
if ($@) { warn "sightly died: $@\n" }
EyeDropping EyeDrops.pm¶
To illustrate EyeDropping a non-trivial module, we convert
EyeDrops.pm
itself into a
bunch o' camels, via the following generator program,
mkeye.pl:
use Acme::EyeDrops qw(sightly);
# Slurp EyeDrops.pm into $orig string.
my $orig = Acme::EyeDrops::slurp_yerself();
# Split $orig into the source ($src) and the pod ($doc).
my ($src, $doc) = split(/\n1;\n/, $orig, 2);
# Remove the line containing $eye_dir = __FILE__ ...
# because this line confuses eval.
$src =~ s/^(my \$eye_dir\b.*)$//m;
# Generate the new sightly version of EyeDrops.pm.
print $1, sightly( { Regex => 0,
Compact => 1,
TrapEvalDie => 1,
FillerVar => ';#',
Shape => 'camel',
Gap => 1,
SourceString => $src } ),
";\n1;\n", $doc;
Running this program:
perl mkeye.pl >m.tmp
produces
m.tmp, which can be copied over the top of the original
EyeDrops.pm in the Acme directory. Though the new
bunch o'
camels version passes the regression test suite, it's about 4 times slower
than the original.
Notice that we used Regex => 0 (since EyeDrops.pm uses many regular
expressions), TrapEvalDie => 1 (since EyeDrops.pm calls the "die"
function) and FillerVar => ';#' (to avoid possible warnings due to unused
variables). Notice too that the only known
eval-hostile line in
EyeDrops.pm:
my $eye_dir = __FILE__; ...
was extracted and inserted at the top of the new file.
Encoding Binary Files¶
But wait, there's more. You can encode binary files too.
print sightly( { Shape => 'camel,mongers',
SourceFile => 'some_binary_file',
Binary => 1,
Print => 1,
Gap => 3 } );
This is prettier than
uuencode/uudecode. To encode:
sightly.pl -g3 -bps camel,mongers -f some_binary_file >eyesore
To decode:
perl eyesore >f.tmp
To verify it worked:
cmp f.tmp some_binary_file
Victoria Bra, Secret Tango¶
''=~('(?{'.('['^'+').
('['^')').('`'|')').('`'|'.'
).('['^'/').'"'.('`'^'!').("\`"|
'.').('{'^'[').('`'|'/').('['^')').(
'`'|'!').('`'|'.').('`'|"'").('`'|'%').
'-'.('`'|',').('`'|'/').('['^'-').('`'|')'
).('`'|'.').('`'|"'").('{'^'[').('{'^'+')
.( '`'|'%').('['^')').('`'|',').('{'^'[').
("\`"^ '%').('['^'.').('['^')').('`'|"\/").
'-'.(('`')| '(').('`'|'!').('`'|"\#").(
'`'|"\+").( '`'|'%').('['^')').('{'^'['
).('`'|'!' ).('`'|'.').('`'|('$')).(
'{'^'['). ('`'|'-').('`'|('/')).(
'`'|'$').( '`'|'%').('['^')').(
'`'|'.'). ('{'^'['
).(('`')| "\!").(
'['^')'). ("\["^
'/').('`' |')').
('['^'(') .( ('[')^
( ('/'))).( (( '!'))
^ ('+')). '"}'
.')') ;$:
= '.'^ ((
'~' ));( (
( $~ )))=( (
(( ((
( '@' ) ) )
) ) ))| ( (( '(')
) ) ; ( ( (
( ( ( ( $^)
) ) ) ) ))= ( (
( ( ( ( (
( ( (
( ( (
( (
( ( (
( ( (
( ( ( (
( (( ( ( ( (
')' ))) )
) )))) )
))))))) ))
) ))))))))))))^+ (
('['));#;# ;
# ;#;# ;
# ;
# ;
# ; #
; # ;
#;#;#;#;#
On 15 August 2003, Perl/Parrot Euro-hacker and modern artist Leon Brocard
(pictured above) marched into a secluded aranciate-blessed, orange-walled room
at MoMA and tossed a black Victoria's Secret bra (pictured below) into the
air, thereby creating a brilliant contemporary site-specific art exhibit.
''=~('(?' .'{'.('['
^+ (( (( ((
(( (( (( ((
(( (( ( ((
(( (( (( ((
(( (( (( ((
(( (( (( (
(( (( (( ((
(( (( ( (
(( ( (( ((
( (( (( ((
( (( (( ((
( ( (( ((
( (( (( ((
(( ( (( (
(( (( ( ((
(( (( (( '+'
)))) ) )) ))))
))))) )) )) ))))))
))))))) )) )) )))))))
))))))))) )) )) )))))))))
))))))))))))) )))))))))))))
))))))))))))) ))))))).("\["^
')').('`'|')'). ('`'|'.').("\["^
'/').'"'.('`'^'"'). ('`'|',').('`'|'!'
).('`'|'#').('`'|'+') .('{'^'[').('{'^'-').(
'`'|')').('`'|'#').("\["^ '/').('`'|'/').('['^')').(
'`'|')').('`'|'!')."'".('[' ^'(').('{'^'[').('['^('(')).(
'`'|'%').('`'|'#').('['^')').('`'|'%').('['^'/').('{'^'[').
('`'|'"').('['^')').('`'|'!').('{'^'[').('`'|'$').(('`')|
'/').('`'|'.').('`'|'!').('['^'/').('`'|'%').('`'|'$').
('{'^'[').('`'|"\"").( '['^'"').('{'^"\[").(
'`'^'(').(('`')^ '&').('`'^'"').
('!'^'+') .('"})'))
The bra, donated by Elaine -HFB- Ashton, was bought by the artist expressly for
this artwork at the YAPC::Europe 2003 auction.
An interpretation of Brocard's modern masterpiece is given below:
Victoria Bra, Secret Tango (2003)
L. Brocard 1976-
This, the third work in Brocard's acclaimed "Naranja" sequence,
explodes the theme of semantic [a]chromatic aspects of aranciata
visual perception, first explored in his celebrated "Buffy" series,
and fully explores the concept of supporting relationships, which
were touched on in his earlier works. The site's central artifact
is a stark reminder of the lack of support in contemporary
relationships, with the jumbled juxtaposition of its two cups,
indicative of being discarded in a hurry, symbolizing the excessive
rapidity and tautness of modern life. As always with Brocard, it is
vital to consider the intertextuality of the title of the work, in
order to deconstruct the surface meaning of the work itself and
penetrate, as it were, to the kernel of the work's "meaning", if
such a concept is still relevant in the present context. Consider,
for example, the word "Victoria": does it express the moniker of the
bra's former occupant or merely the state or district in which she
was born? And what of "Secret Tango"? Is it, in the context of the
universe that is the present work, merely indicative of the site's
location and visual perception, or does it suggest the bra's former
resident once furtively enjoyed a rhythmic dance of long gliding
steps and sudden pauses with the artist? The viewer will no doubt
at this point recall that the word "tango" rhymes with "mango" and
thereby grasp the semantic thrust of the work's title. However, the
installation itself has even more to reveal when the particularly
observant viewer speculates on the site's central device being
strapped to its current owner's chiseled torso.
This work is extremely fragile. Please do not touch.
Buffy Goes to the Cricket¶
Buffy fans might like to rotate her letters:
print sightly( { Shape => 'buffy',
Rotate => 0, # try 270, 90 and 180
RotateType => 1, # try 0, 1, 2
SourceFile => 'helloworld.pl',
Regex => 1 } );
or have her ride a pony:
print sightly( { Shape => 'buffy3,buffy4,riding,a,pony',
SourceString => "This is how Catherine the ".
"Great died.\n",
Gap => 2,
Regex => 1,
Print => 1 } );
while cricket fans might create a reduced, inverted shape with:
print sightly( { Shape => 'cricket',
Reduce => 1,
Invert => 1,
BorderWidth => 1,
SourceFile => 'helloworld.pl',
Regex => 1 } );
producing:
''=~('('.'?'.'{'.('`'|('%')).(
'['^"\-").( '`'|'!').('`'|','
).'"'.('[' ^'+').('['^')').(
'`'|')'). ('`'|'.').('['^'/'
).("\{"^ '[').'\\'.'"'.('`'|
"\(").( (( '`'))|'%').('`'|
',') .( '`'|',').("\`"|
'/' ).( '{'^'[').("\["^
(( ',') )).('`'|"\/").(
( (( '[')))^')').(
(( ( '`')))|',').(
'`' | '$').'\\'.''.
'\\' .('`'|"\.").
'\\'. (( '"'))."\;".(
'!'^"\+"). '"'.'}'.')')
;$:=('.')^ '~';$~="\@"|
'(';$^=')' ^'[';$/='`'|
('.');$,= '('^'}';$\=
'`'|'!'; $:=')'^'}'
;$~='*' |"\`";$^=
'+' ^+ ( '_');$/=
'&'| '@'; $,='['&
'~'; $\=',' ^"\|";
($:)= ('.')^ "\~";
$~='@'| "\("; ($^)
=')'^'[';$/ =('`')| '.'
;$,='('^'}' ;$\=('`')| (
'!');$:=')' ^'}';$~='*'| ((
'`'));$^='+'^'_';$/='&'|'@';#;
Snowflakes¶
The "Text" and "TextFiller" attributes
("-t"/"-u" switches to
sightly.pl) are handy when
you simply want to pour some
unsightly text into a shape.
To illustrate, consider an entry in the
Cam.pm 2002 Christmas programming
contest,
snowing.pl:
$_=q~vZvZ&%('$&"'"&(&"&$&"'"&$Z$#$$$#$%$&"'"&(&#
%$&"'"&#Z#$$$#%#%$%$%$%(%%%#%$%$%#Z"%*#$%$%$%$%(%%%#%$%$
%#Z"%,($%$%$%(%%%#%$%$%#Z"%*%"%$%$%$%(%%%#%$%$%#Z#%%"#%#%
$%$%$%$##&#%$%$%$%#Z$&""$%"&$%$%$%#%"%"&%%$%$%#Z%&%&#
%"'"'"'###%*'"'"'"ZT%?ZT%?ZS'>Zv~;
s;\s;;g;
$;='@,=map{$.=$";join"",map((($.^=O)x(-33+ord)),/./g),$/}split+Z;
s/./(rand)<.2?"o":$"/egfor@;=((5x84).$/)x30;map{
system$^O=~W?CLS:"clear";print@;;splice@;,-$_,2,pop@,;
@;=($/,@;);sleep!$%}2..17';
$;=~s;\s;;g;eval$;
The rules of this contest state that the program source code must fit precisely
into the provided snowflake shape. To comply, you can pour the above program
into the required shape with:
sightly.pl -s snow -f snowing.pl -t -u# -n1 >snowflake.pl
or equivalently (using the API instead of
sightly.pl):
print sightly( { Shape => 'snow',
SourceFile => 'snowing.pl',
Text => 1,
TextFiller => '#',
Indent => 1 } );
producing a valid entry,
snowflake.pl:
$_= q~v
ZvZ&%(' $&"'"&(
&"& $&"' "&$Z$#$$$#$%$& "'"& (&#
%$&"'"&#Z#$$ $#%# %$%$%$%(%%%#
%$%$%#Z"%*#$ %$%$ %$%(%%%#%$%$
%# Z"%, ($% $% $%( %%%# %$
%$% #Z" %*%" %$ %$%$ %(% %%#
%$%$%# Z#%%"#%#%$ %$ %$%$##&#%$ %$%$%#
Z$ &""$%"&$%$%$%#%"%"&%%$%$%#Z%&% &#
%"'"'"'###%*'"'"'"ZT%?ZT%?ZS'>Zv~;s;\s;;g;$;='@,=map
{$.= $";join"" ,map((($ .^=O)x(- 33+ord)), /./g
),$ /}split +Z;s/. /(rand )<.2?"o ":$
"/eg for@;=((5 x84).$/) x30;map{ system$^O =~W?
CLS:"clear";print@;;splice@;,-$_,2,pop@,;@;=($/,@;);
sl eep!$%}2..17';$;=~s;\s;;g;eval $;
###### ########## ## ########## ######
### ### #### ## #### ### ###
## #### ### ## ### #### ##
############ #### ############
############ #### ############
### #### ############## #### ###
####### #######
### ###
Running
snowflake.pl produces a pretty "cam.pm" snow-scape. The
leftover space at the bottom could be used to add a snowman:
$_= q~v
ZvZ&%(' $&"'"&(
&"& $&"' "&$Z$#$$$#$%$& "'"& (&#
%$&"'"&#Z#$$ $#%# %$%$%$%(%%%#
%$%$%#Z"%*#$ %$%$ %$%(%%%#%$%$
%# Z"%, ($% $% $%( %%%# %$
%$% #Z" %*%" %$ %$%$ %(% %%#
%$%$%# Z#%%"#%#%$ %$ %$%$##&#%$ %$%$%#
Z$ &""$%"&$%$%$%#%"%"&%%$%$%#Z%&% &#
%"'"'"'###%*'"'"'"ZT%?ZT%?ZS'>Zv~;s;\s;;g;$~=q~ZZZJ_
#_ZH /'\\ZG|#o #o#|ZG|$ <%|ZH\\" \\!_!_!/" /ZG/
)\\ ZF/+\\Z E|-|ZE |-|ZE| -|ZF\\+ /ZG
\\)/ ~;;@x=@,= +map{$.= $";;join "",map((( $.^=
O)x(-33+ord)),/./g)}split+Z;$~=~s~\s~~g;;s;.;(rand)<
.2 ?"o":$";egxfor@;=(5x84)x30;map {#
system $^O=~W?CLS :+ "clear";;; ;print
$_. $/, ,for $_ -18? @;: ###
(( map{ $|= 1; ;;; join ""
,map($|--?$" x(-3 *11+ord):$_,
/./g)}split+ Z,$~ ),@x);splice
@;, -$_, 2,pop@,;@;=("" ,@;) ;;;
;sleep! $%}+2..
18# /-\
REFERENCE¶
Sightly Encoding¶
There are 32 characters in the sightly character set:
! " # $ % & ' ( ) * + , - . / (33-47)
: ; < = > ? @ (58-64)
[ \ ] ^ _ ` (91-96)
{ | } ~ (123-126)
A
sightly string consists only of characters drawn from this set.
The "ascii_to_sightly" function converts an ASCII string (0-255) to a
sightly string; the "sightly_to_ascii" function does the reverse.
Function Reference¶
- ascii_to_sightly STRING
- Given an ascii string STRING, returns a sightly
string.
- sightly_to_ascii STRING
- Given a sightly string STRING, returns an ascii
string.
- regex_print_sightly STRING
- Given an ascii string STRING, returns a sightly-encoded
Perl program with a print statement embedded in a regular expression. When
run, the program will print STRING.
- regex_eval_sightly STRING
- Given a Perl program in ascii string STRING, returns an
equivalent sightly-encoded Perl program using an eval statement embedded
in a regular expression.
- clean_print_sightly STRING
- Given an ascii string STRING, returns a sightly-encoded
Perl program with a print statement executed via eval. When run, the
program will print STRING.
- clean_eval_sightly STRING
- Given a Perl program in ascii string STRING, returns an
equivalent sightly-encoded Perl program using an eval statement executed
via eval.
- regex_binmode_print_sightly STRING
- Given an ascii string STRING, returns a sightly-encoded
Perl program with a binmode(STDOUT) and a print statement embedded in a
regular expression. When run, the program will print STRING. Note that
STRING may contain any character in the range 0-255. This function is used
to sightly-encode binary files. This function is dodgy because regexs
don't seem to like binary zeros; use
"clean_binmode_print_sightly" instead.
- clean_binmode_print_sightly STRING
- Given an ascii string STRING, returns a sightly-encoded
Perl program with a binmode(STDOUT) and a print statement executed via
eval. When run, the program will print STRING. Note that STRING may
contain any character in the range 0-255. This function is used to
sightly-encode binary files.
- get_builtin_shapes
- Returns a list of the built-in shape names.
- get_eye_dir
- Returns the directory containing the .eye file
shapes. This is the EyeDrops sub-directory underneath where
EyeDrops.pm is located.
- get_eye_shapes
- Returns a list of the eye shapes in ascii-betical
order. An eye shape is just a file with a .eye extension residing
in the get_eye_dir directory.
- get_eye_keywords
- Returns a hash reference keyed by keyword, with the value
being the list of shapes containing the keyword.
- find_eye_shapes KEYWORDLIST
- Returns a list of the eye shapes in ascii-betical
order that contain all keywords in KEYWORDLIST. The keywords in
KEYWORDLIST are implicitly AND'ed together. Additionally, you may use OR
inside any KEYWORDLIST element. If this is unclear, see the examples in
"Shape Properties" section below.
- get_eye_string SHAPENAME
- Given a .eye SHAPENAME, returns the shape string.
- get_eye_properties SHAPENAME
- Given a .eye SHAPENAME, returns a hash reference of the
shape properties or undef if the shape has no properties.
- slurp_yerself
- Returns a string containing the contents of
EyeDrops.pm.
- make_triangle WIDTH
- Returns a triangle shaped string of WIDTH characters.
- make_siertri WIDTH
- Returns a Sierpinski triangle shaped string containing
2**WIDTH lines.
- make_banner WIDTH STRING
- Linux only. Returns a banner of STRING, using the Linux
command "/usr/games/banner -w WIDTH".
- border_shape SHAPESTRING GAP_LEFT GAP_RIGHT GAP_TOP
GAP_BOTTOM WIDTH_LEFT WIDTH_RIGHT WIDTH_TOP WIDTH_BOTTOM
- Put a border around a shape.
- invert_shape SHAPESTRING
- Invert a shape.
- reflect_shape SHAPESTRING
- Reflect a shape.
- reduce_shape SHAPESTRING FACT
- Reduce the size of a shape by a factor of FACT.
- expand_shape SHAPESTRING FACT
- Expand the size of a shape by a factor of FACT.
- rotate_shape SHAPESTRING DEGREES RTYPE FLIP
- Rotate a shape clockwise thru 90, 180 or 270 degrees.
RTYPE=0 big rotated shape, RTYPE=1 small rotated shape, RTYPE=2 squashed
rotated shape. FLIP=1 to flip (reflect) shape in addition to rotating it.
RTYPE and FLIP do not apply to 180 degrees.
- hjoin_shapes GAP SHAPESTRINGLIST
- Join the shapes specified by SHAPESTRINGLIST horizontally
with GAP spaces between each shape.
- pour_text SHAPESTRING TEXTSTRING GAP FILLTEXT
- Given a shape string SHAPESTRING, a string TEXTSTRING, and
a GAP between successive shapes, returns a properly shaped string. That
is, pour TEXTSTRING into SHAPESTRING. FILLTEXT (typically '#') is text to
be used as a filler for any leftover part of the shape (if not set, don't
fill in leftovers).
- pour_sightly SHAPESTRING PROGSTRING GAP RFILLVAR COMPACT
IH
- Given a shape string SHAPESTRING, a sightly-encoded program
string PROGSTRING, and a GAP between successive shapes, returns a properly
shaped program string. That is, pour PROGSTRING into SHAPESTRING. RFILLVAR
is either a reference to an array of filler variables or, alternatively, a
string to fill the leftover of the last shape with. Common filler strings
are '' for no filler at all, or '#' or ';' or ';#'. A filler variable is a
valid Perl variable consisting of two characters: "$" and a
punctuation character. For example, RFILLVAR = "[ '$:', '$^', '$~'
]". Do not use $; or $" or $_ as filler variables. If COMPACT is
1, use compact sightly encoding, if 0 use plain sightly encoding. If IH
(inform handler) is undef, prints status of what it is doing to STDERR;
you can override this by providing a subroutine reference taking a single
inform string argument. To shut it up, set IH to "sub {}".
- sightly HASHREF
- Given a hash reference, HASHREF, describing various
attributes, returns a properly shaped program string. There is no error
return; if something is badly wrong, "die" is called -- so wrap
the call to "sightly" in an eval block if you can't afford to
die.
The attributes that HASHREF may contain are:
Shape Describes the shape you want.
First, a built-in shape is looked for.
Next, a 'eye' shape (.eye file in the
get_eye_dir() directory unless overridden
by the EyeDir attribute) is looked for.
Finally, a file name is looked for.
ShapeString Describes the shape you want.
This time you specify a shape string.
SourceFile The source file name to convert.
SourceHandle Specify a file handle instead of a file name.
SourceString Specify a string instead of a file name.
BannerString String to use with built-in Shape 'banner'.
Regex Boolean. If set, try to embed source program
in a regular expression. Do not set this flag
when converting complex programs.
Compact Boolean. If set, use compact sightly encoding.
Print Boolean. If set, use a print statement instead
of the default eval statement. Set this flag
when converting text files (not programs).
Binary Boolean. Set if encoding a binary file.
Text Boolean. Set if pouring unsightly text.
TextFiller Filler string used with Text attribute.
For example, TextFiller => '#'.
Gap The number of lines between successive shapes.
Rotate Rotate the shape clockwise 90, 180 or 270 degrees.
RotateType 0 = big rotated shape,
1 = small rotated shape,
2 = squashed rotated shape.
RotateFlip Boolean. Set if want to flip (reflect) the shape
in addition to rotating it.
Reflect Boolean. Reflect the shape.
Reduce Reduce the size of the shape.
Expand Expand the size of the shape.
Invert Boolean. Invert the shape.
Indent Indent the shape. The number of spaces to indent.
TrailingSpaces Boolean. Ensure all lines of the shape are of equal
length, adding trailing spaces if required.
RemoveNewlines Boolean. Remove all newlines from the source before
conversion.
BorderGap Put a border around the shape. Gap between border
and the shape.
BorderGapLeft,BorderGapRight,BorderGapTop,BorderGapBottom
You can override BorderGap with one or more from
the above.
BorderWidth Put a border around the shape. Width of border.
BorderWidthLeft,BorderWidthRight,BorderWidthTop,BorderWidthBottom
You can override BorderWidth with one or more from
the above.
Width Ignored for .eye file shapes. For built-in shapes,
interpreted appropriately for the shape, typically the
shape width in characters. If no shape is specified,
a rectangular block of Width characters is generated.
EyeDir Normally .eye files are got from the EyeDrops
directory underneath where EyeDrops.pm is located.
You can override that by specifying a directory
containing the .eye shape files.
InformHandler By default, sightly prints status of what it is
doing to STDERR; you can override this by providing
a subroutine reference taking a single inform string
argument. To shut it up, set to sub {}.
TrapEvalDie Boolean.
Add closing 'die $@ if $@' to generated program.
When an eval code block calls the die function,
the program does not die; instead the die string
is returned to eval in $@. Using this flag allows
you to convert programs that call die.
TrapWarn Boolean.
Add leading 'local $SIG{__WARN__}=sub{};' to
generated program. This shuts up some warnings.
Use this option if generated program emits
'No such signal: SIGHUP at ...' when run with
warnings enabled.
FillerVar Reference to a list of 'filler variables'.
A filler variable is a Perl variable consisting
of two characters: $ and a punctuation character.
For example, FillerVar => [ '$:', '$^' ].
Do not use $; or $" or $_ as filler variables.
Alternatively, you may set this to '' if you don't
want any filler, or to a string (e.g. '#' or ';'
or ';#') to use instead of filler variables to
fill the leftover part of the last shape with.
Specifying a Shape¶
When you specify a shape like this:
sightly( { Shape => 'fred' ...
first a built-in "fred" shape is looked for, then EyeDrops looks for
the file
fred.eye in the
get_eye_dir directory. If you specify a
'/' or '.' in the Shape attribute, a file with that name is looked for
instead, for example:
sightly( { Shape => '/tmp/fred.eye' ...
Finally, you may specify a shape with a string, for example:
my $shapestr = <<'FLAMING_OSTRICHES';
#####
#######################
FLAMING_OSTRICHES
sightly ( { ShapeString => $shapestr ...
If you specify a shape without a source file:
print sightly( { Shape => 'camel' } );
a
no-op filler is used to fill the shape.
If you specify a source file without a shape:
print sightly( { SourceFile => 'helloworld.pl' } );
a shapeless sightly string without any spaces or newlines is generated. You can
break this string into fixed width lines via the Width attribute:
print sightly( { SourceFile => 'helloworld.pl',
Width => 40 } );
Generally, you should specify the Width attribute of
built-in shapes.
Notice that the Width attribute is ignored for
.eye file shapes.
Shape Reference¶
The
built-in shapes are:
banner Linux banner command (/usr/games/banner -w Width)
of text in BannerString attribute
srcbanner Linux banner command (/usr/games/banner -w Width)
of source text
siertri A Sierpinski triangle (2**Width lines)
triangle A triangle (width Width characters)
all A shape consisting of all .eye shapes joined together
(Width blank lines between each shape)
The
.eye file shapes distributed with this version of EyeDrops are:
a Horizontal banner of "a"
acme Perl/Parrot/Ponie Euro-hacker and modern artist who likes
the colour orange and enjoys having his bra-strap twanged
adrianh Perl qa expert
alien An alien (rumoured to be Ton Hospel, from the
Roswell archives circa 1974)
alpaca Lama pacos, from South America, with long shaggy hair
and related to the llama
autrijus The father of Pugs
baghdad Baghdad Bob aka Comical Ali
beer Beer glass designed by Matthew Byng-Maddick for the
cam.pm Beerfestival Perl Programming Contest 2002
bighorn Ovis canadensis (bighorn sheep) found in the Rocky Mountains
bleach Vertical banner of "use Acme::Bleach;"
bottle A bottle of beer
bottle2 Abbreviated version of shape bottle
bottle3 A bottle of champagne with a champagne glass
bra A bra
buffy Vertical banner of "Buffy"
buffy2 Buffy's angelic face
buffy3 Buffy riding a pony
buffy4 Horizontal banner of "Buffy"
camel Dromedary (Camelus dromedarius, one hump)
camel2 Another dromedary (from use.perl.org)
camel3 London.pm's bactrian camel at London zoo
campm Horizontal banner of "cam.pm"
candle A Christmas candle
china1 Chinese characters, roughly translated as
"God is added a year of seniority; human is added a
year of age, Spring fills the universe; luck and
happiness fills the family"
coffee A cup of coffee
cricket Australia are world champions in this game
damian The Acme namespace is all his fault
dan The father of parrot
debian Debian logo (contributed by Richard Hartmann)
dipsy Teletubbies Dipsy (also london.pm infobot name)
eugene Champion Perl golfer, Drs Eugene van der Pijll
of Utrecht, Holland
eye An eye
flag_canada Canada's flag, contributed by `/anick
gelly Featured speaker at every session of Y::E 2003, Paris
golfer A golfer hitting a one iron
halloween A witch riding a broomstick
heart A heart shape contributed by `/anick
hipowls A pair of hip owls
japh JAPHs were invented by Randal L Schwartz in 1988
jon Kick-started the Perl 6 development effort by smashing
a standard-issue white coffee mug against a hotel wall
jon_oxer Linux Australia bigwig (contributed by Paul Fenwick)
kangaroo A kangaroo
kansai_pm Kansai.pm's mascot (Tiger with Perl characters)
contributed by Takanori KAWAI (Japanese)
kermit Kermit the frog
koaladile A cross between a koala and a crocodile
larry Wall, Larry (as opposed to Russell Wall who is
Wall, Russ)
larry2 Caricature of Larry contributed by Ryan King
llama Llamas are so closely related to camels they can
breed with them (their progeny are called camas)
london Haiku "A Day in The Life of a London Perl Monger"
map_australia Map of Australia
map_italy Map of Italy
map_japan Map of Japan
map_uk Map of United Kingdom and Ireland
map_world1 World globe, Asian view
map_world2 World globe, African view
map_world3 World globe, American view
merlyn Just another Perl hacker, aka Randal L Schwartz
mongers Perl Mongers logo
moose A moose
moosecamel A moose and a camel (modelled after http://irclog.perlgeek.de)
mosquito A mosquito
music A musical symbol
naw Naked Arm Wrestling (Y::E 2002, Munich)
opera Opera browser logo (contributed by Cosimo)
panda A panda designed by Yanni Ellen Liu
parrot Originally an April fool's joke, the joke was that
it was not a joke
pgolf Perl Golf logo (inspired by `/anick)
pony Horizontal banner of "Pony"
pony2 Picture of a Pony
pugs Horizontal banner of "Pugs"
pugs2 Picture of a Pugs dog
riding Horizontal banner of "riding"
rose A rose
santa Santa Claus playing golf
santa2 Santa Claus carrying presents
saturn The planet Saturn
schwern is my bitch
schwern2 Shape schwern without the banner
simon The inventor of parrot
smiley A smiley face
smiley2 Pulling a face
smiley3 A sad face
snow Snowflake designed by Matthew Byng-Maddick for the
cam.pm Christmas Perl Programming Contest 2002
spider A spider (tarantula)
spoon A wooden spoon
tonick Pictorial representation of a golf contest between Ton
Hospel and `/anick; colourful but not very suspenseful
tpr Vertical banner of "The Perl Review"
uml A UML diagram
undies A pair of underpants
window A window
writing_perl Perl in camel-style by Takanori KAWAI (Japanese)
yanick Caricature of `/anick's noggin
yanick2 Uttered by `/anick during TPR02
yanick3 Pictorial version of yanick2
yanick4 Abbreviated version of shape yanick
It is easy to create your own shapes. For some ideas on shapes, point your
search engine at
Ascii Art or
Clip Art. If you generate some
nice shapes, please send them in so they can be included in future versions of
EyeDrops.
Shape Properties¶
All the
.eye shape files have a corresponding
.eyp shape property
file, specifying the shape's properties.
Currently, the allowed shape properties are:
name
nick
description
cpanid
author
authorcpanid
source
keywords
where valid keywords are:
face
person
perlhacker
animal
object
planet
map
flag
sport
underwear
hbanner
vbanner
logo
debian
opera
To give an example of how shape properties might be used, to find all shapes
that depict just the faces of perl hackers:
use Acme::EyeDrops qw(find_eye_shapes);
my @perlhackers = find_eye_shapes('face',
'person',
'perlhacker');
Note that there is an implicit AND between each keyword; that is, the above code
finds all shapes with face AND person AND perlhacker keywords.
Additionally, you may use OR in any argument, for example:
my @perlhackers = find_eye_shapes('face',
'person OR animal',
'perlhacker');
finds all shapes matching face AND (person OR animal) AND perlhacker.
Instead of using the API, as shown above, you may also use the
findshapes.pl command in the
demo directory:
findshapes.pl -h (for help)
findshapes.pl -v face person perlhacker
The last example displays the faces and properties of all perl hackers.
Please note that these shape properties are experimental and may change in
future A::E releases.
BUGS¶
A really diabolical shape with lots of single character lines will defeat the
shape-pouring algorithm.
You can eliminate all alphanumerics (via Regex => 1) only if the program to
be converted is careful with its use of regular expressions and $_. To convert
complex programs, you must use Regex => 0, which emits a leading unsightly
double "eval".
The code generated by Regex => 1 requires Perl 5.005 or higher in order to
run; when run on earlier versions, you will likely see the error message:
"Sequence (?{...) not recognized".
The converted program runs inside an "eval" which may cause problems
for non-trivial programs. A "die" statement or an "INIT"
block, for instance, may cause trouble. If desperate, give the
"TrapEvalDie" and "TrapWarn" attributes a go, and see if
they fix the problem.
If the program to be converted uses the Perl format variables $:, $~ or $^ you
may need to explicitly set the "FillerVar" attribute to a Perl
variable/s not used by the program.
Linux
/usr/games/banner does not support the following characters:
\ [ ] { } < > ^ _ | ~
When the CPAN Text::Banner module is enhanced, it will be used in place of the
Linux banner command.
AUTHOR¶
Andrew Savige <asavige@cpan.org>
SEE ALSO¶
Acme::EyeDrops lightning talk by Flavio Poletti at YAPC::Europe 2008 at
http://yapc.tv/.
Acme::EyeDrops in JPerl Advent Calendar (Japanese) at
http://perl-users.jp/articles/advent-calendar/2009/casual/08.html.
The history of Acme::Bleach, Acme::EyeDrops and related modules at
http://www.perlmonks.org/?node_id=967004.
Software Art page at
http://www.runme.org/.
Acme's Y::E 2002 naked arm wrestling movie at
http://astray.com/tmp/yapcbits3.mov.
Japanese translations of selected CPAN modules (including Acme::EyeDrops) can be
found at
http://perldoc.jp/docs/modules/. (Japanized Perl Resources
Project is at
https://sourceforge.jp/projects/perldocjp/).
Perl Obfuscation Engines, for example, yaoe by Perl Monk mtve, at
http://www.perlmonks.org/index.pl?node_id=161087.
More information on 99 bottles of beer can be found at
http://www.99-bottles-of-beer.net/ and
http://archive.develooper.com/fwp@perl.org/msg03193.html. Similar sites
exist for
hello world programs
http://www2.latech.edu/~acm/HelloWorld.shtml, and
quines
http://www.nyx.net/~gthompso/quine.htm.
To learn more about HQ9+ programming visit
http://www.cliff.biffle.org/esoterica/hq9plus.html and
http://search.cpan.org/dist/HQ9PLUS/.
Perl Monks Obfuscation section. In particular, ideas for EyeDrops shapes were
got from:
http://www.perlmonks.org/index.pl?node_id=45213 (Erudil's
camel code),
http://www.perlmonks.org/index.pl?node_id=285157
(Spaghetti Obfu),
http://www.perlmonks.org/index.pl?node_id=289733
(Just another Bach Hacker),
http://www.perlmonks.org/index.pl?node_id=329174 (hello world),
http://www.perlmonks.org/index.pl?node_id=188405 (Sierpinski Triangle),
http://www.perlmonks.org/index.pl?node_id=398757 (Halloween JAPH ?),
http://www.perlmonks.org/index.pl?node_id=397958 (Saturn).
The Y::E 2002
Dark Art of Obfuscation talk by Thomas Klausner at
http://domm.zsi.at/talks/obfu_yapc2002/.
Les Perl Mongueurs de Paris $A++ page at
http://paris.mongueurs.net/aplusplus.html.
Yanni Ellen Liu's excellent Ascii Art collection formerly at
http://www.cs.umanitoba.ca/~yliu/.
More information on
Baghdad Bob can be found at
http://www.welovetheiraqiinformationminister.com/.
More information on koaladiles (and their relationship to kwalitee) can be found
at
http://nntp.perl.org/group/perl.qa/3340.
The cam.pm Obfuscated Programming Contests at
http://cam.pm.org/projects_home.shtml.
Perl Golf was played monthly at
http://perlgolf.sourceforge.net/
and is now played mostly at
http://codegolf.com/. Ton Hospel's
excellent generic golf tester can be got from
http://www.xs4all.nl/~thospel/golf/gentest.pl.
The "--$|" idiom (exploited in the
A Somersaulting Camel
section) is "explained" in this thread:
http://archive.develooper.com/fwp@perl.org/msg01360.html.
Acme::Bleach Acme::Smirch Acme::Buffy Acme::Pony Acme::ChuckNorris
Acme::AsciiArt2HtmlTable Acme::AsciiArtinator
CREDITS¶
I blame Japhy and Ronald J Kimball and others on the fwp mailing list for
exposing the ''=~ trick, Jas Nagra for explaining his "Acme::Smirch"
module, and Rajah Ankur and Supremely Unorthodox Eric for provoking me.
I would also like to thank Ian Phillipps, Philip Newton, Ryan King, Michael G
Schwern, Robert G Werner, Simon Cozens, and others on the fwp mailing list for
their advice on ASCII Art, imaging programs, and on which picture of Larry to
use.
Thanks also to Mtv Europe, Ronald J Kimball and Eugene van der Pijll for their
help in golfing the program in the
Twelve Thousand and Thirty Two
Camels section. Keith Calvert Ivey also contributed some levity to this
section.
Ideas from Adam Antonik, Mtv Europe, Eugene van der Pijll, Ton Hospel and Keith
Calvert Ivey were used in the
Sierpinski Triangles section.
Thanks cog for the prod to add new Shape Properties feature.
The jon shape was derived from
http://www.spidereyeballs.com/os5/set1/small_os5_r06_9705.html. Kudos
to Elaine -HFB- Ashton for showing me this.
The merlyn shape was derived from this photo
http://www.stonehenge.com/merlyn/my_real_proof.jpg of Randal singing a
duet with Samantha Fox.
The simon shape was derived from a pencil sketch by the Japanese artist Eiko
Yamashita.
The candle, china1, panda and santa2 shapes were derived from similar ones at
Yanni Ellen Liu's Ascii Art collection.
COPYRIGHT¶
Copyright (c) 2001-2008 Andrew Savige. All rights reserved.
This program is free software; you can redistribute it and/or modify it under
the same terms as Perl itself.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.